froms and db
This commit is contained in:
parent
fc3a6fe2a0
commit
a1abfad8d6
6 changed files with 141 additions and 54 deletions
33
src/db.rs
33
src/db.rs
|
@ -2,7 +2,6 @@ use anyhow::{anyhow, Result};
|
||||||
use sqlx::database::HasArguments;
|
use sqlx::database::HasArguments;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
|
|
||||||
type QueryAs<'q, T> =
|
type QueryAs<'q, T> =
|
||||||
sqlx::query::QueryAs<'q, sqlx::MySql, T, <sqlx::MySql as HasArguments<'q>>::Arguments>;
|
sqlx::query::QueryAs<'q, sqlx::MySql, T, <sqlx::MySql as HasArguments<'q>>::Arguments>;
|
||||||
type Query<'q> = sqlx::query::Query<'q, sqlx::MySql, <sqlx::MySql as HasArguments<'q>>::Arguments>;
|
type Query<'q> = sqlx::query::Query<'q, sqlx::MySql, <sqlx::MySql as HasArguments<'q>>::Arguments>;
|
||||||
|
@ -45,7 +44,7 @@ SELECT DISTINCT
|
||||||
IF(al.iplong, TRUE, FALSE) present
|
IF(al.iplong, TRUE, FALSE) present
|
||||||
FROM
|
FROM
|
||||||
mac_to_nick mtn
|
mac_to_nick mtn
|
||||||
LEFT JOIN
|
LEFT OUTER JOIN
|
||||||
alive_hosts al
|
alive_hosts al
|
||||||
ON
|
ON
|
||||||
mtn.macaddr = al.macaddr
|
mtn.macaddr = al.macaddr
|
||||||
|
@ -95,6 +94,23 @@ WHERE
|
||||||
.bind(&self.descr)
|
.bind(&self.descr)
|
||||||
.bind(id))
|
.bind(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn delete(self) -> Result<Query<'q>> {
|
||||||
|
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)]
|
#[derive(sqlx::Type, Debug, Clone, Copy)]
|
||||||
|
@ -108,10 +124,6 @@ pub enum PrivacyLevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrivacyLevel {
|
impl PrivacyLevel {
|
||||||
pub fn as_u8(&self) -> u8 {
|
|
||||||
*self as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn selected(&self, level: &PrivacyLevel) -> &'static str {
|
pub fn selected(&self, level: &PrivacyLevel) -> &'static str {
|
||||||
if *self as u8 == *level as u8 {
|
if *self as u8 == *level as u8 {
|
||||||
"selected"
|
"selected"
|
||||||
|
@ -149,16 +161,19 @@ impl<'q> AliveDevice {
|
||||||
"
|
"
|
||||||
SELECT DISTINCT
|
SELECT DISTINCT
|
||||||
al.macaddr macaddr,
|
al.macaddr macaddr,
|
||||||
al.iplong iplong
|
al.iplong iplong,
|
||||||
|
mtn.nickname
|
||||||
FROM
|
FROM
|
||||||
alive_hosts al
|
alive_hosts al
|
||||||
NATURAL LEFT JOIN
|
LEFT OUTER JOIN
|
||||||
mac_to_nick mtn
|
mac_to_nick mtn
|
||||||
|
ON
|
||||||
|
al.macaddr = mtn.macaddr
|
||||||
WHERE
|
WHERE
|
||||||
mtn.nickname IS NULL
|
mtn.nickname IS NULL
|
||||||
AND al.erfda > NOW() - INTERVAL 24 DAY
|
|
||||||
ORDER BY
|
ORDER BY
|
||||||
al.erfda DESC
|
al.erfda DESC
|
||||||
|
;
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
39
src/forms.rs
39
src/forms.rs
|
@ -18,12 +18,11 @@ impl RegisterForm {
|
||||||
Ok(privacy) => privacy,
|
Ok(privacy) => privacy,
|
||||||
Err(_) => return (Level::Error, "unable to parse privacy level".to_string()),
|
Err(_) => return (Level::Error, "unable to parse privacy level".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let dbresult = db::Device {
|
let dbresult = db::Device {
|
||||||
id: None,
|
id: None,
|
||||||
macaddr: self.macaddr,
|
macaddr: self.macaddr,
|
||||||
nickname: USER.to_string(),
|
nickname: USER.to_string(),
|
||||||
descr: self.descr,
|
descr: self.descr.clone(),
|
||||||
privacy,
|
privacy,
|
||||||
present: false,
|
present: false,
|
||||||
};
|
};
|
||||||
|
@ -33,7 +32,10 @@ impl RegisterForm {
|
||||||
.execute(&request.state().pool)
|
.execute(&request.state().pool)
|
||||||
.await;
|
.await;
|
||||||
return match dbresult {
|
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()),
|
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()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
32
src/main.rs
32
src/main.rs
|
@ -6,8 +6,11 @@ use tide::sessions::{MemoryStore, SessionMiddleware};
|
||||||
mod db;
|
mod db;
|
||||||
mod forms;
|
mod forms;
|
||||||
mod routes;
|
mod routes;
|
||||||
|
mod session;
|
||||||
mod templates;
|
mod templates;
|
||||||
|
|
||||||
|
pub use session::AppSession as Session;
|
||||||
|
|
||||||
pub const USER: &str = "foosinn";
|
pub const USER: &str = "foosinn";
|
||||||
|
|
||||||
/// Configuration
|
/// Configuration
|
||||||
|
@ -43,34 +46,6 @@ pub enum Level {
|
||||||
|
|
||||||
pub type Message = (Level, String);
|
pub type Message = (Level, String);
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize)]
|
|
||||||
pub struct AppSession {
|
|
||||||
messages: Vec<Message>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AppSession {
|
|
||||||
pub fn add_message(mut self, message: Message) -> Self {
|
|
||||||
self.messages.push(message);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop_messages(&mut self) -> Vec<Message> {
|
|
||||||
let mut messages: Vec<Message> = 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<State>;
|
pub type Request = tide::Request<State>;
|
||||||
|
|
||||||
#[async_std::main]
|
#[async_std::main]
|
||||||
|
@ -89,6 +64,7 @@ async fn main() -> Result<(), io::Error> {
|
||||||
app.at("/").get(routes::index);
|
app.at("/").get(routes::index);
|
||||||
app.at("/register").post(routes::register);
|
app.at("/register").post(routes::register);
|
||||||
app.at("/update").post(routes::update);
|
app.at("/update").post(routes::update);
|
||||||
|
app.at("/delete").post(routes::delete);
|
||||||
app.at("/healthz").get(routes::healthz);
|
app.at("/healthz").get(routes::healthz);
|
||||||
app.at("/static").serve_dir("static/")?;
|
app.at("/static").serve_dir("static/")?;
|
||||||
app.listen(config.listen).await
|
app.listen(config.listen).await
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::db;
|
use crate::db;
|
||||||
use crate::forms;
|
use crate::forms;
|
||||||
use crate::templates;
|
use crate::templates;
|
||||||
use crate::AppSession;
|
use crate::Session;
|
||||||
use crate::USER;
|
use crate::USER;
|
||||||
use tide::Redirect;
|
use tide::Redirect;
|
||||||
|
|
||||||
|
@ -18,28 +18,27 @@ pub async fn index(mut request: crate::Request) -> tide::Result {
|
||||||
.fetch_all(&request.state().pool)
|
.fetch_all(&request.state().pool)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| dbg!(err))?;
|
.map_err(|err| dbg!(err))?;
|
||||||
|
let messages = Session::from(&mut request).pop_messages();
|
||||||
let mut session = AppSession::from(&mut request);
|
|
||||||
let messages = session.pop_messages();
|
|
||||||
session.commit(&mut request);
|
|
||||||
|
|
||||||
Ok(templates::IndexTemplate::new(my, unassinged, messages).into())
|
Ok(templates::IndexTemplate::new(my, unassinged, messages).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn register(mut request: crate::Request) -> tide::Result {
|
pub async fn register(mut request: crate::Request) -> tide::Result {
|
||||||
let form: forms::RegisterForm = request.body_form().await?;
|
let form: forms::RegisterForm = request.body_form().await?;
|
||||||
let message = form.handle(&request).await;
|
let message = form.handle(&request).await;
|
||||||
AppSession::from(&mut request)
|
Session::from(&mut request).add_message(message);
|
||||||
.add_message(message)
|
|
||||||
.commit(&mut request);
|
|
||||||
Ok(Redirect::see_other("/").into())
|
Ok(Redirect::see_other("/").into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update(mut request: crate::Request) -> tide::Result {
|
pub async fn update(mut request: crate::Request) -> tide::Result {
|
||||||
let form: forms::UpdateForm = request.body_form().await?;
|
let form: forms::UpdateForm = request.body_form().await?;
|
||||||
let message = form.handle(&request).await;
|
let message = form.handle(&request).await;
|
||||||
AppSession::from(&mut request)
|
Session::from(&mut request).add_message(message);
|
||||||
.add_message(message)
|
Ok(Redirect::see_other("/").into())
|
||||||
.commit(&mut request);
|
}
|
||||||
|
|
||||||
|
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())
|
Ok(Redirect::see_other("/").into())
|
||||||
}
|
}
|
||||||
|
|
58
src/session.rs
Normal file
58
src/session.rs
Normal file
|
@ -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<Message> {
|
||||||
|
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<Message>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Inner {
|
||||||
|
pub fn add_message(&mut self, message: Message) {
|
||||||
|
self.messages.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_messages(&mut self) -> Vec<Message> {
|
||||||
|
let mut messages: Vec<Message> = 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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,8 +54,14 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button class="rounded bg-gray-300 font-bold px-2 bg-green-500">Update</button>
|
<button type="submit" name="action" value="update"
|
||||||
<button class="rounded bg-gray-300 font-bold px-2 bg-red-500">Delete</button>
|
class="rounded bg-gray-300 font-bold px-2 bg-green-500">
|
||||||
|
Update
|
||||||
|
</button>
|
||||||
|
<button type="submit"name="action" value="update"
|
||||||
|
class="rounded bg-gray-300 font-bold px-2 bg-red-500">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue