From c27cd945a717fba3c3e389c7658f6f5b64cddb8e Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sun, 31 Mar 2024 18:28:35 -0600 Subject: [PATCH] Policies refactor, guest roles (#6732) --- app/actions/definitions/documents.tsx | 7 +- app/components/AuthenticatedLayout.tsx | 20 +- app/hooks/useSettingsConfig.ts | 12 +- app/menus/DocumentMenu.tsx | 4 +- app/models/User.ts | 14 + app/models/base/Model.ts | 1 - .../Document/components/DocumentMeta.tsx | 5 +- app/scenes/Document/components/Header.tsx | 4 +- .../Settings/components/PeopleTable.tsx | 2 + app/utils/PluginLoader.ts | 3 +- plugins/slack/plugin.json | 2 +- server/models/Share.ts | 7 + server/models/User.ts | 28 +- server/models/base/ParanoidModel.ts | 9 + server/policies/apiKey.ts | 26 +- server/policies/attachment.ts | 42 +- server/policies/authenticationProvider.ts | 39 +- server/policies/collection.test.ts | 56 +- server/policies/collection.ts | 149 ++-- server/policies/comment.ts | 33 +- server/policies/document.test.ts | 115 +++- server/policies/document.ts | 649 ++++++------------ server/policies/fileOperation.ts | 38 +- server/policies/group.ts | 57 +- server/policies/integration.ts | 59 +- server/policies/notification.ts | 8 +- server/policies/pins.ts | 8 +- server/policies/searchQuery.ts | 8 +- server/policies/share.ts | 77 ++- server/policies/star.ts | 8 +- server/policies/subscription.ts | 20 +- server/policies/team.ts | 60 +- server/policies/user.ts | 151 ++-- server/policies/userMembership.ts | 12 +- server/policies/utils.ts | 91 +++ server/policies/webhookSubscription.ts | 42 +- server/routes/api/documents/documents.test.ts | 24 - .../groups/__snapshots__/groups.test.ts.snap | 8 +- server/routes/api/groups/groups.ts | 1 + server/routes/api/revisions/revisions.ts | 8 +- server/routes/api/shares/shares.ts | 4 + .../users/__snapshots__/users.test.ts.snap | 16 +- server/routes/api/users/users.test.ts | 2 +- server/routes/api/views/views.ts | 2 +- shared/i18n/locales/en_US/translation.json | 1 + shared/types.ts | 1 + 46 files changed, 901 insertions(+), 1032 deletions(-) create mode 100644 server/policies/utils.ts diff --git a/app/actions/definitions/documents.tsx b/app/actions/definitions/documents.tsx index b045b57c5..72f592be0 100644 --- a/app/actions/definitions/documents.tsx +++ b/app/actions/definitions/documents.tsx @@ -432,7 +432,8 @@ export const copyDocumentAsMarkdown = createAction({ name: ({ t }) => t("Copy as Markdown"), section: DocumentSection, keywords: "clipboard", - visible: ({ activeDocumentId }) => !!activeDocumentId, + visible: ({ activeDocumentId, stores }) => + !!activeDocumentId && stores.policies.abilities(activeDocumentId).download, perform: ({ stores, activeDocumentId, t }) => { const document = activeDocumentId ? stores.documents.get(activeDocumentId) @@ -856,7 +857,7 @@ export const openDocumentHistory = createAction({ icon: , visible: ({ activeDocumentId, stores }) => { const can = stores.policies.abilities(activeDocumentId ?? ""); - return !!activeDocumentId && can.read && !can.restore; + return !!activeDocumentId && can.listRevisions; }, perform: ({ activeDocumentId, stores }) => { if (!activeDocumentId) { @@ -883,7 +884,7 @@ export const openDocumentInsights = createAction({ return ( !!activeDocumentId && - can.read && + can.listViews && !document?.isTemplate && !document?.isDeleted ); diff --git a/app/components/AuthenticatedLayout.tsx b/app/components/AuthenticatedLayout.tsx index 94567c9da..c0202a8f4 100644 --- a/app/components/AuthenticatedLayout.tsx +++ b/app/components/AuthenticatedLayout.tsx @@ -47,7 +47,8 @@ const AuthenticatedLayout: React.FC = ({ children }: Props) => { const { ui, auth } = useStores(); const location = useLocation(); const layoutRef = React.useRef(null); - const can = usePolicy(ui.activeCollectionId); + const can = usePolicy(ui.activeDocumentId); + const canCollection = usePolicy(ui.activeCollectionId); const team = useCurrentTeam(); const documentContext = useLocalStore(() => ({ editor: null, @@ -69,7 +70,7 @@ const AuthenticatedLayout: React.FC = ({ children }: Props) => { return; } const { activeCollectionId } = ui; - if (!activeCollectionId || !can.createDocument) { + if (!activeCollectionId || !canCollection.createDocument) { return; } history.push(newDocumentPath(activeCollectionId)); @@ -88,15 +89,18 @@ const AuthenticatedLayout: React.FC = ({ children }: Props) => { ); - const showHistory = !!matchPath(location.pathname, { - path: matchDocumentHistory, - }); - const showInsights = !!matchPath(location.pathname, { - path: matchDocumentInsights, - }); + const showHistory = + !!matchPath(location.pathname, { + path: matchDocumentHistory, + }) && can.listRevisions; + const showInsights = + !!matchPath(location.pathname, { + path: matchDocumentInsights, + }) && can.listViews; const showComments = !showInsights && !showHistory && + can.comment && ui.activeDocumentId && ui.commentsExpanded.includes(ui.activeDocumentId) && team.getPreference(TeamPreference.Commenting); diff --git a/app/hooks/useSettingsConfig.ts b/app/hooks/useSettingsConfig.ts index b228bbffb..1183acd95 100644 --- a/app/hooks/useSettingsConfig.ts +++ b/app/hooks/useSettingsConfig.ts @@ -25,6 +25,7 @@ import isCloudHosted from "~/utils/isCloudHosted"; import lazy from "~/utils/lazyWithRetry"; import { settingsPath } from "~/utils/routeHelpers"; import useCurrentTeam from "./useCurrentTeam"; +import useCurrentUser from "./useCurrentUser"; import usePolicy from "./usePolicy"; const ApiKeys = lazy(() => import("~/scenes/Settings/ApiKeys")); @@ -54,6 +55,7 @@ export type ConfigItem = { }; const useSettingsConfig = () => { + const user = useCurrentUser(); const team = useCurrentTeam(); const can = usePolicy(team); const { t } = useTranslation(); @@ -122,7 +124,7 @@ const useSettingsConfig = () => { name: t("Members"), path: settingsPath("members"), component: Members, - enabled: true, + enabled: can.listUsers, group: t("Workspace"), icon: UserIcon, }, @@ -130,7 +132,7 @@ const useSettingsConfig = () => { name: t("Groups"), path: settingsPath("groups"), component: Groups, - enabled: true, + enabled: can.listGroups, group: t("Workspace"), icon: GroupIcon, }, @@ -138,7 +140,7 @@ const useSettingsConfig = () => { name: t("Templates"), path: settingsPath("templates"), component: Templates, - enabled: true, + enabled: can.update, group: t("Workspace"), icon: ShapesIcon, }, @@ -146,7 +148,7 @@ const useSettingsConfig = () => { name: t("Shared Links"), path: settingsPath("shares"), component: Shares, - enabled: true, + enabled: can.listShares, group: t("Workspace"), icon: GlobeIcon, }, @@ -211,7 +213,7 @@ const useSettingsConfig = () => { enabled: enabledInDeployment && hasSettings && - (plugin.config.adminOnly === false || can.update), + (plugin.config.roles?.includes(user.role) || can.update), icon: plugin.icon, } as ConfigItem; diff --git a/app/menus/DocumentMenu.tsx b/app/menus/DocumentMenu.tsx index d0cb614dd..df9b0e7b3 100644 --- a/app/menus/DocumentMenu.tsx +++ b/app/menus/DocumentMenu.tsx @@ -312,7 +312,7 @@ function DocumentMenu({ actionToMenuItem(permanentlyDeleteDocument, context), ]} /> - {(showDisplayOptions || showToggleEmbeds) && ( + {(showDisplayOptions || showToggleEmbeds) && can.update && ( <> @@ -332,7 +332,7 @@ function DocumentMenu({ /> )} - {showDisplayOptions && !isMobile && can.update && ( + {showDisplayOptions && !isMobile && (