Merge pull request 'Refactor route and template organisation' (#28) from route_reorganisation into main

Reviewed-on: #28
This commit is contained in:
glyph 2021-11-16 07:43:38 +00:00
commit dad9ee9392
51 changed files with 602 additions and 441 deletions

View File

@ -12,62 +12,30 @@ The peach-web stack currently consists of [Rocket](https://rocket.rs/) (Rust web
_Note: This is a work-in-progress._
### WEB ROUTES (`src/routes.rs`)
### Setup
| Endpoint | Method | Parameters | Description |
| --- | --- | --- | --- |
| `/` | GET | | Home |
| `/device` | GET | | Device status overview |
| `/device/reboot` | GET | | Reboot device |
| `/device/shutdown` | GET | | Shutdown device |
| `/login` | GET | | Login form |
| `/network` | GET | | Network status overview |
| `/network/ap/activate` | GET | | Activate WiFi access point mode |
| `/network/wifi` | GET | | List of networks |
| `/network/wifi?<ssid>` | GET | `ssid` | Details of a single network |
| `/network/wifi/activate` | GET | | Activate WiFi client mode |
| `/network/wifi/add` | GET | `ssid` (optional - prepopulation value of SSID in form) | Add a WiFi network |
| `/network/wifi/add` | POST | `ssid` & `pass` | Submit form to add a WiFi network |
| `/network/wifi/connect` | POST | `ssid` | Connect to the given WiFi network |
| `/network/wifi/disconnect` | POST | `ssid` | Disconnect from currently associated WiFi network |
| `/network/wifi/forget` | POST | `ssid` | Submit form to forget a saved WiFi network |
| `/network/wifi/modify?<ssid>` | GET | `ssid` | Form for updating a WiFi network password |
| `/network/wifi/modify` | POST | `ssid` & `pass` | Submit form to update a WiFi network password |
| `/network/wifi/usage` | GET | | Network data usage values and a form to update alert thresholds |
| `/network/wifi/usage` | POST | `rx_warn`, `rx_cut`, `tx_warn`, `tx_cut`, `rx_warn_flag`, `rx_cut_flag`, `tx_warn_flag`, `tx_cut_flag` | Submit form to update alert thresholds & set flags |
| `/network/wifi/usage/reset` | GET | | Reset the stored network data usage total to zero |
| `/network/dns` | GET | | View current DNS configurations |
| `/network/dns` | POST | | Modify DNS configurations |
| `/shutdown` | GET | | Shutdown menu |
Clone the `peach-workspace` repo:
### JSON API (`src/json_api.rs`)
`git clone https://git.coopcloud.tech/PeachCloud/peach-workspace`
All JSON API calls are prefixed by `/api/v1/`. This has been excluded from the table below to keep the table compact.
Move into the repo and compile:
| Endpoint | Method | Parameters | Description |
| --- | --- | --- | --- |
| `device/reboot` | POST | | Reboot device |
| `device/shutdown` | POST | | Shutdown device |
| `network/activate_ap` | POST | | Activate WiFi access point mode |
| `network/activate_client` | POST | | Activate WiFi client mode |
| `network/ip` | GET | | Returns IP address values for wlan0 & ap0 interfaces |
| `network/rssi` | GET | | Returns RSSI for connected WiFi network |
| `network/ssid` | GET | | Returns SSID for connected WiFi network |
| `network/state` | GET | | Returns state of wlan0 & ap0 interfaces |
| `network/status` | GET | | Returns status object for connected WiFi network |
| `network/wifi` | GET | | Returns scan results for in-range access-points |
| `network/wifi` | POST | `ssid` & `pass` | Submit SSID & password to create new WiFi connection |
| `network/wifi/connect` | POST | `ssid` | Submit SSID to connect to a given WiFi network |
| `network/wifi/disconnect` | POST | `ssid` | Disconnect from the currently associated WiFi network |
| `network/wifi/forget` | POST | `ssid` | Submit SSID to delete credentials for given WiFi network |
| `network/wifi/modify` | POST | `ssid` & `pass` | Submit SSID & password to update the credentials for given WiFi network |
| `/network/wifi/usage` | POST | `rx_warn`, `rx_cut`, `tx_warn`, `tx_cut`, `rx_warn_flag`, `rx_cut_flag`, `tx_warn_flag`, `tx_cut_flag` | Submit form to update alert thresholds & set flags |
| `/network/wifi/usage/reset` | POST | | Reset network data usage total |
| `ping` | GET | | Returns `pong!` if `peach-web` is running |
| `ping/network` | GET | | Returns `pong!` if `peach-network` microservice is running |
| `ping/oled` | GET | | Returns `pong!` if `peach-oled` microservice is running |
| `ping/stats` | GET | | Returns `pong!` if `peach-stats` microservice is running |
| `dns/configure` | POST | | Modify dns configurations |
`cd peach-workspace/peach-web`
`cargo build --release`
Run the tests:
`cargo test`
Move back to the `peach-workspace` directory:
`cd ..`
Run the binary:
`./target/release/peach-web`
_Note: Networking functionality requires peach-network microservice to be running._
### Environment
@ -75,13 +43,7 @@ The web application deployment mode is configured with the `ROCKET_ENV` environm
`export ROCKET_ENV=stage`
Other deployment modes are `dev` and `prod`. Read the [Rocket Environment Configurations docs](https://rocket.rs/v0.4/guide/configuration/#environment) for further information.
The WebSocket server port can be configured with `PEACH_WEB_WS` environment variable:
`export PEACH_WEB_WS=2333`
When not set, the value defaults to `5115`.
Other deployment modes are `dev` and `prod`. Read the [Rocket Environment Configurations docs](https://rocket.rs/v0.5-rc/guide/configuration/#environment-variables) for further information.
Logging is made available with `env_logger`:
@ -89,27 +51,6 @@ Logging is made available with `env_logger`:
Other logging levels include `debug`, `warn` and `error`.
### Setup
Clone this repo:
`git clone https://github.com/peachcloud/peach-web.git`
Move into the repo and compile:
`cd peach-web`
`cargo build --release`
Run the tests:
`cargo test`
Run the binary:
`./target/release/peach-web`
_Note: Networking functionality requires peach-network microservice to be running._
### Debian Packaging
A `systemd` service file and Debian maintainer scripts are included in the `debian` directory, allowing `peach-web` to be easily bundled as a Debian package (`.deb`). The `cargo-deb` [crate](https://crates.io/crates/cargo-deb) can be used to achieve this.
@ -144,7 +85,7 @@ Remove configuration files (not removed with `apt-get remove`):
### Design
`peach-web` is built on the Rocket webserver and Tera templating engine. It presents a web interface for interacting with the device. HTML is rendered server-side. Request handlers call JSON-RPC microservices and serve HTML and assets. A JSON API is exposed for remote calls and dynamic client-side content updates (via vanilla JavaScript following unobstructive design principles). Each Tera template is passed a context object. In the case of Rust, this object is a `struct` and must implement `Serialize`. The fields of the context object are available in the context of the template to be rendered.
`peach-web` is built on the Rocket webserver and Tera templating engine. It presents a web interface for interacting with the device. HTML is rendered server-side. Request handlers call JSON-RPC microservices and serve HTML and assets. A JSON API is exposed for remote calls and dynamic client-side content updates (via plain JavaScript following unobstructive design principles). Each Tera template is passed a context object. In the case of Rust, this object is a `struct` and must implement `Serialize`. The fields of the context object are available in the context of the template to be rendered.
### Licensing

View File

@ -38,100 +38,124 @@ use rocket_dyn_templates::Template;
use crate::routes::authentication::*;
use crate::routes::catchers::*;
use crate::routes::device::*;
use crate::routes::index::*;
use crate::routes::ping::*;
use crate::routes::scuttlebutt::*;
use crate::routes::status::device::*;
use crate::routes::status::ping::*;
use crate::routes::settings::admin::*;
use crate::routes::settings::dns::*;
use crate::routes::settings::menu::*;
use crate::routes::settings::network::*;
use crate::routes::settings::scuttlebutt::*;
pub type BoxError = Box<dyn std::error::Error>;
/// Create rocket instance & mount all routes.
fn init_rocket() -> Rocket<Build> {
rocket::build()
.mount(
"/scuttlebutt",
routes![
peers, // WEB ROUTE
friends, // WEB ROUTE
follows, // WEB ROUTE
followers, // WEB ROUTE
blocks, // WEB ROUTE
profile, // WEB ROUTE
private, // WEB ROUTE
follow, // WEB ROUTE
unfollow, // WEB ROUTE
block, // WEB ROUTE
publish, // WEB ROUTE
],
)
// GENERAL HTML ROUTES
.mount(
"/",
routes![
add_credentials, // WEB ROUTE
connect_wifi, // WEB ROUTE
disconnect_wifi, // WEB ROUTE
deploy_ap, // WEB ROUTE
deploy_client, // WEB ROUTE
device_stats, // WEB ROUTE
forget_wifi, // WEB ROUTE
help, // WEB ROUTE
index, // WEB ROUTE
login, // WEB ROUTE
login_post, // WEB ROUTE
logout, // WEB ROUTE
network_home, // WEB ROUTE
network_add_ssid, // WEB ROUTE
network_add_wifi, // WEB ROUTE
network_detail, // WEB ROUTE
reboot_cmd, // WEB ROUTE
shutdown_cmd, // WEB ROUTE
shutdown_menu, // WEB ROUTE
wifi_list, // WEB ROUTE
wifi_password, // WEB ROUTE
wifi_set_password, // WEB ROUTE
wifi_usage, // WEB ROUTE
wifi_usage_alerts, // WEB ROUTE
wifi_usage_reset, // WEB ROUTE
configure_dns, // WEB ROUTE
configure_dns_post, // WEB ROUTE
change_password, // WEB ROUTE
change_password_post, // WEB ROUTE
reset_password, // WEB ROUTE
reset_password_post, // WEB ROUTE
forgot_password_page, // WEB ROUTE
send_password_reset_post, // WEB ROUTE
configure_admin, // WEB ROUTE
add_admin, // WEB ROUTE
add_admin_post, // WEB ROUTE
delete_admin_post, // WEB ROUTE
activate_ap, // JSON API
activate_client, // JSON API
add_wifi, // JSON API
connect_ap, // JSON API
disconnect_ap, // JSON API
forget_ap, // JSON API
modify_password, // JSON API
ping_pong, // JSON API
ping_network, // JSON API
ping_oled, // JSON API
ping_stats, // JSON API
reset_data_total, // JSON API
return_ip, // JSON API
return_rssi, // JSON API
return_ssid, // JSON API
return_state, // JSON API
return_status, // JSON API
reboot_device, // JSON API
scan_networks, // JSON API
shutdown_device, // JSON API
update_wifi_alerts, // JSON API
save_dns_configuration_endpoint, // JSON API
save_password_form_endpoint, // JSON API
reset_password_form_endpoint, // JSON API
device_status,
help,
home,
login,
login_post,
logout,
reboot_cmd,
shutdown_cmd,
power_menu,
settings_menu,
],
)
// ADMIN SETTINGS HTML ROUTES
.mount(
"/settings/admin",
routes![
admin_menu,
configure_admin,
add_admin,
add_admin_post,
delete_admin_post,
change_password,
change_password_post,
reset_password,
reset_password_post,
forgot_password_page,
send_password_reset_post,
],
)
// NETWORK SETTINGS HTML ROUTES
.mount(
"/settings/network",
routes![
add_credentials,
connect_wifi,
configure_dns,
configure_dns_post,
disconnect_wifi,
deploy_ap,
deploy_client,
forget_wifi,
network_home,
add_ssid,
add_wifi,
network_detail,
wifi_list,
wifi_password,
wifi_set_password,
wifi_usage,
wifi_usage_alerts,
wifi_usage_reset,
],
)
// SCUTTLEBUTT SETTINGS HTML ROUTES
.mount("/settings/scuttlebutt", routes![ssb_settings_menu])
// SCUTTLEBUTT SOCIAL HTML ROUTES
.mount(
"/scuttlebutt",
routes![
peers, friends, follows, followers, blocks, profile, private, follow, unfollow,
block, publish,
],
)
// GENERAL JSON API ROUTES
.mount(
"/api/v1",
routes![ping_pong, ping_network, ping_oled, ping_stats,],
)
// ADMIN JSON API ROUTES
.mount(
"/api/v1/admin",
routes![
save_password_form_endpoint,
reset_password_form_endpoint,
reboot_device,
shutdown_device,
],
)
// NETWORK JSON API ROUTES
.mount(
"/api/v1/network",
routes![
activate_ap,
activate_client,
add_wifi_credentials,
connect_ap,
disconnect_ap,
forget_ap,
modify_password,
reset_data_total,
return_ip,
return_rssi,
return_ssid,
return_state,
return_status,
scan_networks,
update_wifi_alerts,
save_dns_configuration_endpoint,
],
)
.mount("/", FileServer::from("static"))

View File

@ -1,23 +1,20 @@
use log::{info};
use rocket::request::{FlashMessage};
use log::info;
use rocket::form::{Form, FromForm};
use rocket::request::FlashMessage;
use rocket::response::{Flash, Redirect};
use rocket::{get, post};
use rocket::serde::json::Json;
use rocket_dyn_templates::Template;
use rocket::serde::{Deserialize, Serialize};
use rocket::{get, post};
use rocket_dyn_templates::Template;
use peach_lib::password_utils;
use peach_lib::error::PeachError;
use peach_lib::password_utils;
use crate::error::PeachWebError;
use crate::utils::{build_json_response, TemplateOrRedirect};
use rocket::serde::json::Value;
use rocket::http::{Cookie, CookieJar, Status};
use rocket::request::{self, FromRequest, Request};
use rocket::http::{Cookie, CookieJar, Status};
use rocket::serde::json::Value;
// HELPERS AND STRUCTS FOR AUTHENTICATION WITH COOKIES
@ -32,7 +29,7 @@ pub struct Authenticated;
#[derive(Debug)]
pub enum LoginError {
UserNotLoggedIn
UserNotLoggedIn,
}
/// Request guard which returns an empty Authenticated struct from the request
@ -49,14 +46,10 @@ impl<'r> FromRequest<'r> for Authenticated {
.cookies()
.get_private(AUTH_COOKIE_KEY)
.and_then(|cookie| cookie.value().parse().ok())
.map(|_value: String| { Authenticated { } });
.map(|_value: String| Authenticated {});
match authenticated {
Some(auth) => {
request::Outcome::Success(auth)
},
None => {
request::Outcome::Failure((Status::Forbidden, LoginError::UserNotLoggedIn))
}
Some(auth) => request::Outcome::Success(auth),
None => request::Outcome::Failure((Status::Forbidden, LoginError::UserNotLoggedIn)),
}
}
}
@ -96,7 +89,6 @@ pub fn login(flash: Option<FlashMessage>) -> Template {
Template::render("login", &context)
}
#[derive(Debug, Deserialize, FromForm)]
pub struct LoginForm {
pub username: String,
@ -112,7 +104,7 @@ pub fn verify_login_form(login_form: LoginForm) -> Result<(), PeachError> {
password_utils::verify_password(&login_form.password)
}
#[post("/login", data="<login_form>")]
#[post("/login", data = "<login_form>")]
pub fn login_post(login_form: Form<LoginForm>, cookies: &CookieJar<'_>) -> TemplateOrRedirect {
let result = verify_login_form(login_form.into_inner());
match result {
@ -138,7 +130,6 @@ pub fn login_post(login_form: Form<LoginForm>, cookies: &CookieJar<'_>) -> Templ
}
}
// HELPERS AND ROUTES FOR /logout
#[get("/logout")]
@ -149,7 +140,6 @@ pub fn logout(cookies: &CookieJar<'_>) -> Flash<Redirect> {
Flash::success(Redirect::to("/login"), "Logged out")
}
// HELPERS AND ROUTES FOR /reset_password
#[derive(Debug, Deserialize, FromForm)]
@ -228,7 +218,7 @@ pub fn reset_password(flash: Option<FlashMessage>) -> Template {
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("password/reset_password", &context)
Template::render("settings/admin/reset_password", &context)
}
/// Password reset form request handler. This route is used by a user who is not logged in
@ -245,7 +235,7 @@ pub fn reset_password_post(reset_password_form: Form<ResetPasswordForm>) -> Temp
context.flash_name = Some("success".to_string());
let flash_msg = "New password is now saved. Return home to login".to_string();
context.flash_msg = Some(flash_msg);
Template::render("password/reset_password", &context)
Template::render("settings/admin/reset_password", &context)
}
Err(err) => {
let mut context = ChangePasswordContext::build();
@ -254,18 +244,15 @@ pub fn reset_password_post(reset_password_form: Form<ResetPasswordForm>) -> Temp
context.title = Some("Reset Password".to_string());
context.flash_name = Some("error".to_string());
context.flash_msg = Some(format!("Failed to reset password: {}", err));
Template::render("password/reset_password", &context)
Template::render("settings/admin/reset_password", &context)
}
}
}
/// JSON password reset form request handler. This route is used by a user who is not logged in
/// and is specifically for users who have forgotten their password.
/// All routes under /public/* are excluded from nginx basic auth via the nginx config.
#[post("/public/api/v1/reset_password", data = "<reset_password_form>")]
pub fn reset_password_form_endpoint(
reset_password_form: Json<ResetPasswordForm>,
) -> Value {
#[post("/reset_password", data = "<reset_password_form>")]
pub fn reset_password_form_endpoint(reset_password_form: Json<ResetPasswordForm>) -> Value {
let result = save_reset_password_form(reset_password_form.into_inner());
match result {
Ok(_) => {
@ -316,7 +303,7 @@ pub fn forgot_password_page(flash: Option<FlashMessage>) -> Template {
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("password/forgot_password", &context)
Template::render("settings/admin/forgot_password", &context)
}
/// Send password reset request handler. This route is used by a user who is not logged in
@ -335,7 +322,7 @@ pub fn send_password_reset_post() -> Template {
let flash_msg =
"A password reset link has been sent to the admin of this device".to_string();
context.flash_msg = Some(flash_msg);
Template::render("password/forgot_password", &context)
Template::render("settings/admin/forgot_password", &context)
}
Err(err) => {
let mut context = ChangePasswordContext::build();
@ -343,7 +330,7 @@ pub fn send_password_reset_post() -> Template {
context.title = Some("Send Password Reset".to_string());
context.flash_name = Some("error".to_string());
context.flash_msg = Some(format!("Failed to send password reset link: {}", err));
Template::render("password/forgot_password", &context)
Template::render("settings/admin/forgot_password", &context)
}
}
}
@ -375,11 +362,11 @@ pub fn save_password_form(password_form: PasswordForm) -> Result<(), PeachWebErr
}
/// Change password request handler. This is used by a user who is already logged in.
#[get("/settings/change_password")]
#[get("/change_password")]
pub fn change_password(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = ChangePasswordContext::build();
// set back icon link to network route
context.back = Some("/network".to_string());
context.back = Some("/settings/admin".to_string());
context.title = Some("Change Password".to_string());
// check to see if there is a flash message to display
if let Some(flash) = flash {
@ -387,39 +374,42 @@ pub fn change_password(flash: Option<FlashMessage>, _auth: Authenticated) -> Tem
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("password/change_password", &context)
Template::render("settings/admin/change_password", &context)
}
/// Change password form request handler. This route is used by a user who is already logged in.
#[post("/settings/change_password", data = "<password_form>")]
#[post("/change_password", data = "<password_form>")]
pub fn change_password_post(password_form: Form<PasswordForm>, _auth: Authenticated) -> Template {
let result = save_password_form(password_form.into_inner());
match result {
Ok(_) => {
let mut context = ChangePasswordContext::build();
// set back icon link to network route
context.back = Some("/network".to_string());
context.back = Some("/settings/admin".to_string());
context.title = Some("Change Password".to_string());
context.flash_name = Some("success".to_string());
context.flash_msg = Some("New password is now saved".to_string());
// template_dir is set in Rocket.toml
Template::render("password/change_password", &context)
Template::render("settings/admin/change_password", &context)
}
Err(err) => {
let mut context = ChangePasswordContext::build();
// set back icon link to network route
context.back = Some("/network".to_string());
context.back = Some("/settings/admin".to_string());
context.title = Some("Configure DNS".to_string());
context.flash_name = Some("error".to_string());
context.flash_msg = Some(format!("Failed to save new password: {}", err));
Template::render("password/change_password", &context)
Template::render("settings/admin/change_password", &context)
}
}
}
/// JSON change password form request handler.
#[post("/api/v1/settings/change_password", data = "<password_form>")]
pub fn save_password_form_endpoint(password_form: Json<PasswordForm>, _auth: Authenticated) -> Value {
#[post("/change_password", data = "<password_form>")]
pub fn save_password_form_endpoint(
password_form: Json<PasswordForm>,
_auth: Authenticated,
) -> Value {
let result = save_password_form(password_form.into_inner());
match result {
Ok(_) => {

View File

@ -1,7 +1,7 @@
use log::debug;
use rocket::{catch};
use rocket_dyn_templates::Template;
use rocket::catch;
use rocket::response::Redirect;
use rocket_dyn_templates::Template;
use serde::Serialize;
// HELPERS AND ROUTES FOR 404 ERROR
@ -34,7 +34,7 @@ pub fn not_found() -> Template {
context.flash_name = Some("error".to_string());
context.flash_msg = Some("No resource found for given URL".to_string());
Template::render("not_found", context)
Template::render("catchers/not_found", context)
}
// HELPERS AND ROUTES FOR 500 ERROR
@ -48,7 +48,7 @@ pub fn internal_error() -> Template {
context.flash_name = Some("error".to_string());
context.flash_msg = Some("Internal server error".to_string());
Template::render("internal_error", context)
Template::render("catchers/internal_error", context)
}
// HELPERS AND ROUTES FOR 403 FORBIDDEN
@ -57,4 +57,4 @@ pub fn internal_error() -> Template {
pub fn forbidden() -> Redirect {
debug!("403 Forbidden");
Redirect::to("/login")
}
}

View File

@ -24,13 +24,13 @@ impl HomeContext {
}
#[get("/")]
pub fn index(_auth: Authenticated) -> Template {
pub fn home(_auth: Authenticated) -> Template {
let context = HomeContext {
flash_name: None,
flash_msg: None,
title: None,
};
Template::render("index", &context)
Template::render("home", &context)
}
// HELPERS AND ROUTES FOR /help

View File

@ -1,7 +1,6 @@
pub mod authentication;
pub mod device;
pub mod catchers;
pub mod index;
pub mod ping;
pub mod scuttlebutt;
pub mod settings;
pub mod settings;
pub mod status;

View File

@ -45,7 +45,7 @@ pub fn private(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("messages", &context)
Template::render("scuttlebutt/messages", &context)
}
// HELPERS AND ROUTES FOR /peers
@ -81,7 +81,7 @@ pub fn peers(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("peers", &context)
Template::render("scuttlebutt/peers", &context)
}
// HELPERS AND ROUTES FOR /post/publish
@ -209,7 +209,7 @@ pub fn profile(
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("profile", &context)
Template::render("scuttlebutt/profile", &context)
}
// HELPERS AND ROUTES FOR /friends
@ -247,7 +247,7 @@ pub fn friends(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("peers_list", &context)
Template::render("scuttlebutt/peers_list", &context)
}
// HELPERS AND ROUTES FOR /follows
@ -285,7 +285,7 @@ pub fn follows(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("peers_list", &context)
Template::render("scuttlebutt/peers_list", &context)
}
// HELPERS AND ROUTES FOR /followers
@ -323,7 +323,7 @@ pub fn followers(flash: Option<FlashMessage>, _auth: Authenticated) -> Template
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("peers_list", &context)
Template::render("scuttlebutt/peers_list", &context)
}
// HELPERS AND ROUTES FOR /blocks
@ -361,5 +361,5 @@ pub fn blocks(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("peers_list", &context)
Template::render("scuttlebutt/peers_list", &context)
}

View File

@ -1,12 +1,12 @@
use rocket::serde::{Deserialize, Serialize};
use rocket::{
form::{Form, FromForm},
get, post,
request::FlashMessage,
form::{Form, FromForm},
response::{Flash, Redirect},
uri,
};
use rocket_dyn_templates::Template;
use rocket::serde::{Deserialize, Serialize};
use peach_lib::config_manager;
use peach_lib::config_manager::load_peach_config;
@ -14,7 +14,44 @@ use peach_lib::config_manager::load_peach_config;
use crate::error::PeachWebError;
use crate::routes::authentication::Authenticated;
// HELPERS AND ROUTES FOR /settings/configure_admin
// HELPERS AND ROUTES FOR /settings/admin
#[derive(Debug, Serialize)]
pub struct AdminMenuContext {
pub back: Option<String>,
pub title: Option<String>,
pub flash_name: Option<String>,
pub flash_msg: Option<String>,
}
impl AdminMenuContext {
pub fn build() -> AdminMenuContext {
AdminMenuContext {
back: None,
title: None,
flash_name: None,
flash_msg: None,
}
}
}
/// Administrator settings menu.
#[get("/")]
pub fn admin_menu(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = AdminMenuContext::build();
// set back icon link to settings route
context.back = Some("/settings".to_string());
context.title = Some("Administrator Settings".to_string());
// check to see if there is a flash message to display
if let Some(flash) = flash {
// add flash message contents to the context object
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("settings/admin/menu", &context)
}
// HELPERS AND ROUTES FOR /settings/admin/configure
#[derive(Debug, Serialize)]
pub struct ConfigureAdminContext {
@ -40,11 +77,11 @@ impl ConfigureAdminContext {
}
/// View and delete currently configured admin.
#[get("/settings/configure_admin")]
#[get("/configure")]
pub fn configure_admin(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = ConfigureAdminContext::build();
// set back icon link to network route
context.back = Some("/network".to_string());
// set back icon link to settings route
context.back = Some("/settings/admin".to_string());
context.title = Some("Configure Admin".to_string());
// check to see if there is a flash message to display
if let Some(flash) = flash {
@ -52,7 +89,7 @@ pub fn configure_admin(flash: Option<FlashMessage>, _auth: Authenticated) -> Tem
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("admin/configure_admin", &context)
Template::render("settings/admin/configure_admin", &context)
}
// HELPERS AND ROUTES FOR /settings/admin/add
@ -83,14 +120,14 @@ impl AddAdminContext {
pub fn save_add_admin_form(admin_form: AddAdminForm) -> Result<(), PeachWebError> {
let _result = config_manager::add_ssb_admin_id(&admin_form.ssb_id)?;
// if the previous line didn't throw an error then it was a success
// if the previous line didn't throw an error then it was a success
Ok(())
}
#[get("/settings/admin/add")]
#[get("/add")]
pub fn add_admin(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = AddAdminContext::build();
context.back = Some("/settings/configure_admin".to_string());
context.back = Some("/settings/admin/configure".to_string());
context.title = Some("Add Admin".to_string());
// check to see if there is a flash message to display
if let Some(flash) = flash {
@ -99,10 +136,10 @@ pub fn add_admin(flash: Option<FlashMessage>, _auth: Authenticated) -> Template
context.flash_msg = Some(flash.message().to_string());
};
// template_dir is set in Rocket.toml
Template::render("admin/add_admin", &context)
Template::render("settings/admin/add_admin", &context)
}
#[post("/settings/admin/add", data = "<add_admin_form>")]
#[post("/add", data = "<add_admin_form>")]
pub fn add_admin_post(add_admin_form: Form<AddAdminForm>, _auth: Authenticated) -> Flash<Redirect> {
let result = save_add_admin_form(add_admin_form.into_inner());
let url = uri!(configure_admin);
@ -119,8 +156,11 @@ pub struct DeleteAdminForm {
pub ssb_id: String,
}
#[post("/settings/admin/delete", data = "<delete_admin_form>")]
pub fn delete_admin_post(delete_admin_form: Form<DeleteAdminForm>, _auth: Authenticated) -> Flash<Redirect> {
#[post("/delete", data = "<delete_admin_form>")]
pub fn delete_admin_post(
delete_admin_form: Form<DeleteAdminForm>,
_auth: Authenticated,
) -> Flash<Redirect> {
let result = config_manager::delete_ssb_admin_id(&delete_admin_form.ssb_id);
let url = uri!(configure_admin);
match result {

View File

@ -1,12 +1,14 @@
use log::info;
use rocket::{
form::{Form, FromForm},
get, post,
request::FlashMessage,
form::{Form, FromForm}
serde::{
json::{Json, Value},
Deserialize, Serialize,
},
};
use rocket::serde::json::Json;
use rocket_dyn_templates::Template;
use rocket::serde::{Deserialize, Serialize};
use peach_lib::config_manager;
use peach_lib::config_manager::load_peach_config;
@ -22,7 +24,6 @@ use peach_lib::jsonrpc_core::types::error::ErrorCode;
use crate::error::PeachWebError;
use crate::routes::authentication::Authenticated;
use crate::utils::build_json_response;
use rocket::serde::json::Value;
#[derive(Debug, Deserialize, FromForm)]
pub struct DnsForm {
@ -113,11 +114,11 @@ impl ConfigureDNSContext {
}
}
#[get("/network/dns")]
#[get("/dns")]
pub fn configure_dns(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = ConfigureDNSContext::build();
// set back icon link to network route
context.back = Some("/network".to_string());
context.back = Some("/settings/network".to_string());
context.title = Some("Configure DNS".to_string());
// check to see if there is a flash message to display
if let Some(flash) = flash {
@ -125,35 +126,35 @@ pub fn configure_dns(flash: Option<FlashMessage>, _auth: Authenticated) -> Templ
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("configure_dns", &context)
Template::render("settings/network/configure_dns", &context)
}
#[post("/network/dns", data = "<dns>")]
#[post("/dns", data = "<dns>")]
pub fn configure_dns_post(dns: Form<DnsForm>, _auth: Authenticated) -> Template {
let result = save_dns_configuration(dns.into_inner());
match result {
Ok(_) => {
let mut context = ConfigureDNSContext::build();
// set back icon link to network route
context.back = Some("/network".to_string());
context.back = Some("/settings/network".to_string());
context.title = Some("Configure DNS".to_string());
context.flash_name = Some("success".to_string());
context.flash_msg = Some("New dynamic dns configuration is now enabled".to_string());
Template::render("configure_dns", &context)
Template::render("settings/network/configure_dns", &context)
}
Err(err) => {
let mut context = ConfigureDNSContext::build();
// set back icon link to network route
context.back = Some("/network".to_string());
context.back = Some("/settings/network".to_string());
context.title = Some("Configure DNS".to_string());
context.flash_name = Some("error".to_string());
context.flash_msg = Some(format!("Failed to save dns configurations: {}", err));
Template::render("configure_dns", &context)
Template::render("settings/network/configure_dns", &context)
}
}
}
#[post("/api/v1/dns/configure", data = "<dns_form>")]
#[post("/dns/configure", data = "<dns_form>")]
pub fn save_dns_configuration_endpoint(dns_form: Json<DnsForm>, _auth: Authenticated) -> Value {
let result = save_dns_configuration(dns_form.into_inner());
match result {

View File

@ -0,0 +1,41 @@
use rocket::{get, request::FlashMessage, serde::Serialize};
use rocket_dyn_templates::Template;
use crate::routes::authentication::Authenticated;
// HELPERS AND ROUTES FOR /settings
#[derive(Debug, Serialize)]
pub struct SettingsMenuContext {
pub back: Option<String>,
pub title: Option<String>,
pub flash_name: Option<String>,
pub flash_msg: Option<String>,
}
impl SettingsMenuContext {
pub fn build() -> SettingsMenuContext {
SettingsMenuContext {
back: None,
title: None,
flash_name: None,
flash_msg: None,
}
}
}
/// View and delete currently configured admin.
#[get("/settings")]
pub fn settings_menu(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = SettingsMenuContext::build();
// set back icon link to network route
context.back = Some("/".to_string());
context.title = Some("Settings".to_string());
// check to see if there is a flash message to display
if let Some(flash) = flash {
// add flash message contents to the context object
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("settings/menu", &context)
}

View File

@ -1,3 +1,5 @@
pub mod admin;
pub mod dns;
pub mod network;
pub mod menu;
pub mod network;
pub mod scuttlebutt;

View File

@ -1,27 +1,27 @@
use log::{debug, warn};
use rocket::{
get,
post,
request::FlashMessage,
form::{Form, FromForm},
get, post,
request::FlashMessage,
response::{Flash, Redirect},
serde::{
json::{json, Json, Value},
Deserialize, Serialize,
},
uri, UriDisplayQuery,
};
use rocket::serde::json::{json, Json};
use rocket_dyn_templates::Template;
use rocket::serde::{Deserialize, Serialize};
use std::collections::HashMap;
use peach_lib::network_client;
use peach_lib::network_client::{AccessPoint, Networks, Scan};
use peach_lib::stats_client::Traffic;
use crate::routes::authentication::Authenticated;
use crate::utils::build_json_response;
use crate::utils::monitor;
use crate::utils::monitor::{Alert, Data, Threshold};
use crate::utils::build_json_response;
use crate::routes::authentication::Authenticated;
use rocket::serde::json::Value;
// STRUCTS USED BY NETWORK ROUTES
@ -36,9 +36,9 @@ pub struct WiFi {
pub pass: String,
}
// HELPERS AND ROUTES FOR /network/wifi/usage/reset
// HELPERS AND ROUTES FOR /settings/network/wifi/usage/reset
#[get("/network/wifi/usage/reset")]
#[get("/wifi/usage/reset")]
pub fn wifi_usage_reset(_auth: Authenticated) -> Flash<Redirect> {
let url = uri!(wifi_usage);
match monitor::reset_data() {
@ -50,7 +50,7 @@ pub fn wifi_usage_reset(_auth: Authenticated) -> Flash<Redirect> {
}
}
#[post("/network/wifi/connect", data = "<network>")]
#[post("/wifi/connect", data = "<network>")]
pub fn connect_wifi(network: Form<Ssid>, _auth: Authenticated) -> Flash<Redirect> {
let ssid = &network.ssid;
let url = uri!(network_detail(ssid = ssid));
@ -63,7 +63,7 @@ pub fn connect_wifi(network: Form<Ssid>, _auth: Authenticated) -> Flash<Redirect
}
}
#[post("/network/wifi/disconnect", data = "<network>")]
#[post("/wifi/disconnect", data = "<network>")]
pub fn disconnect_wifi(network: Form<Ssid>, _auth: Authenticated) -> Flash<Redirect> {
let ssid = &network.ssid;
let url = uri!(network_home);
@ -73,7 +73,7 @@ pub fn disconnect_wifi(network: Form<Ssid>, _auth: Authenticated) -> Flash<Redir
}
}
#[post("/network/wifi/forget", data = "<network>")]
#[post("/wifi/forget", data = "<network>")]
pub fn forget_wifi(network: Form<Ssid>, _auth: Authenticated) -> Flash<Redirect> {
let ssid = &network.ssid;
let url = uri!(network_home);
@ -86,10 +86,10 @@ pub fn forget_wifi(network: Form<Ssid>, _auth: Authenticated) -> Flash<Redirect>
}
}
#[get("/network/wifi/modify?<ssid>")]
#[get("/wifi/modify?<ssid>")]
pub fn wifi_password(ssid: &str, flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = NetworkAddContext {
back: Some("/network/wifi".to_string()),
back: Some("/settings/network/wifi".to_string()),
flash_name: None,
flash_msg: None,
selected: Some(ssid.to_string()),
@ -102,10 +102,10 @@ pub fn wifi_password(ssid: &str, flash: Option<FlashMessage>, _auth: Authenticat
context.flash_msg = Some(flash.message().to_string());
};
// template_dir is set in Rocket.toml
Template::render("network_modify", &context)
Template::render("settings/network/network_modify", &context)
}
#[post("/network/wifi/modify", data = "<wifi>")]
#[post("/wifi/modify", data = "<wifi>")]
pub fn wifi_set_password(wifi: Form<WiFi>, _auth: Authenticated) -> Flash<Redirect> {
let ssid = &wifi.ssid;
let pass = &wifi.pass;
@ -119,7 +119,7 @@ pub fn wifi_set_password(wifi: Form<WiFi>, _auth: Authenticated) -> Flash<Redire
}
}
// HELPERS AND ROUTES FOR /network
// HELPERS AND ROUTES FOR /settings/network
#[derive(Debug, Serialize)]
pub struct NetworkContext {
@ -273,12 +273,12 @@ impl NetworkContext {
}
}
#[get("/network")]
#[get("/")]
pub fn network_home(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
// assign context through context_builder call
let mut context = NetworkContext::build();
// set back button (nav) url
context.back = Some("/".to_string());
context.back = Some("/settings".to_string());
// set page title
context.title = Some("Network Configuration".to_string());
// check to see if there is a flash message to display
@ -288,25 +288,28 @@ pub fn network_home(flash: Option<FlashMessage>, _auth: Authenticated) -> Templa
context.flash_msg = Some(flash.message().to_string());
};
// template_dir is set in Rocket.toml
Template::render("network_card", &context)
Template::render("settings/network/network_card", &context)
}
// HELPERS AND ROUTES FOR /network/ap/activate
// HELPERS AND ROUTES FOR /settings/network/ap/activate
#[get("/network/ap/activate")]
#[get("/ap/activate")]
pub fn deploy_ap(_auth: Authenticated) -> Flash<Redirect> {
// activate the wireless access point
debug!("Activating WiFi access point.");
match network_client::activate_ap() {
Ok(_) => Flash::success(Redirect::to("/network"), "Activated WiFi access point"),
Ok(_) => Flash::success(
Redirect::to("/settings/network"),
"Activated WiFi access point",
),
Err(_) => Flash::error(
Redirect::to("/network"),
Redirect::to("/settings/network"),
"Failed to activate WiFi access point",
),
}
}
// HELPERS AND ROUTES FOR /network/wifi
// HELPERS AND ROUTES FOR /settings/network/wifi
#[derive(Debug, Serialize)]
pub struct NetworkListContext {
@ -375,11 +378,11 @@ impl NetworkListContext {
}
}
#[get("/network/wifi")]
#[get("/wifi")]
pub fn wifi_list(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
// assign context through context_builder call
let mut context = NetworkListContext::build();
context.back = Some("/network".to_string());
context.back = Some("/settings/network".to_string());
context.title = Some("WiFi Networks".to_string());
// check to see if there is a flash message to display
if let Some(flash) = flash {
@ -388,10 +391,10 @@ pub fn wifi_list(flash: Option<FlashMessage>, _auth: Authenticated) -> Template
context.flash_msg = Some(flash.message().to_string());
};
// template_dir is set in Rocket.toml
Template::render("network_list", &context)
Template::render("settings/network/network_list", &context)
}
// HELPERS AND ROUTES FOR /network/wifi<ssid>
// HELPERS AND ROUTES FOR /settings/network/wifi<ssid>
#[derive(Debug, Serialize)]
pub struct NetworkDetailContext {
@ -540,11 +543,11 @@ impl NetworkDetailContext {
}
}
#[get("/network/wifi?<ssid>")]
#[get("/wifi?<ssid>")]
pub fn network_detail(ssid: &str, flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
// assign context through context_builder call
let mut context = NetworkDetailContext::build();
context.back = Some("/network/wifi".to_string());
context.back = Some("/settings/network/wifi".to_string());
context.title = Some("WiFi Network".to_string());
context.selected = Some(ssid.to_string());
// check to see if there is a flash message to display
@ -554,28 +557,31 @@ pub fn network_detail(ssid: &str, flash: Option<FlashMessage>, _auth: Authentica
context.flash_msg = Some(flash.message().to_string());
};
// template_dir is set in Rocket.toml
Template::render("network_detail", &context)
Template::render("settings/network/network_detail", &context)
}
// HELPERS AND ROUTES FOR /network/wifi/activate
// HELPERS AND ROUTES FOR /settings/network/wifi/activate
#[get("/network/wifi/activate")]
#[get("/wifi/activate")]
pub fn deploy_client(_auth: Authenticated) -> Flash<Redirect> {
// activate the wireless client
debug!("Activating WiFi client mode.");
match network_client::activate_client() {
Ok(_) => Flash::success(Redirect::to("/network"), "Activated WiFi client"),
Err(_) => Flash::error(Redirect::to("/network"), "Failed to activate WiFi client"),
Ok(_) => Flash::success(Redirect::to("/settings/network"), "Activated WiFi client"),
Err(_) => Flash::error(
Redirect::to("/settings/network"),
"Failed to activate WiFi client",
),
}
}
// HELPERS AND ROUTES FOR /network/wifi/add
// HELPERS AND ROUTES FOR /settings/network/wifi/add
#[get("/network/wifi/add")]
pub fn network_add_wifi(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
#[get("/wifi/add")]
pub fn add_wifi(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = NetworkContext::build();
// set back icon link to network route
context.back = Some("/network".to_string());
context.back = Some("/settings/network".to_string());
context.title = Some("Add WiFi Network".to_string());
// check to see if there is a flash message to display
if let Some(flash) = flash {
@ -584,10 +590,10 @@ pub fn network_add_wifi(flash: Option<FlashMessage>, _auth: Authenticated) -> Te
context.flash_msg = Some(flash.message().to_string());
};
// template_dir is set in Rocket.toml
Template::render("network_add", &context)
Template::render("settings/network/network_add", &context)
}
// used in /network/wifi/add?<ssid>
// used in /settings/network/wifi/add?<ssid>
#[derive(Debug, Serialize)]
pub struct NetworkAddContext {
pub back: Option<String>,
@ -609,10 +615,10 @@ impl NetworkAddContext {
}
}
#[get("/network/wifi/add?<ssid>")]
pub fn network_add_ssid(ssid: &str, flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
#[get("/wifi/add?<ssid>")]
pub fn add_ssid(ssid: &str, flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = NetworkAddContext::build();
context.back = Some("/network/wifi".to_string());
context.back = Some("/settings/network/wifi".to_string());
context.selected = Some(ssid.to_string());
context.title = Some("Add WiFi Network".to_string());
// check to see if there is a flash message to display
@ -622,10 +628,10 @@ pub fn network_add_ssid(ssid: &str, flash: Option<FlashMessage>, _auth: Authenti
context.flash_msg = Some(flash.message().to_string());
};
// template_dir is set in Rocket.toml
Template::render("network_add", &context)
Template::render("settings/network/network_add", &context)
}
#[post("/network/wifi/add", data = "<wifi>")]
#[post("/wifi/add", data = "<wifi>")]
pub fn add_credentials(wifi: Form<WiFi>, _auth: Authenticated) -> Template {
// check if the credentials already exist for this access point
// note: this is nicer but it's an unstable feature:
@ -634,13 +640,13 @@ pub fn add_credentials(wifi: Form<WiFi>, _auth: Authenticated) -> Template {
let creds_exist = network_client::saved_ap(&wifi.ssid).unwrap_or(false);
if creds_exist {
let mut context = NetworkAddContext::build();
context.back = Some("/network".to_string());
context.back = Some("/settings/network".to_string());
context.flash_name = Some("error".to_string());
context.flash_msg =
Some("Network credentials already exist for this access point".to_string());
context.title = Some("Add WiFi Network".to_string());
// return early from handler with "creds already exist" message
return Template::render("network_add", &context);
return Template::render("settings/network/network_add", &context);
};
// if credentials not found, generate and write wifi config to wpa_supplicant
@ -653,20 +659,20 @@ pub fn add_credentials(wifi: Form<WiFi>, _auth: Authenticated) -> Template {
Err(_) => warn!("Failed to reconfigure wpa_supplicant"),
}
let mut context = NetworkAddContext::build();
context.back = Some("/network".to_string());
context.back = Some("/settings/network".to_string());
context.flash_name = Some("success".to_string());
context.flash_msg = Some("Added WiFi credentials".to_string());
context.title = Some("Add WiFi Network".to_string());
Template::render("network_add", &context)
Template::render("settings/network/network_add", &context)
}
Err(_) => {
debug!("Failed to add WiFi credentials.");
let mut context = NetworkAddContext::build();
context.back = Some("/network".to_string());
context.back = Some("/settings/network".to_string());
context.flash_name = Some("error".to_string());
context.flash_msg = Some("Failed to add WiFi credentials".to_string());
context.title = Some("Add WiFi Network".to_string());
Template::render("network_add", &context)
Template::render("settings/network/network_add", &context)
}
}
}
@ -719,11 +725,11 @@ impl NetworkAlertContext {
}
}
#[get("/network/wifi/usage")]
#[get("/wifi/usage")]
pub fn wifi_usage(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = NetworkAlertContext::build();
// set back icon link to network route
context.back = Some("/network".to_string());
context.back = Some("/settings/network".to_string());
context.title = Some("Network Data Usage".to_string());
// check to see if there is a flash message to display
if let Some(flash) = flash {
@ -732,30 +738,32 @@ pub fn wifi_usage(flash: Option<FlashMessage>, _auth: Authenticated) -> Template
context.flash_msg = Some(flash.message().to_string());
};
// template_dir is set in Rocket.toml
Template::render("network_usage", &context)
Template::render("settings/network/network_usage", &context)
}
#[post("/network/wifi/usage", data = "<thresholds>")]
#[post("/wifi/usage", data = "<thresholds>")]
pub fn wifi_usage_alerts(thresholds: Form<Threshold>, _auth: Authenticated) -> Flash<Redirect> {
match monitor::update_store(thresholds.into_inner()) {
Ok(_) => {
debug!("WiFi data usage thresholds updated.");
Flash::success(
Redirect::to("/network/wifi/usage"),
Redirect::to("/settings/network/wifi/usage"),
"Updated alert thresholds and flags",
)
}
Err(_) => {
warn!("Failed to update WiFi data usage thresholds.");
Flash::error(
Redirect::to("/network/wifi/usage"),
Redirect::to("/settings/network/wifi/usage"),
"Failed to update alert thresholds and flags",
)
}
}
}
#[post("/api/v1/network/wifi/usage", data = "<thresholds>")]
// JSON ROUTES FOR NETWORK SETTINGS
#[post("/wifi/usage", data = "<thresholds>")]
pub fn update_wifi_alerts(thresholds: Json<Threshold>, _auth: Authenticated) -> Value {
match monitor::update_store(thresholds.into_inner()) {
Ok(_) => {
@ -773,7 +781,7 @@ pub fn update_wifi_alerts(thresholds: Json<Threshold>, _auth: Authenticated) ->
}
}
#[post("/api/v1/network/wifi/usage/reset")]
#[post("/wifi/usage/reset")]
pub fn reset_data_total(_auth: Authenticated) -> Value {
match monitor::reset_data() {
Ok(_) => {
@ -805,7 +813,7 @@ pub fn reset_data_total(_auth: Authenticated) -> Value {
// HELPERS AND ROUTES FOR ACCESS POINT ACTIVATION
#[post("/api/v1/network/activate_ap")]
#[post("/activate_ap")]
pub fn activate_ap(_auth: Authenticated) -> Value {
// activate the wireless access point
debug!("Activating WiFi access point.");
@ -824,7 +832,7 @@ pub fn activate_ap(_auth: Authenticated) -> Value {
// HELPERS AND ROUTES FOR WIFI CLIENT MANAGEMENT
#[post("/api/v1/network/activate_client")]
#[post("/activate_client")]
pub fn activate_client(_auth: Authenticated) -> Value {
// activate the wireless client
debug!("Activating WiFi client mode.");
@ -841,8 +849,8 @@ pub fn activate_client(_auth: Authenticated) -> Value {
}
}
#[post("/api/v1/network/wifi", data = "<wifi>")]
pub fn add_wifi(wifi: Json<WiFi>, _auth: Authenticated) -> Value {
#[post("/wifi", data = "<wifi>")]
pub fn add_wifi_credentials(wifi: Json<WiFi>, _auth: Authenticated) -> Value {
// generate and write wifi config to wpa_supplicant
match network_client::add(&wifi.ssid, &wifi.pass) {
Ok(_) => {
@ -867,7 +875,7 @@ pub fn add_wifi(wifi: Json<WiFi>, _auth: Authenticated) -> Value {
}
}
#[post("/api/v1/network/wifi/connect", data = "<ssid>")]
#[post("/wifi/connect", data = "<ssid>")]
pub fn connect_ap(ssid: Json<Ssid>, _auth: Authenticated) -> Value {
// retrieve the id for the given network ssid
match network_client::id("wlan0", &ssid.ssid) {
@ -892,7 +900,7 @@ pub fn connect_ap(ssid: Json<Ssid>, _auth: Authenticated) -> Value {
}
}
#[post("/api/v1/network/wifi/disconnect", data = "<ssid>")]
#[post("/wifi/disconnect", data = "<ssid>")]
pub fn disconnect_ap(ssid: Json<Ssid>, _auth: Authenticated) -> Value {
// attempt to disable the current network for wlan0 interface
match network_client::disable("wlan0", &ssid.ssid) {
@ -909,7 +917,7 @@ pub fn disconnect_ap(ssid: Json<Ssid>, _auth: Authenticated) -> Value {
}
}
#[post("/api/v1/network/wifi/forget", data = "<network>")]
#[post("/wifi/forget", data = "<network>")]
pub fn forget_ap(network: Json<Ssid>, _auth: Authenticated) -> Value {
let ssid = &network.ssid;
match network_client::forget("wlan0", ssid) {
@ -928,7 +936,7 @@ pub fn forget_ap(network: Json<Ssid>, _auth: Authenticated) -> Value {
}
}
#[post("/api/v1/network/wifi/modify", data = "<wifi>")]
#[post("/wifi/modify", data = "<wifi>")]
pub fn modify_password(wifi: Json<WiFi>, _auth: Authenticated) -> Value {
let ssid = &wifi.ssid;
let pass = &wifi.pass;
@ -953,7 +961,7 @@ pub fn modify_password(wifi: Json<WiFi>, _auth: Authenticated) -> Value {
// HELPERS AND ROUTES FOR NETWORK STATE QUERIES
#[get("/api/v1/network/ip")]
#[get("/ip")]
pub fn return_ip(_auth: Authenticated) -> Value {
// retrieve ip for wlan0 or set to x.x.x.x if not found
let wlan_ip = match network_client::ip("wlan0") {
@ -973,7 +981,7 @@ pub fn return_ip(_auth: Authenticated) -> Value {
build_json_response(status, Some(data), None)
}
#[get("/api/v1/network/rssi")]
#[get("/rssi")]
pub fn return_rssi(_auth: Authenticated) -> Value {
// retrieve rssi for connected network
match network_client::rssi("wlan0") {
@ -990,7 +998,7 @@ pub fn return_rssi(_auth: Authenticated) -> Value {
}
}
#[get("/api/v1/network/ssid")]
#[get("/ssid")]
pub fn return_ssid(_auth: Authenticated) -> Value {
// retrieve ssid for connected network
match network_client::ssid("wlan0") {
@ -1007,7 +1015,7 @@ pub fn return_ssid(_auth: Authenticated) -> Value {
}
}
#[get("/api/v1/network/state")]
#[get("/state")]
pub fn return_state(_auth: Authenticated) -> Value {
// retrieve state of wlan0 or set to x.x.x.x if not found
let wlan_state = match network_client::state("wlan0") {
@ -1027,7 +1035,7 @@ pub fn return_state(_auth: Authenticated) -> Value {
build_json_response(status, Some(data), None)
}
#[get("/api/v1/network/status")]
#[get("/status")]
pub fn return_status(_auth: Authenticated) -> Value {
// retrieve status info for wlan0 interface
match network_client::status("wlan0") {
@ -1044,7 +1052,7 @@ pub fn return_status(_auth: Authenticated) -> Value {
}
}
#[get("/api/v1/network/wifi")]
#[get("/wifi")]
pub fn scan_networks(_auth: Authenticated) -> Value {
// retrieve scan results for access-points within range of wlan0
match network_client::available_networks("wlan0") {

View File

@ -0,0 +1,41 @@
use rocket::{get, request::FlashMessage, serde::Serialize};
use rocket_dyn_templates::Template;
use crate::routes::authentication::Authenticated;
// HELPERS AND ROUTES FOR /settings/scuttlebutt
#[derive(Debug, Serialize)]
pub struct ScuttlebuttSettingsContext {
pub back: Option<String>,
pub title: Option<String>,
pub flash_name: Option<String>,
pub flash_msg: Option<String>,
}
impl ScuttlebuttSettingsContext {
pub fn build() -> ScuttlebuttSettingsContext {
ScuttlebuttSettingsContext {
back: None,
title: None,
flash_name: None,
flash_msg: None,
}
}
}
/// Scuttlebutt settings menu.
#[get("/")]
pub fn ssb_settings_menu(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = ScuttlebuttSettingsContext::build();
// set back icon link to network route
context.back = Some("/settings".to_string());
context.title = Some("Scuttlebutt Settings".to_string());
// check to see if there is a flash message to display
if let Some(flash) = flash {
// add flash message contents to the context object
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("settings/scuttlebutt", &context)
}

View File

@ -16,15 +16,15 @@ use peach_lib::config_manager::load_peach_config;
use peach_lib::stats_client::{CpuStatPercentages, DiskUsage, LoadAverage, MemStat};
use peach_lib::{dyndns_client, network_client, oled_client, sbot_client, stats_client};
use crate::utils::build_json_response;
use crate::routes::authentication::Authenticated;
use crate::utils::build_json_response;
use rocket::serde::json::Value;
// HELPERS AND ROUTES FOR /device
// HELPERS AND ROUTES FOR /status
/// System statistics data.
#[derive(Debug, Serialize)]
pub struct DeviceContext {
pub struct StatusContext {
pub back: Option<String>,
pub cpu_stat_percent: Option<CpuStatPercentages>,
pub disk_stats: Vec<DiskUsage>,
@ -43,8 +43,8 @@ pub struct DeviceContext {
pub uptime: Option<i32>,
}
impl DeviceContext {
pub fn build() -> DeviceContext {
impl StatusContext {
pub fn build() -> StatusContext {
// convert result to Option<CpuStatPercentages>, discard any error
let cpu_stat_percent = stats_client::cpu_stats_percent().ok();
let load_average = stats_client::load_average().ok();
@ -129,7 +129,7 @@ impl DeviceContext {
}
}
DeviceContext {
StatusContext {
back: None,
cpu_stat_percent,
disk_stats,
@ -150,10 +150,10 @@ impl DeviceContext {
}
}
#[get("/device")]
pub fn device_stats(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
#[get("/status")]
pub fn device_status(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
// assign context through context_builder call
let mut context = DeviceContext::build();
let mut context = StatusContext::build();
context.back = Some("/".to_string());
context.title = Some("Device Status".to_string());
// check to see if there is a flash message to display
@ -166,7 +166,7 @@ pub fn device_stats(flash: Option<FlashMessage>, _auth: Authenticated) -> Templa
Template::render("device", &context)
}
// HELPERS AND ROUTES FOR /device/reboot
// HELPERS AND ROUTES FOR /power/reboot
/// Executes a system command to reboot the device immediately.
pub fn reboot() -> io::Result<Output> {
@ -181,16 +181,16 @@ pub fn reboot() -> io::Result<Output> {
.output()
}
#[get("/device/reboot")]
#[get("/power/reboot")]
pub fn reboot_cmd(_auth: Authenticated) -> Flash<Redirect> {
match reboot() {
Ok(_) => Flash::success(Redirect::to("/shutdown"), "Rebooting the device"),
Err(_) => Flash::error(Redirect::to("/shutdown"), "Failed to reboot the device"),
Ok(_) => Flash::success(Redirect::to("/power"), "Rebooting the device"),
Err(_) => Flash::error(Redirect::to("/power"), "Failed to reboot the device"),
}
}
/// JSON request handler for device reboot.
#[post("/api/v1/device/reboot")]
#[post("/api/v1/admin/reboot")]
pub fn reboot_device(_auth: Authenticated) -> Value {
match reboot() {
Ok(_) => {
@ -208,7 +208,7 @@ pub fn reboot_device(_auth: Authenticated) -> Value {
}
}
// HELPERS AND ROUTES FOR /device/shutdown
// HELPERS AND ROUTES FOR /power/shutdown
/// Executes a system command to shutdown the device immediately.
pub fn shutdown() -> io::Result<Output> {
@ -219,16 +219,16 @@ pub fn shutdown() -> io::Result<Output> {
Command::new("sudo").arg("shutdown").arg("now").output()
}
#[get("/device/shutdown")]
#[get("/power/shutdown")]
pub fn shutdown_cmd(_auth: Authenticated) -> Flash<Redirect> {
match shutdown() {
Ok(_) => Flash::success(Redirect::to("/shutdown"), "Shutting down the device"),
Err(_) => Flash::error(Redirect::to("/shutdown"), "Failed to shutdown the device"),
Ok(_) => Flash::success(Redirect::to("/power"), "Shutting down the device"),
Err(_) => Flash::error(Redirect::to("/power"), "Failed to shutdown the device"),
}
}
// shutdown the device
#[post("/api/v1/device/shutdown")]
#[post("/power/shutdown")]
pub fn shutdown_device(_auth: Authenticated) -> Value {
match shutdown() {
Ok(_) => {
@ -246,19 +246,19 @@ pub fn shutdown_device(_auth: Authenticated) -> Value {
}
}
// HELPERS AND ROUTES FOR /shutdown
// HELPERS AND ROUTES FOR /power
#[derive(Debug, Serialize)]
pub struct ShutdownContext {
pub struct PowerContext {
pub back: Option<String>,
pub flash_name: Option<String>,
pub flash_msg: Option<String>,
pub title: Option<String>,
}
impl ShutdownContext {
pub fn build() -> ShutdownContext {
ShutdownContext {
impl PowerContext {
pub fn build() -> PowerContext {
PowerContext {
back: None,
flash_name: None,
flash_msg: None,
@ -267,16 +267,16 @@ impl ShutdownContext {
}
}
#[get("/shutdown")]
pub fn shutdown_menu(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = ShutdownContext::build();
#[get("/power")]
pub fn power_menu(flash: Option<FlashMessage>, _auth: Authenticated) -> Template {
let mut context = PowerContext::build();
context.back = Some("/".to_string());
context.title = Some("Shutdown Device".to_string());
context.title = Some("Power Menu".to_string());
// check to see if there is a flash message to display
if let Some(flash) = flash {
// add flash message contents to the context object
context.flash_name = Some(flash.kind().to_string());
context.flash_msg = Some(flash.message().to_string());
};
Template::render("shutdown", &context)
Template::render("power", &context)
}

View File

@ -0,0 +1,2 @@
pub mod device;
pub mod ping;

View File

@ -1,19 +1,19 @@
//! Helper routes for pinging services to check that they are active
use log::{debug, warn};
use rocket::get;
use rocket::serde::json::{Value};
use rocket::serde::json::Value;
use peach_lib::network_client;
use peach_lib::oled_client;
use peach_lib::stats_client;
use crate::utils::build_json_response;
use crate::routes::authentication::Authenticated;
use crate::utils::build_json_response;
/// Status route: useful for checking connectivity from web client.
#[get("/api/v1/ping")]
#[get("/ping")]
pub fn ping_pong(_auth: Authenticated) -> Value {
//pub fn ping_pong() -> Value {
//pub fn ping_pong() -> Value {
// ping pong
let status = "success".to_string();
let msg = "pong!".to_string();
@ -21,7 +21,7 @@ pub fn ping_pong(_auth: Authenticated) -> Value {
}
/// Status route: check availability of `peach-network` microservice.
#[get("/api/v1/ping/network")]
#[get("/ping/network")]
pub fn ping_network(_auth: Authenticated) -> Value {
match network_client::ping() {
Ok(_) => {
@ -40,7 +40,7 @@ pub fn ping_network(_auth: Authenticated) -> Value {
}
/// Status route: check availability of `peach-oled` microservice.
#[get("/api/v1/ping/oled")]
#[get("/ping/oled")]
pub fn ping_oled(_auth: Authenticated) -> Value {
match oled_client::ping() {
Ok(_) => {
@ -59,7 +59,7 @@ pub fn ping_oled(_auth: Authenticated) -> Value {
}
/// Status route: check availability of `peach-stats` microservice.
#[get("/api/v1/ping/stats")]
#[get("/ping/stats")]
pub fn ping_stats(_auth: Authenticated) -> Value {
match stats_client::ping() {
Ok(_) => {

View File

@ -47,15 +47,15 @@ fn index_html() {
assert!(body.contains("/peers"));
assert!(body.contains("/profile"));
assert!(body.contains("/private"));
assert!(body.contains("/device"));
assert!(body.contains("/status"));
assert!(body.contains("/help"));
assert!(body.contains("/network"));
assert!(body.contains("/settings"));
}
#[test]
fn network_card_html() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client.get("/network").dispatch();
let response = client.get("/settings/network").dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::HTML));
let body = response.into_string().unwrap();
@ -73,7 +73,7 @@ fn network_card_html() {
#[test]
fn network_list_html() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client.get("/network/wifi").dispatch();
let response = client.get("/settings/network/wifi").dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::HTML));
let body = response.into_string().unwrap();
@ -85,7 +85,7 @@ fn network_list_html() {
#[test]
fn network_detail_html() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client.get("/network/wifi?ssid=Home").dispatch();
let response = client.get("/settings/network/wifi?ssid=Home").dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::HTML));
//let body = response.into_string().unwrap();
@ -95,7 +95,7 @@ fn network_detail_html() {
#[test]
fn network_add_html() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client.get("/network/wifi/add").dispatch();
let response = client.get("/settings/network/wifi/add").dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::HTML));
let body = response.into_string().unwrap();
@ -109,7 +109,9 @@ fn network_add_html() {
#[test]
fn network_add_ssid_html() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client.get("/network/wifi/add?ssid=Home").dispatch();
let response = client
.get("/settings/network/wifi/add?ssid=Home")
.dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::HTML));
let body = response.into_string().unwrap();
@ -121,9 +123,9 @@ fn network_add_ssid_html() {
}
#[test]
fn device_html() {
fn status_html() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client.get("/device").dispatch();
let response = client.get("/status").dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::HTML));
let body = response.into_string().unwrap();
@ -269,9 +271,9 @@ fn profile_html() {
}
#[test]
fn shutdown_html() {
fn power_html() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client.get("/shutdown").dispatch();
let response = client.get("/power").dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::HTML));
let body = response.into_string().unwrap();
@ -281,7 +283,7 @@ fn shutdown_html() {
#[test]
fn network_usage_html() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client.get("/network/wifi/usage").dispatch();
let response = client.get("/settings/network/wifi/usage").dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::HTML));
let body = response.into_string().unwrap();
@ -295,7 +297,7 @@ fn network_usage_html() {
fn add_credentials() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client
.post("/network/wifi/add")
.post("/settings/network/wifi/add")
.header(ContentType::Form)
.body("ssid=Home&pass=Password")
.dispatch();
@ -307,7 +309,7 @@ fn add_credentials() {
fn forget_wifi() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client
.post("/network/wifi/forget")
.post("/settings/network/wifi/forget")
.header(ContentType::Form)
.body("ssid=Home")
.dispatch();
@ -319,7 +321,7 @@ fn forget_wifi() {
fn modify_password() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client
.post("/network/wifi/modify")
.post("/settings/network/wifi/modify")
.header(ContentType::Form)
.body("ssid=Home&pass=Password")
.dispatch();
@ -330,7 +332,7 @@ fn modify_password() {
#[test]
fn deploy_ap() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client.get("/network/ap/activate").dispatch();
let response = client.get("/settings/network/ap/activate").dispatch();
// check for 303 status (redirect)
assert_eq!(response.status(), Status::SeeOther);
assert_eq!(response.content_type(), None);
@ -339,7 +341,7 @@ fn deploy_ap() {
#[test]
fn deploy_client() {
let client = Client::tracked(init_rocket()).expect("valid rocket instance");
let response = client.get("/network/wifi/activate").dispatch();
let response = client.get("/settings/network/wifi/activate").dispatch();
// check for 303 status (redirect)
assert_eq!(response.status(), Status::SeeOther);
assert_eq!(response.content_type(), None);

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 984 B

After

Width:  |  Height:  |  Size: 984 B

View File

@ -23,7 +23,7 @@ PEACH.add = function() {
// write in-progress status message to ui
PEACH.flashMsg("info", "Saving new password.");
// send add_wifi POST request
fetch("/api/v1/settings/change_password", {
fetch("/api/v1/admin/change_password", {
method: "post",
headers: {
'Content-Type': 'application/json',

View File

@ -38,7 +38,7 @@ PEACH_DNS.add = function() {
// write in-progress status message to ui
PEACH_DNS.flashMsg("info", "Saving new DNS configurations");
// send add_wifi POST request
fetch("/api/v1/dns/configure", {
fetch("/api/v1/network/dns/configure", {
method: "post",
headers: {
'Content-Type': 'application/json',

View File

@ -1,7 +1,7 @@
/*
behavioural layer for the `shutdown.html.tera` template,
corresponding to the web route `/shutdown`
behavioural layer for the `power.html.tera` template,
corresponding to the web route `/power`
- intercept button clicks for reboot & shutdown
- perform json api calls
@ -28,7 +28,7 @@ PEACH_DEVICE.reboot = function() {
// write reboot flash message
PEACH_DEVICE.flashMsg("success", "Rebooting the device...");
// send reboot_device POST request
fetch("/api/v1/device/reboot", {
fetch("/api/v1/admin/reboot", {
method: "post",
headers: {
'Accept': 'application/json',
@ -59,7 +59,7 @@ PEACH_DEVICE.shutdown = function() {
// write shutdown flash message
PEACH_DEVICE.flashMsg("success", "Shutting down the device...");
// send shutdown_device POST request
fetch("/api/v1/device/shutdown", {
fetch("/api/v1/shutdown", {
method: "post",
headers: {
'Accept': 'application/json',

View File

@ -23,7 +23,7 @@ PEACH.add = function() {
// write in-progress status message to ui
PEACH.flashMsg("info", "Saving new password.");
// send add_wifi POST request
fetch("/public/api/v1/reset_password", {
fetch("/api/v1/admin/reset_password", {
method: "post",
headers: {
'Content-Type': 'application/json',

View File

@ -25,7 +25,7 @@
<div class="three-grid" style="padding-top: 1rem;">
<!-- PEACH-NETWORK STATUS STACK -->
<div class="stack capsule{% if network_ping == "ONLINE" %} success-border{% else %} warning-border{% endif %}">
<img id="networkIcon" class="icon{% if network_ping == "OFFLINE" %} icon-inactive{% endif %} icon-medium" alt="Network" title="Network microservice status" src="icons/wifi.svg">
<img id="networkIcon" class="icon{% if network_ping == "OFFLINE" %} icon-inactive{% endif %} icon-medium" alt="Network" title="Network microservice status" src="/icons/wifi.svg">
<div class="stack" style="padding-top: 0.5rem;">
<label class="label-small font-near-black">Networking</label>
<label class="label-small font-near-black">{{ network_ping }}</label>
@ -33,7 +33,7 @@
</div>
<!-- PEACH-OLED STATUS STACK -->
<div class="stack capsule{% if oled_ping == "ONLINE" %} success-border{% else %} warning-border{% endif %}">
<img id="oledIcon" class="icon{% if oled_ping == "OFFLINE" %} icon-inactive{% endif %} icon-medium" alt="Display" title="OLED display microservice status" src="icons/lcd.svg">
<img id="oledIcon" class="icon{% if oled_ping == "OFFLINE" %} icon-inactive{% endif %} icon-medium" alt="Display" title="OLED display microservice status" src="/icons/lcd.svg">
<div class="stack" style="padding-top: 0.5rem;">
<label class="label-small font-near-black">Display</label>
<label class="label-small font-near-black">{{ oled_ping }}</label>
@ -41,7 +41,7 @@
</div>
<!-- PEACH-STATS STATUS STACK -->
<div class="stack capsule{% if stats_ping == "ONLINE" %} success-border{% else %} warning-border{% endif %}">
<img id="statsIcon" class="icon{% if stats_ping == "OFFLINE" %} icon-inactive{% endif %} icon-medium" alt="Stats" title="System statistics microservice status" src="icons/chart.svg">
<img id="statsIcon" class="icon{% if stats_ping == "OFFLINE" %} icon-inactive{% endif %} icon-medium" alt="Stats" title="System statistics microservice status" src="/icons/chart.svg">
<div class="stack" style="padding-top: 0.5rem;">
<label class="label-small font-near-black">Statistics</label>
<label class="label-small font-near-black">{{ stats_ping }}</label>
@ -51,7 +51,7 @@
<div class="three-grid" style="padding-bottom: 1rem; margin-top: 0px;">
<!-- DYNDNS STATUS STACK -->
<div class="stack capsule{% if dyndns_is_online %} success-border{% else %} warning-border{% endif %}">
<img id="networkIcon" class="icon{% if dyndns_is_online != true %} icon-inactive {% endif %} icon-medium" alt="Dyndns" title="Dyndns status" src="icons/wifi.svg">
<img id="networkIcon" class="icon{% if dyndns_is_online != true %} icon-inactive{% endif %} icon-medium" alt="Dyndns" title="Dyndns status" src="/icons/dns.png">
<div class="stack" style="padding-top: 0.5rem;">
<label class="label-small font-near-black">Dyn DNS</label>
<label class="label-small font-near-black">{% if dyndns_is_online %} ONLINE {% else %} OFFLINE {% endif %} </label>
@ -59,7 +59,7 @@
</div>
<!-- CONFIG STATUS STACK -->
<div class="stack capsule{% if config_is_valid %} success-border{% else %} warning-border{% endif %}">
<img id="networkIcon" class="icon{% if config_is_valid != true %} icon-inactive {% endif %} icon-medium" alt="Config" title="Config status" src="icons/wifi.svg">
<img id="networkIcon" class="icon{% if config_is_valid != true %} icon-inactive{% endif %} icon-medium" alt="Config" title="Config status" src="/icons/clipboard.png">
<div class="stack" style="padding-top: 0.5rem;">
<label class="label-small font-near-black">Config</label>
<label class="label-small font-near-black">{% if config_is_valid %} LOADED {% else %} INVALID {% endif %} </label>
@ -67,7 +67,7 @@
</div>
<!-- SBOT STATUS STACK -->
<div class="stack capsule{% if sbot_is_online %} success-border{% else %} warning-border{% endif %}">
<img id="networkIcon" class="icon{% if sbot_is_online != true %} icon-inactive {% endif %} icon-medium" alt="Sbot" title="Sbot status" src="icons/wifi.svg">
<img id="networkIcon" class="icon{% if sbot_is_online != true %} icon-inactive{% endif %} icon-medium" alt="Sbot" title="Sbot status" src="/icons/hermies.svg">
<div class="stack" style="padding-top: 0.5rem;">
<label class="label-small font-near-black">Sbot</label>
<label class="label-small font-near-black">{% if sbot_is_online %} ONLINE {% else %} OFFLINE {% endif %} </label>

View File

@ -6,21 +6,21 @@
<!-- PEERS LINK AND ICON -->
<a class="top-left" href="/scuttlebutt/peers" title="Scuttlebutt Peers">
<div class="circle circle-small">
<img class="icon-medium" src="icons/users.svg">
<img class="icon-medium" src="/icons/users.svg">
</div>
</a>
<!-- top-middle -->
<!-- CURRENT USER LINK AND ICON -->
<a class="top-middle" href="/scuttlebutt/profile" title="Profile">
<div class="circle circle-small">
<img class="icon-medium" src="icons/user.svg">
<img class="icon-medium" src="/icons/user.svg">
</div>
</a>
<!-- top-right -->
<!-- MESSAGES LINK AND ICON -->
<a class="top-right" href="/scuttlebutt/private" title="Private Messages">
<div class="circle circle-small">
<img class="icon-medium" src="icons/envelope.svg">
<img class="icon-medium" src="/icons/envelope.svg">
</div>
</a>
<!-- middle -->
@ -30,23 +30,23 @@
</a>
<!-- bottom-left -->
<!-- SYSTEM STATUS LINK AND ICON -->
<a class="bottom-left" href="/device" title="Device Status">
<a class="bottom-left" href="/status" title="Status">
<div class="circle circle-small">
<img class="icon-medium" src="icons/heart-pulse.svg">
<img class="icon-medium" src="/icons/heart-pulse.svg">
</div>
</a>
<!-- bottom-middle -->
<!-- PEACHCLOUD GUIDEBOOK LINK AND ICON -->
<a class="bottom-middle" href="/help" title="Help Menu">
<div class="circle circle-small">
<img class="icon-medium" src="icons/book.svg">
<img class="icon-medium" src="/icons/book.svg">
</div>
</a>
<!-- bottom-right -->
<!-- SYSTEM SETTINGS LINK AND ICON -->
<a class="bottom-right" href="/network" title="Network Configuration">
<a class="bottom-right" href="/settings" title="Settings Menu">
<div class="circle circle-small">
<img class="icon-medium" src="icons/cog.svg">
<img class="icon-medium" src="/icons/cog.svg">
</div>
</a>
</div>

View File

@ -17,7 +17,7 @@
{% include "snippets/flash_message" %}
<div class="center-text" style="margin-top: 25px;">
<a href="/forgot_password" class="label-small link">Forgot Password?</a>
<a href="/settings/admin/forgot_password" class="label-small link">Forgot Password?</a>
</div>
</div>
</div>

View File

@ -22,8 +22,8 @@
<a class="nav-item" href="/">
<img class="icon nav-icon-left" src="/icons/peach-icon.png" alt="PeachCloud" title="Home">
</a>
<a class="nav-item" href="/help">
<img class="icon-medium nav-icon-right icon-active" title="Help" src="/icons/question-circle.svg" alt="Question mark">
<a class="nav-item" href="/power">
<img class="icon-medium nav-icon-right icon-active" title="Shutdown" src="/icons/power.svg" alt="Power switch">
</a>
</nav>
{%- endblock nav -%}

View File

@ -5,8 +5,8 @@
<div class="card-container">
<!-- BUTTONS -->
<div id="buttonDiv">
<a id="rebootBtn" class="button button-primary center" href="/device/reboot" title="Reboot Device">Reboot</a>
<a id="shutdownBtn" class="button button-warning center" href="/device/shutdown" title="Shutdown Device">Shutdown</a>
<a id="rebootBtn" class="button button-primary center" href="/power/reboot" title="Reboot Device">Reboot</a>
<a id="shutdownBtn" class="button button-warning center" href="/power/shutdown" title="Shutdown Device">Shutdown</a>
<a id="cancelBtn" class="button button-secondary center" href="/" title="Cancel">Cancel</a>
</div>
<!-- FLASH MESSAGE -->
@ -15,5 +15,5 @@
{% include "snippets/noscript" %}
</div>
</div>
<script type="text/javascript" src="/js/shutdown_menu.js"></script>
<script type="text/javascript" src="/js/power_menu.js"></script>
{%- endblock card -%}

View File

@ -7,7 +7,7 @@
<input id="ssb_id" name="ssb_id" class="center input" type="text" placeholder="SSB ID" title="SSB ID of Admin" value=""/>
<div id="buttonDiv">
<input id="addAdmin" class="button button-primary center" title="Add" type="submit" value="Add">
<a class="button button-secondary center" href="/settings/configure_admin" title="Cancel">Cancel</a>
<a class="button button-secondary center" href="/settings/admin/configure" title="Cancel">Cancel</a>
</div>
</form>

View File

@ -0,0 +1,13 @@
{%- extends "nav" -%}
{%- block card %}
<!-- ADMIN SETTINGS MENU -->
<div class="card center">
<div class="card-container">
<!-- BUTTONS -->
<div id="settingsButtons">
<a id="change" class="button button-primary center" href="/settings/admin/change_password" title="Change Password">Change Password</a>
<a id="configure" class="button button-primary center" href="/settings/admin/configure" title="Configure Admin">Configure Admin</a>
</div>
</div>
</div>
{%- endblock card -%}

View File

@ -18,7 +18,7 @@
</div>
{% endif %}
<form id="configureDNS" action="/network/dns" method="post">
<form id="configureDNS" action="/settings/network/dns" method="post">
<div class="input-wrapper">
<!-- input for externaldomain -->
<label id="external_domain" class="label-small input-label font-near-black">

View File

@ -10,7 +10,7 @@
<input id="pass" name="pass" class="center input" type="password" placeholder="Password" title="Password for WiFi access point">
<div id="buttonDiv">
<input id="addWifi" class="button button-primary center" title="Add" type="submit" value="Add">
<a class="button button-secondary center" href="/network" title="Cancel">Cancel</a>
<a class="button button-secondary center" href="/settings/network" title="Cancel">Cancel</a>
</div>
</form>
<!-- FLASH MESSAGE -->

View File

@ -11,7 +11,7 @@
<!-- left column -->
<!-- network mode icon with label -->
<div class="grid-column-1">
<img id="netModeIcon" class="center icon icon-active" src="icons/router.svg" alt="WiFi router">
<img id="netModeIcon" class="center icon icon-active" src="/icons/router.svg" alt="WiFi router">
<label id="netModeLabel" for="netModeIcon" class="center label-small font-gray" title="Access Point Online">ONLINE</label>
</div>
<!-- right column -->
@ -27,10 +27,10 @@
</div>
<!-- BUTTONS -->
<div id="buttons">
<a class="button button-primary center" href="/network/wifi/add" title="Add WiFi Network">Add WiFi Network</a>
<a id="connectWifi" class="button button-primary center" href="/network/wifi/activate" title="Enable WiFi">Enable WiFi</a>
<a id="listWifi" class="button button-primary center" href="/network/wifi" title="List WiFi Networks">List WiFi Networks</a>
<a id="viewUsage" class="button button-primary center" href="/network/wifi/usage" title="View Data Usage">View Data Usage</a>
<a class="button button-primary center" href="/settings/network/wifi/add" title="Add WiFi Network">Add WiFi Network</a>
<a id="connectWifi" class="button button-primary center" href="/settings/network/wifi/activate" title="Enable WiFi">Enable WiFi</a>
<a id="listWifi" class="button button-primary center" href="/settings/network/wifi" title="List WiFi Networks">List WiFi Networks</a>
<a id="viewUsage" class="button button-primary center" href="/settings/network/wifi/usage" title="View Data Usage">View Data Usage</a>
</div>
<!-- FLASH MESSAGE -->
{% include "snippets/flash_message" %}
@ -38,14 +38,14 @@
<div class="card-container">
<div class="three-grid">
<div class="stack">
<img id="devices" class="icon icon-medium" title="Connected devices" src="icons/devices.svg" alt="Digital devices">
<img id="devices" class="icon icon-medium" title="Connected devices" src="/icons/devices.svg" alt="Digital devices">
<div class="flex-grid" style="padding-top: 0.5rem;">
<label class="label-medium" for="devices" style="padding-right: 3px;" title="Number of connected devices"></label>
</div>
<label class="label-small font-gray">DEVICES</label>
</div>
<div class="stack">
<img id="dataDownload" class="icon icon-medium" title="Download" src="icons/down-arrow.svg" alt="Download">
<img id="dataDownload" class="icon icon-medium" title="Download" src="/icons/down-arrow.svg" alt="Download">
<div class="flex-grid" style="padding-top: 0.5rem;">
{%- if ap_traffic -%}
<label class="label-medium" for="dataDownload" style="padding-right: 3px;" title="Data download total in {{ ap_traffic.rx_unit }}">{{ ap_traffic.received }}</label>
@ -58,7 +58,7 @@
<label class="label-small font-gray">DOWNLOAD</label>
</div>
<div class="stack">
<img id="dataUpload" class="icon icon-medium" title="Upload" src="icons/up-arrow.svg" alt="Upload">
<img id="dataUpload" class="icon icon-medium" title="Upload" src="/icons/up-arrow.svg" alt="Upload">
<div class="flex-grid" style="padding-top: 0.5rem;">
{%- if ap_traffic -%}
<label class="label-medium" for="dataUpload" style="padding-right: 3px;" title="Data upload total in {{ ap_traffic.tx_unit }}">{{ ap_traffic.transmitted }}</label>
@ -83,12 +83,12 @@
<!-- left column -->
<!-- network mode icon with label -->
<div class="grid-column-1">
<img id="netModeIcon" class="center icon icon-active" src="icons/wifi.svg" alt="WiFi online">
<img id="netModeIcon" class="center icon icon-active" src="/icons/wifi.svg" alt="WiFi online">
<label id="netModeLabel" for="netModeIcon" class="center label-small font-gray" title="WiFi Client Status">ONLINE</label>
{%- else %}
<div id="netInfoBox" class="two-grid capsule warning-border" title="PeachCloud network mode and status">
<div class="grid-column-1">
<img id="netModeIcon" class="center icon icon-inactive" src="icons/wifi.svg" alt="WiFi offline">
<img id="netModeIcon" class="center icon icon-inactive" src="/icons/wifi.svg" alt="WiFi offline">
<label id="netModeLabel" for="netModeIcon" class="center label-small font-gray" title="WiFi Client Status">OFFLINE</label>
{%- endif %}
</div>
@ -105,13 +105,13 @@
</div>
<!-- BUTTONS -->
<div id="buttons">
<a class="button button-primary center" href="/network/wifi/add" title="Add WiFi Network">Add WiFi Network</a>
<a id="deployAccessPoint" class="button button-primary center" href="/network/ap/activate" title="Deploy Access Point">Deploy Access Point</a>
<a id="listWifi" class="button button-primary center" href="/network/wifi" title="List WiFi Networks">List WiFi Networks</a>
<a id="viewUsage" class="button button-primary center" href="/network/wifi/usage" title="View Data Usage">View Data Usage</a>
<a id="configureDNS" class="button button-primary center" href="/network/dns" title="Configure DNS">Configure DNS</a>
<a id="changePassword" class="button button-primary center" href="/settings/change_password" title="Change Password">Change Password</a>
<a id="configureAdmin" class="button button-primary center" href="/settings/configure_admin" title="Configure Admin">Configure Admin</a>
<a class="button button-primary center" href="/settings/network/wifi/add" title="Add WiFi Network">Add WiFi Network</a>
<a id="deployAccessPoint" class="button button-primary center" href="/settings/network/ap/activate" title="Deploy Access Point">Deploy Access Point</a>
<a id="listWifi" class="button button-primary center" href="/settings/network/wifi" title="List WiFi Networks">List WiFi Networks</a>
<a id="viewUsage" class="button button-primary center" href="/settings/network/wifi/usage" title="View Data Usage">View Data Usage</a>
<a id="configureDNS" class="button button-primary center" href="/settings/network/dns" title="Configure DNS">Configure DNS</a>
<a id="changePassword" class="button button-primary center" href="/settings/admin/change_password" title="Change Password">Change Password</a>
<a id="configureAdmin" class="button button-primary center" href="/settings/admin/configure_admin" title="Configure Admin">Configure Admin</a>
</div>
<!-- FLASH MESSAGE -->
{% include "snippets/flash_message" %}
@ -120,14 +120,14 @@
<!-- row of icons representing network statistics -->
<div class="three-grid">
<div class="stack">
<img id="netSignal" class="icon icon-medium" alt="Signal" title="WiFi Signal (%)" src="icons/low-signal.svg">
<img id="netSignal" class="icon icon-medium" alt="Signal" title="WiFi Signal (%)" src="/icons/low-signal.svg">
<div class="flex-grid" style="padding-top: 0.5rem;">
<label class="label-medium" for="netSignal" style="padding-right: 3px;" title="Signal strength of WiFi connection (%)">{% if wlan_rssi %}{{ wlan_rssi }}{% else %}0{% endif %}%</label>
</div>
<label class="label-small font-gray">SIGNAL</label>
</div>
<div class="stack">
<img id="dataDownload" class="icon icon-medium" alt="Download" title="WiFi download total" src="icons/down-arrow.svg">
<img id="dataDownload" class="icon icon-medium" alt="Download" title="WiFi download total" src="/icons/down-arrow.svg">
<div class="flex-grid" style="padding-top: 0.5rem;">
{%- if wlan_traffic %}
<!-- display wlan traffic data -->
@ -142,7 +142,7 @@
<label class="label-small font-gray">DOWNLOAD</label>
</div>
<div class="stack">
<img id="dataUpload" class="icon icon-medium" alt="Upload" title="WiFi upload total" src="icons/up-arrow.svg">
<img id="dataUpload" class="icon icon-medium" alt="Upload" title="WiFi upload total" src="/icons/up-arrow.svg">
<div class="flex-grid" style="padding-top: 0.5rem;">
{%- if wlan_traffic %}
<!-- display wlan traffic data -->

View File

@ -29,7 +29,7 @@
<div class="card-container" style="padding-top: 0;">
<div id="buttonDiv">
{%- if wlan_ssid == selected -%}
<form id="wifiDisconnect" action="/network/wifi/disconnect" method="post">
<form id="wifiDisconnect" action="/settings/network/wifi/disconnect" method="post">
<!-- hidden element: allows ssid to be sent in request -->
<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">
@ -44,14 +44,14 @@
{# 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="/network/wifi/connect" method="post">
<form id="wifiConnect" action="/settings/network/wifi/connect" method="post">
<!-- hidden element: allows ssid to be sent in request -->
<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">
</form>
{%- endif -%}
<a class="button button-primary center" href="/network/wifi/modify?ssid={{ ssid }}">Modify</a>
<form id="wifiForget" action="/network/wifi/forget" method="post">
<a class="button button-primary center" href="/settings/network/wifi/modify?ssid={{ ssid }}">Modify</a>
<form id="wifiForget" action="/settings/network/wifi/forget" method="post">
<!-- hidden element: allows ssid to be sent in request -->
<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">
@ -61,9 +61,9 @@
{%- 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="/network/wifi/add?ssid={{ ssid }}">Add</a>
<a class="button button-primary center" href="/settings/network/wifi/add?ssid={{ ssid }}">Add</a>
{%- endif -%}
<a class="button button-secondary center" href="/network/wifi" title="Cancel">Cancel</a>
<a class="button button-secondary center" href="/settings/network/wifi" title="Cancel">Cancel</a>
</div>
<!-- FLASH MESSAGE -->
{% include "snippets/flash_message" %}

View File

@ -9,19 +9,19 @@
{%- for ssid, state in wlan_networks %}
<li>
{%- if ssid == wlan_ssid %}
<a class="list-item link primary-bg" href="/network/wifi?ssid={{ wlan_ssid }}">
<a class="list-item link primary-bg" href="/settings/network/wifi?ssid={{ wlan_ssid }}">
<img id="netStatus" class="icon icon-active icon-medium list-icon" src="/icons/wifi.svg" alt="WiFi online">
<p class="list-text">{{ wlan_ssid }}</p>
<label class="label-small list-label font-gray" for="netStatus" title="Status">Connected</label>
</a>
{%- elif state == "Available" %}
<a class="list-item link light-bg" href="/network/wifi?ssid={{ ssid }}">
<a class="list-item link light-bg" href="/settings/network/wifi?ssid={{ ssid }}">
<img id="netStatus" class="icon icon-inactive icon-medium list-icon" src="/icons/wifi.svg" alt="WiFi offline">
<p class="list-text">{{ ssid }}</p>
<label class="label-small list-label font-gray" for="netStatus" title="Status">{{ state }}</label>
</a>
{%- else %}
<a class="list-item link" href="/network/wifi?ssid={{ ssid }}">
<a class="list-item link" href="/settings/network/wifi?ssid={{ ssid }}">
<img id="netStatus" class="icon icon-inactive icon-medium list-icon" src="/icons/wifi.svg" alt="WiFi offline">
<p class="list-text">{{ ssid }}</p>
<label class="label-small list-label font-gray" for="netStatus" title="Status">{{ state }}</label>

View File

@ -3,14 +3,14 @@
<!-- NETWORK MODIFY AP PASSWORD FORM -->
<div class="card center">
<div class="card-container">
<form id="wifiModify" action="/network/wifi/modify" method="post">
<form id="wifiModify" action="/settings/network/wifi/modify" method="post">
<!-- input for network ssid -->
<input id="ssid" name="ssid" class="center input" type="text" placeholder="SSID" title="Network name (SSID) for WiFi access point" value="{% if selected %}{{ selected }}{% endif %}" autofocus>
<!-- input for network password -->
<input id="pass" name="pass" class="center input" type="password" placeholder="Password" title="Password for WiFi access point">
<div id="buttonDiv">
<input id="savePassword" class="button button-primary center" title="Save" type="submit" value="Save">
<a class="button button-secondary center" href="/network" title="Cancel">Cancel</a>
<a class="button button-secondary center" href="/settings/network" title="Cancel">Cancel</a>
</div>
</form>
<!-- FLASH MESSAGE -->

View File

@ -1,7 +1,7 @@
{%- extends "nav" -%}
{%- block card -%}
<!-- NETWORK DATA ALERTS VIEW -->
<form id="wifiAlerts" action="/network/wifi/usage" class="card center" method="post">
<form id="wifiAlerts" action="/settings/network/wifi/usage" class="card center" method="post">
<div class="stack capsule" style="margin-left: 2rem; margin-right: 2rem;">
<div class="flex-grid">
<label id="dataTotal" class="label-large" title="Data download total in MB">{{ data_total.total / 1024 / 1024 | round }}</label>
@ -37,8 +37,8 @@
</div>
<div id="buttonDiv" class="button-div">
<input id="updateAlerts" class="button button-primary center" title="Update" type="submit" value="Update">
<a id="resetTotal" class="button button-warning center" href="/network/wifi/usage/reset" title="Reset stored usage total to zero">Reset</a>
<a class="button button-secondary center" href="/network" title="Cancel">Cancel</a>
<a id="resetTotal" class="button button-warning center" href="/settings/network/wifi/usage/reset" title="Reset stored usage total to zero">Reset</a>
<a class="button button-secondary center" href="/settings/network" title="Cancel">Cancel</a>
</div>
<!-- FLASH MESSAGE -->
{% include "snippets/flash_message" %}