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()
}
}
}
|