Skip to content

Commit 30675ba

Browse files
committed
i think it works now
1 parent d5b18b8 commit 30675ba

File tree

2 files changed

+69
-25
lines changed

2 files changed

+69
-25
lines changed

rustytime/src/handlers/user.rs

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ use crate::utils::http::extract_client_ip_cloudflare;
1414

1515
use crate::db::connection::DbPool;
1616
use crate::get_db_conn;
17-
use crate::models::heartbeat::Heartbeat;
1817
use crate::models::heartbeat::*;
18+
use crate::models::heartbeat::{Heartbeat, StoredHeartbeat};
1919
use crate::models::project::get_or_create_project_id;
2020
use crate::schema::heartbeats;
21+
use crate::schema::heartbeats::dsl as heartbeats_dsl;
2122
use crate::state::AppState;
2223
use crate::utils::auth::{get_user_id_from_api_key, get_valid_api_key};
2324
use crate::utils::time::{TimeFormat, human_readable_duration};
@@ -65,13 +66,18 @@ async fn process_heartbeat_request(
6566
);
6667

6768
match store_heartbeats_in_db(&app_state.db_pool, vec![new_heartbeat]).await {
68-
Ok(mut heartbeats) => {
69-
if let Some(heartbeat) = heartbeats.pop() {
69+
Ok(mut stored_results) => {
70+
if let Some(StoredHeartbeat { heartbeat, status }) = stored_results.pop() {
7071
let response = HeartbeatApiResponse {
71-
data: heartbeat.into(),
72+
data: HeartbeatResponse::from(heartbeat),
73+
};
74+
let http_status = if status == 201 {
75+
StatusCode::CREATED
76+
} else {
77+
StatusCode::ACCEPTED
7278
};
7379
let response_data = Json(HeartbeatApiResponseVariant::Single(response));
74-
Ok((StatusCode::ACCEPTED, response_data).into_response())
80+
Ok((http_status, response_data).into_response())
7581
} else {
7682
Err((StatusCode::INTERNAL_SERVER_ERROR, "Internal server error")
7783
.into_response())
@@ -89,19 +95,25 @@ async fn process_heartbeat_request(
8995
.collect();
9096

9197
match store_heartbeats_in_db(&app_state.db_pool, new_heartbeats).await {
92-
Ok(heartbeats) => {
93-
if heartbeats.is_empty() {
98+
Ok(stored_results) => {
99+
if stored_results.is_empty() {
94100
let response_data = Json(HeartbeatApiResponseVariant::Multiple(
95101
HeartbeatBulkApiResponse { responses: vec![] },
96102
));
97103
Ok((StatusCode::CREATED, response_data).into_response())
98104
} else {
105+
let has_new = stored_results.iter().any(|stored| stored.status == 201);
106+
let http_status = if has_new {
107+
StatusCode::CREATED
108+
} else {
109+
StatusCode::ACCEPTED
110+
};
99111
let response_data = Json(HeartbeatApiResponseVariant::Multiple(
100112
HeartbeatBulkApiResponse {
101-
responses: heartbeats.into_iter().map(|h| h.into()).collect(),
113+
responses: stored_results.into_iter().map(Into::into).collect(),
102114
},
103115
));
104-
Ok((StatusCode::CREATED, response_data).into_response())
116+
Ok((http_status, response_data).into_response())
105117
}
106118
}
107119
Err(e) => {
@@ -216,7 +228,7 @@ pub async fn get_statusbar_today(
216228
pub async fn store_heartbeats_in_db(
217229
pool: &DbPool,
218230
new_heartbeats: Vec<NewHeartbeat>,
219-
) -> Result<Vec<Heartbeat>, diesel::result::Error> {
231+
) -> Result<Vec<StoredHeartbeat>, diesel::result::Error> {
220232
let pool = pool.clone();
221233
tokio::task::spawn_blocking(move || {
222234
let mut connection = pool.get().expect("Failed to get DB connection from pool");
@@ -238,15 +250,37 @@ pub async fn store_heartbeats_in_db(
238250
}
239251
}
240252

241-
match diesel::insert_into(heartbeats::table)
242-
.values(&new_heartbeats)
243-
.on_conflict_do_nothing()
244-
.get_results(conn)
245-
{
246-
Ok(heartbeats) => Ok(heartbeats),
247-
Err(diesel::result::Error::NotFound) => Ok(vec![]),
248-
Err(e) => Err(e),
253+
let mut results = Vec::with_capacity(new_heartbeats.len());
254+
255+
for heartbeat in new_heartbeats {
256+
let key_user_id = heartbeat.user_id;
257+
let key_time = heartbeat.time;
258+
259+
match diesel::insert_into(heartbeats::table)
260+
.values(&heartbeat)
261+
.on_conflict_do_nothing()
262+
.returning(Heartbeat::as_returning())
263+
.get_result::<Heartbeat>(conn)
264+
{
265+
Ok(inserted) => results.push(StoredHeartbeat {
266+
heartbeat: inserted,
267+
status: 201,
268+
}),
269+
Err(diesel::result::Error::NotFound) => {
270+
let existing = heartbeats_dsl::heartbeats
271+
.find((key_user_id, key_time))
272+
.first::<Heartbeat>(conn)?;
273+
274+
results.push(StoredHeartbeat {
275+
heartbeat: existing,
276+
status: 201,
277+
});
278+
}
279+
Err(err) => return Err(err),
280+
}
249281
}
282+
283+
Ok(results)
250284
})
251285
})
252286
.await

rustytime/src/models/heartbeat.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,18 @@ pub struct HeartbeatBulkApiResponse {
186186
#[derive(Serialize, Debug)]
187187
pub struct BulkResponseItem(pub HeartbeatResponse, pub u16);
188188

189+
#[derive(Debug, Clone)]
190+
pub struct StoredHeartbeat {
191+
pub heartbeat: Heartbeat,
192+
pub status: u16,
193+
}
194+
195+
impl From<StoredHeartbeat> for BulkResponseItem {
196+
fn from(value: StoredHeartbeat) -> Self {
197+
BulkResponseItem(HeartbeatResponse::from(value.heartbeat), value.status)
198+
}
199+
}
200+
189201
#[derive(Queryable, Selectable, Serialize, Deserialize, Debug, Clone)]
190202
#[diesel(table_name = heartbeats)]
191203
#[diesel(check_for_backend(diesel::pg::Pg))]
@@ -284,14 +296,12 @@ impl SanitizedHeartbeatRequest {
284296
// Parse the category
285297
let category = if let Some(cat) = request.category {
286298
Some(cat)
299+
} else if type_ == "domain" || type_ == "url" {
300+
Some("browsing".to_string())
301+
} else if type_ == "file" && request.language.is_some() {
302+
Some("coding".to_string())
287303
} else {
288-
if type_ == "domain" || type_ == "url" {
289-
Some("browsing".to_string())
290-
} else if type_ == "file" && request.language.is_some() {
291-
Some("coding".to_string())
292-
} else {
293-
None
294-
}
304+
None
295305
};
296306

297307
// Convert dependencies and apply limits

0 commit comments

Comments
 (0)