🏡 index : ~doyle/chartered.git

author Jordan Doyle <jordan@doyle.la> 2022-09-10 12:21:05.0 +01:00:00
committer Jordan Doyle <jordan@doyle.la> 2022-09-10 12:21:05.0 +01:00:00
commit
cdcf6781095158278ddf4c6e3e67657f36b6c90d [patch]
tree
1d169ca361c0a37f7c8ac479ef9d64593d289111
parent
efc6ce2225a5d6ba530be037eae365181efeedf8
download
cdcf6781095158278ddf4c6e3e67657f36b6c90d.tar.gz

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(-)

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<ResponseVersion<'a>>,
    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<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>