diff options
Diffstat (limited to 'src/strava.rs')
-rw-r--r-- | src/strava.rs | 108 |
1 files changed, 85 insertions, 23 deletions
diff --git a/src/strava.rs b/src/strava.rs index 6be5466..284d8b1 100644 --- a/src/strava.rs +++ b/src/strava.rs @@ -1,4 +1,6 @@ +use crate::error; use crate::error::Error; +use crate::models; use chrono::serde::ts_seconds; use chrono::DateTime; use chrono::Utc; @@ -8,53 +10,113 @@ use serde::Serialize; use serde_json::from_value; use serde_json::Value; +#[derive(Serialize, Deserialize, Debug)] +pub struct Token { + #[serde(with = "ts_seconds")] + pub expires_at: DateTime<Utc>, + pub refresh_token: String, + pub access_token: String, +} + +impl Token { + pub fn update_model(&self, out: &mut models::StravaToken) { + out.expires_at = self.expires_at.clone(); + out.refresh_token = self.refresh_token.clone(); + out.access_token = self.access_token.clone(); + } +} + +impl From<&models::StravaToken> for Token { + fn from(t: &models::StravaToken) -> Token { + Token { + expires_at: t.expires_at, + refresh_token: t.refresh_token.clone(), + access_token: t.access_token.clone(), + } + } +} + pub trait StravaApi { - fn get<T: Serialize + ?Sized>(&self, method: &str, access_token: &str, parasm: &T) -> Result<Value, Error>; + fn get<T: Serialize + ?Sized>( + &self, + method: &str, + access_token: &str, + parasm: &T, + ) -> Result<Value, Error>; + + fn refresh_token( + &self, + token: &Token) -> Result<Token, Error>; } pub struct StravaImpl { client: reqwest::blocking::Client, base_url: String, + api_url: String, + client_id: String, + client_secret: String, } impl StravaImpl { - pub fn new() -> StravaImpl { + pub fn new(client_id: String, client_secret: String) -> StravaImpl { StravaImpl { client: reqwest::blocking::Client::new(), - base_url: "https://www.strava.com/api/v3".to_string(), + base_url: "https://www.strava.com".to_string(), + api_url: "/api/v3".to_string(), + client_id, + client_secret, } } } impl StravaApi for StravaImpl { - fn get<T: Serialize + ?Sized>(&self, method: &str, access_token: &str, - params: &T) -> Result<Value, Error> { - let uri = format!("{}{}", self.base_url, method); - let response = self.client.get(&uri) + fn get<T: Serialize + ?Sized>( + &self, + method: &str, + access_token: &str, + params: &T, + ) -> Result<Value, Error> { + let uri = format!("{}{}{}", self.base_url, self.api_url, method); + let response = self + .client + .get(&uri) .bearer_auth(access_token) .query(params) .send()?; info!("StravaApi::get({}) returned {:?}", method, response); - let json = response.json()?; + let status = response.status(); + let json: Value = response.json()?; + + if !status.is_success() { + return Err(From::from(error::StravaApiError::new(status, json))); + } Ok(json) } -} -#[derive(Serialize, Deserialize, Debug)] -pub struct AthleteSummary { - id: i64, - username: String, - firstname: String, - lastname: String, -} + fn refresh_token( + &self, + token: &Token) -> Result<Token, Error> { + let uri = format!("{}{}{}", self.base_url, self.api_url, "/oauth/token"); + let params = [ + ("client_id", self.client_id.as_str()), + ("client_secret", self.client_secret.as_str()), + ("grant_type", "refresh_token"), + ("refresh_token", token.refresh_token.as_str()), + ]; + let response = self + .client + .post(&uri) + .form(¶ms) + .send()?; + info!("StravaApi::refresh_token returned {:?}", response); + let status = response.status(); + let json: Value = response.json()?; -#[derive(Serialize, Deserialize, Debug)] -pub struct Token { - #[serde(with = "ts_seconds")] - pub expires_at: DateTime<Utc>, - pub refresh_token: String, - pub access_token: String, - pub athlete: AthleteSummary, + if !status.is_success() { + return Err(From::from(error::StravaApiError::new(status, json))); + } + from_value(json).map_err(From::from) + } } pub fn exchange_token(client_id: &str, client_secret: &str, code: &str) -> Result<Token, Error> { |