work
This commit is contained in:
parent
7100621f5e
commit
09a3f096c7
8 changed files with 154 additions and 115 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1054,6 +1054,7 @@ dependencies = [
|
|||
name = "macnickenson"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argh",
|
||||
"askama",
|
||||
"askama_tide",
|
||||
|
|
|
@ -5,9 +5,10 @@ authors = ["Stefan Schwarz <stefan@f2o.io>"]
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
argh = "0.1.3"
|
||||
askama = { version = "0.10", features = ["with-tide"]}
|
||||
askama_tide = "0.10"
|
||||
askama = { version = "0.10", features = ["with-tide"]}
|
||||
async-std = { version = "1.6", features = ["attributes"] }
|
||||
chrono = "0.4"
|
||||
sqlx = { version = "0.4.0-beta.1", features = ["mysql", "chrono", "macros"] }
|
||||
|
|
100
src/db.rs
100
src/db.rs
|
@ -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,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
|
20
src/main.rs
20
src/main.rs
|
@ -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
18
src/routes.rs
Normal 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())
|
||||
}
|
|
@ -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())
|
||||
}
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,28 @@
|
|||
|
||||
<div class="p-2">
|
||||
<h2 class="underline">Your Devices:</h2>
|
||||
<div class="grid grid-cols-3 grid-gap-1">
|
||||
<div>macaddr: "00:18:e7:34:11:1c"</div>
|
||||
{% for device in my %}
|
||||
<div class="grid grid-cols-3 grid-gap-1 p-1">
|
||||
<div class="font-mono">{{ device.macaddr }}</div>
|
||||
<div>
|
||||
<input class="focus:shadow-outline border border-gray-300 px-2"
|
||||
value="Thinkpad T30 Wifi"/>
|
||||
value="{{ device.descr }}"/>
|
||||
<select class="focus:shadow-outline border border-gray-300 px-2">
|
||||
<option value="1">Public</option>
|
||||
<option value="2">Private</option>
|
||||
<option value="3">Internal</option>
|
||||
<option value="0"
|
||||
{{ device.privacy.selected(crate::db::PrivacyLevel::ShowUserAndDevice) }}
|
||||
>Show User and Device</option>
|
||||
<option value="1"
|
||||
{{ device.privacy.selected(crate::db::PrivacyLevel::ShowUser) }}
|
||||
>Show User</option>
|
||||
<option value="2"
|
||||
{{ device.privacy.selected(crate::db::PrivacyLevel::ShowAnonymous) }}
|
||||
>Show Anonymous</option>
|
||||
<option value="3"
|
||||
{{ device.privacy.selected(crate::db::PrivacyLevel::HideUser) }}
|
||||
>Hide User</option>
|
||||
<option value="4"
|
||||
{{ device.privacy.selected(crate::db::PrivacyLevel::DontLog) }}
|
||||
>Dont Log</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
|
@ -34,23 +47,14 @@
|
|||
<button class="rounded bg-gray-300 font-bold px-2 bg-red-500">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 grid-gap-1">
|
||||
<div>macaddr: "90:78:41:bd:10:23"</div>
|
||||
<div>nickname: "Neptun"</div>
|
||||
<div>descr: "Neptun"</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 grid-gap-1">
|
||||
<div>macaddr: "10:0b:a9:ad:9f:30"</div>
|
||||
<div>nickname: "Wu"</div>
|
||||
<div>descr: "x220"</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="p-2">
|
||||
<h2 class="underline">Unregistred Devices:</h2>
|
||||
|
||||
<div class="grid grid-cols-3 grid-gap-1">
|
||||
|
||||
<div>macaddr: "f0:d5:bf:cc:a2:f9"</div>
|
||||
{% for device in unassinged %}
|
||||
<div class="grid grid-cols-4 grid-gap-1 p-1">
|
||||
<div class="font-mono">{{ device.macaddr }}</div>
|
||||
<div class="font-mono">{{ device.ip() }}</div>
|
||||
<div>
|
||||
<input class="focus:shadow-outline border border-gray-300 px-2"
|
||||
placeholder="awesome new device"/>
|
||||
|
@ -59,54 +63,7 @@
|
|||
<button class="rounded bg-gray-300 font-bold px-2 bg-blue-300">Register</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-3 grid-gap-1">
|
||||
|
||||
<div>macaddr: "6a:f4:a2:c4:e2:2e"</div>
|
||||
<div>nickname: "Mondschauer93"</div>
|
||||
<div>descr: "Smartphone"</div>
|
||||
|
||||
</div>
|
||||
<div class="grid grid-cols-3 grid-gap-1">
|
||||
<div>macaddr: "f8:ff:c2:20:b6:0d"</div>
|
||||
<div>nickname: "idefix"</div>
|
||||
<div>descr: "MacBook"</div>
|
||||
|
||||
</div>
|
||||
<div class="grid grid-cols-3 grid-gap-1">
|
||||
<div>macaddr: "30:57:14:db:34:d3"</div>
|
||||
<div>nickname: "idefix"</div>
|
||||
<div>descr: "IPhone"</div>
|
||||
|
||||
</div>
|
||||
<div class="grid grid-cols-3 grid-gap-1">
|
||||
<div>macaddr: "98:01:a7:b6:48:5b"</div>
|
||||
<div>nickname: "idefix"</div>
|
||||
<div>descr: "UbuntuBook"</div>
|
||||
|
||||
</div>
|
||||
<div class="grid grid-cols-3 grid-gap-1">
|
||||
<div>macaddr: "f4:db:e3:3f:7e:18"</div>
|
||||
<div>nickname: "raphii"</div>
|
||||
<div>descr: "iPhone 11"</div>
|
||||
|
||||
</div>
|
||||
<div class="grid grid-cols-3 grid-gap-1">
|
||||
<div>macaddr: "70:48:0f:98:de:23"</div>
|
||||
<div>nickname: "raphii"</div>
|
||||
<div>descr: "iPad Pro"</div>
|
||||
|
||||
</div>
|
||||
<div class="grid grid-cols-3 grid-gap-1">
|
||||
<div>macaddr: "e0:cc:f8:6a:d1:d4"</div>
|
||||
<div>nickname: "stoneos"</div>
|
||||
<div>descr: "xiaomi mi10"</div>
|
||||
|
||||
</div>
|
||||
<div class="grid grid-cols-3 grid-gap-1">
|
||||
<div>macaddr: "74:e5:f9:86:98:8b"</div>
|
||||
<div>nickname: "ptflea"</div>
|
||||
<div>descr: "computer"</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="shadow-lg p-2">
|
||||
footer
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue