aboutsummaryrefslogtreecommitdiffstats
path: root/teleterm/src/oauth/recurse_center.rs
blob: c43be15981735d5801aedb04ae0d8dd8482f5c50 (plain) (blame)
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
use crate::prelude::*;

pub struct RecurseCenter {
    client: oauth2::basic::BasicClient,
    user_id: String,
}

impl RecurseCenter {
    pub fn new(config: super::Config, user_id: &str) -> Self {
        Self {
            client: config.into_basic_client(),
            user_id: user_id.to_string(),
        }
    }

    pub fn config(
        client_id: &str,
        client_secret: &str,
        redirect_url: &url::Url,
    ) -> super::Config {
        super::Config {
            client_id: client_id.to_string(),
            client_secret: client_secret.to_string(),
            auth_url: url::Url::parse(
                "https://www.recurse.com/oauth/authorize",
            )
            .unwrap(),
            token_url: url::Url::parse("https://www.recurse.com/oauth/token")
                .unwrap(),
            redirect_url: redirect_url.clone(),
        }
    }
}

impl super::Oauth for RecurseCenter {
    fn client(&self) -> &oauth2::basic::BasicClient {
        &self.client
    }

    fn user_id(&self) -> &str {
        &self.user_id
    }

    fn name(&self) -> &str {
        crate::protocol::AuthType::RecurseCenter.name()
    }

    fn get_username_from_access_token(
        self: Box<Self>,
        token: &str,
    ) -> Box<dyn futures::Future<Item = String, Error = Error> + Send> {
        let fut = reqwest::r#async::Client::new()
            .get("https://www.recurse.com/api/v1/profiles/me")
            .bearer_auth(token)
            .send()
            .context(crate::error::GetRecurseCenterProfile)
            .and_then(|mut res| res.json().context(crate::error::ParseJson))
            .map(|user: User| user.name());
        Box::new(fut)
    }
}

#[derive(serde::Deserialize)]
struct User {
    name: String,
    stints: Vec<Stint>,
}

#[derive(serde::Deserialize)]
struct Stint {
    batch: Option<Batch>,
    start_date: String,
}

#[derive(serde::Deserialize)]
struct Batch {
    short_name: String,
}

impl User {
    fn name(&self) -> String {
        let latest_stint =
            self.stints.iter().max_by_key(|s| &s.start_date).unwrap();
        if let Some(batch) = &latest_stint.batch {
            format!("{} ({})", self.name, batch.short_name)
        } else {
            self.name.to_string()
        }
    }
}