From 100ef2504406fe05d9a417082dcedf1f21f3ffd2 Mon Sep 17 00:00:00 2001 From: Joshua Coles Date: Mon, 6 Nov 2023 13:48:46 +0000 Subject: [PATCH] (toggl-portal): Add clients and projects routes --- Cargo.toml | 1 + src/client.rs | 22 +++++++++++++++++++++- src/main.rs | 17 ++++++++++++----- src/types.rs | 23 +++++++++++++++++++++++ 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8563620..8b5e5fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,4 +30,5 @@ sea-orm = { version = "0.12", features = [ migration = { path = "./migration" } chrono = { version = "0.4.31", features = ["serde"] } futures = "0.3.29" +rucron = "0.1.5" #tokio-cron-scheduler = "0.9.4" diff --git a/src/client.rs b/src/client.rs index 83f4d8e..eba7231 100644 --- a/src/client.rs +++ b/src/client.rs @@ -6,7 +6,7 @@ use axum::http::StatusCode; use hyper::HeaderMap; use tracing::instrument; use tracing::log::debug; -use crate::types::{Current, Project, ReportEntry, TogglQuery}; +use crate::types::{Current, Project, ProjectClient, ReportEntry, TogglQuery}; #[derive(Debug, Clone)] pub struct TogglClient { @@ -67,6 +67,26 @@ impl TogglClient { Ok(res) } + pub async fn fetch_clients(&self) -> Result, reqwest::Error> { + let url = format!( + "{base_url}/workspaces/{}/clients", + self.workspace_id, + base_url = self.base_url, + ); + + let res = self + .client + .get(&url) + .headers(self.headers.clone()) + .send() + .await? + .json::>() + .await + .unwrap(); + + Ok(res) + } + pub async fn get_current(&self) -> Result, reqwest::Error> { let url = format!( "{base_url}/me/time_entries/current", diff --git a/src/main.rs b/src/main.rs index b7ab1a9..53e9cda 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use crate::client::TogglClient; use crate::entity::time_entry::{self, Entity as TimeEntry}; -use crate::types::{Current, ReportEntry, TogglQuery}; +use crate::types::{Current, Project, ProjectClient, ReportEntry, TogglQuery}; use anyhow::anyhow; use axum::http::StatusCode; use axum::response::IntoResponse; @@ -50,10 +50,7 @@ pub async fn report( Ok(Json(report)) } -async fn cache_report( - db: &DatabaseConnection, - models: &Vec, -) -> Result<()> { +async fn cache_report(db: &DatabaseConnection, models: &Vec) -> Result<()> { let models = models.iter().flat_map(|entry| entry.as_models()); TimeEntry::insert_many(models) @@ -88,6 +85,14 @@ pub async fn start_time_entry( Ok((StatusCode::OK, "Ok")) } +async fn projects(Extension(toggl_client): Extension) -> Result>> { + Ok(Json(toggl_client.fetch_projects().await?)) +} + +async fn clients(Extension(toggl_client): Extension) -> Result>> { + Ok(Json(toggl_client.fetch_clients().await?)) +} + async fn health(Extension(toggl_client): Extension) -> Result<&'static str> { return if toggl_client.check_health().await { Ok("Ok") @@ -120,6 +125,8 @@ async fn main() -> Result<()> { .route("/health", get(health)) .route("/current", get(current)) .route("/report", post(report)) + .route("/projects", get(projects)) + .route("/clients", get(clients)) .route("/start_time_entry", post(start_time_entry)) .layer(Extension(toggl_client)) .layer(Extension(db)) diff --git a/src/types.rs b/src/types.rs index bda0da2..ffd7f24 100644 --- a/src/types.rs +++ b/src/types.rs @@ -3,6 +3,7 @@ use serde_json::Value; use serde_with::skip_serializing_none; use std::collections::HashMap; use std::option::Option; +use chrono::{DateTime, Utc}; #[derive(Clone, Serialize, Deserialize, Debug)] pub struct TimeEntry { @@ -56,6 +57,28 @@ pub struct Project { pub rest: HashMap, } +/// Represents a client in Toggl. +#[derive(Debug, Serialize, Deserialize)] +pub struct ProjectClient { + /// Indicates whether the client is archived or not. + archived: bool, + + /// Represents the timestamp of the last update made to the client. + at: DateTime, + + /// The unique identifier for the client. + id: i32, + + /// The name of the client. + name: String, + + /// Indicates the timestamp when the client was deleted. If the client is not deleted, this property will be null. + server_deleted_at: Option>, + + /// The Workspace ID associated with the client. + wid: i32, +} + #[allow(non_snake_case)] #[skip_serializing_none] #[derive(Debug, Serialize, Deserialize, Clone, Default)]