remove web admin

feature/admin
overlisted 8 months ago
parent 8534407f14
commit 1d141740d5
Signed by: me
GPG Key ID: 1ACCDCC0429C9737
  1. 1
      .env.example
  2. 67
      src/fairings/admin/api.rs
  3. 51
      src/fairings/admin/frontend.rs
  4. 28
      src/fairings/admin/mod.rs
  5. 2
      src/fairings/mod.rs
  6. 25
      src/guards/admin.rs
  7. 2
      src/guards/mod.rs
  8. 1
      src/main.rs
  9. 2
      static/robots.txt
  10. 75
      templates/admin/index.html.hbs
  11. 24
      templates/admin/ip-log.html.hbs

@ -1,2 +1 @@
# ADMIN_KEY=poop
# DATABASE_URL=postgres://localhost/mango

@ -1,67 +0,0 @@
use crate::fairings::prelude::*;
#[rocket::post("/login", data = "<key>")]
pub fn login(jar: &CookieJar<'_>, key: String) {
jar.add(Cookie::new("nothing", key));
}
#[derive(FromForm)]
pub struct HighlightProject {
id: String,
highlight: String,
}
#[rocket::post("/highlights", data = "<data>")]
pub async fn highlight_project(_access: AdminAccess, db: Db, data: Form<Strict<HighlightProject>>) {
let highlight = if &data.highlight == "true" {
true
} else {
false
};
db.run(move |conn| {
let id = schema::highlights::id.eq(&data.id);
if highlight {
diesel::insert_into(schema::highlights::table)
.values(id)
.execute(conn)
} else {
diesel::delete(schema::highlights::table.filter(id))
.execute(conn)
}
})
.await
.unwrap();
}
#[rocket::post("/projects", data = "<data>")]
pub async fn upsert_project(_access: AdminAccess, db: Db, data: Form<Strict<model::Project>>) {
db.run(move |conn| {
diesel::insert_into(schema::projects::table)
.values(&**data)
.on_conflict(schema::projects::id)
.do_update()
.set(&**data)
.execute(conn)
})
.await
.unwrap();
}
#[rocket::post("/config/<name>", data = "<data>")]
pub async fn upsert_config(_access: AdminAccess, db: Db, name: String, data: Json<serde_json::Value>) {
db.run(move |conn| {
diesel::insert_into(schema::configs::table)
.values(model::PageConfig {
name: name.clone(),
data: data.0.clone(),
})
.on_conflict(schema::configs::name)
.do_update()
.set(model::PageConfig { name, data: data.0 })
.execute(conn)
})
.await
.unwrap();
}

@ -1,51 +0,0 @@
use crate::fairings::prelude::*;
#[rocket::get("/")]
pub async fn index(_access: AdminAccess, db: Db) -> Template {
let projects = db
.run(|conn| schema::projects::table.load::<model::Project>(conn))
.await
.expect("failed to load projects");
let configs: Vec<_> = db
.run(|conn| schema::configs::table.load::<model::PageConfig>(conn))
.await
.expect("failed to load configs")
.into_iter()
.map(|it| json!({ "name": it.name, "data": serde_json::to_string_pretty(&it.data).unwrap() }))
.collect();
Template::render(
"admin/index",
json!({ "projects": projects, "configs": configs }),
)
}
#[rocket::get("/ip-log?<page>&<search>")]
pub async fn ip_log(
_access: AdminAccess,
db: Db,
page: Option<u32>,
search: Option<std::net::IpAddr>,
) -> Template {
let logs = db
.run(move |conn| {
let base = schema::ip_log::table
.order(schema::ip_log::timestamp.desc())
.offset(page.unwrap_or(0) as i64 * 50)
.limit(50);
if let Some(x) = search {
base.filter(schema::ip_log::addr.eq(ipnetwork::IpNetwork::from(x)))
.load::<model::IpLogEntry>(conn)
} else {
base.load::<model::IpLogEntry>(conn)
}
})
.await
.expect("failed to load ip log");
Template::render(
"admin/ip-log",
json!({ "entries": logs, "nextPage": page.unwrap_or(0) + 1, "search": search }),
)
}

