From a1abfad8d67d88880ae2335f215831c5cb820704 Mon Sep 17 00:00:00 2001 From: Stefan Schwarz Date: Thu, 20 Aug 2020 23:08:18 +0200 Subject: [PATCH] froms and db --- src/db.rs | 33 ++++++++++++++++++------- src/forms.rs | 39 ++++++++++++++++++++++++++--- src/main.rs | 32 +++--------------------- src/routes.rs | 23 +++++++++--------- src/session.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++ templates/index.html | 10 ++++++-- 6 files changed, 141 insertions(+), 54 deletions(-) create mode 100644 src/session.rs diff --git a/src/db.rs b/src/db.rs index 1a2e161..6eec869 100644 --- a/src/db.rs +++ b/src/db.rs @@ -2,7 +2,6 @@ use anyhow::{anyhow, Result}; use sqlx::database::HasArguments; use std::convert::TryFrom; use std::net::IpAddr; - type QueryAs<'q, T> = sqlx::query::QueryAs<'q, sqlx::MySql, T, >::Arguments>; type Query<'q> = sqlx::query::Query<'q, sqlx::MySql, >::Arguments>; @@ -45,7 +44,7 @@ SELECT DISTINCT IF(al.iplong, TRUE, FALSE) present FROM mac_to_nick mtn -LEFT JOIN +LEFT OUTER JOIN alive_hosts al ON mtn.macaddr = al.macaddr @@ -95,6 +94,23 @@ WHERE .bind(&self.descr) .bind(id)) } + + pub fn delete(self) -> Result> { + let id = match self.id { + Some(id) => id, + None => return Err(anyhow!("selected device has no id")), + }; + Ok(sqlx::query( + " +DELETE FROM + mac_to_nick +WHERE + id = ? +LIMIT 1 +", + ) + .bind(id)) + } } #[derive(sqlx::Type, Debug, Clone, Copy)] @@ -108,10 +124,6 @@ pub enum PrivacyLevel { } impl PrivacyLevel { - pub fn as_u8(&self) -> u8 { - *self as u8 - } - pub fn selected(&self, level: &PrivacyLevel) -> &'static str { if *self as u8 == *level as u8 { "selected" @@ -149,16 +161,19 @@ impl<'q> AliveDevice { " SELECT DISTINCT al.macaddr macaddr, - al.iplong iplong + al.iplong iplong, + mtn.nickname FROM alive_hosts al -NATURAL LEFT JOIN +LEFT OUTER JOIN mac_to_nick mtn +ON + al.macaddr = mtn.macaddr WHERE mtn.nickname IS NULL - AND al.erfda > NOW() - INTERVAL 24 DAY ORDER BY al.erfda DESC +; ", ) } diff --git a/src/forms.rs b/src/forms.rs index 59f793f..4cd546a 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -18,12 +18,11 @@ impl RegisterForm { Ok(privacy) => privacy, Err(_) => return (Level::Error, "unable to parse privacy level".to_string()), }; - let dbresult = db::Device { id: None, macaddr: self.macaddr, nickname: USER.to_string(), - descr: self.descr, + descr: self.descr.clone(), privacy, present: false, }; @@ -33,7 +32,10 @@ impl RegisterForm { .execute(&request.state().pool) .await; return match dbresult { - Ok(_) => (Level::Info, "assinged device".to_string()), + Ok(_) => ( + Level::Info, + format!("assinged device \"{}\" to {}", self.descr, USER), + ), Err(_) => (Level::Error, "unable to create device".to_string()), }; } @@ -76,3 +78,34 @@ impl UpdateForm { } } } + +#[derive(Deserialize)] +pub struct DeleteForm { + macaddr: String, +} + +impl DeleteForm { + pub async fn handle(self, request: &crate::Request) -> Message { + let device = match db::Device::for_mac(&self.macaddr) + .fetch_one(&request.state().pool) + .await + { + Ok(device) => device, + Err(_) => { + return ( + Level::Error, + "unable to load device from database".to_string(), + ) + } + }; + match device + .delete() + .unwrap() + .execute(&request.state().pool) + .await + { + Ok(_) => (Level::Info, "delete device".to_string()), + Err(_) => (Level::Error, "unable to delete device".to_string()), + } + } +} diff --git a/src/main.rs b/src/main.rs index d8d5656..875719a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,8 +6,11 @@ use tide::sessions::{MemoryStore, SessionMiddleware}; mod db; mod forms; mod routes; +mod session; mod templates; +pub use session::AppSession as Session; + pub const USER: &str = "foosinn"; /// Configuration @@ -43,34 +46,6 @@ pub enum Level { pub type Message = (Level, String); -#[derive(Default, Deserialize, Serialize)] -pub struct AppSession { - messages: Vec, -} - -impl AppSession { - pub fn add_message(mut self, message: Message) -> Self { - self.messages.push(message); - self - } - - pub fn pop_messages(&mut self) -> Vec { - let mut messages: Vec = Vec::new(); - std::mem::swap(&mut messages, &mut self.messages); - messages - } - - pub fn commit(self, request: &mut Request) { - request.session_mut().insert("app", self).unwrap() - } -} - -impl From<&mut Request> for AppSession { - fn from(request: &mut Request) -> Self { - request.session().get("app").unwrap_or_default() - } -} - pub type Request = tide::Request; #[async_std::main] @@ -89,6 +64,7 @@ async fn main() -> Result<(), io::Error> { app.at("/").get(routes::index); app.at("/register").post(routes::register); app.at("/update").post(routes::update); + app.at("/delete").post(routes::delete); app.at("/healthz").get(routes::healthz); app.at("/static").serve_dir("static/")?; app.listen(config.listen).await diff --git a/src/routes.rs b/src/routes.rs index 9dac139..784289c 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -1,7 +1,7 @@ use crate::db; use crate::forms; use crate::templates; -use crate::AppSession; +use crate::Session; use crate::USER; use tide::Redirect; @@ -18,28 +18,27 @@ pub async fn index(mut request: crate::Request) -> tide::Result { .fetch_all(&request.state().pool) .await .map_err(|err| dbg!(err))?; - - let mut session = AppSession::from(&mut request); - let messages = session.pop_messages(); - session.commit(&mut request); - + let messages = Session::from(&mut request).pop_messages(); Ok(templates::IndexTemplate::new(my, unassinged, messages).into()) } pub async fn register(mut request: crate::Request) -> tide::Result { let form: forms::RegisterForm = request.body_form().await?; let message = form.handle(&request).await; - AppSession::from(&mut request) - .add_message(message) - .commit(&mut request); + Session::from(&mut request).add_message(message); Ok(Redirect::see_other("/").into()) } pub async fn update(mut request: crate::Request) -> tide::Result { let form: forms::UpdateForm = request.body_form().await?; let message = form.handle(&request).await; - AppSession::from(&mut request) - .add_message(message) - .commit(&mut request); + Session::from(&mut request).add_message(message); + Ok(Redirect::see_other("/").into()) +} + +pub async fn delete(mut request: crate::Request) -> tide::Result { + let form: forms::DeleteForm = request.body_form().await?; + let message = form.handle(&request).await; + Session::from(&mut request).add_message(message); Ok(Redirect::see_other("/").into()) } diff --git a/src/session.rs b/src/session.rs new file mode 100644 index 0000000..33f7e7b --- /dev/null +++ b/src/session.rs @@ -0,0 +1,58 @@ +use crate::Message; +use crate::Request; +use serde::{Deserialize, Serialize}; + +pub struct AppSession<'r> { + request: &'r mut Request, + session: Inner, +} + +impl<'r> AppSession<'r> { + pub fn add_message(&mut self, message: Message) { + self.session.add_message(message); + } + + pub fn pop_messages(&mut self) -> Vec { + self.session.pop_messages() + } +} + +impl<'r> From<&'r mut Request> for AppSession<'r> { + fn from(request: &'r mut Request) -> Self { + let session = Inner::from(&*request); + Self { request, session } + } +} + +impl<'r> Drop for AppSession<'r> { + fn drop(&mut self) { + self.session.commit(self.request); + } +} + +#[derive(Default, Deserialize, Serialize)] +struct Inner { + messages: Vec, +} + +impl Inner { + pub fn add_message(&mut self, message: Message) { + self.messages.push(message); + } + + pub fn pop_messages(&mut self) -> Vec { + let mut messages: Vec = Vec::new(); + std::mem::swap(&mut messages, &mut self.messages); + messages + } + + pub fn commit(&mut self, request: &mut Request) { + request.session_mut().insert("app", self).unwrap() + } +} + +impl From<&Request> for Inner { + fn from(request: &Request) -> Self { + request.session().get("app").unwrap_or_default() + } +} diff --git a/templates/index.html b/templates/index.html index c2dd093..78ca8ec 100644 --- a/templates/index.html +++ b/templates/index.html @@ -54,8 +54,14 @@
- - + +