From 83bfba3bc85c1da694bb0f83a30bb41081fe52ed Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Mon, 10 Feb 2025 21:32:56 +0100 Subject: [PATCH 1/7] feat(user page): Recently published --- api/src/api/users.rs | 19 +++++++++++++++++++ api/src/db/database.rs | 20 ++++++++++++++++++++ frontend/routes/user/[id].tsx | 33 +++++++++++++++++++++++---------- 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/api/src/api/users.rs b/api/src/api/users.rs index 975cfb4a6..dd6604985 100644 --- a/api/src/api/users.rs +++ b/api/src/api/users.rs @@ -13,6 +13,7 @@ use crate::util::ApiResult; use crate::util::RequestIdExt; use super::ApiError; +use super::ApiPackage; use super::ApiScope; use super::ApiUser; @@ -20,6 +21,7 @@ pub fn users_router() -> Router { Router::builder() .get("/:id", util::json(get_handler)) .get("/:id/scopes", util::json(get_scopes_handler)) + .get("/:id/packages", util::json(get_packages_handler)) .build() .unwrap() } @@ -54,3 +56,20 @@ pub async fn get_scopes_handler( Ok(scopes.into_iter().map(ApiScope::from).collect()) } + +#[instrument(name = "GET /api/users/:id/packages", skip(req), err, fields(id))] +pub async fn get_packages_handler( + req: Request, +) -> ApiResult> { + let id = req.param_uuid("id")?; + Span::current().record("id", field::display(id)); + + let db = req.data::().unwrap(); + db.get_user_public(id) + .await? + .ok_or(ApiError::UserNotFound)?; + + let packages = db.get_recent_packages_by_user(&id).await?; + + Ok(packages.into_iter().map(ApiPackage::from).collect()) +} diff --git a/api/src/db/database.rs b/api/src/db/database.rs index 9be634d35..5eaf64f7e 100644 --- a/api/src/db/database.rs +++ b/api/src/db/database.rs @@ -3173,6 +3173,26 @@ impl Database { .fetch_all(&self.pool) .await } + + pub async fn get_recent_packages_by_user( + &self, + user_id: &uuid::Uuid, + ) -> Result> { + let packages = sqlx::query_as!( + Package, + r#" + SELECT * FROM packages + WHERE owner_id = $1 + ORDER BY published_at DESC + LIMIT 10 + "#, + user_id + ) + .fetch_all(&self.pool) + .await?; + + Ok(packages) + } } async fn finalize_package_creation( diff --git a/frontend/routes/user/[id].tsx b/frontend/routes/user/[id].tsx index 75580dd2f..17f8f3438 100644 --- a/frontend/routes/user/[id].tsx +++ b/frontend/routes/user/[id].tsx @@ -2,7 +2,7 @@ import { HttpError } from "fresh"; import { define } from "../../util.ts"; import { path } from "../../utils/api.ts"; -import { FullUser, Scope, User } from "../../utils/api_types.ts"; +import { FullUser, Package, Scope, User } from "../../utils/api_types.ts"; import { ListPanel } from "../../components/ListPanel.tsx"; import { AccountLayout } from "../account/(_components)/AccountLayout.tsx"; @@ -31,14 +31,24 @@ export default define.page(function UserPage({ data, state }) { )} - { - /*
- Recently published -
- TODO: all packages recently published by this user -
-
*/ - } + {data.packages.length > 0 + ? ( + ({ + value: pkg.name, + href: `/packages/${pkg.id}`, + }))} + /> + ) + : ( +
+ {state.user?.id === data.user.id ? "You have" : "This user has"} + {" "} + not published any packages recently. +
+ )} ); @@ -46,10 +56,11 @@ export default define.page(function UserPage({ data, state }) { export const handler = define.handlers({ async GET(ctx) { - const [currentUser, userRes, scopesRes] = await Promise.all([ + const [currentUser, userRes, scopesRes, packagesRes] = await Promise.all([ ctx.state.userPromise, ctx.state.api.get(path`/users/${ctx.params.id}`), ctx.state.api.get(path`/users/${ctx.params.id}/scopes`), + ctx.state.api.get(path`/users/${ctx.params.id}/packages`), ]); if (currentUser instanceof Response) return currentUser; @@ -61,6 +72,7 @@ export const handler = define.handlers({ throw userRes; // gracefully handle errors } if (!scopesRes.ok) throw scopesRes; // gracefully handle errors + if (!packagesRes.ok) throw packagesRes; // gracefully handle errors let user: User | FullUser = userRes.data; if (ctx.params.id === currentUser?.id) { @@ -74,6 +86,7 @@ export const handler = define.handlers({ data: { user, scopes: scopesRes.data, + packages: packagesRes.data, }, }; }, From 960e2a05a1b81439707eb39a2fffb5bbcf770811 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Mon, 10 Feb 2025 21:40:20 +0100 Subject: [PATCH 2/7] FIx: wrong link --- frontend/routes/user/[id].tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/routes/user/[id].tsx b/frontend/routes/user/[id].tsx index 17f8f3438..90c4b417d 100644 --- a/frontend/routes/user/[id].tsx +++ b/frontend/routes/user/[id].tsx @@ -38,7 +38,8 @@ export default define.page(function UserPage({ data, state }) { subtitle="Packages recently published by this user" children={data.packages.map((pkg) => ({ value: pkg.name, - href: `/packages/${pkg.id}`, + //@am/neuralnetwork + href: `/${pkg.scope}/${pkg.name}`, }))} /> ) From 751dd9ebd49c41cd675a3b6ddb1fcd12581d4747 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Mon, 10 Feb 2025 21:50:27 +0100 Subject: [PATCH 3/7] fix: rs build ? --- api/src/api/users.rs | 2 +- api/src/db/database.rs | 36 +++++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/api/src/api/users.rs b/api/src/api/users.rs index dd6604985..0eab90fb6 100644 --- a/api/src/api/users.rs +++ b/api/src/api/users.rs @@ -13,9 +13,9 @@ use crate::util::ApiResult; use crate::util::RequestIdExt; use super::ApiError; -use super::ApiPackage; use super::ApiScope; use super::ApiUser; +use super::ApiPackage; pub fn users_router() -> Router { Router::builder() diff --git a/api/src/db/database.rs b/api/src/db/database.rs index 5eaf64f7e..f4f585de7 100644 --- a/api/src/db/database.rs +++ b/api/src/db/database.rs @@ -3174,25 +3174,43 @@ impl Database { .await } - pub async fn get_recent_packages_by_user( - &self, - user_id: &uuid::Uuid, - ) -> Result> { + pub async fn get_recent_packages_by_user(&self, user_id: &uuid::Uuid) -> Result, PackageVersionMeta)>> { let packages = sqlx::query_as!( - Package, - r#" + Package, + r#" SELECT * FROM packages WHERE owner_id = $1 ORDER BY published_at DESC LIMIT 10 "#, - user_id + user_id ) .fetch_all(&self.pool) .await?; - Ok(packages) - } + let mut result = Vec::new(); + for package in packages { + let repo = sqlx::query_as!( + GithubRepository, + "SELECT * FROM github_repositories WHERE package_id = $1", + package.id + ) + .fetch_optional(&self.pool) + .await?; + + let meta = sqlx::query_as!( + PackageVersionMeta, + "SELECT * FROM package_version_meta WHERE package_id = $1", + package.id + ) + .fetch_one(&self.pool) + .await?; + + result.push((package, repo, meta)); + } + + Ok(result) +} } async fn finalize_package_creation( From 187f498d416827de1b6a4e9e720a17edd6091dc3 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Mon, 10 Feb 2025 22:52:02 +0100 Subject: [PATCH 4/7] refracto --- api/src/api/users.rs | 9 +++++-- api/src/db/database.rs | 54 ++++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/api/src/api/users.rs b/api/src/api/users.rs index 0eab90fb6..3b394168a 100644 --- a/api/src/api/users.rs +++ b/api/src/api/users.rs @@ -13,9 +13,9 @@ use crate::util::ApiResult; use crate::util::RequestIdExt; use super::ApiError; +use super::ApiPackage; use super::ApiScope; use super::ApiUser; -use super::ApiPackage; pub fn users_router() -> Router { Router::builder() @@ -71,5 +71,10 @@ pub async fn get_packages_handler( let packages = db.get_recent_packages_by_user(&id).await?; - Ok(packages.into_iter().map(ApiPackage::from).collect()) + Ok( + packages + .into_iter() + .map(|package| ApiPackage::from((package, None, Default::default()))) + .collect(), + ) } diff --git a/api/src/db/database.rs b/api/src/db/database.rs index f4f585de7..3a7da5b8a 100644 --- a/api/src/db/database.rs +++ b/api/src/db/database.rs @@ -1145,7 +1145,7 @@ impl Database { let newest = sqlx::query!( r#"SELECT packages.scope "package_scope: ScopeName", packages.name "package_name: PackageName", packages.description "package_description", packages.github_repository_id "package_github_repository_id", packages.runtime_compat as "package_runtime_compat: RuntimeCompat", packages.when_featured "package_when_featured", packages.is_archived "package_is_archived", packages.updated_at "package_updated_at", packages.created_at "package_created_at", (SELECT COUNT(created_at) FROM package_versions WHERE scope = packages.scope AND name = packages.name) as "package_version_count!", - (SELECT version FROM package_versions WHERE scope = packages.scope AND name = packages.name AND version NOT LIKE '%-%' AND is_yanked = false ORDER BY version DESC LIMIT 1) as "package_latest_version", + (SELECT version FROM package_versions WHERE scope = packages.scope AND name = packages.name AND is_yanked = false AND version IS NOT NULL ORDER BY version DESC LIMIT 1) as "package_latest_version", (SELECT meta FROM package_versions WHERE scope = packages.scope AND name = packages.name AND version NOT LIKE '%-%' AND is_yanked = false ORDER BY version DESC LIMIT 1) as "package_version_meta: PackageVersionMeta", github_repositories.id "github_repository_id?", github_repositories.owner "github_repository_owner?", github_repositories.name "github_repository_name?", github_repositories.updated_at "github_repository_updated_at?", github_repositories.created_at "github_repository_created_at?" FROM packages @@ -3174,43 +3174,29 @@ impl Database { .await } - pub async fn get_recent_packages_by_user(&self, user_id: &uuid::Uuid) -> Result, PackageVersionMeta)>> { - let packages = sqlx::query_as!( - Package, - r#" - SELECT * FROM packages - WHERE owner_id = $1 - ORDER BY published_at DESC - LIMIT 10 - "#, - user_id - ) - .fetch_all(&self.pool) - .await?; - - let mut result = Vec::new(); - for package in packages { - let repo = sqlx::query_as!( - GithubRepository, - "SELECT * FROM github_repositories WHERE package_id = $1", - package.id - ) - .fetch_optional(&self.pool) - .await?; + pub async fn get_recent_packages_by_user( + &self, + user_id: &uuid::Uuid, + ) -> Result> { + // need to fetch all scopes where user is in + // then fetch all packages in those scopes + // then sort by created_at + // then limit 10 + let scopes = self.get_member_scopes_by_user(user_id).await?; - let meta = sqlx::query_as!( - PackageVersionMeta, - "SELECT * FROM package_version_meta WHERE package_id = $1", - package.id - ) - .fetch_one(&self.pool) + let mut packages = Vec::new(); + for scope in scopes { + let (_, scope_packages) = self + .list_packages_by_scope(&scope.scope, true, 0, 100) .await?; - - result.push((package, repo, meta)); + packages.extend(scope_packages.into_iter().map(|(p, _, _)| p)); } - Ok(result) -} + packages.sort_by(|a, b| b.created_at.cmp(&a.created_at)); + packages.truncate(10); + + Ok(packages) + } } async fn finalize_package_creation( From e5b29428e4a28282f9350fa1ca0cf4cad43ce341 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Tue, 11 Feb 2025 11:15:28 +0100 Subject: [PATCH 5/7] revert useless changes --- api/src/db/database.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/db/database.rs b/api/src/db/database.rs index 3a7da5b8a..aa0f6799e 100644 --- a/api/src/db/database.rs +++ b/api/src/db/database.rs @@ -1145,7 +1145,7 @@ impl Database { let newest = sqlx::query!( r#"SELECT packages.scope "package_scope: ScopeName", packages.name "package_name: PackageName", packages.description "package_description", packages.github_repository_id "package_github_repository_id", packages.runtime_compat as "package_runtime_compat: RuntimeCompat", packages.when_featured "package_when_featured", packages.is_archived "package_is_archived", packages.updated_at "package_updated_at", packages.created_at "package_created_at", (SELECT COUNT(created_at) FROM package_versions WHERE scope = packages.scope AND name = packages.name) as "package_version_count!", - (SELECT version FROM package_versions WHERE scope = packages.scope AND name = packages.name AND is_yanked = false AND version IS NOT NULL ORDER BY version DESC LIMIT 1) as "package_latest_version", + (SELECT version FROM package_versions WHERE scope = packages.scope AND name = packages.name AND version NOT LIKE '%-%' AND is_yanked = false ORDER BY version DESC LIMIT 1) as "package_latest_version", (SELECT meta FROM package_versions WHERE scope = packages.scope AND name = packages.name AND version NOT LIKE '%-%' AND is_yanked = false ORDER BY version DESC LIMIT 1) as "package_version_meta: PackageVersionMeta", github_repositories.id "github_repository_id?", github_repositories.owner "github_repository_owner?", github_repositories.name "github_repository_name?", github_repositories.updated_at "github_repository_updated_at?", github_repositories.created_at "github_repository_created_at?" FROM packages From 4f011c1bab63826228545771a09eb3e8ed19aef7 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Tue, 11 Feb 2025 20:40:35 +0100 Subject: [PATCH 6/7] fix + clean --- api/src/db/database.rs | 41 +++++++++++++++++++++-------------- frontend/routes/user/[id].tsx | 2 +- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/api/src/db/database.rs b/api/src/db/database.rs index aa0f6799e..0f29c4a94 100644 --- a/api/src/db/database.rs +++ b/api/src/db/database.rs @@ -3178,22 +3178,31 @@ impl Database { &self, user_id: &uuid::Uuid, ) -> Result> { - // need to fetch all scopes where user is in - // then fetch all packages in those scopes - // then sort by created_at - // then limit 10 - let scopes = self.get_member_scopes_by_user(user_id).await?; - - let mut packages = Vec::new(); - for scope in scopes { - let (_, scope_packages) = self - .list_packages_by_scope(&scope.scope, true, 0, 100) - .await?; - packages.extend(scope_packages.into_iter().map(|(p, _, _)| p)); - } - - packages.sort_by(|a, b| b.created_at.cmp(&a.created_at)); - packages.truncate(10); + let packages = sqlx::query_as!( + Package, + r#" + SELECT DISTINCT ON (packages.scope, packages.name) + packages.scope as "scope: ScopeName", + packages.name as "name: PackageName", + packages.description, + packages.github_repository_id, + packages.runtime_compat as "runtime_compat: RuntimeCompat", + packages.when_featured, + packages.is_archived, + packages.updated_at, + packages.created_at, + (SELECT COUNT(created_at) FROM package_versions WHERE scope = packages.scope AND name = packages.name) as "version_count!", + (SELECT version FROM package_versions WHERE scope = packages.scope AND name = packages.name AND version NOT LIKE '%-%' AND is_yanked = false ORDER BY version DESC LIMIT 1) as "latest_version" + FROM packages + JOIN scope_members ON packages.scope = scope_members.scope + WHERE scope_members.user_id = $1 + ORDER BY packages.scope, packages.name, packages.created_at DESC + LIMIT 10; + "#, + user_id + ) + .fetch_all(&self.pool) + .await?; Ok(packages) } diff --git a/frontend/routes/user/[id].tsx b/frontend/routes/user/[id].tsx index 90c4b417d..df8d4bf30 100644 --- a/frontend/routes/user/[id].tsx +++ b/frontend/routes/user/[id].tsx @@ -37,7 +37,7 @@ export default define.page(function UserPage({ data, state }) { title="Recently published" subtitle="Packages recently published by this user" children={data.packages.map((pkg) => ({ - value: pkg.name, + value: `@${pkg.scope}/${pkg.name}`, //@am/neuralnetwork href: `/${pkg.scope}/${pkg.name}`, }))} From 23071eb6269599e5df752882f16769bbd797c488 Mon Sep 17 00:00:00 2001 From: Augustin Mauroy <97875033+AugustinMauroy@users.noreply.github.com> Date: Tue, 11 Mar 2025 21:37:10 +0100 Subject: [PATCH 7/7] fix: lint --- frontend/routes/user/[id].tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/routes/user/[id].tsx b/frontend/routes/user/[id].tsx index 669fa0325..45cc840fb 100644 --- a/frontend/routes/user/[id].tsx +++ b/frontend/routes/user/[id].tsx @@ -37,6 +37,7 @@ export default define.page(function UserPage({ data, state }) { ({ value: `@${pkg.scope}/${pkg.name}`, //@am/neuralnetwork