Initial db sync work

This commit is contained in:
2024-07-27 17:58:34 +01:00
parent 5969a1b3d8
commit 5887ae4946
4 changed files with 260 additions and 42 deletions
+97 -33
View File
@@ -10,7 +10,7 @@ use reqwest::header::{HeaderMap, HeaderValue};
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use chrono::{DateTime, SecondsFormat, Utc};
use reqwest::{Response, Url};
use reqwest::Response;
use serde::de::DeserializeOwned;
struct ReqwestRateLimiter {
@@ -89,6 +89,19 @@ impl TogglApi {
Ok(workspaces)
}
/// Get a specific workspace by its ID
pub async fn get_workspace(&self, id: u64) -> Result<types::Workspace, TogglError> {
let url = format!(
"{base_url}/workspaces/{id}",
base_url = BASE_URL,
id = id
);
Self::parse(self.client.get(&url)
.headers(self.headers.clone())
.send().await?).await
}
/// Fetches all time entries for this user from Toggl that have been modified since the given
/// date.
pub async fn get_time_entries_for_user_modified_since(&self, since: DateTime<Utc>) -> Result<Vec<types::TimeEntry>, TogglError> {
@@ -214,7 +227,8 @@ impl TogglApi {
data.into_iter().for_each(|e| results.push(e));
}
Ok(results) }
Ok(results)
}
}
pub mod types {
@@ -225,32 +239,32 @@ pub mod types {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TimeEntry {
id: u64,
workspace_id: u64,
user_id: u64,
project_id: Option<u64>,
task_id: Option<u64>,
pub id: u64,
pub workspace_id: u64,
pub user_id: u64,
pub project_id: Option<u64>,
pub task_id: Option<u64>,
start: DateTime<Utc>,
stop: Option<DateTime<Utc>>,
pub start: DateTime<Utc>,
pub stop: Option<DateTime<Utc>>,
#[serde(with = "duration_field")]
duration: Option<u32>,
pub duration: Option<u32>,
#[serde(rename = "at")]
updated_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
description: String,
pub description: String,
#[serde(default)]
tags: Vec<String>,
pub tags: Vec<String>,
#[serde(default)]
tag_ids: Vec<u64>,
pub tag_ids: Vec<u64>,
billable: bool,
server_deleted_at: Option<DateTime<Utc>>,
permissions: Option<String>,
pub billable: bool,
pub server_deleted_at: Option<DateTime<Utc>>,
pub permissions: Option<String>,
}
mod duration_field {
@@ -281,25 +295,25 @@ pub mod types {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Project {
id: i64,
workspace_id: i64,
client_id: Option<i64>,
pub id: i64,
pub workspace_id: i64,
pub client_id: Option<i64>,
name: String,
color: String,
status: ProjectStatus,
active: bool,
pub name: String,
pub color: String,
pub status: ProjectStatus,
pub active: bool,
#[serde(rename = "at")]
updated_at: DateTime<Utc>,
start_date: NaiveDate,
created_at: DateTime<Utc>,
server_deleted_at: Option<DateTime<Utc>>,
pub updated_at: DateTime<Utc>,
pub start_date: NaiveDate,
pub created_at: DateTime<Utc>,
pub server_deleted_at: Option<DateTime<Utc>>,
actual_hours: Option<i64>,
actual_seconds: Option<i64>,
can_track_time: bool,
permissions: Option<String>,
pub actual_hours: Option<i64>,
pub actual_seconds: Option<i64>,
pub can_track_time: bool,
pub permissions: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
@@ -312,6 +326,18 @@ pub mod types {
Deleted,
}
impl fmt::Display for ProjectStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", match self {
ProjectStatus::Upcoming => "upcoming",
ProjectStatus::Active => "active",
ProjectStatus::Archived => "archived",
ProjectStatus::Ended => "ended",
ProjectStatus::Deleted => "deleted",
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TrackingClient {
/// The unique identifier for the client.
@@ -355,7 +381,7 @@ pub mod types {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ReportEntry {
pub user_id: u32,
pub user_id: u64,
pub username: String,
pub project_id: Option<u64>,
pub task_id: Option<u64>,
@@ -368,10 +394,22 @@ pub mod types {
pub time_entries: Vec<ReportEntryTimeDetails>,
pub row_number: u32,
#[serde(flatten)]
pub enriched_information: Option<ReportEntryEnrichedInfo>,
#[serde(flatten)]
pub rest: HashMap<String, serde_json::Value>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ReportEntryEnrichedInfo {
pub project_id: Option<u64>,
pub project_name: Option<String>,
pub project_hex: Option<String>,
pub tag_names: Vec<String>,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct ReportEntryTimeDetails {
pub id: u64,
@@ -382,6 +420,31 @@ pub mod types {
pub updated_at: DateTime<Utc>,
}
impl ReportEntry {
fn into_time_entry(self, workspace_id: u64) -> TimeEntry {
TimeEntry {
id: self.time_entries[0].id,
workspace_id,
user_id: self.user_id,
project_id: self.project_id,
task_id: self.task_id,
start: self.time_entries[0].start,
stop: Some(self.time_entries[0].stop),
duration: Some(self.time_entries[0].seconds),
updated_at: self.time_entries[0].updated_at,
description: self.description,
tags: self.enriched_information
.map(|e| e.tag_names.clone())
.unwrap_or_default(),
tag_ids: self.tag_ids,
billable: self.billable,
server_deleted_at: None,
permissions: None,
}
}
}
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Clone, Default)]
pub struct TogglReportFilters {
@@ -419,6 +482,7 @@ pub mod types {
}
use std::fmt;
use std::path::Display;
impl fmt::Debug for TogglReportFilters {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {