fix(projects): include project_members when listing user projects
Users who accepted a project invitation could not see that project
on their /user/{username} page because get_user_projects only queried
projects where created_by == user_uid, ignoring project_members entries.
Now unions created_projects and member_projects with privacy filtering.
This commit is contained in:
parent
16b681c55b
commit
aef5280ae8
@ -60,25 +60,55 @@ impl AppService {
|
|||||||
let per_page = std::cmp::Ord::min(std::cmp::Ord::max(query.per_page.unwrap_or(20), 1), 100);
|
let per_page = std::cmp::Ord::min(std::cmp::Ord::max(query.per_page.unwrap_or(20), 1), 100);
|
||||||
let offset = (page - 1) * per_page;
|
let offset = (page - 1) * per_page;
|
||||||
|
|
||||||
let mut condition = Condition::all().add(project::Column::CreatedBy.eq(target_user.uid));
|
// Projects where user is the creator
|
||||||
|
let created_projects: Vec<Uuid> = project::Entity::find()
|
||||||
if !is_owner && !has_admin_privilege {
|
.filter(project::Column::CreatedBy.eq(target_user.uid))
|
||||||
condition = condition.add(project::Column::IsPublic.eq(true));
|
.select_only()
|
||||||
}
|
.column(project::Column::Id)
|
||||||
|
.into_tuple::<Uuid>()
|
||||||
let total_count = project::Entity::find()
|
|
||||||
.filter(condition.clone())
|
|
||||||
.count(&self.db)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let project_list = project::Entity::find()
|
|
||||||
.filter(condition)
|
|
||||||
.order_by_desc(project::Column::CreatedAt)
|
|
||||||
.limit(per_page)
|
|
||||||
.offset(offset)
|
|
||||||
.all(&self.db)
|
.all(&self.db)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
// Projects where user is a member (via invitation)
|
||||||
|
let member_projects: Vec<Uuid> = project_members::Entity::find()
|
||||||
|
.filter(project_members::Column::User.eq(target_user.uid))
|
||||||
|
.select_only()
|
||||||
|
.column(project_members::Column::Project)
|
||||||
|
.into_tuple::<Uuid>()
|
||||||
|
.all(&self.db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Union + dedup (preserving first occurrence order)
|
||||||
|
let mut project_ids: Vec<Uuid> = created_projects;
|
||||||
|
let new_ids: Vec<Uuid> = member_projects.into_iter().filter(|id| !project_ids.contains(id)).collect();
|
||||||
|
project_ids.extend(new_ids);
|
||||||
|
|
||||||
|
let total_count = project_ids.len() as u64;
|
||||||
|
|
||||||
|
// Paginate
|
||||||
|
let page_ids: Vec<Uuid> = project_ids.into_iter().skip(offset as usize).take(per_page as usize).collect();
|
||||||
|
|
||||||
|
if page_ids.is_empty() {
|
||||||
|
return Ok(UserProjectsResponse {
|
||||||
|
username: target_user.username,
|
||||||
|
projects: vec![],
|
||||||
|
total_count,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let project_list: Vec<project::Model> = project::Entity::find()
|
||||||
|
.filter(project::Column::Id.is_in(page_ids.clone()))
|
||||||
|
.all(&self.db)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Preserve the order from project_ids (created projects first, then member projects)
|
||||||
|
let mut sorted_projects = project_list;
|
||||||
|
sorted_projects.sort_by(|a, b| {
|
||||||
|
let a_idx = page_ids.iter().position(|&x| x == a.id).unwrap_or(usize::MAX);
|
||||||
|
let b_idx = page_ids.iter().position(|&x| x == b.id).unwrap_or(usize::MAX);
|
||||||
|
a_idx.cmp(&b_idx)
|
||||||
|
});
|
||||||
|
|
||||||
let user_project_memberships: std::collections::HashSet<Uuid> =
|
let user_project_memberships: std::collections::HashSet<Uuid> =
|
||||||
if let Some(uid) = current_user_uid {
|
if let Some(uid) = current_user_uid {
|
||||||
project_members::Entity::find()
|
project_members::Entity::find()
|
||||||
@ -95,7 +125,11 @@ impl AppService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut project_infos: Vec<UserProjectInfo> = Vec::new();
|
let mut project_infos: Vec<UserProjectInfo> = Vec::new();
|
||||||
for project in project_list {
|
for project in sorted_projects {
|
||||||
|
// Privacy: non-owners/non-admins only see public projects (member or created)
|
||||||
|
if !is_owner && !has_admin_privilege && !project.is_public {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let member_count = project_members::Entity::find()
|
let member_count = project_members::Entity::find()
|
||||||
.filter(project_members::Column::Project.eq(project.id))
|
.filter(project_members::Column::Project.eq(project.id))
|
||||||
.count(&self.db)
|
.count(&self.db)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user