Hide 'Members' pages if the user doesn't have the MANAGE_USERS permission for the org/crate
Diff
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(-)
@@ -6,6 +6,8 @@
homepage?: string;
documentation?: string;
versions: Version[];
permissions: string;
}
export interface Version {
@@ -6,7 +6,7 @@
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,
})
@@ -56,6 +57,7 @@
#[serde(flatten)]
info: ResponseInfo<'a>,
versions: Vec<ResponseVersion<'a>>,
permissions: UserPermission,
}
#[derive(Serialize)]
@@ -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.
@@ -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<Crate>;
$: 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<Crate>;
$: 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;
}
}
});
</script>
<header>