From ead22776c3770d0c6299b0c372459a6bfa5bb515 Mon Sep 17 00:00:00 2001 From: Joshua Coles Date: Sat, 27 Jul 2024 19:34:48 +0100 Subject: [PATCH] Refactor API and add 'fetch_within' method Changed `workspace_id` type to `u64` for broader compatibility. Introduced `fetch_within` to allow fetching time entries within a given date range and abstracted database update logic into `update_database`. --- src/main.rs | 46 ++++++++++++++++++++++++++++++++++++++-------- src/toggl/mod.rs | 8 ++++---- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/main.rs b/src/main.rs index 5be1644..6770f04 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ -use chrono::{DateTime, TimeDelta, Utc}; +use chrono::{DateTime, DurationRound, NaiveDate, TimeDelta, Utc}; use sqlx::{Connection, PgConnection}; use toggl::TogglApi; +use crate::toggl::types::{TimeEntry, TogglReportFilters}; mod toggl; mod sensitive; @@ -55,7 +56,21 @@ impl Worker { }) } - async fn fetch_changed_since(&mut self, look_back: TimeDelta) -> Result<(), AppError> { + pub async fn fetch_within(&mut self, start: DateTime, end: DateTime) -> Result<(), AppError> { + let results = self.toggl_api.search(self.toggl_api.workspace_id, TogglReportFilters { + start_date: Some(start.date_naive()), + end_date: Some(end.date_naive()), + ..Default::default() + }).await?; + + let time_entries = results.into_iter() + .map(|entry| entry.into_time_entry(self.toggl_api.workspace_id)) + .collect::>(); + + self.update_database(time_entries).await + } + + pub async fn fetch_changed_since(&mut self, look_back: TimeDelta) -> Result<(), AppError> { if look_back > TimeDelta::days(90) { return Err(AppError::LookBackTooLarge) } @@ -63,7 +78,7 @@ impl Worker { self.update_time_entries(Utc::now() - look_back).await } - async fn update(&mut self, default_look_back: TimeDelta) -> Result<(), AppError> { + pub async fn update(&mut self, default_look_back: TimeDelta) -> Result<(), AppError> { let result = sqlx::query!("select max(updated_at) as last_updated_at from time_entries") .fetch_optional(&mut self.db) .await @@ -77,11 +92,15 @@ impl Worker { } async fn update_time_entries(&mut self, fetch_since: DateTime) -> Result<(), AppError> { - let existing_ids = self.get_ids().await?; - let time_entries = self.toggl_api .get_time_entries_for_user_modified_since(fetch_since).await?; + self.update_database(time_entries).await + } + + async fn update_database(&mut self, time_entries: Vec) -> Result<(), AppError> { + let existing_ids = self.get_ids().await?; + let fetch_workspaces = time_entries.iter() .map(|entry| entry.workspace_id) .filter(|workspace_id| !existing_ids.workspace_ids.contains(&workspace_id)) @@ -324,7 +343,18 @@ async fn main() { toggl_api: api, }; - worker.fetch_changed_since(TimeDelta::days(90)) - .await - .unwrap(); + let start = NaiveDate::from_ymd_opt(2024, 2, 1) + .expect("Invalid date") + .and_hms_opt(0, 0, 0) + .expect("Invalid time") + .and_utc(); + + let end = NaiveDate::from_ymd_opt(2024, 5, 1) + .expect("Invalid date") + .and_hms_opt(0, 0, 0) + .expect("Invalid time") + .and_utc(); + + worker.fetch_within(start, end).await + .expect("Failed to fetch time entries"); } diff --git a/src/toggl/mod.rs b/src/toggl/mod.rs index 86fb413..bc3a543 100644 --- a/src/toggl/mod.rs +++ b/src/toggl/mod.rs @@ -39,7 +39,7 @@ impl reqwest_ratelimit::RateLimiter for ReqwestRateLimiter { #[derive(Clone)] pub struct TogglApi { client: ClientWithMiddleware, - workspace_id: u32, + pub workspace_id: u64, headers: HeaderMap, } @@ -212,11 +212,11 @@ impl TogglApi { } #[tracing::instrument(skip(self))] - pub async fn search(&self, filters: types::TogglReportFilters) -> Result, TogglError> { + pub async fn search(&self, workspace_id: u64, filters: types::TogglReportFilters) -> Result, TogglError> { let url = format!( "{base_url}/workspace/{workspace_id}/search/time_entries", base_url = &REPORTS_BASE_URL, - workspace_id = self.workspace_id, + workspace_id = workspace_id, ); let mut last_row_number = Some(0); @@ -432,7 +432,7 @@ pub mod types { } impl ReportEntry { - fn into_time_entry(self, workspace_id: u64) -> TimeEntry { + pub fn into_time_entry(self, workspace_id: u64) -> TimeEntry { TimeEntry { id: self.time_entries[0].id, workspace_id,