Sync your own workout data from your "Strong" app
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

added user_response struct

+176 -6
+44 -3
src/main.rs
··· 2 2 use std::env; 3 3 use dotenv::dotenv; 4 4 use serde::Deserialize; 5 - use crate::strong_api::StrongApi; 5 + use serde_json::Value::String; 6 + use crate::strong_api::{Includes, StrongApi}; 6 7 7 8 mod strong_api; 9 + mod user_response; 8 10 9 11 #[tokio::main] 10 12 async fn main() -> Result<(), Box<dyn std::error::Error>> { ··· 18 20 let mut strong_api = StrongApi::new(url); 19 21 20 22 strong_api.login(username.as_str(), password.as_str()).await?; 21 - strong_api.get_user().await?; 23 + let user = strong_api.get_user( 24 + "", 25 + 500, 26 + vec![ 27 + Includes::Log, 28 + Includes::Folder, 29 + Includes::Measurement, 30 + Includes::MeasuredValue, 31 + Includes::Tag, 32 + Includes::Template, 33 + Includes::Widget 34 + ] 35 + ).await?; 36 + 37 + for log in &user.embedded.log { 38 + if let Some(start_date) = &log.start_date { 39 + print!("{}: ", start_date); 40 + } 41 + 42 + let display_name = log.name.as_ref() 43 + .and_then(|name| name.custom.as_deref().or(name.en.as_deref())) 44 + .unwrap_or("Unknown"); 45 + 46 + println!("{}", display_name); 47 + for cell_set_group in &log.embedded.cell_set_group { 48 + 49 + for cell_set in &cell_set_group.cell_sets { 50 + for cell in &cell_set.cells { 51 + if (cell.cell_type == "OTHER_WEIGHT" || cell.cell_type == "REPS") { 52 + println!(" {}", cell_set.id); 53 + print!("{} - {:?}", cell.cell_type, cell.value); 54 + } 55 + } 56 + } 57 + } 58 + println!(); 59 + } 60 + 61 + 62 + /*strong_api.get_logs().await?; 22 63 23 64 dbg!(strong_api.access_token); 24 65 dbg!(strong_api.refresh_token); 25 - dbg!(strong_api.user_id); 66 + dbg!(strong_api.user_id);*/ 26 67 27 68 Ok(()) 28 69 }
+23 -3
src/strong_api.rs
··· 2 2 use reqwest::{Client, header::{HeaderMap, HeaderName, HeaderValue}, Url}; 3 3 use serde::Deserialize; 4 4 use serde_json::json; 5 + use crate::user_response::UserResponse; 5 6 6 7 #[derive(Debug)] 7 8 pub struct StrongApi { ··· 157 158 Ok(()) 158 159 } 159 160 160 - pub async fn get_user(&self, continuation: &str, limit: i16, includes: Vec<Includes>) -> Result<(), Box<dyn std::error::Error>> { 161 + pub async fn get_user(&self, continuation: &str, limit: i16, includes: Vec<Includes>) -> Result<UserResponse, Box<dyn std::error::Error>> { 161 162 let user_id = &*self.user_id.clone().unwrap(); 162 163 let mut url = self.url.join(format!("api/users/{user_id}").as_str()).unwrap(); 163 164 ··· 178 179 179 180 let response_text = response.text().await?; 180 181 182 + 183 + let parsed: UserResponse = serde_json::from_str(&response_text)?; 184 + 185 + Ok(parsed) 186 + } 187 + 188 + pub async fn get_measurements(&self) -> Result<(), Box<dyn std::error::Error>> { 189 + let user_id = &*self.user_id.clone().unwrap(); 190 + let url = self.url.join(format!("api/measurements/{user_id}").as_str()).unwrap(); 191 + 192 + let response = self.client 193 + .get(url) 194 + .bearer_auth(self.access_token.clone().unwrap()) 195 + .headers(self.headers.clone()) 196 + .send() 197 + .await?; 198 + 199 + let response_text = response.text().await?; 200 + 181 201 dbg!(response_text); 182 202 183 203 Ok(()) 184 204 } 185 205 186 - pub async fn get_measurements(&self) -> Result<(), Box<dyn std::error::Error>> { 206 + pub async fn get_logs(&self) -> Result<(), Box<dyn std::error::Error>> { 187 207 let user_id = &*self.user_id.clone().unwrap(); 188 - let url = self.url.join(format!("api/measurements/{user_id}").as_str()).unwrap(); 208 + let url = self.url.join(format!("api/logs/{user_id}").as_str()).unwrap(); 189 209 190 210 let response = self.client 191 211 .get(url)
+109
src/user_response.rs
··· 1 + use serde::{Deserialize, Serialize}; 2 + use serde_json::Value; 3 + 4 + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 5 + pub struct UserResponse { 6 + #[serde(rename = "_links")] 7 + pub links: Value, 8 + #[serde(rename = "_embedded")] 9 + pub embedded: Embedded, 10 + pub id: String, 11 + pub created: String, 12 + #[serde(rename = "lastChanged")] 13 + pub last_changed: String, 14 + pub username: String, 15 + pub email: String, 16 + #[serde(rename = "emailVerified")] 17 + pub email_verified: bool, 18 + pub name: Option<String>, 19 + pub avatar: Value, 20 + pub preferences: Value, 21 + #[serde(rename = "legacyPurchase")] 22 + pub legacy_purchase: Value, 23 + #[serde(rename = "legacyGoals")] 24 + pub legacy_goals: Value, 25 + #[serde(rename = "startHistoryFromDate")] 26 + pub start_history_from_date: String, 27 + #[serde(rename = "firstWeekDay")] 28 + pub first_week_day: String, 29 + #[serde(rename = "availableLogins")] 30 + pub available_logins: Vec<Value>, 31 + pub migrated: String, 32 + } 33 + 34 + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 35 + pub struct Embedded { 36 + pub measurement: Vec<Value>, 37 + #[serde(rename = "measuredValue")] 38 + pub measured_value: Vec<Value>, 39 + pub template: Vec<Value>, 40 + pub log: Vec<Log>, 41 + pub tag: Vec<Value>, 42 + pub folder: Vec<Value>, 43 + pub widget: Vec<Value>, 44 + } 45 + 46 + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 47 + pub struct Log { 48 + #[serde(rename = "_links")] 49 + pub links: Value, 50 + #[serde(rename = "_embedded")] 51 + pub embedded: LogEmbedded, 52 + #[serde(rename = "timezoneId")] 53 + pub timezone_id: Option<String>, 54 + pub id: String, 55 + pub created: String, 56 + #[serde(rename = "lastChanged")] 57 + pub last_changed: String, 58 + pub name: Option<Name>, 59 + pub access: String, 60 + #[serde(rename = "startDate")] 61 + pub start_date: Option<String>, 62 + #[serde(rename = "endDate")] 63 + pub end_date: Option<String>, 64 + #[serde(rename = "logType")] 65 + pub log_type: String, 66 + } 67 + 68 + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 69 + pub struct Name { 70 + pub en: Option<String>, 71 + pub custom: Option<String>, 72 + } 73 + 74 + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 75 + pub struct LogEmbedded { 76 + #[serde(rename = "cellSetGroup")] 77 + pub cell_set_group: Vec<CellSetGroup>, 78 + } 79 + 80 + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 81 + pub struct CellSetGroup { 82 + #[serde(rename = "_links")] 83 + pub links: Value, 84 + #[serde(rename = "_embedded")] 85 + pub embedded: CellSetGroupEmbedded, 86 + pub id: String, 87 + #[serde(rename = "cellSets")] 88 + pub cell_sets: Vec<CallSet>, 89 + } 90 + 91 + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 92 + pub struct CellSetGroupEmbedded { 93 + } 94 + 95 + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 96 + pub struct CallSet { 97 + pub id: String, 98 + pub cells: Vec<Cell>, 99 + #[serde(rename = "isCompleted")] 100 + pub is_completed: Option<bool>, 101 + } 102 + 103 + #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] 104 + pub struct Cell { 105 + pub id: String, 106 + #[serde(rename = "cellType")] 107 + pub cell_type: String, 108 + pub value: Option<String>, 109 + }