@@ -14,10 +14,11 @@ use crate::utils::http::extract_client_ip_cloudflare;
1414
1515use crate :: db:: connection:: DbPool ;
1616use crate :: get_db_conn;
17- use crate :: models:: heartbeat:: Heartbeat ;
1817use crate :: models:: heartbeat:: * ;
18+ use crate :: models:: heartbeat:: { Heartbeat , StoredHeartbeat } ;
1919use crate :: models:: project:: get_or_create_project_id;
2020use crate :: schema:: heartbeats;
21+ use crate :: schema:: heartbeats:: dsl as heartbeats_dsl;
2122use crate :: state:: AppState ;
2223use crate :: utils:: auth:: { get_user_id_from_api_key, get_valid_api_key} ;
2324use 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(
216228pub 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
0 commit comments