hey_sdk/services/
time_tracks.rs1use std::borrow::Cow;
8
9use bytes::Bytes;
10use chrono::Utc;
11
12use crate::error::Error;
13use crate::generated::routes;
14use crate::generated::types::{Recording, UpdateTimeTrackPayload, UpdateTimeTrackRequestContent};
15use crate::http::Method;
16use crate::observability::OperationInfo;
17use crate::services::write_info;
18
19pub use crate::generated::services::time_tracks::*;
20
21impl TimeTracks<'_> {
22 pub async fn start_tracking(&self) -> Result<Recording, Error> {
31 match self.start().await {
32 Ok(track) => Ok(track),
33 Err(error) if error.http_status() == Some(409) => Err(already_running(&error)),
34 Err(error) => Err(error),
35 }
36 }
37
38 pub async fn stop(&self, time_track_id: i64) -> Result<(), Error> {
40 self.stop_and_file(time_track_id, None).await
41 }
42
43 pub async fn stop_and_file(
54 &self,
55 time_track_id: i64,
56 category_title: Option<&str>,
57 ) -> Result<(), Error> {
58 let body = UpdateTimeTrackRequestContent {
59 calendar_time_track: UpdateTimeTrackPayload {
60 ends_at: Some(Utc::now()),
61 category_title: category_title
64 .filter(|title| !title.is_empty())
65 .map(str::to_string),
66 ..UpdateTimeTrackPayload::default()
67 },
68 };
69
70 let mut operation = self
71 .client()
72 .operation(&routes::UPDATE_TIME_TRACK, &[&time_track_id]);
73 operation.operation_name("StopTimeTrack");
74 operation.resource_id(time_track_id);
75 operation.json(&body)?;
76 self.client().send_unit(operation).await
77 }
78
79 pub async fn create_category(&self, title: &str) -> Result<(), Error> {
81 let mut operation = self
82 .client()
83 .form(Method::POST, "/calendar/time_tracks/categories")?;
84 operation.info(write_info(
85 "TimeTracks",
86 "CreateTimeTrackCategory",
87 "category",
88 None,
89 ));
90 operation.form(&[("category[title]", title)]);
91 self.client().send_unit(operation).await
92 }
93
94 pub async fn update_category(&self, category_id: i64, title: &str) -> Result<(), Error> {
96 let mut operation = self.client().form(
97 Method::PATCH,
98 &format!("/calendar/time_tracks/categories/{category_id}"),
99 )?;
100 operation.info(write_info(
101 "TimeTracks",
102 "UpdateTimeTrackCategory",
103 "category",
104 Some(category_id),
105 ));
106 operation.form(&[("category[title]", title)]);
107 self.client().send_unit(operation).await
108 }
109
110 pub async fn delete_category(&self, category_id: i64) -> Result<(), Error> {
112 let mut operation = self.client().form(
113 Method::DELETE,
114 &format!("/calendar/time_tracks/categories/{category_id}"),
115 )?;
116 operation.info(write_info(
117 "TimeTracks",
118 "DeleteTimeTrackCategory",
119 "category",
120 Some(category_id),
121 ));
122 self.client().send_unit(operation).await
123 }
124
125 pub async fn export(&self) -> Result<Bytes, Error> {
128 let mut operation = self.client().csv("/calendar/time_tracks/exports")?;
129 operation.info(OperationInfo {
130 service: Cow::Borrowed("TimeTracks"),
131 operation: Cow::Borrowed("ExportTimeTracks"),
132 resource_type: Cow::Borrowed("time_track"),
133 is_mutation: false,
134 resource_id: None,
135 });
136 Ok(self.client().execute(operation).await?.body)
137 }
138}
139
140fn already_running(refusal: &Error) -> Error {
141 match refusal.hint() {
142 Some(message) => Error::conflict(message),
143 None => Error::conflict("a time track is already running"),
144 }
145}