summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config.rs2
-rw-r--r--src/main.rs13
-rw-r--r--src/repo/constants.rs9
-rw-r--r--src/repo/mod.rs28
-rw-r--r--src/routes/mod.rs (renamed from src/handlers/mod.rs)45
-rw-r--r--src/templates/base.hbs155
-rw-r--r--src/templates/index.hbs74
-rw-r--r--src/templates/index.html85
-rw-r--r--src/templates/login.hbs7
-rw-r--r--src/templates/login.html6
-rw-r--r--src/templates/mod.rs25
-rw-r--r--src/templates/suggestions.hbs9
12 files changed, 321 insertions, 137 deletions
diff --git a/src/config.rs b/src/config.rs
index 7798967..b3c9715 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,7 +1,7 @@
use once_cell::sync::Lazy;
use std::{env::var, error::Error, net::SocketAddr};
-pub static INSTANCE: Lazy<AppConfig> =
+pub static CONFIG_INSTANCE: Lazy<AppConfig> =
Lazy::new(|| AppConfig::from_env().expect("Error loading config"));
#[derive(Clone, Debug)]
diff --git a/src/main.rs b/src/main.rs
index 1947ff8..4a5a8b1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,28 +1,27 @@
+use crate::config::CONFIG_INSTANCE;
+use crate::error::TwinHError;
use hyper::{
service::{make_service_fn, service_fn},
Server,
};
-use std::convert::Infallible; // TODO:
mod config;
mod error;
-mod handlers;
mod models;
mod repo;
+mod routes;
mod templates;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
- let addr = config::INSTANCE.addr;
+ let addr = CONFIG_INSTANCE.addr;
- let make_svc = make_service_fn(move |_conn| async {
- Ok::<_, Infallible>(service_fn(|req| handlers::router(req)))
- });
+ let make_svc =
+ make_service_fn(move |_conn| async { Ok::<_, TwinHError>(service_fn(routes::router)) });
let server = Server::bind(&addr).serve(make_svc);
let graceful = server.with_graceful_shutdown(shutdown_signal());
- // run until shutdown signal
if let Err(e) = graceful.await {
eprintln!("server error: {}", e);
}
diff --git a/src/repo/constants.rs b/src/repo/constants.rs
index e168a77..6da641f 100644
--- a/src/repo/constants.rs
+++ b/src/repo/constants.rs
@@ -1,11 +1,2 @@
-use once_cell::sync::Lazy;
-use sled::{Config, Db};
-
pub const PARTS_TREE: &str = "parts";
pub const CARS_TREE: &str = "cars";
-pub static REPO_INSTANCE: Lazy<Db> = Lazy::new(|| {
- Config::default()
- .path("/tmp/twinh")
- .open()
- .expect("Couldn't open DB!")
-});
diff --git a/src/repo/mod.rs b/src/repo/mod.rs
index d4c5e44..f0bb95c 100644
--- a/src/repo/mod.rs
+++ b/src/repo/mod.rs
@@ -1,16 +1,36 @@
+use crate::config::CONFIG_INSTANCE;
use crate::error::TwinHError;
use crate::models::Car;
use crate::models::Part;
use bincode::deserialize;
use constants::*;
+use once_cell::sync::Lazy;
+use sled::{Config, Db};
mod constants;
+static REPO_INSTANCE: Lazy<Db> = Lazy::new(|| {
+ Config::default()
+ .path(&CONFIG_INSTANCE.db_uri)
+ .temporary(true)
+ .open()
+ .expect("Couldn't open DB!")
+});
+
+pub fn create_demo_db() -> Result<(), TwinHError> {
+ let db = sled::Config::default()
+ .path(&CONFIG_INSTANCE.db_uri)
+ .create_new(true)
+ .open()?;
+ let cars_tree = db.open_tree(CARS_TREE)?;
+ Ok(())
+}
+
pub fn create_new_db() -> Result<(), TwinHError> {
- let config = sled::Config::default()
- .path("/var/db/twinh")
- .create_new(true);
- let db = config.open()?;
+ sled::Config::default()
+ .path(&CONFIG_INSTANCE.db_uri)
+ .create_new(true)
+ .open()?;
Ok(())
}
diff --git a/src/handlers/mod.rs b/src/routes/mod.rs
index 3ad7f49..1866e49 100644
--- a/src/handlers/mod.rs
+++ b/src/routes/mod.rs
@@ -1,19 +1,20 @@
+use crate::error::TwinHError;
+use crate::repo;
use crate::templates;
-use handlebars::Handlebars;
use hyper::body::HttpBody as _;
use hyper::Method;
use hyper::StatusCode;
use hyper::{Body, Request, Response};
use serde::{Deserialize, Serialize};
-use sled::Db;
-use std::convert::Infallible; // TODO:
-pub async fn router(req: Request<Body>) -> Result<Response<Body>, Infallible> {
+pub async fn router(req: Request<Body>) -> Result<Response<Body>, TwinHError> {
match (req.method(), req.uri().path()) {
- (&Method::GET, "/") | (&Method::GET, "/index.html") => index(req).await,
- (&Method::GET, "/login") | (&Method::GET, "/login/index.html") => login().await,
+ (&Method::GET, "/") => index(req).await,
+ (&Method::GET, "/cars") => cars(req).await,
+ (&Method::GET, "/login") => login().await,
(&Method::GET, "/login/google") => login_google().await,
(&Method::GET, "/login/google/code") => login_google_code(req).await,
+ (&Method::GET, "/suggestions") => suggestions().await,
_ => Ok(Response::builder()
.status(StatusCode::NOT_FOUND)
.body("Not found.".into())
@@ -21,11 +22,17 @@ pub async fn router(req: Request<Body>) -> Result<Response<Body>, Infallible> {
}
}
-async fn login() -> Result<Response<Body>, Infallible> {
- Ok(Response::new(templates::LOGIN_T.into()))
+async fn suggestions() -> Result<Response<Body>, TwinHError> {
+ todo!()
}
-async fn login_google() -> Result<Response<Body>, Infallible> {
+async fn login() -> Result<Response<Body>, TwinHError> {
+ Ok(Response::new(
+ templates::REGISTRY.render("login", &"").unwrap().into(),
+ ))
+}
+
+async fn login_google() -> Result<Response<Body>, TwinHError> {
let uri = hyper::Uri::builder()
.scheme("https")
.authority("accounts.google.com")
@@ -69,7 +76,7 @@ impl Default for AuthRequest {
}
}
-async fn login_google_code(req: Request<Body>) -> Result<Response<Body>, Infallible> {
+async fn login_google_code(req: Request<Body>) -> Result<Response<Body>, TwinHError> {
let query = req.uri().query().unwrap_or_default();
let query = serde_urlencoded::de::from_str::<GoogleOAuthQuery>(query).unwrap();
if query.state != "BLARGH" {
@@ -116,12 +123,14 @@ pub struct AccessToken {
token_type: String,
}
-async fn index(req: Request<Body>) -> Result<Response<Body>, Infallible> {
+async fn cars(req: Request<Body>) -> Result<Response<Body>, TwinHError> {
+ let cars = repo::get_all_cars().unwrap();
+ todo!()
+}
+
+async fn index(req: Request<Body>) -> Result<Response<Body>, TwinHError> {
let query = req.uri().query().unwrap_or_default();
let filter = serde_urlencoded::de::from_str::<PartsQuery>(query).unwrap();
- let mut reg = Handlebars::new();
- reg.register_template_string("index", templates::INDEX_T)
- .unwrap();
let mut data = PartsData::default();
data.makes = Some(vec!["Hudson".into(), "Essex".into(), "Terraplane".into()]);
@@ -140,8 +149,12 @@ async fn index(req: Request<Body>) -> Result<Response<Body>, Infallible> {
data.selected_model = Some(model);
}
- let result = reg.render("index", &data).unwrap();
- Ok(Response::new(result.into()))
+ let body = templates::REGISTRY.render("index", &data).unwrap();
+ let resp = Response::builder()
+ .header(hyper::header::CONTENT_TYPE, "text/html; charset=utf-8")
+ .body(body.into())
+ .unwrap();
+ Ok(resp)
}
#[derive(Debug, Deserialize)]
diff --git a/src/templates/base.hbs b/src/templates/base.hbs
new file mode 100644
index 0000000..df3ba9d
--- /dev/null
+++ b/src/templates/base.hbs
@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <style>
+ :root {
+ --balboa: #195970;
+ }
+
+ body {
+ margin: 0;
+ padding: 0;
+ font-size: 1em;
+ }
+
+ .model::before {
+ content: "⤷";
+ }
+
+ .topbar {
+ background-color: var(--balboa);
+ box-shadow: 0 0 0.5em black;
+ position: relative;
+ height: 3em;
+ z-index: 2;
+ }
+
+ .topbar ul {
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+ }
+
+ .topbar li {
+ float: left;
+ display: block;
+ padding: 14px 14px;
+ }
+
+ .topbar li.right {
+ float: right;
+ }
+
+ .topbar li a {
+ color: white;
+ text-decoration: none;
+ }
+
+ .sidebar {
+ background-color: var(--balboa);
+ box-shadow: inset -0.5em 0 0.5em -0.5em black;
+ z-index: 1;
+ position: fixed;
+ top: 3em;
+ left: 0;
+ width: 20%;
+ height: 100%;
+ transition: 0.25s;
+ }
+
+ .sidebar form {
+ padding: 10px 10px;
+ }
+
+ .sidebar button {
+ font-size: 1em;
+ display: block;
+ background: none;
+ border: 0 none;
+ cursor: pointer;
+ color: white;
+ }
+
+ .model {
+ margin-left: 20px;
+ }
+
+ #hidden:target .sidebar {
+ left: -20%;
+ }
+
+ .menuToggle a.openMenu {
+ display: none;
+ }
+
+ #hidden:target .menuToggle a.closeMenu {
+ display: none;
+ }
+
+ #hidden:target .menuToggle a.openMenu {
+ display: block;
+ }
+
+ #hidden:target section {
+ margin-left: 0;
+ }
+
+ .catalogTable {
+ width: 100%;
+ border-collapse: collapse;
+ }
+
+ .catalogTable td,
+ .catalogTable th {
+ padding: 0.5em;
+ }
+
+ .catalogTable tr:nth-child(even) {
+ background-color: #f2f2f2;
+ }
+
+ .catalogTable tr:hover {
+ background-color: #ddd;
+ }
+
+ .catalogTable th {
+ padding-top: 12px;
+ padding-bottom: 12px;
+ text-align: left;
+ background-color: var(--balboa);
+ color: white;
+ }
+
+ input[type="search"] {
+ width: 100%;
+ }
+
+ section {
+ /* TODO: need to make this not applicable to other templates that don't have sidebar */
+ margin-left: 20%;
+ transition: margin-left 0.25s;
+ padding-top: 2em;
+ padding-left: 2em;
+ padding-right: 2em;
+ }
+ </style>
+</head>
+
+<body id="hidden">
+ <nav class="topbar">
+ <ul>
+ {{~> navItem}}
+ <li><a href="/">Index</a></li>
+ <li><a href="#">Parts</a></li>
+ <li><a href="#">Cars</a></li>
+ <li><a href="#">Suggestions</a></li>
+ <li><a href="#">About</a></li>
+ <li class="right"><a href="/login">Login</a></li>
+ </ul>
+ </nav>
+
+ {{~> body}}
+</body>
+
+</html>
diff --git a/src/templates/index.hbs b/src/templates/index.hbs
new file mode 100644
index 0000000..6bd539b
--- /dev/null
+++ b/src/templates/index.hbs
@@ -0,0 +1,74 @@
+{{#> base}}
+{{#*inline "navItem"}}
+<li>
+ <div class="menuToggle">
+ <a class="openMenu" href="#"><span>
+ <svg style="width: 24px; height: 24px" viewBox="0 0 24 24">
+ <path fill="currentColor" d="M3,6H21V8H3V6M3,11H21V13H3V11M3,16H21V18H3V16Z" />
+ </svg>
+ </span></a>
+ <a class="closeMenu" href="#hidden"><span>
+ <svg style="width: 24px; height: 24px" viewBox="0 0 24 24">
+ <path fill="currentColor"
+ d="M21,15.61L19.59,17L14.58,12L19.59,7L21,8.39L17.44,12L21,15.61M3,6H16V8H3V6M3,13V11H13V13H3M3,18V16H16V18H3Z" />
+ </svg>
+ </span></a>
+ </div>
+</li>
+{{/inline}}
+{{#*inline "body"}}
+<nav class="sidebar">
+ {{#each makes}}
+ <form action="/">
+ {{#if (eq this ../selected_make)}}
+ <button disabled class="make">
+ {{ this }}
+ </button>
+ <input type="hidden" name="make" value="{{ ../selected_make }}" />
+ {{#each ../models}}
+ {{#if (eq this ../../selected_model)}}
+ <button disabled class="model">{{~ this ~}}</button>
+ {{else}}
+ <button class="model" name="model" value="{{ this }}">
+ {{~ this ~}}
+ </button>
+ {{/if}}
+ {{else}}
+ <button disabled class="model">(No models found)</button>
+ {{/each}}
+ {{else}}
+ <button class="make" name="make" value="{{ this }}">
+ {{~ this ~}}
+ </button>
+ {{/if}}
+ </form>
+ {{else}}
+ <button disabled class="make">(No makes found)</button>
+ {{/each}}
+</nav>
+
+<section>
+ <form>
+ {{#if selected_make}}
+ <input type="hidden" name="make" value="{{ selected_make }}" />
+ {{/if}}
+ {{#if selected_model}}
+ <input type="hidden" name="model" value="{{ selected_model }}" />
+ {{/if}}
+ <input autofocus type="search" name="search" placeholder="hit enter to search" />
+ </form>
+</section>
+
+<section>
+ <table class="catalogTable">
+ <tbody>
+ {{#each parts}}
+ <tr>
+ <td>{{ this }}</td>
+ </tr>
+ {{/each}}
+ </tbody>
+ </table>
+</section>
+{{/inline}}
+{{/base}}
diff --git a/src/templates/index.html b/src/templates/index.html
deleted file mode 100644
index 4663f5d..0000000
--- a/src/templates/index.html
+++ /dev/null
@@ -1,85 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="UTF-8" />
-
- <style>
- .make {
- display: block;
- background: none;
- border: 0 none;
- cursor: pointer;
- }
-
- .model {
- display: block;
- background: none;
- border: 0 none;
- cursor: pointer;
- margin-left: 20px;
- }
-
- .sidebar {
- width: 300px;
- height: 100%;
- position: fixed;
- z-index: 1;
- }
-
- .main {
- margin-left: 300px;
- height: 100%;
- }
- </style>
- </head>
- <body>
- <div class="sidebar">
- <h1>Parts Catalog</h1>
- {{#each makes}}
- <form action="/parts">
- {{#if (eq this ../selected_make)}}
- <button disabled class="make">
- {{ this }}
- </button>
- <input type="hidden" name="make" value="{{ ../selected_make }}" />
- {{#each ../models}}
- {{#if (eq this ../../selected_model)}}
- <button disabled class="model">{{ this }}</button>
- {{else}}
- <button class="model" name="model" value="{{ this }}">
- {{ this }}
- </button>
- {{/if}}
- {{else}}
- <button disabled class="model">(No models found)</button>
- {{/each}}
- {{else}}
- <button class="make" name="make" value="{{ this }}">{{ this }}</button>
- {{/if}}
- </form>
- {{else}}
- No makes found.
- {{/each}}
- </div>
-
- <div class="main">
- <form action="/parts">
- <input type="hidden" name="make" value="{{ selected_make }}" />
- <input type="hidden" name="model" value="{{ selected_model }}" />
- <input
- type="search"
- name="search"
- placeholder="Part #, Name, Source, etc."
- />
- <button>Search</button>
- </form>
- <table>
- {{#each parts}}
- <tr>
- <td>{{ this }}</td>
- </tr>
- {{/each}}
- </table>
- </div>
- </body>
-</html>
diff --git a/src/templates/login.hbs b/src/templates/login.hbs
new file mode 100644
index 0000000..84b354b
--- /dev/null
+++ b/src/templates/login.hbs
@@ -0,0 +1,7 @@
+{{#> base}}
+{{#*inline "body"}}
+<body>
+ <a href="/login/google">Login with Google</a>
+</body>
+{{/inline}}
+{{/base}}
diff --git a/src/templates/login.html b/src/templates/login.html
deleted file mode 100644
index 9329a22..0000000
--- a/src/templates/login.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE html>
-<html>
- <body>
- <a href="/login/google">Login with Google</a>
- </body>
-</html>
diff --git a/src/templates/mod.rs b/src/templates/mod.rs
index 3a6eb2b..534ada0 100644
--- a/src/templates/mod.rs
+++ b/src/templates/mod.rs
@@ -1,9 +1,16 @@
-pub static INDEX_T: &str = include_str!("index.html");
-pub static LOGIN_T: &str = include_str!("login.html");
-pub const CATALOG_L: &str = "/#menu";
-pub const PARTS_L: &str = "/parts";
-pub const PARTS_CSV_L: &str = "/parts.csv";
-pub const CARS_L: &str = "/cars";
-pub const CARS_CSV_L: &str = "/cars.csv";
-pub const SUGGESTIONS_L: &str = "/suggestions";
-pub const LOGIN_L: &str = "/login";
+use handlebars::Handlebars;
+use once_cell::sync::Lazy;
+
+pub static REGISTRY: Lazy<Handlebars> = Lazy::new(|| {
+ let mut handlebars = Handlebars::new();
+ handlebars
+ .register_template_string("index", include_str!("index.hbs"))
+ .unwrap();
+ handlebars
+ .register_template_string("login", include_str!("login.hbs"))
+ .unwrap();
+ handlebars
+ .register_template_string("base", include_str!("base.hbs"))
+ .unwrap();
+ handlebars
+});
diff --git a/src/templates/suggestions.hbs b/src/templates/suggestions.hbs
new file mode 100644
index 0000000..f979be7
--- /dev/null
+++ b/src/templates/suggestions.hbs
@@ -0,0 +1,9 @@
+{{#> base}}
+{{#*inline "body"}}
+<section>
+ <form>
+ <!-- input for new car or part -->
+ </form>
+</section>
+{{/inline}}
+{{/base}}