This commit is contained in:
Stefan Schwarz 2020-08-15 16:34:23 +02:00
parent 09a3f096c7
commit 288f193754
7 changed files with 53 additions and 17 deletions

1
Cargo.lock generated
View file

@ -1060,6 +1060,7 @@ dependencies = [
"askama_tide", "askama_tide",
"async-std", "async-std",
"chrono", "chrono",
"serde",
"sqlx", "sqlx",
"tide", "tide",
] ]

View file

@ -6,11 +6,12 @@ edition = "2018"
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
argh = "0.1.3" argh = "0.1"
askama_tide = "0.10" askama_tide = "0.10"
askama = { version = "0.10", features = ["with-tide"]} askama = { version = "0.10", features = ["with-tide"]}
async-std = { version = "1.6", features = ["attributes"] } async-std = { version = "1.6", features = ["attributes"] }
chrono = "0.4" chrono = "0.4"
serde = "1.0"
sqlx = { version = "0.4.0-beta.1", features = ["mysql", "chrono", "macros"] } sqlx = { version = "0.4.0-beta.1", features = ["mysql", "chrono", "macros"] }
tide = "0.13" tide = "0.13"

View file

@ -4,9 +4,10 @@ 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>;
#[derive(sqlx::FromRow, Debug)] #[derive(sqlx::FromRow, Debug)]
pub struct Entry { pub struct Device {
pub id: i32, pub id: i32,
pub macaddr: String, pub macaddr: String,
pub nickname: String, pub nickname: String,
@ -26,7 +27,7 @@ pub enum PrivacyLevel {
DontLog = 4, DontLog = 4,
} }
impl<'q> Entry { impl<'q> Device {
pub fn all() -> QueryAs<'q, Self> { pub fn all() -> QueryAs<'q, Self> {
sqlx::query_as("SELECT * FROM mac_to_nick") sqlx::query_as("SELECT * FROM mac_to_nick")
} }
@ -34,21 +35,37 @@ impl<'q> Entry {
pub fn for_user(user: &'q str) -> QueryAs<'q, Self> { pub fn for_user(user: &'q str) -> QueryAs<'q, Self> {
sqlx::query_as( sqlx::query_as(
" "
SELECT SELECT DISTINCT
mtn.*, mtn.*,
IF(al.iplong != NULL, TRUE, FALSE) present IF(al.iplong, TRUE, FALSE) present
FROM FROM
mac_to_nick mtn, mac_to_nick mtn
LEFT JOIN
alive_hosts al alive_hosts al
ON
mtn.macaddr = al.macaddr
AND al.erfda > NOW() - INTERVAL 24 DAY
WHERE WHERE
al.macaddr = mtn.macaddr nickname = ?
AND nickname = ? ORDER BY
GROUP BY al.erfda DESC
mtn.macaddr
", ",
) )
.bind(user) .bind(user)
} }
pub fn register(mac: &'q str, user: &'q str) -> Query<'q> {
sqlx::query(
"
INSERT
INTO mac_to_nick
(macaddr, nickname, descr, privacy, created)
VALUES
(?, ?, ?, ?, NOW())
",
)
.bind(mac)
}
} }
impl PrivacyLevel { impl PrivacyLevel {
@ -79,11 +96,14 @@ SELECT DISTINCT
al.macaddr macaddr, al.macaddr macaddr,
al.iplong iplong al.iplong iplong
FROM FROM
alive_hosts al, alive_hosts al
NATURAL LEFT JOIN
mac_to_nick mtn mac_to_nick mtn
WHERE WHERE
mtn.nickname IS NULL mtn.nickname IS NULL
AND al.erfda > NOW() - INTERVAL 24 DAY AND al.erfda > NOW() - INTERVAL 24 DAY
ORDER BY
al.erfda DESC
", ",
) )
} }

View file

@ -37,6 +37,7 @@ async fn main() -> Result<(), io::Error> {
let mut app = tide::with_state(State { pool }); let mut app = tide::with_state(State { pool });
app.at("/").get(routes::index); app.at("/").get(routes::index);
app.at("/register").post(routes::register);
app.at("/healthz").get(routes::healthz); app.at("/healthz").get(routes::healthz);
app.at("/static").serve_dir("static/")?; app.at("/static").serve_dir("static/")?;

View file

@ -1,12 +1,15 @@
use crate::db; use crate::db;
use crate::templates; use crate::templates;
use tide::prelude::*;
const USER: &str = "foosinn";
pub async fn healthz(_request: crate::Request) -> tide::Result { pub async fn healthz(_request: crate::Request) -> tide::Result {
Ok("ok".into()) Ok("ok".into())
} }
pub async fn index(request: crate::Request) -> tide::Result { pub async fn index(request: crate::Request) -> tide::Result {
let my = db::Entry::for_user("foosinn") let my = db::Device::for_user(USER)
.fetch_all(&request.state().pool) .fetch_all(&request.state().pool)
.await .await
.map_err(|err| dbg!(err))?; .map_err(|err| dbg!(err))?;
@ -16,3 +19,13 @@ pub async fn index(request: crate::Request) -> tide::Result {
.map_err(|err| dbg!(err))?; .map_err(|err| dbg!(err))?;
Ok(templates::IndexTemplate::new(my, unassinged).into()) Ok(templates::IndexTemplate::new(my, unassinged).into())
} }
#[derive(Deserialize)]
struct RegisterForm {
macaddr: String,
}
pub async fn register(mut request: crate::Request) -> tide::Result {
let form: RegisterForm = request.body_form().await?;
unimplemented!();
}

View file

@ -4,12 +4,12 @@ use askama::Template;
#[derive(Template, Default)] #[derive(Template, Default)]
#[template(path = "index.html")] #[template(path = "index.html")]
pub struct IndexTemplate { pub struct IndexTemplate {
my: Vec<db::Entry>, my: Vec<db::Device>,
unassinged: Vec<db::AliveDevice>, unassinged: Vec<db::AliveDevice>,
} }
impl IndexTemplate { impl IndexTemplate {
pub fn new(my: Vec<db::Entry>, unassinged: Vec<db::AliveDevice>) -> Self { pub fn new(my: Vec<db::Device>, unassinged: Vec<db::AliveDevice>) -> Self {
Self { my, unassinged } Self { my, unassinged }
} }
} }

View file

@ -19,8 +19,8 @@
<div class="p-2"> <div class="p-2">
<h2 class="underline">Your Devices:</h2> <h2 class="underline">Your Devices:</h2>
{% for device in my %} {% for device in my %}
<div class="grid grid-cols-3 grid-gap-1 p-1"> <div class="grid grid-cols-3 grid-gap-1">
<div class="font-mono">{{ device.macaddr }}</div> <div class="font-mono">{{ device.macaddr }} {{ device.present }}</div>
<div> <div>
<input class="focus:shadow-outline border border-gray-300 px-2" <input class="focus:shadow-outline border border-gray-300 px-2"
value="{{ device.descr }}"/> value="{{ device.descr }}"/>
@ -52,7 +52,7 @@
<div class="p-2"> <div class="p-2">
<h2 class="underline">Unregistred Devices:</h2> <h2 class="underline">Unregistred Devices:</h2>
{% for device in unassinged %} {% for device in unassinged %}
<div class="grid grid-cols-4 grid-gap-1 p-1"> <div class="grid grid-cols-4 grid-gap-1 p-2">
<div class="font-mono">{{ device.macaddr }}</div> <div class="font-mono">{{ device.macaddr }}</div>
<div class="font-mono">{{ device.ip() }}</div> <div class="font-mono">{{ device.ip() }}</div>
<div> <div>