feat: add analytics fetch users mapping (#6439)

* feat: add users mapping

* remove skip_serialize_if

---------

Co-authored-by: aecsocket <43144841+aecsocket@users.noreply.github.com>
This commit is contained in:
Truman Gao
2026-06-22 15:06:12 +00:00
committed by GitHub
co-authored by aecsocket
parent b7d097d74d
commit 2c53e1240e
@@ -18,6 +18,7 @@ use std::{
use crate::database::{PgPool, models::DBUserId};
use actix_web::{HttpRequest, post, web};
use ariadne::ids::UserId;
use chrono::{DateTime, TimeDelta, Utc};
use eyre::eyre;
use serde::{Deserialize, Serialize};
@@ -43,7 +44,7 @@ use crate::{
projects::ProjectStatus,
teams::ProjectPermissions,
threads::MessageBody,
v3::{analytics::DownloadReason, projects::Project},
v3::{analytics::DownloadReason, projects::Project, users::User},
},
queue::session::AuthQueue,
routes::ApiError,
@@ -131,6 +132,9 @@ pub struct GetResponse {
/// Project metadata for projects referenced in the response metrics.
#[serde(default)]
pub projects: HashMap<ProjectId, Project>,
/// User metadata for users referenced in the response metrics.
#[serde(default)]
pub users: HashMap<UserId, User>,
/// List of events associated with projects that were requested.
pub project_events: Vec<ProjectAnalyticsEvent>,
}
@@ -422,10 +426,12 @@ pub async fn fetch_analytics(
let projects =
fetch_response_projects(&mut time_slices, &user, &pool, &redis).await?;
let users = fetch_response_users(&time_slices, &pool, &redis).await?;
Ok(web::Json(GetResponse {
metrics: time_slices,
projects,
users,
project_events,
}))
}
@@ -545,6 +551,43 @@ async fn fetch_response_projects(
.collect())
}
async fn fetch_response_users(
time_slices: &[TimeSlice],
pool: &PgPool,
redis: &RedisPool,
) -> Result<HashMap<UserId, User>, ApiError> {
let mut user_ids = HashSet::<DBUserId>::new();
for time_slice in time_slices {
for data in &time_slice.0 {
let AnalyticsData::Project(project) = data else {
continue;
};
if let ProjectMetrics::Revenue(revenue) = &project.metrics
&& let Some(user_id) = revenue.user_id
{
user_ids.insert(user_id.into());
}
}
}
let user_ids = user_ids.into_iter().collect::<Vec<_>>();
if user_ids.is_empty() {
return Ok(HashMap::new());
}
let users = DBUser::get_many_ids(&user_ids, pool, redis).await?;
Ok(users
.into_iter()
.map(|user| {
let user_id = UserId::from(user.id);
(user_id, User::from(user))
})
.collect())
}
fn filter_response_project_ids(
time_slices: &mut [TimeSlice],
visible_project_ids: &HashSet<DBProjectId>,
@@ -993,6 +1036,7 @@ mod tests {
})]),
],
projects: HashMap::new(),
users: HashMap::new(),
project_events: vec![],
};
let target = json!({
@@ -1020,6 +1064,7 @@ mod tests {
]
],
"projects": {},
"users": {},
"project_events": []
});