Initial db sync work
This commit is contained in:
+97
-33
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user