(toggl-portal): Add clients and projects routes
This commit is contained in:
parent
6971e4a874
commit
100ef25044
@ -30,4 +30,5 @@ sea-orm = { version = "0.12", features = [
|
|||||||
migration = { path = "./migration" }
|
migration = { path = "./migration" }
|
||||||
chrono = { version = "0.4.31", features = ["serde"] }
|
chrono = { version = "0.4.31", features = ["serde"] }
|
||||||
futures = "0.3.29"
|
futures = "0.3.29"
|
||||||
|
rucron = "0.1.5"
|
||||||
#tokio-cron-scheduler = "0.9.4"
|
#tokio-cron-scheduler = "0.9.4"
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use axum::http::StatusCode;
|
|||||||
use hyper::HeaderMap;
|
use hyper::HeaderMap;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use tracing::log::debug;
|
use tracing::log::debug;
|
||||||
use crate::types::{Current, Project, ReportEntry, TogglQuery};
|
use crate::types::{Current, Project, ProjectClient, ReportEntry, TogglQuery};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TogglClient {
|
pub struct TogglClient {
|
||||||
@ -67,6 +67,26 @@ impl TogglClient {
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn fetch_clients(&self) -> Result<Vec<ProjectClient>, 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::<Vec<ProjectClient>>()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_current(&self) -> Result<Option<Current>, reqwest::Error> {
|
pub async fn get_current(&self) -> Result<Option<Current>, reqwest::Error> {
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"{base_url}/me/time_entries/current",
|
"{base_url}/me/time_entries/current",
|
||||||
|
|||||||
17
src/main.rs
17
src/main.rs
@ -1,6 +1,6 @@
|
|||||||
use crate::client::TogglClient;
|
use crate::client::TogglClient;
|
||||||
use crate::entity::time_entry::{self, Entity as TimeEntry};
|
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 anyhow::anyhow;
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::response::IntoResponse;
|
use axum::response::IntoResponse;
|
||||||
@ -50,10 +50,7 @@ pub async fn report(
|
|||||||
Ok(Json(report))
|
Ok(Json(report))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn cache_report(
|
async fn cache_report(db: &DatabaseConnection, models: &Vec<ReportEntry>) -> Result<()> {
|
||||||
db: &DatabaseConnection,
|
|
||||||
models: &Vec<ReportEntry>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let models = models.iter().flat_map(|entry| entry.as_models());
|
let models = models.iter().flat_map(|entry| entry.as_models());
|
||||||
|
|
||||||
TimeEntry::insert_many(models)
|
TimeEntry::insert_many(models)
|
||||||
@ -88,6 +85,14 @@ pub async fn start_time_entry(
|
|||||||
Ok((StatusCode::OK, "Ok"))
|
Ok((StatusCode::OK, "Ok"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn projects(Extension(toggl_client): Extension<TogglClient>) -> Result<Json<Vec<Project>>> {
|
||||||
|
Ok(Json(toggl_client.fetch_projects().await?))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn clients(Extension(toggl_client): Extension<TogglClient>) -> Result<Json<Vec<ProjectClient>>> {
|
||||||
|
Ok(Json(toggl_client.fetch_clients().await?))
|
||||||
|
}
|
||||||
|
|
||||||
async fn health(Extension(toggl_client): Extension<TogglClient>) -> Result<&'static str> {
|
async fn health(Extension(toggl_client): Extension<TogglClient>) -> Result<&'static str> {
|
||||||
return if toggl_client.check_health().await {
|
return if toggl_client.check_health().await {
|
||||||
Ok("Ok")
|
Ok("Ok")
|
||||||
@ -120,6 +125,8 @@ async fn main() -> Result<()> {
|
|||||||
.route("/health", get(health))
|
.route("/health", get(health))
|
||||||
.route("/current", get(current))
|
.route("/current", get(current))
|
||||||
.route("/report", post(report))
|
.route("/report", post(report))
|
||||||
|
.route("/projects", get(projects))
|
||||||
|
.route("/clients", get(clients))
|
||||||
.route("/start_time_entry", post(start_time_entry))
|
.route("/start_time_entry", post(start_time_entry))
|
||||||
.layer(Extension(toggl_client))
|
.layer(Extension(toggl_client))
|
||||||
.layer(Extension(db))
|
.layer(Extension(db))
|
||||||
|
|||||||
23
src/types.rs
23
src/types.rs
@ -3,6 +3,7 @@ use serde_json::Value;
|
|||||||
use serde_with::skip_serializing_none;
|
use serde_with::skip_serializing_none;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::option::Option;
|
use std::option::Option;
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||||
pub struct TimeEntry {
|
pub struct TimeEntry {
|
||||||
@ -56,6 +57,28 @@ pub struct Project {
|
|||||||
pub rest: HashMap<String, Value>,
|
pub rest: HashMap<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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<Utc>,
|
||||||
|
|
||||||
|
/// 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<DateTime<Utc>>,
|
||||||
|
|
||||||
|
/// The Workspace ID associated with the client.
|
||||||
|
wid: i32,
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user