From 3eab3e3687911be068872f3bf7653971b12a738d Mon Sep 17 00:00:00 2001 From: glyph Date: Tue, 18 Oct 2022 12:01:28 +0100 Subject: [PATCH] add and mount ap detail template --- peach-web/src/private_router.rs | 4 + .../src/routes/settings/network/ap_details.rs | 254 ++++++++++++------ peach-web/src/routes/settings/network/mod.rs | 1 + 3 files changed, 170 insertions(+), 89 deletions(-) diff --git a/peach-web/src/private_router.rs b/peach-web/src/private_router.rs index 90a89e1..248e375 100644 --- a/peach-web/src/private_router.rs +++ b/peach-web/src/private_router.rs @@ -240,6 +240,10 @@ pub fn mount_peachpub_routes( Response::html(routes::settings::network::modify_ap::build_template(request, Some(ssid))).reset_flash() }, + (GET) (/settings/network/wifi/{ssid: String}) => { + Response::html(routes::settings::network::ap_details::build_template(request, ssid)) + }, + (GET) (/settings/theme/{theme: String}) => { routes::settings::theme::set_theme(theme) }, diff --git a/peach-web/src/routes/settings/network/ap_details.rs b/peach-web/src/routes/settings/network/ap_details.rs index d6e5c82..6a67847 100644 --- a/peach-web/src/routes/settings/network/ap_details.rs +++ b/peach-web/src/routes/settings/network/ap_details.rs @@ -1,5 +1,7 @@ -use maud::{html, PreEscaped}; -use peach_network::{network, network::Scan}; +use std::collections::HashMap; + +use maud::{html, Markup, PreEscaped}; +use peach_network::{network, network::AccessPoint, NetworkError}; use rouille::Request; use crate::{ @@ -9,112 +11,186 @@ use crate::{ // ROUTE: /settings/network/wifi? -fn render_status_elements<'a>() -> () { - let wlan_ssid = match network::ssid("wlan0") { - Ok(Some(ssid)) => ssid, - _ => String::from("Not connected") +fn render_network_status_icon(ssid: &str, wlan_ssid: &str, ap_state: &str) -> Markup { + let status_label_value = if ssid == wlan_ssid { + "CONNECTED" + } else if ap_state == "Available" { + "AVAILABLE" + } else { + "NOT IN RANGE" }; - - if - div class="two-grid capsule{% if ssid == wlan_ssid %} success-border{% endif %}" title="PeachCloud network mode and status" { + html! { + (PreEscaped("")) + div class="grid-column-1" { + img id="wifiIcon" class="center icon" src="/icons/wifi.svg" alt="WiFi icon"; + label class="center label-small font-gray" for="wifiIcon" title="Access Point Status" { (status_label_value) } + } + } } -fn render_network_status_icon() { - +fn render_network_detailed_info(ssid: &str, ap_protocol: &str, ap_signal: Option) -> Markup { + let ap_signal_value = match ap_signal { + Some(signal) => signal.to_string(), + None => "Unknown".to_string(), + }; - (PreEscaped("")) - - div class="grid-column-1" { - img id="wifiIcon" class="center icon" src="/icons/wifi.svg" alt="WiFi icon"; - label class="center label-small font-gray" for="wifiIcon" title="Access Point Status">{% if ssid == wlan_ssid %}CONNECTED{% elif ap.state == "Available" %}AVAILABLE{% else %}NOT IN RANGE{% endif %}; - } -} - -fn render_network_detailed_info() -> Markup { html! { (PreEscaped("")) div class="grid-column-2" { label class="label-small font-gray" for="netSsid" title="WiFi network SSID" { "SSID" }; p id="netSsid" class="card-text" title="SSID" { (ssid) } label class="label-small font-gray" for="netSec" title="Security protocol" { "SECURITY" }; - p id="netSec" class="card-text" title="Security protocol in use by {{ ssid }}" { "{% if ap.detail %}{% if ap.detail.protocol != "" %}{{ ap.detail.protocol }}{% else %}None{% endif %}{% else %}Unknown{% endif %}" } + p id="netSec" class="card-text" title={ "Security protocol in use by " (ssid) } { (ap_protocol) } label class="label-small font-gray" for="netSig" title="Signal Strength" { "SIGNAL" }; - p id="netSig" class="card-text" title="Signal strength of WiFi access point" { "{% if ap.signal %}{{ ap.signal }}%{% else %}Unknown{% endif %}" } + p id="netSig" class="card-text" title="Signal strength of WiFi access point" { (ap_signal_value) } } } } -// fn render_network_card -// -fn render_buttons() -> Markup { +fn render_disconnect_form(ssid: &str) -> Markup { + html! { + form id="wifiDisconnect" action="/settings/network/wifi/disconnect" method="post" { + (PreEscaped("")) + input id="disconnectSsid" name="ssid" type="text" value=(ssid) style="display: none;"; + input id="disconnectWifi" class="button button-warning center" title="Disconnect from Network" type="submit" value="Disconnect"; + } + } +} + +fn render_connect_form(ssid: &str) -> Markup { + html! { + form id="wifiConnect" action="/settings/network/wifi/connect" method="post" { + (PreEscaped("")) + input id="connectSsid" name="ssid" type="text" value=(ssid) style="display: none;"; + input id="connectWifi" class="button button-primary center" title="Connect to Network" type="submit" value="Connect"; + } + } +} + +fn render_forget_form(ssid: &str) -> Markup { + html! { + form id="wifiForget" action="/settings/network/wifi/forget" method="post" { + (PreEscaped("")) + input id="forgetSsid" name="ssid" type="text" value=(ssid) style="display: none;"; + input id="forgetWifi" class="button button-warning center" title="Forget Network" type="submit" value="Forget"; + } + } +} + +fn render_buttons( + selected_ap: &str, + wlan_ssid: &str, + ap: &AccessPoint, + saved_wifi_networks: Vec, +) -> Markup { html! { (PreEscaped("")) - div class="card-container" style="padding-top: 0;" { - div id="buttonDiv" { - {%- if wlan_ssid == selected -%} - form id="wifiDisconnect" action="/settings/network/wifi/disconnect" method="post" { - (PreEscaped("")) - input id="disconnectSsid" name="ssid" type="text" value="{{ ssid }}" style="display: none;"; - input id="disconnectWifi" class="button button-warning center" title="Disconnect from Network" type="submit" value="Disconnect"; - } - {%- endif -%} - {%- if saved_aps -%} - {# Loop through the list of AP's with saved credentials #} - {%- for ap in saved_aps -%} - {# If the selected access point appears in the list, #} - {# display the Modify and Forget buttons. #} - {%- if ap.ssid == selected -%} - {# Set 'in_list' to true to allow correct Add button display #} - {% set_global in_list = true %} - {%- if wlan_ssid != selected and ap.state == "Available" -%} - form id="wifiConnect" action="/settings/network/wifi/connect" method="post" { - (PreEscaped("")) - input id="connectSsid" name="ssid" type="text" value="{{ ap.ssid }}" style="display: none;"; - input id="connectWifi" class="button button-primary center" title="Connect to Network" type="submit" value="Connect"; - } - {%- endif -%} - a class="button button-primary center" href="/settings/network/wifi/modify?ssid={{ ssid }}" { "Modify" } - form id="wifiForget" action="/settings/network/wifi/forget" method="post" { - (PreEscaped("")) - input id="forgetSsid" name="ssid" type="text" value="{{ ap.ssid }}" style="display: none;"; - input id="forgetWifi" class="button button-warning center" title="Forget Network" type="submit" value="Forget"; - } - {%- endif -%} - {%- endfor -%} - {%- endif -%} - {%- if in_list == false -%} - {# Display the Add button if AP creds not already in saved networks list #} - a class="button button-primary center" href="/settings/network/wifi/add?ssid={{ ssid }}" { "Add" } - {%- endif -%} - a class="button button-secondary center" href="/settings/network/wifi" title="Cancel" { "Cancel" }/ - -/// WiFi access point (AP) details. -pub fn build_template(request: &Request, selected_ap: String) -> PreEscaped { - let network_list_template = html! { - @if let Ok(Some(wlan_networks)) = network::all_networks("wlan0") { - @for ssid, ap in wlan_networks { - // select only the access point we are interested in displaying - @if ssid == selected_ap { - (PreEscaped("")) - div class="card center" { - (PreEscaped("")) - div class="two-grid capsule{% if ssid == wlan_ssid %} success-border{% endif %}" title="PeachCloud network mode and status" { - (PreEscaped("")) - // network status icon goes here - // ... - // network detailed info goes here - // ... - } - // buttons go here - // ... - - } - // flash - } - } - } + div id="buttons" { + @if wlan_ssid == selected_ap { + (render_disconnect_form(selected_ap)) } + @if saved_wifi_networks.contains(&selected_ap.to_string()) { + @if wlan_ssid != selected_ap && ap.state == "Available" { + (render_connect_form(selected_ap)) + } + a class="button button-primary center" href={ "/settings/network/wifi/modify?ssid=" (selected_ap) } { "Modify" } + (render_forget_form(selected_ap)) + } @else { + // display the Add button if AP creds not already in saved + // networks list + a class="button button-primary center" href={ "/settings/network/wifi/add?ssid=" (selected_ap) } { "Add" } + } + a class="button button-secondary center" href="/settings/network/wifi" title="Cancel" { "Cancel" } } } } + +/// Retrieve the list of all saved and in-range networks (including SSID and +/// AP details for each network), the list of all saved networks (SSIDs only) +/// and the SSID for the WiFi interface. +fn retrieve_network_data() -> ( + Result, NetworkError>, + Vec, + String, +) { + let all_wifi_networks = network::all_networks("wlan0"); + let saved_wifi_networks = match network::saved_networks() { + Ok(Some(ssids)) => ssids, + _ => Vec::new(), + }; + let wlan_ssid = match network::ssid("wlan0") { + Ok(Some(ssid)) => ssid, + _ => String::from("Not connected"), + }; + + (all_wifi_networks, saved_wifi_networks, wlan_ssid) +} + +/// WiFi access point (AP) template builder. +/// +/// Render a UI card with details about the selected access point, including +/// the connection state, security protocol being used, the SSID and the +/// signal strength. Buttons are also rendering based on the state of the +/// access point and whether or not credentials for the AP have previously +/// been saved. +/// +/// If the AP is available (ie. in-range) then a Connect button is rendered. +/// A Disconnect button is rendered if the WiFi client is currently +/// connected to the AP. +/// +/// If credentials have not previously been saved for the AP, an Add button is +/// rendered. Forget and Modify buttons are rendered if credentials for the AP +/// have previously been saved. +pub fn build_template(request: &Request, selected_ap: String) -> PreEscaped { + let (flash_name, flash_msg) = request.retrieve_flash(); + + let (all_wifi_networks, saved_wifi_networks, wlan_ssid) = retrieve_network_data(); + + let network_info_box_class = if selected_ap == wlan_ssid { + "two-grid capsule success-border" + } else { + "two-grid capsule" + }; + + let network_list_template = html! { + (PreEscaped("")) + div class="card center" { + @if let Ok(wlan_networks) = all_wifi_networks { + // select only the access point we are interested in displaying + @if let Some((ssid, ap)) = wlan_networks.get_key_value(&selected_ap) { + @let ap_protocol = match &ap.detail { + Some(detail) => detail.protocol.clone(), + None => "None".to_string() + }; + (PreEscaped("")) + div class=(network_info_box_class) title="PeachCloud network mode and status" { + (PreEscaped("")) + (render_network_status_icon(ssid, &wlan_ssid, &ap.state)) + (PreEscaped("")) + (render_network_detailed_info(ssid, &ap_protocol, ap.signal)) + } + (render_buttons(ssid, &wlan_ssid, ap, saved_wifi_networks)) + } @else { + p class="card-text list-item" { (selected_ap) " not found in saved or in-range networks" } + } + } @else { + p class="card-text list-item" { "No saved or in-range networks found" } + } + @if let (Some(name), Some(msg)) = (flash_name, flash_msg) { + (PreEscaped("")) + (templates::flash::build_template(name, msg)) + } + } + }; + + let body = templates::nav::build_template( + network_list_template, + "WiFi Networks", + Some("/settings/network"), + ); + + let theme = theme::get_theme(); + + templates::base::build_template(body, theme) +} diff --git a/peach-web/src/routes/settings/network/mod.rs b/peach-web/src/routes/settings/network/mod.rs index a55a2f0..666bc39 100644 --- a/peach-web/src/routes/settings/network/mod.rs +++ b/peach-web/src/routes/settings/network/mod.rs @@ -1,4 +1,5 @@ pub mod add_ap; +pub mod ap_details; pub mod configure_dns; // TODO: uncomment this once data usage feature is in place // pub mod data_usage_limits;