diff --git a/.gitignore b/.gitignore index dcad5b4..4a3b37d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /target config.toml -Cargo.lock diff --git a/src/main.rs b/src/main.rs index 8f430cc..3766eb3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,6 @@ use youtrack::{Duration, IssueWorkItem}; use regex::Regex; -mod token; mod youtrack; mod toggl; @@ -24,7 +23,7 @@ struct Config { youtrack_api: ApiConfig, } -#[derive(Deserialize)] +#[derive(Deserialize, Clone)] struct ApiConfig { token: String, } @@ -45,7 +44,7 @@ async fn main() -> Result<(), reqwest::Error> { let config: Config = toml::from_str(&config_content).expect("Failed to parse config file"); // Get the current youtrack user for later use - let user = youtrack::get_current_user().await.unwrap(); + let user = youtrack::get_current_user(config.youtrack_api.clone()).await.unwrap(); info!("User: {:#?}", user); // Get all toggl time entries of the last X days. @@ -93,8 +92,9 @@ async fn main() -> Result<(), reqwest::Error> { // The association is represented by a HashMap. This should happen asynchronously (slow web reqs). let work_items_map = stream::iter(unique_issue_ids) .filter_map(|issue_id| { + let youtrack_apiconfig_clone = config.youtrack_api.clone(); async move { - match youtrack::get_workitems(issue_id.clone()).await { + match youtrack::get_workitems(issue_id.clone(), youtrack_apiconfig_clone).await { // If WorkItems are obtained for this issue ID, return them. Ok(work_items) => Some((issue_id.clone(), work_items)), // Otherwise do not include that Issue ID in the HashMap. @@ -190,7 +190,7 @@ async fn main() -> Result<(), reqwest::Error> { "Issue {} - creating work_item: {:#?}", &entry.issue_id, &work_item ); - youtrack::create_work_item(&entry.issue_id, work_item).await + youtrack::create_work_item(&entry.issue_id, work_item, config.youtrack_api.clone()).await } else { log::warn!("Duration not > 0. Skipping entry: {:#?}", entry); } @@ -216,8 +216,3 @@ mod test { assert_eq!(caps.get(2).unwrap().as_str(), "My Description"); } } - -#[tokio::test] -async fn test_wrong_issue_id() { - youtrack::get_workitems("ABC-123".to_string()).await; -} diff --git a/src/token.rs.template b/src/token.rs.template deleted file mode 100644 index fe62e69..0000000 --- a/src/token.rs.template +++ /dev/null @@ -1,2 +0,0 @@ -// Enter token and rename to "token.rs" -pub const AUTH_TOKEN: &str = "perm:ABCDEFG"; \ No newline at end of file diff --git a/src/youtrack.rs b/src/youtrack.rs index 9edb796..0d5e7b4 100644 --- a/src/youtrack.rs +++ b/src/youtrack.rs @@ -1,8 +1,9 @@ -use crate::token::AUTH_TOKEN; use chrono::{serde::ts_milliseconds, DateTime, Utc}; use log::debug; use serde::{Deserialize, Serialize}; +use crate::ApiConfig; + const BASE_URL: &str = "https://systemscape.youtrack.cloud"; const WORK_ITEMS_FIELDS: &str = "author(id,login),creator(id,login),date,created(minutes),duration(minutes),id,name,text,issue(idReadable)"; //const WORK_ITEMS_FIELDS: &str = "author(id,login),creator(id,login),date,created(minutes),duration(minutes),id,name,text,type(id,name),issue(idReadable)"; @@ -45,14 +46,14 @@ pub struct User { pub id: String, } -pub async fn create_work_item(issue_id: &str, item: IssueWorkItem) { +pub async fn create_work_item(issue_id: &str, item: IssueWorkItem, config: ApiConfig) { let client = reqwest::Client::new(); let res = client .post(format!( "{BASE_URL}/api/issues/{issue_id}/timeTracking/workItems?fields={WORK_ITEMS_FIELDS}" )) - .bearer_auth(AUTH_TOKEN) + .bearer_auth(config.token) .header("Content-Type", "application/json") .body(serde_json::to_string(&item).unwrap()) .send() @@ -64,30 +65,30 @@ pub async fn create_work_item(issue_id: &str, item: IssueWorkItem) { ); } -pub async fn get_workitems(issue_id: String) -> Result, reqwest::Error> { +pub async fn get_workitems(issue_id: String, config: ApiConfig) -> Result, reqwest::Error> { debug!("get_workitems for issue_id {}", &issue_id); let url = format!( "{BASE_URL}/api/issues/{issue_id}/timeTracking/workItems?fields={WORK_ITEMS_FIELDS}" ); - let res = perform_request(&url).await.unwrap(); + let res = perform_request(&url, config).await.unwrap(); let res = res.error_for_status()?.text().await.unwrap(); let items: Vec = serde_json::from_str(&res).unwrap(); Ok(items) } -pub async fn perform_request(url: &str) -> Result { +pub async fn perform_request(url: &str, config: ApiConfig) -> Result { let client = reqwest::Client::new(); - client.get(url).bearer_auth(AUTH_TOKEN).send().await + client.get(url).bearer_auth(config.token).send().await } -pub async fn get_current_user() -> Result { +pub async fn get_current_user(config: ApiConfig) -> Result { let client = reqwest::Client::new(); let res = client .get(format!("{BASE_URL}/api/users/me?fields=id,login")) - .bearer_auth(AUTH_TOKEN) + .bearer_auth(config.token) .send() .await; @@ -101,16 +102,23 @@ pub async fn get_current_user() -> Result { #[cfg(test)] mod test { use log::info; - + use std::fs; + + use crate::Config; use crate::youtrack; #[tokio::test] async fn test_serde() { simple_logger::init().unwrap(); - let user = youtrack::get_current_user().await.unwrap(); + // Read the config file + let config_content = fs::read_to_string("config.toml").expect("Failed to read config file"); + let config: Config = toml::from_str(&config_content).expect("Failed to parse config file"); + + + let user = youtrack::get_current_user(config.youtrack_api.clone()).await.unwrap(); info!("User: {:#?}", user); - youtrack::get_workitems("SO-106").await; + youtrack::get_workitems("SO-106".to_string(), config.youtrack_api.clone()).await; } }