From cfff8556109029d80d4584e743de8c551302cb1c Mon Sep 17 00:00:00 2001 From: stepski Date: Tue, 13 Aug 2024 00:46:42 +0200 Subject: [PATCH 1/4] Modified client functions to manage data from the server storage, added few endpoints and improved styling --- management-ui/server.py | 96 +++- management-ui/static/m1-user-interface.js | 550 +++++++++++++--------- management-ui/static/style.css | 54 ++- management-ui/templates/index.html | 6 +- 4 files changed, 452 insertions(+), 254 deletions(-) diff --git a/management-ui/server.py b/management-ui/server.py index d4ec8086..a7460469 100644 --- a/management-ui/server.py +++ b/management-ui/server.py @@ -94,11 +94,36 @@ async def new_provisioning_session(app_id: Optional[str] = None, asp_id: Optiona return {"provisioning_session_id": provisioning_session_id} +""" +Endpoint: Fetch all provisioning sessions +HTTP Method: GET +Path: /fetch_all_sessions +Description: This endpoint will a list of all provisioning sessions. +""" +@app.get("/fetch_all_sessions") +async def get_all_sessions(): + session = await get_session(config) + session_ids = await session.provisioningSessionIds() + return {"session_ids": list(session_ids)} + +""" +Endpoint: Remove all provisioning sessions +HTTP Method: DELETE +Path: /remove_all_sessions +Description: This endpoint will remove all provisioning sessions from the memory. +""" +@app.delete("/remove_all_sessions") +async def remove_all_sessions(): + session = await get_session(config) + session._M1Session__provisioning_sessions.clear() + return {"message": "All sessions removed from the memory."} + + """ Endpoint: Delete Provisioning Session HTTP Method: DELETE Path: /delete_session/{provisioning_session_id} -Description: This endpoint will remove a provisioning session with all its resources. +Description: This endpoint will delete a particular provisioning session with all its resources. """ @app.delete("/delete_session/{provisioning_session_id}") async def cmd_delete_session(provisioning_session_id: str, config: Configuration = Depends(get_config)): @@ -200,26 +225,45 @@ async def get_provisioning_session_details(): @app.post("/certificate/{provisioning_session_id}") async def new_certificate(provisioning_session_id: str, csr: bool = Query(False), extra_domain_names: str = Query(None)): config = Configuration() + session = await get_session(config) + cert_id = None + try: - session = await get_session(config) - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) - if csr: - try: + if csr: result = await session.certificateNewSigningRequest(provisioning_session_id, extra_domain_names=extra_domain_names) if result is None: raise HTTPException(status_code=400, detail='Failed to reserve certificate') cert_id, csr_data = result return {"certificate_id": cert_id, "csr": csr_data} - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) - try: - cert_id = await session.createNewCertificate(provisioning_session_id, extra_domain_names=extra_domain_names) - if cert_id is None: - raise HTTPException(status_code=400, detail='Failed to create certificate') + else: + cert_id = await session.createNewCertificate(provisioning_session_id, extra_domain_names=extra_domain_names) + if cert_id is None: + raise HTTPException(status_code=400, detail='Failed to create certificate') + + session_data = session._M1Session__provisioning_sessions.get(provisioning_session_id) + if session_data is not None: + session_data['certificate_id'] = cert_id + return {"certificate_id": cert_id} + except Exception as e: raise HTTPException(status_code=500, detail=str(e)) + +""" +Endpoint: Get certificate ID for the provisioning session +HTTP Method: GET +Path: /get_certificate_id/{provisioning_session_id} +Description: This endpoint will return the certificate ID for a particular provisioning session. +""" +@app.get("/get_certificate_id/{provisioning_session_id}") +async def get_certificate_id(provisioning_session_id: str): + session = await get_session(config) + session_data = session._M1Session__provisioning_sessions.get(provisioning_session_id) + if session_data and 'certificate_id' in session_data: + return {"certificate_id": session_data['certificate_id']} + else: + raise HTTPException(status_code=404, detail="Certificate ID not found for the given session.") + """ Endpoint: Show certificate for provisioning session @@ -229,12 +273,11 @@ async def new_certificate(provisioning_session_id: str, csr: bool = Query(False) """ @app.get("/show_certificate/{provisioning_session_id}/{certificate_id}") async def show_certificate(provisioning_session_id: str, certificate_id: str, raw: Optional[bool] = False): - session = await get_session(config) cert_data = await session.certificateGet(provisioning_session_id, certificate_id) if cert_data is None: - raise HTTPException(status_code=404, detail=f"Unable to get certificate {certificate_id} for provisioning session {provisioning_session_id}") + raise HTTPException(status_code=404, detail=f"Certificate might not be activated for the provisioning session: {provisioning_session_id}") if raw: return {"raw_data": cert_data} @@ -341,6 +384,31 @@ async def create_policy_template(provisioning_session_id: str, request: Request) return {"policy_template_id": policy_template_id} else: raise HTTPException(status_code=400, detail="Addition of PolicyTemplate to provisioning session failed!") + +""" +Endpoint: Retrieve list policy template IDs for provisioning session +HTTP Method: GET +Path: /list_policy_template_ids/{provisioning_session_id} +Description: This endpoint will retrieve a list of policy template IDs for a particular provisioning session. +""" +@app.get("/list_policy_template_ids/{provisioning_session_id}") +async def list_policy_template_ids(provisioning_session_id: str): + provisionig_session_url = f"{OPTIONS_ENDPOINT}/{provisioning_session_id}" + try: + async with httpx.AsyncClient() as client: + response = await client.get(provisionig_session_url) + response.raise_for_status() + except httpx.HTTPStatusError as e: + raise HTTPException(status_code=e.response.status_code, detail=f"Error when listing policy template IDs: {str(e)}") + except httpx.RequestError as e: + raise HTTPException(status_code=500, detail="Connection error to M1 interface") + + all_data = response.json() + policy_template_ids = all_data.get("policyTemplateIds") + if not policy_template_ids: + raise HTTPException(status_code=404, detail="No PolicyTemplate found") + + return policy_template_ids """ diff --git a/management-ui/static/m1-user-interface.js b/management-ui/static/m1-user-interface.js index 77495bf4..3278f2ab 100644 --- a/management-ui/static/m1-user-interface.js +++ b/management-ui/static/m1-user-interface.js @@ -7,17 +7,38 @@ program. If this file is missing then the license can be retrieved from https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view */ -// Auxiliary function to clear storage when the connection is lost + +document.addEventListener('DOMContentLoaded', async () => { + await loadAllSessions(); +}); let operatingUrl = ''; +let isConnectionLost = false; -let isStorageCleared = false; -function clearStorage() { - localStorage.clear(); - let session_table = document.getElementById('session_table'); - for (let i = session_table.rows.length - 1; i > 0; i--) { - session_table.deleteRow(i); - } +function checkAFstatus() { + fetch(`${operatingUrl}connection_checker`) + .then(response => { + if (!response.ok && !isConnectionLost) { + document.getElementById('AFStatus').innerText = 'Connection with Application Function: ❌'; + clearTable(); + removeAllSessionsFromWebServer(); + showConnectionLostAlert(); + isConnectionLost = true; + } else if (response.ok) { + document.getElementById('AFStatus').innerText = 'Connection with Application Function: ✅'; + isConnectionLost = false; + } + }) + .catch(error => { + console.error('Error:', error); + if (!isConnectionLost) { + document.getElementById('AFStatus').innerText = 'Connection with AF interrupted.'; + clearTable(); + removeAllSessionsFromWebServer(); + showConnectionLostAlert(); + isConnectionLost = true; + } + }); } function showConnectionLostAlert() { @@ -29,154 +50,161 @@ function showConnectionLostAlert() { }); } -function checkAFstatus() { - fetch(`${operatingUrl}connection_checker`) +function policyTemplateOptionsCheck(session_id, fn) { + fetch(`${operatingUrl}policy_template_checker/${session_id}`).then(response => (response.ok && response.json()['enabled']), response => false).then(fn); +} + + +function clearTable() { + + const m1Table = document.getElementById('m1_table'); + while (m1Table.rows.length > 1) { + m1Table.deleteRow(1); + } +} + +function removeAllSessionsFromWebServer() { + fetch(`${operatingUrl}remove_all_sessions`, { + method: 'DELETE' + }) .then(response => { - if (!response.ok && !isStorageCleared) { - document.getElementById('AFStatus').innerText = 'Connection with Application Function: ❌'; - clearStorage(); - showConnectionLostAlert(); - isStorageCleared = true; - } else if (response.ok) { - document.getElementById('AFStatus').innerText = 'Connection with Application Function: ✅'; - isStorageCleared = false;} + if (!response.ok) { + console.error('Failed to purge all sessions from the backend server.'); + } }) .catch(error => { - console.error('Error:', error); - if (!isStorageCleared) { - document.getElementById('AFStatus').innerText = 'Connection with AF interrupted.'; - clearStorage(); - showConnectionLostAlert(); - isStorageCleared = true;} + console.error('Error clearing sessions from the backend server:', error); }); } -function do_on_policy_templates_check(session_id, fn) { - fetch(`${operatingUrl}policy_template_checker/${session_id}`).then(response => (response.ok && response.json()['enabled']), response => false).then(fn); -} - function addSessionToTable(sessionId) { - const sessionData = JSON.parse(localStorage.getItem(sessionId)); - const session_table = document.getElementById('session_table'); - let row = session_table.insertRow(-1); - - let cell1 = row.insertCell(0); // Session ID - let cell2 = row.insertCell(1); // Create CHC from JSON - let cell3 = row.insertCell(2); // Create and show certificate - let cell4 = row.insertCell(3); // Show Protocols button + const m1Table = document.getElementById('m1_table'); + let row = m1Table.insertRow(-1); + + let cell1 = row.insertCell(0); // Provisioning Session ID + let cell2 = row.insertCell(1); // Content Hosting Configuration + let cell3 = row.insertCell(2); // Certification (Create, Show) + let cell4 = row.insertCell(3); // Show Protocols let cell5 = row.insertCell(4); // Consumption Reporting (Set, Show, Delete) let cell6 = row.insertCell(5); // Dynamic Policies - let cell7 = row.insertCell(6); // Show Session Details - let cell8 = row.insertCell(7); // Metrics Reporting Configuration + let cell7 = row.insertCell(6); // Metrics Reporting Configuration + let cell8 = row.insertCell(7); // Session Details let cell9 = row.insertCell(8); // Delete session - + cell1.innerHTML = sessionId; + cell2.innerHTML = ``; + cell3.innerHTML = ` - ` - cell4.innerHTML = ``; + `; + + cell4.innerHTML = ``; + cell5.innerHTML = ` - + `; - cell6.innerHTML = ` - - -

loading... Checking feature availability...

`; - do_on_policy_templates_check(sessionId, enabled => { - buttons = cell6.getElementsByTagName('button'); - for (but of buttons) { - but.classList.remove('loading'); - but.disabled = !enabled; - if (!enabled) { - but.classList.add('disabled'); - } - } - msg = cell6.getElementsByTagName('p')[0]; - if (enabled) { - msg.innerText=''; - } else { - msg.innerText='Feature not configured'; - } - }); - cell7.innerHTML = ``; - cell8.innerHTML = ` - - `; - cell9.innerHTML = ``; + + cell6.innerHTML = ` +

loading... Checking feature availability...

+ Set
+ Show
+ Delete + `; + + policyTemplateOptionsCheck(sessionId, enabled => { + const links = cell6.getElementsByClassName('dynamic-policy-link'); + for (let link of links) { + link.classList.remove('disabled-link'); + if (!enabled) { + link.classList.add('disabled-link'); + link.style.pointerEvents = 'none'; + link.style.color = 'white'; + } else { + link.style.pointerEvents = 'auto'; + link.style.color = ''; + } + } + const msg = cell6.getElementsByClassName('policy-message')[0]; + msg.style.display = 'none'; + }); + + cell7.innerHTML = ` + + `; + + cell8.innerHTML = ``; + + cell9.innerHTML = ``; } -async function createNewSession() { - const response = await fetch(`${operatingUrl}create_session`, { method: 'POST' }); - if (!response.ok) { - Swal.fire({ - title: 'Failed to create new session!', - text: 'Please, make sure that Application Function is running!', - icon: 'error', - confirmButtonText: 'OK' - }); - return;} +async function loadAllSessions() { + try { + const response = await fetch(`${operatingUrl}fetch_all_sessions`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }); - const data = await response.json(); - Swal.fire({ - title: 'Created Provisioning Session', - text: `ID: ${data.provisioning_session_id}`, - icon: 'success', - confirmButtonText: 'OK' - }); - localStorage.setItem(data.provisioning_session_id, JSON.stringify({ - certificate_id: 'not yet created' - })); - addSessionToTable(data.provisioning_session_id); -} + if (!response.ok) { + Swal.fire({ + title: 'Failed to load data!', + text: 'Check connection with the 5GMS Application Function.', + icon: 'error', + confirmButtonText: 'OK' + }); + return; + } -function removeSessionFromTableAndStorage(sessionId) { - let session_table = document.getElementById('session_table'); - for (let i = 1; i < session_table.rows.length; i++) { - if (session_table.rows[i].cells[0].innerHTML === sessionId) { - session_table.deleteRow(i); - break; - } - } - localStorage.removeItem(sessionId); - localStorage.removeItem(sessionId + "-cert"); -} + const data = await response.json(); + const sessionIds = data.session_ids; -async function deleteProvisioningSession(sessionId) { - const result = await Swal.fire({ - title: 'Delete Provisioning Session?', - text: "Permanently remove provisioning session?", - icon: 'warning', - showCancelButton: true, - confirmButtonText: 'Yes', - cancelButtonText: 'No' - }); - if (result.value) { - const response = await fetch(`${operatingUrl}delete_session/${sessionId}`, { - method: 'DELETE' - }); + sessionIds.forEach(sessionId => { + addSessionToTable(sessionId); + }); - if (!response.ok) { - if (response.status === 404) { - removeSessionFromTableAndStorage(sessionId); - } else { - Swal.fire({ - title: 'Failed to delete the provisioning session.', - text: '', + } catch (error) { + //console.error('Error:', error); + Swal.fire({ + title: 'Error', + text: 'An unexpected error occurred while loading the sessions.', icon: 'error', confirmButtonText: 'OK' - }); - } + }); + } +}; + +async function createNewSession(){ + try { + const response = await fetch(`${operatingUrl}create_session`, { method: 'POST' }); + if (!response.ok) { + Swal.fire({ + title: 'Failed to create new provisioning session!', + text: 'Please, make sure that Application Function is running!', + icon: 'error', + confirmButtonText: 'OK' + }); return; } + const data = await response.json(); Swal.fire({ - title: `Deleted Provisioning session`, - text: `${sessionId} deleted with all resources`, + title: 'Created Provisioning Session', + text: `ID: ${data.provisioning_session_id}`, icon: 'success', confirmButtonText: 'OK' }); - removeSessionFromTableAndStorage(sessionId); + addSessionToTable(data.provisioning_session_id); } -} + catch (error) { + console.error('Caught error:', error); + Swal.fire({ + title: 'Network Error', + text: 'Failed to communicate with the backend server.', + icon: 'error', + confirmButtonText: 'OK' + }); + } +}; async function createChcFromJson(sessionId) { const response = await fetch(`${operatingUrl}set_stream/${sessionId}`, { @@ -203,10 +231,6 @@ async function createChcFromJson(sessionId) { }); } -async function getProvisioningSessionDetails() { - window.open(`${operatingUrl}details`, '_blank'); -} - async function createNewCertificate(sessionId) { try { const response = await fetch(`${operatingUrl}certificate/${sessionId}`, { @@ -214,30 +238,14 @@ async function createNewCertificate(sessionId) { }); const data = await response.json(); if (response.ok) { - - // Storing certificate_id to the local storage - let session_data = JSON.parse(localStorage.getItem(sessionId)) || {}; - session_data.certificate_id = data.certificate_id; - localStorage.setItem(sessionId, JSON.stringify(session_data)); - Swal.fire({ title: 'Certificate created successfully!', text: `ID: ${data.certificate_id}`, icon: 'success', confirmButtonText: 'OK' - }); - - let session_table = document.getElementById('session_table'); - - for (let i = 1; i < session_table.rows.length; i++) { - if (session_table.rows[i].cells[0].innerHTML === sessionId) { - let cell = session_table.rows[i].cells[2]; - cell.innerHTML = ` - `; - } - } + }); - } else { + } else { Swal.fire({ title: 'Error', text: data.detail || 'An error occurred', @@ -254,18 +262,44 @@ async function createNewCertificate(sessionId) { }); } } + +async function showCertificateDetails(sessionId) { + try { + const response = await fetch(`${operatingUrl}get_certificate_id/${sessionId}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }); -function showCertificateDetails(sessionId) { - let session_data = JSON.parse(localStorage.getItem(sessionId)); - let certificate_id = session_data.certificate_id; - window.open(`${operatingUrl}show_certificate/${sessionId}/${certificate_id}`, '_blank');l -} + if (!response.ok) { + Swal.fire({ + title: 'Error', + text: 'Certificate might not be activated for this Provisioning Session.', + icon: 'error', + confirmButtonText: 'OK' + }); + return; + } + + const data = await response.json(); + const certificateId = data.certificate_id; + window.open(`${operatingUrl}show_certificate/${sessionId}/${certificateId}`, '_blank'); -function getProtocols(sessionId) { - window.open(`${operatingUrl}show_protocol/${sessionId}`, '_blank'); + } catch (error) { + Swal.fire({ + title: 'Network Error', + text: 'Failed to communicate with the server.', + icon: 'error', + confirmButtonText: 'OK' + }); + } } +function showProtocols(sessionId) { + window.open(`${operatingUrl}show_protocol/${sessionId}`, '_blank'); +} async function setConsumptionReporting(session_id) { const { value: formValues, dismiss } = await Swal.fire({ @@ -445,9 +479,9 @@ async function setDynamicPolicy(sessionId) { `, - customClass:{ - popup: 'policies-swall' - }, + customClass: { + popup: 'policies-swall' + }, focusConfirm: false, preConfirm: () => { const externalReference = document.getElementById('externalReference').value; @@ -519,6 +553,7 @@ async function setDynamicPolicy(sessionId) { }, showCancelButton: true, }); + if (formValues) { try { const response = await fetch(`${operatingUrl}create_policy_template/${sessionId}`, { @@ -534,7 +569,6 @@ async function setDynamicPolicy(sessionId) { return; } const data = await response.json(); - localStorage.setItem(`policyTemplateId_${sessionId}`, data.policy_template_id); Swal.fire('Success', `Created Dynamic Policies with ID: "${data.policy_template_id}"`, 'success'); } catch (error) { console.error('Error:', error); @@ -544,74 +578,88 @@ async function setDynamicPolicy(sessionId) { } async function showDynamicPolicies(sessionId) { - const policy_template_id = localStorage.getItem(`policyTemplateId_${sessionId}`); - if (policy_template_id && policy_template_id !== 'undefined') { - const url = `${operatingUrl}show_policy_template/${sessionId}/${policy_template_id}`; + try { + const response = await fetch(`${operatingUrl}list_policy_template_ids/${sessionId}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }); + + if (!response.ok) { + Swal.fire('Error', 'Failed to retrieve policy templates.', 'error'); + return; + } + + const policyTemplateIds = await response.json(); + + if (policyTemplateIds.length > 0) { + const policyTemplateId = policyTemplateIds[0]; + const url = `${operatingUrl}show_policy_template/${sessionId}/${policyTemplateId}`; window.open(url, '_blank'); - } else { - Swal.fire({ - title: 'Error', - text: 'Policy template ID not found or not created yet.', - icon: 'error' - }); + } else { + Swal.fire('Error', 'No policy template IDs found for this session.', 'error'); + } + } catch (error) { + console.error('Error:', error); + Swal.fire('Error', 'An unexpected error occurred while retrieving the policy templates.', 'error'); } } async function deleteDynamicPolicy(sessionId) { - const policyTemplateId = localStorage.getItem(`policyTemplateId_${sessionId}`); - if (!policyTemplateId || policyTemplateId === 'undefined') { - await Swal.fire({ - title: 'Error', - text: 'Policy template ID not found or not created yet.', - icon: 'error', - confirmButtonText: 'OK' + try { + const response = await fetch(`${operatingUrl}list_policy_template_ids/${sessionId}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } }); - return; - } - const result = await Swal.fire({ - title: 'Delete Policy Template?', - text: `Are you sure you want to delete the policy template with ID: ${policyTemplateId}?`, - icon: 'warning', - showCancelButton: true, - confirmButtonText: 'Yes', - cancelButtonText: 'No', - }); - if (result.isConfirmed) { - try { - const response = await fetch(`${operatingUrl}delete_policy_template/${sessionId}/${policyTemplateId}`, { - method: 'DELETE' + + if (!response.ok) { + Swal.fire('Error', 'Failed to retrieve policy templates.', 'error'); + return; + } + + const policyTemplateIds = await response.json(); + if (policyTemplateIds.length > 0) { + const policyTemplateId = policyTemplateIds[0]; + + const result = await Swal.fire({ + title: 'Delete Policy Template?', + text: `Are you sure you want to delete the policy template with ID: ${policyTemplateId}?`, + icon: 'warning', + showCancelButton: true, + confirmButtonText: 'Yes', + cancelButtonText: 'No', }); - if (response.status === 204) { - await Swal.fire({ - title: 'Deleted!', - text: `The policy template with ID: ${policyTemplateId} has been deleted.`, - icon: 'success', - confirmButtonText: 'OK' - }); - localStorage.removeItem(`policyTemplateId_${sessionId}`); - } else { - let data; + if (result.isConfirmed) { try { - data = await response.json(); + const deleteResponse = await fetch(`${operatingUrl}delete_policy_template/${sessionId}/${policyTemplateId}`, { + method: 'DELETE' + }); + + if (deleteResponse.status === 204) { + Swal.fire({ + title: 'Deleted!', + text: `The policy template with ID: ${policyTemplateId} has been deleted.`, + icon: 'success', + confirmButtonText: 'OK' + }); + } else { + const data = await deleteResponse.json(); + Swal.fire('Failed to Delete', data.detail, 'error'); + } } catch (error) { - data = { detail: "Unknown error occurred." }; + Swal.fire('Error', 'Network error or server not responding.', 'error'); } - await Swal.fire({ - title: 'Failed to Delete', - text: data.detail, - icon: 'error', - confirmButtonText: 'OK' - }); } - } catch (error) { - await Swal.fire({ - title: 'Error', - text: 'Network error or server not responding.', - icon: 'error', - confirmButtonText: 'OK' - }); + } else { + Swal.fire('Error', 'No policy template IDs found for this session.', 'error'); } + } catch (error) { + console.error('Error:', error); + Swal.fire('Error', 'An unexpected error occurred while retrieving the policy templates.', 'error'); } } @@ -797,12 +845,76 @@ async function deleteMetrics(sessionId, metricsId) { } } -window.onload = function() { +async function getProvisioningSessionDetails() { + window.open(`${operatingUrl}details`, '_blank'); +} - setInterval(checkAFstatus, 5000); +async function deleteProvisioningSession(sessionId) { + const result = await Swal.fire({ + title: 'Delete Provisioning Session?', + text: "Permanently remove provisioning session and it resources?", + icon: 'warning', + showCancelButton: true, + confirmButtonText: 'Yes', + cancelButtonText: 'No' + }); - for (let i = 0; i < localStorage.length; i++) { - let session_id = localStorage.key(i); - addSessionToTable(session_id); + if (result.value) { + try { + const response = await fetch(`${operatingUrl}delete_session/${sessionId}`, { + method: 'DELETE' + }); + + if (!response.ok) { + if (response.status === 404) { + Swal.fire({ + title: 'Provisioning session not found.', + text: 'The session might have already been deleted.', + icon: 'info', + confirmButtonText: 'OK' + }); + removeSessionFromTable(sessionId); + } else { + Swal.fire({ + title: 'Failed to delete the provisioning session.', + text: '', + icon: 'error', + confirmButtonText: 'OK' + }); + } + return; + } + + Swal.fire({ + title: 'Deleted Provisioning session', + text: `${sessionId} deleted with all resources`, + icon: 'success', + confirmButtonText: 'OK' + }); + + removeSessionFromTable(sessionId); + + } catch (error) { + Swal.fire({ + title: 'Error', + text: 'An error occurred while deleting the session.', + icon: 'error', + confirmButtonText: 'OK' + }); + } } } + +function removeSessionFromTable(sessionId) { + let m1_table = document.getElementById('m1_table'); + for (let i = 1; i < m1_table.rows.length; i++) { + if (m1_table.rows[i].cells[0].innerHTML === sessionId) { + m1_table.deleteRow(i); + break; + } + } +} + +window.onload = function() { + setInterval(checkAFstatus, 5000); +} diff --git a/management-ui/static/style.css b/management-ui/static/style.css index d1d774cb..bdf88ce8 100644 --- a/management-ui/static/style.css +++ b/management-ui/static/style.css @@ -65,7 +65,7 @@ button { text-align: center; background-color: #0073ad; border: none; - border-radius: 12px; + border-radius: 2em; color: white; padding: 10px 20px; text-align: center; @@ -79,10 +79,11 @@ button { /*font-family: 'Poppins ExtraLight', sans-serif;*/ font-family: 'Poppins Semibold', sans-serif; border: 1px solid white; + } .create-session-button:hover { - background-color: green; + background-color: #2596be; color: white; } @@ -92,54 +93,72 @@ button { } /* Session table */ - -#session_table { - border-collapse: collapse; +#m1_table { + border-collapse: inherit; width: 1100px; max-width: 1500px; + /*border-radius: 3em;*/ margin: 0 auto; margin-top: 2em; + overflow: hidden; + border: 1px solid white; /* border color around the entire table */ + background-color: #2596be; } -#session_table td, #session_table th { - border: 2px solid #ddd; +#m1_table td, #m1_table th { + border: 1px solid white; padding: 8px; color: white; text-align: center; - width: 11.1%; word-wrap: break-word; vertical-align: middle; } -#session_table th { +#m1_table td:first-child, #m1_table th:first-child { + width: 25%; +} + +#m1_table td:not(:first-child), #m1_table th:not(:first-child) { + width: calc((100% - 25%) / 8); +} + +#m1_table th { font-family: 'Poppins Semibold'; padding-top: 12px; padding-bottom: 12px; text-align: center; background-color: #0073ad; color: white; - /* controls mmovement of the header with scrolling */ position: sticky; top: 0; z-index: 2; + border: 1px solid white; + font-size: 13px; } .table-button { display: block; - width: 75%; + width: 75%; + max-width: 120px; margin: 4px auto; - padding: 10px; - font-size: 14px; - height: 45px; + font-size: 12px; + padding: 6px 8px; + box-sizing: border-box; } -/* even-odd rows coloration */ +button { + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} -#session_table tr:nth-child(even) { +/* Even-odd rows coloration */ +#m1_table tr:nth-child(even) { background-color: #2596be; } -#session_table tr:nth-child(odd) { +#m1_table tr:nth-child(odd) { background-color: #2596be; } @@ -163,6 +182,7 @@ button { width: 50px; height: 50px; text-align: center; + font-size: .8em; } diff --git a/management-ui/templates/index.html b/management-ui/templates/index.html index 3646fa53..274c8e24 100644 --- a/management-ui/templates/index.html +++ b/management-ui/templates/index.html @@ -24,7 +24,6 @@

5GMS Application Provider

-

Provisioning Portal


Connection with Application Function...

@@ -38,7 +37,7 @@

Connection with Applicatio - +
@@ -47,8 +46,8 @@

Connection with Applicatio

- + @@ -59,7 +58,6 @@

Connection with Applicatio

- @@ -103,4 +103,4 @@

Connection with Applicatio - \ No newline at end of file + From ca85ce08ce0dac28445b12e2433dfbc2b2c0bc3b Mon Sep 17 00:00:00 2001 From: stepski Date: Thu, 22 Aug 2024 15:33:02 +0200 Subject: [PATCH 4/4] Addressed issues with the M1Session Class --- management-ui/server.py | 59 ++++++++++------------- management-ui/static/m1-user-interface.js | 16 +++++- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/management-ui/server.py b/management-ui/server.py index a7460469..bc3143b9 100644 --- a/management-ui/server.py +++ b/management-ui/server.py @@ -115,8 +115,15 @@ async def get_all_sessions(): @app.delete("/remove_all_sessions") async def remove_all_sessions(): session = await get_session(config) - session._M1Session__provisioning_sessions.clear() - return {"message": "All sessions removed from the memory."} + session_ids = await session.provisioningSessionIds() + + for session_id in session_ids: + result = await session.provisioningSessionDestroy(session_id) + if result is None: + raise HTTPException(status_code=404, detail=f"Provisioning Session {session_id} not found") + if not result: + raise HTTPException(status_code=500, detail=f"Failed to remove session {session_id}") + return {"message": "All provisioning sessions were destroyed"} """ @@ -173,8 +180,6 @@ async def set_stream(provisioning_session_id: str, config: Configuration = Depen Path: /details Description: This endpoint will return all details for all active provisioning sessions """ - -# Auxiliary function to get details for a particular provisioning session in async manner async def get_session_details(session, ps_id): details = {"Certificates": {}} certs = await session.certificateIds(ps_id) @@ -227,7 +232,6 @@ async def new_certificate(provisioning_session_id: str, csr: bool = Query(False) config = Configuration() session = await get_session(config) cert_id = None - try: if csr: result = await session.certificateNewSigningRequest(provisioning_session_id, extra_domain_names=extra_domain_names) @@ -239,31 +243,23 @@ async def new_certificate(provisioning_session_id: str, csr: bool = Query(False) cert_id = await session.createNewCertificate(provisioning_session_id, extra_domain_names=extra_domain_names) if cert_id is None: raise HTTPException(status_code=400, detail='Failed to create certificate') - - session_data = session._M1Session__provisioning_sessions.get(provisioning_session_id) - if session_data is not None: - session_data['certificate_id'] = cert_id - return {"certificate_id": cert_id} - except Exception as e: raise HTTPException(status_code=500, detail=str(e)) -""" -Endpoint: Get certificate ID for the provisioning session -HTTP Method: GET -Path: /get_certificate_id/{provisioning_session_id} -Description: This endpoint will return the certificate ID for a particular provisioning session. -""" -@app.get("/get_certificate_id/{provisioning_session_id}") -async def get_certificate_id(provisioning_session_id: str): + +@app.get("/list_certificate_ids/{provisioning_session_id}") +async def list_certificate_ids(provisioning_session_id: str): + config = Configuration() session = await get_session(config) - session_data = session._M1Session__provisioning_sessions.get(provisioning_session_id) - if session_data and 'certificate_id' in session_data: - return {"certificate_id": session_data['certificate_id']} - else: - raise HTTPException(status_code=404, detail="Certificate ID not found for the given session.") + try: + cert_ids = await session.certificateIds(provisioning_session_id) + if cert_ids is None: + raise HTTPException(status_code=404, detail="No certificates found for the provided provisioning session ID") + return {"certificate_ids": cert_ids} + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) """ Endpoint: Show certificate for provisioning session @@ -272,17 +268,12 @@ async def get_certificate_id(provisioning_session_id: str): Description: This endpoint will show a certificate for a particular provisioning session. """ @app.get("/show_certificate/{provisioning_session_id}/{certificate_id}") -async def show_certificate(provisioning_session_id: str, certificate_id: str, raw: Optional[bool] = False): +async def show_certificate(provisioning_session_id: str, certificate_id: str): session = await get_session(config) - cert_data = await session.certificateGet(provisioning_session_id, certificate_id) - - if cert_data is None: - raise HTTPException(status_code=404, detail=f"Certificate might not be activated for the provisioning session: {provisioning_session_id}") - - if raw: - return {"raw_data": cert_data} - - return {"certificate_details": cert_data} + cert = await session.certificateGet(provisioning_session_id, certificate_id) + if cert is None: + raise HTTPException(status_code=404, detail="Certificate not found") + return cert """ Endpoint: Show protocol for provisioning session diff --git a/management-ui/static/m1-user-interface.js b/management-ui/static/m1-user-interface.js index 07929cd0..268d5022 100644 --- a/management-ui/static/m1-user-interface.js +++ b/management-ui/static/m1-user-interface.js @@ -265,7 +265,7 @@ async function createNewCertificate(sessionId) { async function showCertificateDetails(sessionId) { try { - const response = await fetch(`${operatingUrl}get_certificate_id/${sessionId}`, { + const response = await fetch(`${operatingUrl}list_certificate_ids/${sessionId}`, { method: 'GET', headers: { 'Content-Type': 'application/json' @@ -283,8 +283,19 @@ async function showCertificateDetails(sessionId) { } const data = await response.json(); - const certificateId = data.certificate_id; + const certificateIds = data.certificate_ids; + if (!certificateIds || certificateIds.length === 0) { + Swal.fire({ + title: 'No Certificates for session', + text: 'No certificates found for this Provisioning Session.', + icon: 'info', + confirmButtonText: 'OK' + }); + return; + } + + const certificateId = certificateIds[0]; window.open(`${operatingUrl}show_certificate/${sessionId}/${certificateId}`, '_blank'); } catch (error) { @@ -297,6 +308,7 @@ async function showCertificateDetails(sessionId) { } } + function showProtocols(sessionId) { window.open(`${operatingUrl}show_protocol/${sessionId}`, '_blank'); }

Provisioning Session IDContent Protocols Consumption Reporting Dynamic PolicySession Details Metrics ReportingSession Details Remove Provisioning Session