summaryrefslogblamecommitdiff
path: root/src/routes/mod.rs
blob: 1866e492c27c3a01bca59927eee0fb7aff1d0eb0 (plain) (tree)
1
2
3
4
5
6
7
8
9

                             
                     
                               



                                     
 
                                                                               
                                            


                                                   

                                                                             
                                                              






                                          

                                                              

 






                                                                 










































                                                                                 
                                                                                      













































                                                                                      





                                                                          

                                                                              

















                                                                                   





                                                                        


                             





                             


















                                    
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>>,
}