:art: Tweak some names dealing with user activity

Max Brunsfeld created

* Rename `project_activity_summary` to `top_users_activity_summary`
to make clearer the distinction between it and the per-user summary.
* Rename `user_activity_summary` to `user_activity_timeline`, since
its output is structured a bit differently than the courser-grained
"summary" returned by the top-user query.
* Rename `ActivityDuration` -> `ActivityPeriod`

Change summary

crates/collab/src/api.rs | 12 ++--
crates/collab/src/db.rs  | 95 +++++++++++++++++++++++------------------
crates/collab/src/rpc.rs |  2 
3 files changed, 60 insertions(+), 49 deletions(-)

Detailed changes

crates/collab/src/api.rs 🔗

@@ -36,8 +36,8 @@ pub fn routes(rpc_server: &Arc<rpc::Server>, state: Arc<AppState>) -> Router<Bod
         .route("/panic", post(trace_panic))
         .route("/rpc_server_snapshot", get(get_rpc_server_snapshot))
         .route(
-            "/project_activity_summary",
-            get(get_project_activity_summary),
+            "/user_activity/summary",
+            get(get_top_users_activity_summary),
         )
         .route("/project_metadata", get(get_project_metadata))
         .layer(
@@ -264,20 +264,20 @@ async fn get_rpc_server_snapshot(
 }
 
 #[derive(Deserialize)]
-struct GetProjectActivityParams {
+struct TimePeriodParams {
     #[serde(with = "time::serde::iso8601")]
     start: OffsetDateTime,
     #[serde(with = "time::serde::iso8601")]
     end: OffsetDateTime,
 }
 
-async fn get_project_activity_summary(
-    Query(params): Query<GetProjectActivityParams>,
+async fn get_top_users_activity_summary(
+    Query(params): Query<TimePeriodParams>,
     Extension(app): Extension<Arc<AppState>>,
 ) -> Result<ErasedJson> {
     let summary = app
         .db
-        .summarize_project_activity(params.start..params.end, 100)
+        .get_top_users_activity_summary(params.start..params.end, 100)
         .await?;
     Ok(ErasedJson::pretty(summary))
 }

crates/collab/src/db.rs 🔗

@@ -7,7 +7,7 @@ use axum::http::StatusCode;
 use collections::HashMap;
 use futures::StreamExt;
 use nanoid::nanoid;
-use serde::Serialize;
+use serde::{Deserialize, Serialize};
 pub use sqlx::postgres::PgPoolOptions as DbOptions;
 use sqlx::{types::Uuid, FromRow, QueryBuilder, Row};
 use time::{OffsetDateTime, PrimitiveDateTime};
@@ -63,7 +63,7 @@ pub trait Db: Send + Sync {
 
     /// Record which users have been active in which projects during
     /// a given period of time.
-    async fn record_project_activity(
+    async fn record_user_activity(
         &self,
         time_period: Range<OffsetDateTime>,
         active_projects: &[(UserId, ProjectId)],
@@ -71,18 +71,18 @@ pub trait Db: Send + Sync {
 
     /// Get the users that have been most active during the given time period,
     /// along with the amount of time they have been active in each project.
-    async fn summarize_project_activity(
+    async fn get_top_users_activity_summary(
         &self,
         time_period: Range<OffsetDateTime>,
         max_user_count: usize,
     ) -> Result<Vec<UserActivitySummary>>;
 
     /// Get the project activity for the given user and time period.
-    async fn summarize_user_activity(
+    async fn get_user_activity_timeline(
         &self,
-        user_id: UserId,
         time_period: Range<OffsetDateTime>,
-    ) -> Result<Vec<UserActivityDuration>>;
+        user_id: UserId,
+    ) -> Result<Vec<UserActivityPeriod>>;
 
     async fn get_contacts(&self, id: UserId) -> Result<Vec<Contact>>;
     async fn has_contact(&self, user_id_a: UserId, user_id_b: UserId) -> Result<bool>;
@@ -564,7 +564,7 @@ impl Db for PostgresDb {
         Ok(extension_counts)
     }
 
-    async fn record_project_activity(
+    async fn record_user_activity(
         &self,
         time_period: Range<OffsetDateTime>,
         projects: &[(UserId, ProjectId)],
@@ -593,7 +593,7 @@ impl Db for PostgresDb {
         Ok(())
     }
 
-    async fn summarize_project_activity(
+    async fn get_top_users_activity_summary(
         &self,
         time_period: Range<OffsetDateTime>,
         max_user_count: usize,
@@ -648,11 +648,11 @@ impl Db for PostgresDb {
         Ok(result)
     }
 
-    async fn summarize_user_activity(
+    async fn get_user_activity_timeline(
         &self,
-        user_id: UserId,
         time_period: Range<OffsetDateTime>,
-    ) -> Result<Vec<UserActivityDuration>> {
+        user_id: UserId,
+    ) -> Result<Vec<UserActivityPeriod>> {
         const COALESCE_THRESHOLD: Duration = Duration::from_secs(5);
 
         let query = "
@@ -689,19 +689,19 @@ impl Db for PostgresDb {
         .bind(time_period.end)
         .fetch(&self.pool);
 
-        let mut durations: HashMap<ProjectId, Vec<UserActivityDuration>> = Default::default();
+        let mut time_periods: HashMap<ProjectId, Vec<UserActivityPeriod>> = Default::default();
         while let Some(row) = rows.next().await {
             let (ended_at, duration_millis, project_id, extension, extension_count) = row?;
             let ended_at = ended_at.assume_utc();
             let duration = Duration::from_millis(duration_millis as u64);
             let started_at = ended_at - duration;
-            let project_durations = durations.entry(project_id).or_default();
+            let project_time_periods = time_periods.entry(project_id).or_default();
 
-            if let Some(prev_duration) = project_durations.last_mut() {
+            if let Some(prev_duration) = project_time_periods.last_mut() {
                 if started_at - prev_duration.end <= COALESCE_THRESHOLD {
                     prev_duration.end = ended_at;
                 } else {
-                    project_durations.push(UserActivityDuration {
+                    project_time_periods.push(UserActivityPeriod {
                         project_id,
                         start: started_at,
                         end: ended_at,
@@ -709,7 +709,7 @@ impl Db for PostgresDb {
                     });
                 }
             } else {
-                project_durations.push(UserActivityDuration {
+                project_time_periods.push(UserActivityPeriod {
                     project_id,
                     start: started_at,
                     end: ended_at,
@@ -718,7 +718,7 @@ impl Db for PostgresDb {
             }
 
             if let Some((extension, extension_count)) = extension.zip(extension_count) {
-                project_durations
+                project_time_periods
                     .last_mut()
                     .unwrap()
                     .extensions
@@ -726,7 +726,7 @@ impl Db for PostgresDb {
             }
         }
 
-        let mut durations = durations.into_values().flatten().collect::<Vec<_>>();
+        let mut durations = time_periods.into_values().flatten().collect::<Vec<_>>();
         durations.sort_unstable_by_key(|duration| duration.start);
         Ok(durations)
     }
@@ -1206,7 +1206,18 @@ impl Db for PostgresDb {
 macro_rules! id_type {
     ($name:ident) => {
         #[derive(
-            Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Serialize,
+            Clone,
+            Copy,
+            Debug,
+            Default,
+            PartialEq,
+            Eq,
+            PartialOrd,
+            Ord,
+            Hash,
+            sqlx::Type,
+            Serialize,
+            Deserialize,
         )]
         #[sqlx(transparent)]
         #[serde(transparent)]
@@ -1263,7 +1274,7 @@ pub struct UserActivitySummary {
 }
 
 #[derive(Clone, Debug, PartialEq, Serialize)]
-pub struct UserActivityDuration {
+pub struct UserActivityPeriod {
     project_id: ProjectId,
     start: OffsetDateTime,
     end: OffsetDateTime,
@@ -1549,24 +1560,24 @@ pub mod tests {
 
         // User 2 opens a project
         let t1 = t0 + Duration::from_secs(10);
-        db.record_project_activity(t0..t1, &[(user_2, project_2)])
+        db.record_user_activity(t0..t1, &[(user_2, project_2)])
             .await
             .unwrap();
 
         let t2 = t1 + Duration::from_secs(10);
-        db.record_project_activity(t1..t2, &[(user_2, project_2)])
+        db.record_user_activity(t1..t2, &[(user_2, project_2)])
             .await
             .unwrap();
 
         // User 1 joins the project
         let t3 = t2 + Duration::from_secs(10);
-        db.record_project_activity(t2..t3, &[(user_2, project_2), (user_1, project_2)])
+        db.record_user_activity(t2..t3, &[(user_2, project_2), (user_1, project_2)])
             .await
             .unwrap();
 
         // User 1 opens another project
         let t4 = t3 + Duration::from_secs(10);
-        db.record_project_activity(
+        db.record_user_activity(
             t3..t4,
             &[
                 (user_2, project_2),
@@ -1579,7 +1590,7 @@ pub mod tests {
 
         // User 3 joins that project
         let t5 = t4 + Duration::from_secs(10);
-        db.record_project_activity(
+        db.record_user_activity(
             t4..t5,
             &[
                 (user_2, project_2),
@@ -1593,18 +1604,18 @@ pub mod tests {
 
         // User 2 leaves
         let t6 = t5 + Duration::from_secs(5);
-        db.record_project_activity(t5..t6, &[(user_1, project_1), (user_3, project_1)])
+        db.record_user_activity(t5..t6, &[(user_1, project_1), (user_3, project_1)])
             .await
             .unwrap();
 
         let t7 = t6 + Duration::from_secs(60);
         let t8 = t7 + Duration::from_secs(10);
-        db.record_project_activity(t7..t8, &[(user_1, project_1)])
+        db.record_user_activity(t7..t8, &[(user_1, project_1)])
             .await
             .unwrap();
 
         assert_eq!(
-            db.summarize_project_activity(t0..t6, 10).await.unwrap(),
+            db.get_top_users_activity_summary(t0..t6, 10).await.unwrap(),
             &[
                 UserActivitySummary {
                     id: user_1,
@@ -1627,15 +1638,15 @@ pub mod tests {
             ]
         );
         assert_eq!(
-            db.summarize_user_activity(user_1, t3..t6).await.unwrap(),
+            db.get_user_activity_timeline(t3..t6, user_1).await.unwrap(),
             &[
-                UserActivityDuration {
+                UserActivityPeriod {
                     project_id: project_1,
                     start: t3,
                     end: t6,
                     extensions: HashMap::from_iter([("rs".to_string(), 5), ("md".to_string(), 7)]),
                 },
-                UserActivityDuration {
+                UserActivityPeriod {
                     project_id: project_2,
                     start: t3,
                     end: t5,
@@ -1644,21 +1655,21 @@ pub mod tests {
             ]
         );
         assert_eq!(
-            db.summarize_user_activity(user_1, t0..t8).await.unwrap(),
+            db.get_user_activity_timeline(t0..t8, user_1).await.unwrap(),
             &[
-                UserActivityDuration {
+                UserActivityPeriod {
                     project_id: project_2,
                     start: t2,
                     end: t5,
                     extensions: Default::default(),
                 },
-                UserActivityDuration {
+                UserActivityPeriod {
                     project_id: project_1,
                     start: t3,
                     end: t6,
                     extensions: HashMap::from_iter([("rs".to_string(), 5), ("md".to_string(), 7)]),
                 },
-                UserActivityDuration {
+                UserActivityPeriod {
                     project_id: project_1,
                     start: t7,
                     end: t8,
@@ -2450,27 +2461,27 @@ pub mod tests {
             unimplemented!()
         }
 
-        async fn record_project_activity(
+        async fn record_user_activity(
             &self,
-            _period: Range<OffsetDateTime>,
+            _time_period: Range<OffsetDateTime>,
             _active_projects: &[(UserId, ProjectId)],
         ) -> Result<()> {
             unimplemented!()
         }
 
-        async fn summarize_project_activity(
+        async fn get_top_users_activity_summary(
             &self,
-            _period: Range<OffsetDateTime>,
+            _time_period: Range<OffsetDateTime>,
             _limit: usize,
         ) -> Result<Vec<UserActivitySummary>> {
             unimplemented!()
         }
 
-        async fn summarize_user_activity(
+        async fn get_user_activity_timeline(
             &self,
-            _user_id: UserId,
             _time_period: Range<OffsetDateTime>,
-        ) -> Result<Vec<UserActivityDuration>> {
+            _user_id: UserId,
+        ) -> Result<Vec<UserActivityPeriod>> {
             unimplemented!()
         }
 

crates/collab/src/rpc.rs 🔗

@@ -332,7 +332,7 @@ impl Server {
                     let period_end = OffsetDateTime::now_utc();
                     this.app_state
                         .db
-                        .record_project_activity(period_start..period_end, &active_projects)
+                        .record_user_activity(period_start..period_end, &active_projects)
                         .await
                         .trace_err();
                     period_start = period_end;