@ -1,28 +0,0 @@
use super::prelude::*;
mod api;
mod frontend;
#[rocket::catch(401)]
fn teapot() -> (Status, &'static str) {
(Status { code: 418 }, "🫖")
}
pub fn fairing() -> impl Fairing {
AdHoc::on_ignite("Admin Frontend", |rocket| async {
rocket
.register("/admin", rocket::catchers![teapot])
.mount(
"/admin",
rocket::routes![api::login, frontend::index, frontend::ip_log],
)
.mount(
"/admin/api",
rocket::routes![
api::highlight_project,
api::upsert_project,
api::upsert_config
],
)
})
}

@ -1,12 +1,10 @@
mod prelude;
mod admin;
mod db;
mod frontend;
mod handlebars;
mod ip_log;
pub use admin::fairing as admin;
pub use db::fairing as db;
pub use frontend::fairing as frontend;
pub use self::handlebars::fairing as handlebars;

@ -1,25 +0,0 @@
use super::prelude::*;
pub struct AdminAccess;
#[async_trait]
impl<'r> FromRequest<'r> for AdminAccess {
type Error = ();
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
let cookie = request
.cookies()
.get("nothing")
.map(|x| String::from(x.value()));
if let Ok(key) = std::env::var("ADMIN_KEY") {
if cookie == Some(key) {
Outcome::Success(AdminAccess)
} else {
Outcome::Failure((Status::Unauthorized, ()))
}
} else {
Outcome::Failure((Status::Unauthorized, ()))
}
}
}

@ -1,9 +1,7 @@
mod prelude;
mod admin;
mod db;
mod page_configs;
pub use admin::*;
pub use db::*;
pub use page_configs::*;

@ -17,6 +17,5 @@ fn rocket() -> _ {
.attach(fairings::db())
.attach(fairings::ip_log())
.attach(fairings::handlebars())
.attach(fairings::admin())
.attach(fairings::frontend())
}

@ -1,2 +0,0 @@
User-agent: *
Disallow: /admin/

@ -1,75 +0,0 @@
<html>
good morning
<script>
window.onload = () => {
document.getElementById("highlight-project").onsubmit = async e => {
e.preventDefault();
await fetch("admin/api/highlights", { method: "post", body: new FormData(e.target) });
window.location = window.location;
};
document.getElementById("upsert-project").onsubmit = async e => {
e.preventDefault();
await fetch("admin/api/projects", { method: "post", body: new FormData(e.target) });
window.location = window.location;
};
document.getElementById("upsert-config").onsubmit = async e => {
e.preventDefault();
const name = document.getElementById("upsert-config-name").value;
const data = document.getElementById("upsert-config-data").value;
await fetch(`admin/api/config/${name}`, { method: "post", body: data });
window.location = window.location;
};
};
</script>
<body>
<a href="/admin/ip-log?page=0">ip log</a>
<h1>page configs</h1>
<h2>upsert</h2>
<form id="upsert-config" autocomplete="off">
<label>name</label>
<input id="upsert-config-name" name="name">
<label>data</label>
<input id="upsert-config-data" name="data">
<input type="submit" value="send">
</form>
{{#each configs}}
<h2>{{name}}</h2>
<code>{{data}}</code>
{{/each}}
<h1>projects</h1>
<h2>highlight</h2>
<form id="highlight-project" autocomplete="off">
<label>id</label>
<input name="id">
<label>highlight ("true" | _)</label>
<input name="highlight">
<input type="submit" value="send">
</form>
<h2>upsert</h2>
<form id="upsert-project" autocomplete="off">
<label>id</label>
<input name="id">
<label>display name</label>
<input name="name">
<label>desc</label>
<input name="description">
<label>image</label>
<input name="image">
<input type="submit" value="send">
</form>
{{#each projects}}
<article>
<h2>{{name}} (id {{id}})</h2>
<span>{{description}}</span>
</article>
{{/each}}
</body>
</html>

@ -1,24 +0,0 @@
<html>
<a href="?page={{nextPage}}&search={{search}}">next page</a>
<div>
<form>
<label>ip</label>
<input name="search">
<input type="submit" value="search"/>
</form>
</div>
<table>
<tr>
<th>addr</th>
<th>timestamp</th>
<th>path</th>
</tr>
{{#each entries}}
<tr>
<td>{{addr}}</td>
<td>{{timestamp}}</td>
<td>{{path}}</td>
</tr>
{{/each}}
</table>
</html>
Loading…
Cancel
Save