From cdcf6781095158278ddf4c6e3e67657f36b6c90d Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sat, 10 Sep 2022 12:21:05 +0100 Subject: [PATCH] Hide 'Members' pages if the user doesn't have the MANAGE_USERS permission for the org/crate --- chartered-frontend/src/types/crate.ts | 2 ++ chartered-web/src/endpoints/web_api/crates/info.rs | 4 +++- chartered-frontend/src/routes/(authed)/crates/[organisation]/+page.svelte | 34 ++++++++++++++++++++++++++++++++-- chartered-frontend/src/routes/(authed)/crates/[organisation]/[crate]/+page.svelte | 42 +++++++++++++++++++++++++++++++++++++----- 4 files changed, 65 insertions(+), 17 deletions(-) diff --git a/chartered-frontend/src/types/crate.ts b/chartered-frontend/src/types/crate.ts index a44a7fc..b338e02 100644 --- a/chartered-frontend/src/types/crate.ts +++ a/chartered-frontend/src/types/crate.ts @@ -6,6 +6,8 @@ homepage?: string; documentation?: string; versions: Version[]; + /// The current user's permissions for this crate, taking org permissions into account + permissions: string; } export interface Version { diff --git a/chartered-web/src/endpoints/web_api/crates/info.rs b/chartered-web/src/endpoints/web_api/crates/info.rs index db9d15a..59ed0e2 100644 --- a/chartered-web/src/endpoints/web_api/crates/info.rs +++ a/chartered-web/src/endpoints/web_api/crates/info.rs @@ -6,7 +6,7 @@ //! need to have version-specific info responses - we'll just send an overview of each one. use axum::{extract, response::IntoResponse, Json}; -use chartered_db::{crates::Crate, users::User, ConnectionPool}; +use chartered_db::{crates::Crate, permissions::UserPermission, users::User, ConnectionPool}; use chartered_types::cargo::CrateVersion; use chrono::TimeZone; use serde::Serialize; @@ -42,6 +42,7 @@ }, }) .collect(), + permissions: crate_with_permissions.permissions, }) // returning a Response instead of Json here so we don't have to clone // every Crate/CrateVersion etc, would be easier if we just had an owned @@ -56,6 +57,7 @@ #[serde(flatten)] info: ResponseInfo<'a>, versions: Vec>, + permissions: UserPermission, } #[derive(Serialize)] diff --git a/chartered-frontend/src/routes/(authed)/crates/[organisation]/+page.svelte b/chartered-frontend/src/routes/(authed)/crates/[organisation]/+page.svelte index 49a1bc6..408c393 100644 --- a/chartered-frontend/src/routes/(authed)/crates/[organisation]/+page.svelte +++ a/chartered-frontend/src/routes/(authed)/crates/[organisation]/+page.svelte @@ -39,21 +39,43 @@ * Mapping of `Tab`s to their human-readable form alongside a friendly icon to show to the * user. */ - const allTabs = [ + let allTabs: { id: Tab; name: string; icon: string }[] = [ { id: Tab.CRATES, name: 'Crates', icon: 'package', }, - { - id: Tab.MEMBERS, - name: 'Members', - icon: 'user', - }, ]; // binding to the current tab the user has selected let currentTab = Tab.CRATES; + + $: organisationPromise.then((org) => { + if (org.members) { + // user has access to the member page but the tab isn't currently being shown, so we should + // add it + if (!allTabs.some((tab) => tab.id === Tab.MEMBERS)) { + allTabs = [ + ...allTabs, + { + id: Tab.MEMBERS, + name: 'Members', + icon: 'user', + }, + ]; + } + } else { + // user doesn't have access to the members page for this org, so remove it from the tab + // list, if it exists + allTabs = allTabs.filter((tab) => tab.id !== Tab.CRATES); + + // make sure the current tab is MEMBERS switch them off it, so we don't leave them with + // an empty page + if (currentTab === Tab.MEMBERS) { + currentTab = Tab.CRATES; + } + } + }); // contains the member the user is currently considering adding to the org & has not yet persisted to // the server. diff --git a/chartered-frontend/src/routes/(authed)/crates/[organisation]/[crate]/+page.svelte b/chartered-frontend/src/routes/(authed)/crates/[organisation]/[crate]/+page.svelte index 216be13..d3a22c4 100644 --- a/chartered-frontend/src/routes/(authed)/crates/[organisation]/[crate]/+page.svelte +++ a/chartered-frontend/src/routes/(authed)/crates/[organisation]/[crate]/+page.svelte @@ -9,6 +9,10 @@ import VersionTab from './VersionTab.svelte'; import MemberTab from './MemberTab.svelte'; + // lookup the crate currently requested by the user based on the URL + let cratePromise: Promise; + $: cratePromise = request(`/web/v1/crates/${$page.params.organisation}/${$page.params.crate}`); + /** * Contains all the possible tabs, used for maintaining state on the current tab. */ @@ -22,7 +26,7 @@ * Mapping of `Tab`s to their human-readable form alongside a friendly icon to show to the * user. */ - const allTabs = [ + let allTabs = [ { id: Tab.README, name: 'Readme', @@ -32,20 +36,38 @@ id: Tab.VERSIONS, name: 'Versions', icon: 'archive', - }, - { - id: Tab.MEMBERS, - name: 'Members', - icon: 'user', }, ]; - // lookup the crate currently requested by the user based on the URL - let cratePromise: Promise; - $: cratePromise = request(`/web/v1/crates/${$page.params.organisation}/${$page.params.crate}`); - // binding to the current tab the user has selected let currentTab = Tab.README; + + $: cratePromise.then((crate) => { + if (crate.permissions.includes('MANAGE_USERS')) { + // user has access to the member page but the tab isn't currently being shown, so we should + // add it + if (!allTabs.some((tab) => tab.id === Tab.MEMBERS)) { + allTabs = [ + ...allTabs, + { + id: Tab.MEMBERS, + name: 'Members', + icon: 'user', + }, + ]; + } + } else { + // user doesn't have access to the members page for this crate, so remove it from the tab + // list, if it exists + allTabs = allTabs.filter((tab) => tab.id !== Tab.MEMBERS); + + // if the user's currently on the MEMBERS page, move them off it so they don't end up with + // a blank page + if (currentTab === Tab.MEMBERS) { + currentTab = Tab.README; + } + } + });
-- rgit 0.1.3