summaryrefslogtreecommitdiff
path: root/src/server.rs
blob: 4f9833711633cbe1308ec6b7b94f9747a69bc363 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use diesel::pg::PgConnection;
use rocket::http::Cookies;
use rocket::http::Cookie;
use rocket::config::Config;
use rocket::config::Environment;
use rocket::config::Value;
use rocket::http::Status;
use rocket::request::Form;
use rocket::request::FromForm;
use rocket::response;
use rocket::response::Redirect;
use rocket::State;
use rocket_contrib::templates::Template;
use std::collections::HashMap;

use crate::db;
use crate::error::Error;
use crate::strava;

pub struct Params {
    pub base_url: String,
}

#[database("db")]
pub struct Db(diesel::PgConnection);

#[get("/")]
fn index() -> Template {
    let mut context = HashMap::new();
    context.insert("parent", "layout");
    context.insert("message", "Hello, World");
    Template::render("index", context)
}

#[get("/login?<failed>")]
fn login(failed: bool) -> Template {
    let mut context = HashMap::new();
    context.insert("parent", "layout");
    if failed {
        context.insert("message", "Incorrect username or password");
    }
    Template::render("login", context)
}

#[derive(FromForm)]
struct LoginData {
    username: String,
    password: String,
}

// Request guard for logged in user: https://api.rocket.rs/v0.4/rocket/request/trait.FromRequest.html

#[post("/login", data = "<data>")]
fn login_submit(conn: Db, data: Form<LoginData>, mut cookies: Cookies) -> Result<Redirect, Error> {
    match db::authenticate(&*conn, &data.username, &data.password) {
        Ok(user) => {
            cookies.add_private(Cookie::new("user", data.username.clone()));
            Ok(Redirect::to(uri!(index).to_string()))
        },
        Err(Error::NotFound) => Ok(Redirect::to(uri!(login: failed = true).to_string())),
        Err(e) => Err(e),
    }
}

#[get("/link_strava_callback?<code>")]
fn link_strava_callback(
    config: State<Params>,
    code: String,
) -> Result<String, impl std::error::Error> {
    strava::exchange_token("&config.client_id", "&config.client_secret", &code)
        .map(|t| format!("{:#?}", t))
}

#[get("/link_strava")]
fn link_strava(config: State<Params>) -> Redirect {
    Redirect::to(format!(
        concat!(
            "https://www.strava.com/oauth/authorize?",
            "client_id={}&",
            "response_type=code&",
            "redirect_uri={}&",
            "approval_prompt=force&",
            "scope=read",
        ),
        "config.client_id",
        format!("{}/link_strava_callback", config.base_url)
    ))
}

pub fn start(db_url: &str, params: Params) {
    let mut database_config = HashMap::new();
    let mut databases = HashMap::new();
    database_config.insert("url", Value::from(db_url));
    databases.insert("db", Value::from(database_config));

    let config = Config::build(Environment::Development)
        .extra("databases", databases)
        .finalize()
        .unwrap();

    rocket::custom(config)
        .manage(params)
        .mount(
            "/",
            routes![
                index,
                login,
                login_submit,
                link_strava,
                link_strava_callback
            ],
        )
        .attach(Template::fairing())
        .attach(Db::fairing())
        .launch();
}