diff --git a/apps/labrinth/src/routes/v3/analytics_get/facets.rs b/apps/labrinth/src/routes/v3/analytics_get/facets.rs index c40a6ffb4a..c5ea26162a 100644 --- a/apps/labrinth/src/routes/v3/analytics_get/facets.rs +++ b/apps/labrinth/src/routes/v3/analytics_get/facets.rs @@ -252,12 +252,27 @@ async fn fetch_project_downloads_facets( fn normalize_download_source_facets( user_agents: &[String], ) -> Vec { - user_agents + let mut sources = user_agents .iter() .filter_map(|user_agent| normalize_download_source(user_agent)) .collect::>() .into_iter() - .collect() + .collect::>(); + sources.sort_by(|a, b| { + download_source_sort_key(a).cmp(download_source_sort_key(b)) + }); + sources +} + +fn download_source_sort_key(source: &DownloadSource) -> &str { + match source { + DownloadSource::Named(name) => name, + DownloadSource::Website => "website", + DownloadSource::ModrinthApp => "modrinth_app", + DownloadSource::ModrinthHosting => "modrinth_hosting", + DownloadSource::ModrinthMaven => "modrinth_maven", + DownloadSource::Other => "other", + } } async fn fetch_project_playtime_facets( diff --git a/apps/labrinth/src/routes/v3/users.rs b/apps/labrinth/src/routes/v3/users.rs index bfb366a73a..c76e71845a 100644 --- a/apps/labrinth/src/routes/v3/users.rs +++ b/apps/labrinth/src/routes/v3/users.rs @@ -40,10 +40,10 @@ pub fn config(cfg: &mut web::ServiceConfig) { cfg.route("user", web::get().to(user_auth_get)); cfg.route("users", web::get().to(users_get)); cfg.route("user_email", web::get().to(admin_user_email)); - cfg.route("all-projects", web::get().to(all_projects)); cfg.service( web::scope("user") + .route("{user_id}/all-projects", web::get().to(all_projects)) .route("{user_id}/projects", web::get().to(projects_list)) .route("{id}/notes", web::patch().to(user_notes_edit)) .route("{id}", web::get().to(user_get)) @@ -72,6 +72,7 @@ pub struct UserEmailQuery { pub async fn all_projects( req: HttpRequest, + info: web::Path<(String,)>, pool: web::Data, redis: web::Data, session_queue: web::Data, @@ -81,15 +82,19 @@ pub async fn all_projects( &**pool, &redis, &session_queue, - Scopes::PROJECT_READ | Scopes::ORGANIZATION_READ, + Scopes::PROJECT_READ, ) - .await? - .1; + .await + .map(|x| x.1) + .ok(); + let target_user = DBUser::get(&info.into_inner().0, &**pool, &redis) + .await? + .ok_or(ApiError::NotFound)?; let user_project_ids = - DBUser::get_projects(user.id.into(), &**pool, &redis).await?; + DBUser::get_projects(target_user.id, &**pool, &redis).await?; let organization_ids = - DBUser::get_organizations(user.id.into(), &**pool).await?; + DBUser::get_organizations(target_user.id, &**pool).await?; let organizations_data = DBOrganization::get_many_ids(&organization_ids, &**pool, &redis) .await?; @@ -124,22 +129,29 @@ pub async fn all_projects( let mut organizations = HashMap::new(); let mut visible_organization_ids = Vec::new(); for data in organizations_data { - if !is_visible_organization(&data, &Some(user.clone()), &pool, &redis) - .await? - { + if !is_visible_organization(&data, &user, &pool, &redis).await? { continue; } visible_organization_ids.push(data.id); let members_data = team_groups.remove(&data.team_id).unwrap_or(vec![]); + let logged_in = user + .as_ref() + .and_then(|user| { + members_data + .iter() + .find(|x| x.user_id == user.id.into() && x.accepted) + }) + .is_some(); let team_members = members_data .into_iter() + .filter(|x| logged_in || x.accepted || target_user.id == x.user_id) .filter_map(|data| { users.iter().find(|x| x.id == data.user_id).map(|member| { crate::models::teams::TeamMember::from( data, member.clone(), - false, + !logged_in, ) }) }) @@ -179,8 +191,7 @@ pub async fn all_projects( crate::database::DBProject::get_many_ids(&project_ids, &**pool, &redis) .await?; let projects = - filter_visible_projects(projects_data, &Some(user), &pool, true) - .await?; + filter_visible_projects(projects_data, &user, &pool, true).await?; Ok(web::Json(AllProjectsResponse { projects,