This commit is contained in:
Stefan Schwarz 2020-08-15 09:10:47 +02:00
parent 7100621f5e
commit 09a3f096c7
8 changed files with 154 additions and 115 deletions

100
src/db.rs
View file

@ -1,11 +1,99 @@
use chrono::{DateTime, Utc};
use sqlx::database::HasArguments;
use std::net::IpAddr;
type QueryAs<'q, T> =
sqlx::query::QueryAs<'q, sqlx::MySql, T, <sqlx::MySql as HasArguments<'q>>::Arguments>;
#[derive(sqlx::FromRow, Debug)]
pub struct Entry {
id: i32,
macaddr: String,
nickname: String,
descr: String,
privacy: i8,
created: DateTime<Utc>,
pub id: i32,
pub macaddr: String,
pub nickname: String,
pub descr: String,
pub privacy: PrivacyLevel,
pub created: DateTime<Utc>,
pub present: bool,
}
#[derive(sqlx::Type, Debug, Clone, Copy)]
#[repr(i8)]
pub enum PrivacyLevel {
ShowUserAndDevice = 0,
ShowUser = 1,
ShowAnonymous = 2,
HideUser = 3,
DontLog = 4,
}
impl<'q> Entry {
pub fn all() -> QueryAs<'q, Self> {
sqlx::query_as("SELECT * FROM mac_to_nick")
}
pub fn for_user(user: &'q str) -> QueryAs<'q, Self> {
sqlx::query_as(
"
SELECT
mtn.*,
IF(al.iplong != NULL, TRUE, FALSE) present
FROM
mac_to_nick mtn,
alive_hosts al
WHERE
al.macaddr = mtn.macaddr
AND nickname = ?
GROUP BY
mtn.macaddr
",
)
.bind(user)
}
}
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"
} else {
""
}
}
}
#[derive(sqlx::FromRow, Debug)]
pub struct AliveDevice {
pub macaddr: String,
pub iplong: i32,
}
impl<'q> AliveDevice {
pub fn unassinged() -> QueryAs<'q, Self> {
sqlx::query_as(
"
SELECT DISTINCT
al.macaddr macaddr,
al.iplong iplong
FROM
alive_hosts al,
mac_to_nick mtn
WHERE
mtn.nickname IS NULL
AND al.erfda > NOW() - INTERVAL 24 DAY
",
)
}
pub fn ip(&self) -> IpAddr {
IpAddr::from([
(self.iplong >> 24 & 0xff) as u8,
(self.iplong >> 16 & 0xff) as u8,
(self.iplong >> 8 & 0xff) as u8,
(self.iplong & 0xff) as u8,
])
}
}

View file

@ -11,6 +11,13 @@ struct Config {
/// listen address
#[argh(option, default = "\"[::1]:8080\".to_string()")]
listen: String,
/// database dsn
#[argh(
option,
default = "\"mysql://administration:foosinn123@127.0.0.1/administration\".to_string()"
)]
dsn: String,
}
#[derive(Clone)]
@ -24,12 +31,7 @@ pub type Request = tide::Request<State>;
async fn main() -> Result<(), io::Error> {
let config: Config = argh::from_env();
let dsn = "mysql://administration:foosinn123@127.0.0.1/administration";
let pool = MySqlPool::connect(dsn)
.await
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
let mut conn = pool
.acquire()
let pool = MySqlPool::connect(&config.dsn)
.await
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
@ -38,11 +40,5 @@ async fn main() -> Result<(), io::Error> {
app.at("/healthz").get(routes::healthz);
app.at("/static").serve_dir("static/")?;
let entries: Vec<db::Entry> = sqlx::query_as("select * from mac_to_nick")
.fetch_all(&mut conn)
.await
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
entries.into_iter().for_each(|e| println!("{:?}", e));
app.listen(config.listen).await
}

18
src/routes.rs Normal file
View file

@ -0,0 +1,18 @@
use crate::db;
use crate::templates;
pub async fn healthz(_request: crate::Request) -> tide::Result {
Ok("ok".into())
}
pub async fn index(request: crate::Request) -> tide::Result {
let my = db::Entry::for_user("foosinn")
.fetch_all(&request.state().pool)
.await
.map_err(|err| dbg!(err))?;
let unassinged = db::AliveDevice::unassinged()
.fetch_all(&request.state().pool)
.await
.map_err(|err| dbg!(err))?;
Ok(templates::IndexTemplate::new(my, unassinged).into())
}

View file

@ -1,9 +0,0 @@
use crate::templates;
pub async fn healthz(_request: crate::Request) -> tide::Result {
Ok("ok".into())
}
pub async fn index(request: crate::Request) -> tide::Result {
Ok(templates::IndexTemplate::new().into())
}

View file

@ -3,26 +3,13 @@ use askama::Template;
#[derive(Template, Default)]
#[template(path = "index.html")]
pub struct IndexTemplate<'a> {
devices: Vec<Device<'a>>,
pub struct IndexTemplate {
my: Vec<db::Entry>,
unassinged: Vec<db::AliveDevice>,
}
pub struct Device<'a> {
pub macaddr: &'a str,
pub nickname: &'a str,
pub descr: &'a str,
pub privacy: PrivacyLevel,
}
#[repr(u8)]
pub enum PrivacyLevel {
Public = 1,
Private = 2,
Internal = 3,
}
impl<'a> IndexTemplate<'a> {
pub fn new() -> Self {
Self::default()
impl IndexTemplate {
pub fn new(my: Vec<db::Entry>, unassinged: Vec<db::AliveDevice>) -> Self {
Self { my, unassinged }
}
}