diff options
| author | Adam T. Carpenter <atc@53hor.net> | 2021-04-09 18:50:55 -0400 | 
|---|---|---|
| committer | Adam T. Carpenter <atc@53hor.net> | 2021-04-09 18:50:55 -0400 | 
| commit | 201a37e8d3d0ef4c59b184c0707ec8ddd301a25a (patch) | |
| tree | 1aae6c03bfb9f694adea81510dacf586311fcc12 /src/routes | |
| parent | 881e4bf3c9141b4bebaefaf6385652ed46d9a9fe (diff) | |
| download | twinh-201a37e8d3d0ef4c59b184c0707ec8ddd301a25a.tar.xz twinh-201a37e8d3d0ef4c59b184c0707ec8ddd301a25a.zip  | |
spruced up templates, some repo impl
Diffstat (limited to 'src/routes')
| -rw-r--r-- | src/routes/mod.rs | 185 | 
1 files changed, 185 insertions, 0 deletions
diff --git a/src/routes/mod.rs b/src/routes/mod.rs new file mode 100644 index 0000000..1866e49 --- /dev/null +++ b/src/routes/mod.rs @@ -0,0 +1,185 @@ +use crate::error::TwinHError; +use crate::repo; +use crate::templates; +use hyper::body::HttpBody as _; +use hyper::Method; +use hyper::StatusCode; +use hyper::{Body, Request, Response}; +use serde::{Deserialize, Serialize}; + +pub async fn router(req: Request<Body>) -> Result<Response<Body>, TwinHError> { +    match (req.method(), req.uri().path()) { +        (&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()) +            .unwrap()), +    } +} + +async fn suggestions() -> Result<Response<Body>, TwinHError> { +    todo!() +} + +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") +        .path_and_query(format!( +            "{}?client_id={}&redirect_uri={}&response_type={}&scope={}&state={}", +            "/o/oauth2/v2/auth", +            "???", +            "http://localhost:3000/login/google/code", +            "code", +            "openid%20profile%20email", +            "BLARGH" +        )) +        .build() +        .unwrap(); +    let resp = Response::builder() +        .header(hyper::header::LOCATION, uri.to_string()) +        .status(StatusCode::TEMPORARY_REDIRECT) +        .body("".into()) +        .unwrap(); +    Ok(resp) +} + +#[derive(Serialize)] +struct AuthRequest { +    client_id: String, +    client_secret: String, +    grant_type: &'static str, +    redirect_uri: String, +    code: String, +} + +impl Default for AuthRequest { +    fn default() -> Self { +        Self { +            client_id: "???".into(), +            client_secret: "???".into(), +            grant_type: "authorization_code", +            redirect_uri: String::new(), +            code: String::new(), +        } +    } +} + +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" { +        dbg!("tampering?"); +    } + +    // get access token +    let auth_body = AuthRequest { +        code: query.code, +        redirect_uri: "http://localhost:3000/login/google/code".to_owned(), +        ..Default::default() +    }; + +    let https = hyper_rustls::HttpsConnector::with_native_roots(); +    let client: hyper::Client<_, hyper::Body> = hyper::Client::builder().build(https); + +    let req = Request::builder() +        .method(Method::POST) +        .uri("https://oauth2.googleapis.com/token") +        .header( +            hyper::header::CONTENT_TYPE, +            "application/x-www-form-urlencoded", +        ) +        .body(serde_urlencoded::ser::to_string(auth_body).unwrap().into()) +        .unwrap(); +    let mut resp = client.request(req).await.unwrap(); +    use std::io::prelude::*; +    while let Some(chunk) = resp.body_mut().data().await { +        std::io::stdout().write_all(&chunk.unwrap()).unwrap(); +    } + +    let resp = Response::builder() +        .header(hyper::header::LOCATION, "/".to_string()) +        .status(StatusCode::TEMPORARY_REDIRECT) +        .body("Successful login, redirecting...".into()) +        .unwrap(); +    Ok(resp) +} + +pub struct AccessToken { +    access_token: String, +    expires_in: String, +    scope: String, +    token_type: String, +} + +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 data = PartsData::default(); +    data.makes = Some(vec!["Hudson".into(), "Essex".into(), "Terraplane".into()]); + +    if let Some(make) = filter.make { +        if make.eq("Hudson") { +            data.models = Some(vec!["Hornet".into(), "Wasp".into(), "Jet".into()]); +        } else if make.eq("Essex") { +            data.models = Some(vec!["Super Six".into()]); +        } +        data.selected_make = Some(make); +    } + +    data.parts = Some(Vec::new()); +    if let Some(model) = filter.model { +        data.parts = Some(vec!["1".into(), "2".into(), "3".into()]); +        data.selected_model = Some(model); +    } + +    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)] +struct GoogleOAuthQuery { +    code: String, +    state: String, +} + +#[derive(Debug, Deserialize)] +struct PartsQuery { +    make: Option<String>, +    year: Option<String>, +    model: Option<String>, +    engine: Option<String>, +} + +#[derive(Debug, Serialize, Default)] +struct PartsData { +    makes: Option<Vec<String>>, +    years: Option<Vec<String>>, +    models: Option<Vec<String>>, +    engines: Option<Vec<String>>, +    selected_make: Option<String>, +    selected_year: Option<String>, +    selected_model: Option<String>, +    selected_engine: Option<String>, +    parts: Option<Vec<String>>, +}  |