From b597b525d1c11b576459cbf12c0c2306d102d52b Mon Sep 17 00:00:00 2001 From: Tim Haasdyk Date: Thu, 7 Nov 2024 13:18:49 +0100 Subject: [PATCH] Always query and show projects members This ensures our "middleware" can detect when the user was added to the project and stops hiding members on non-confidential projects --- .../project/[project_code]/+page.svelte | 68 +++++++++---------- .../project/[project_code]/+page.ts | 57 +++++++--------- .../project/[project_code]/MembersList.svelte | 4 +- 3 files changed, 61 insertions(+), 68 deletions(-) diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/+page.svelte b/frontend/src/routes/(authenticated)/project/[project_code]/+page.svelte index b10792ae9..7d8660a65 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/+page.svelte +++ b/frontend/src/routes/(authenticated)/project/[project_code]/+page.svelte @@ -64,7 +64,7 @@ $: isEmpty = project?.lastCommit == null; // TODO: Once we've stabilized the lastCommit issue with project reset, get rid of the next line $: if (! $changesetStore.fetching) isEmpty = $changesetStore.changesets.length === 0; - $: members = project.users?.sort((a, b) => { + $: members = project.users.sort((a, b) => { if (a.role !== b.role) { return a.role === ProjectRole.Manager ? -1 : 1; } @@ -118,12 +118,12 @@ $: orgRoles = project.organizations ?.map((o) => user.orgs?.find((org) => org.orgId === o.id)?.role) .filter(r => !!r) ?? []; - $: projectRole = project?.users?.find((u) => u.user.id == user.id)?.role; + $: projectRole = project?.users.find((u) => u.user.id == user.id)?.role; // Mirrors PermissionService.CanViewProjectMembers() in C# - $: canViewProjectMembers = user.isAdmin + $: canViewOtherMembers = user.isAdmin || projectRole == ProjectRole.Manager - || projectRole == ProjectRole.Editor && !project.isConfidential + || projectRole && !project.isConfidential // public by default for members (non-members shouldn't even be here) || orgRoles.some(role => role === OrgRole.Admin); let resetProjectModal: ResetProjectModal; @@ -178,7 +178,7 @@ $: userId = user.id; $: orgsManagedByUser = user.orgs.filter(o => o.role === OrgRole.Admin).map(o => o.orgId); - $: canManage = user.isAdmin || project?.users?.find((u) => u.user.id == userId)?.role == ProjectRole.Manager || !!project?.organizations?.find((o) => orgsManagedByUser.includes(o.id)); + $: canManage = user.isAdmin || project?.users.find((u) => u.user.id == userId)?.role == ProjectRole.Manager || !!project?.organizations?.find((o) => orgsManagedByUser.includes(o.id)); const projectNameValidation = z.string().trim().min(1, $t('project_page.project_name_empty_error')); @@ -486,37 +486,35 @@ {$t('project_page.confirm_remove_org', {orgName: orgToRemove})} - {#if members} - canManage && (member.user?.id !== userId || user.isAdmin)} - canManageList={canManage} - canViewMembers={canViewProjectMembers} - on:openUserModal={(event) => userModal.open(event.detail.user)} - on:deleteProjectUser={(event) => deleteProjectUser(event.detail)} + canManage && (member.user?.id !== userId || user.isAdmin)} + canManageList={canManage} + {canViewOtherMembers} + on:openUserModal={(event) => userModal.open(event.detail.user)} + on:deleteProjectUser={(event) => deleteProjectUser(event.detail)} + > + + addProjectMember.openModal(undefined, undefined)}> + {$t('project_page.add_user.add_button')} + + + + + + + + - - addProjectMember.openModal(undefined, undefined)}> - {$t('project_page.add_user.add_button')} - - - - - - - - - {$t('project_page.confirm_remove', { - userName: userToDelete?.user.name ?? '', - })} - - - {/if} + {$t('project_page.confirm_remove', { + userName: userToDelete?.user.name ?? '', + })} + +

diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/+page.ts b/frontend/src/routes/(authenticated)/project/[project_code]/+page.ts index cde428c3c..e245a86f8 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/+page.ts +++ b/frontend/src/routes/(authenticated)/project/[project_code]/+page.ts @@ -25,12 +25,12 @@ import type { UpdateProjectLanguageListMutation, UpdateProjectLexEntryCountMutation, } from '$lib/gql/types'; -import { getClient, graphql } from '$lib/gql'; +import {getClient, graphql} from '$lib/gql'; -import type { PageLoadEvent } from './$types'; -import { derived } from 'svelte/store'; -import { error } from '@sveltejs/kit'; -import { tryMakeNonNullable } from '$lib/util/store'; +import type {PageLoadEvent} from './$types'; +import {derived} from 'svelte/store'; +import {error} from '@sveltejs/kit'; +import {tryMakeNonNullable} from '$lib/util/store'; export type Project = NonNullable; export type ProjectUser = NonNullable[number]; @@ -41,13 +41,10 @@ export async function load(event: PageLoadEvent) { const client = getClient(); const user = (await event.parent()).user; const projectCode = event.params.project_code; - const projectId = event.url.searchParams.get('id') ?? ''; - //projectId is not required, so if it's not there we assume the user is a member, if we're wrong there will be an error - const userIsMember = projectId === '' ? true : (user.isAdmin || user.projects.some(p => p.projectId === projectId)); const projectResult = await client .awaitedQueryStore(event.fetch, graphql(` - query projectPage($projectCode: String!, $userIsAdmin: Boolean!, $userIsMember: Boolean!) { + query projectPage($projectCode: String!, $userIsAdmin: Boolean!) { projectByCode(code: $projectCode) { id name @@ -63,28 +60,26 @@ export async function load(event: PageLoadEvent) { organizations { id } - ... on Project @include(if: $userIsMember) { - users { + users { + id + role + user { id - role - user { - id - name - ... on User @include(if: $userIsAdmin) { - locked - username - createdDate - updatedDate - email - localizationCode - lastActive - canCreateProjects - isAdmin - emailVerified - createdBy { - id - name - } + name + ... on User @include(if: $userIsAdmin) { + locked + username + createdDate + updatedDate + email + localizationCode + lastActive + canCreateProjects + isAdmin + emailVerified + createdBy { + id + name } } } @@ -112,7 +107,7 @@ export async function load(event: PageLoadEvent) { } } `), - { projectCode, userIsAdmin: user.isAdmin, userIsMember } + { projectCode, userIsAdmin: user.isAdmin } ); const changesetResultStore = client .queryStore(event.fetch, diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/MembersList.svelte b/frontend/src/routes/(authenticated)/project/[project_code]/MembersList.svelte index 40e6b3e57..3ff873bb1 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/MembersList.svelte +++ b/frontend/src/routes/(authenticated)/project/[project_code]/MembersList.svelte @@ -27,7 +27,7 @@ export let canManageMember: (member: Member) => boolean; export let canManageList: boolean; export let projectId: string; - export let canViewMembers: boolean; + export let canViewOtherMembers: boolean; const dispatch = createEventDispatcher<{ openUserModal: Member; @@ -81,7 +81,7 @@

{$t('project_page.members.title')} - {#if !canViewMembers} + {#if !canViewOtherMembers}