UNPKG

@speckle/shared

Version:

Shared code between various Speckle JS packages

193 lines 9.18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ensureModelCanBeCreatedFragment = exports.ensureWorkspaceProjectCanBeCreatedFragment = exports.ensureWorkspaceNotReadOnlyFragment = exports.ensureWorkspacesEnabledFragment = exports.ensureWorkspaceRoleAndSessionFragment = void 0; const result_1 = require("true-myth/result"); const workspaceRole_js_1 = require("../checks/workspaceRole.js"); const authErrors_js_1 = require("../domain/authErrors.js"); const constants_js_1 = require("../../core/constants.js"); const plans_js_1 = require("../../workspaces/helpers/plans.js"); const workspaceSeat_js_1 = require("../checks/workspaceSeat.js"); /** * Ensure user has a workspace role, and a valid SSO session (if SSO is configured) */ const ensureWorkspaceRoleAndSessionFragment = (loaders) => async ({ userId, workspaceId, role }) => { const testedRole = role ?? constants_js_1.Roles.Workspace.Guest; const testingForMinimumRole = testedRole === constants_js_1.Roles.Workspace.Guest; // Get workspace, so we can resolve its slug for error scenarios const workspace = await loaders.getWorkspace({ workspaceId }); // hides the fact, that the workspace does not exist if (!workspace) return (0, result_1.err)(new authErrors_js_1.WorkspaceNoAccessError()); const hasMinimumRole = await (0, workspaceRole_js_1.hasMinimumWorkspaceRole)(loaders)({ userId, workspaceId, role: testedRole }); if (!hasMinimumRole) return (0, result_1.err)(testingForMinimumRole ? new authErrors_js_1.WorkspaceNoAccessError() : new authErrors_js_1.WorkspaceNotEnoughPermissionsError()); const hasMinimumMemberRole = await (0, workspaceRole_js_1.hasMinimumWorkspaceRole)(loaders)({ userId, workspaceId, role: 'workspace:member' }); // only members and above need to use sso if (!hasMinimumMemberRole) return (0, result_1.ok)(); const workspaceSsoProvider = await loaders.getWorkspaceSsoProvider({ workspaceId }); if (!workspaceSsoProvider) return (0, result_1.ok)(); const workspaceSsoSession = await loaders.getWorkspaceSsoSession({ userId, workspaceId }); if (!workspaceSsoSession) return (0, result_1.err)(new authErrors_js_1.WorkspaceSsoSessionNoAccessError({ payload: { workspaceSlug: workspace.slug } })); const isExpiredSession = new Date().getTime() > workspaceSsoSession.validUntil.getTime(); if (isExpiredSession) return (0, result_1.err)(new authErrors_js_1.WorkspaceSsoSessionNoAccessError({ payload: { workspaceSlug: workspace.slug } })); return (0, result_1.ok)(); }; exports.ensureWorkspaceRoleAndSessionFragment = ensureWorkspaceRoleAndSessionFragment; /** * Ensure the workspaces module is enabled */ const ensureWorkspacesEnabledFragment = (loaders) => async () => { const env = await loaders.getEnv(); if (!env.FF_WORKSPACES_MODULE_ENABLED) return (0, result_1.err)(new authErrors_js_1.WorkspacesNotEnabledError()); return (0, result_1.ok)(); }; exports.ensureWorkspacesEnabledFragment = ensureWorkspacesEnabledFragment; /** * Ensure workspace is not read-only */ const ensureWorkspaceNotReadOnlyFragment = (loaders) => async ({ workspaceId }) => { const workspacePlan = await loaders.getWorkspacePlan({ workspaceId }); if (!workspacePlan) return (0, result_1.err)(new authErrors_js_1.WorkspaceNoAccessError()); if ((0, plans_js_1.isWorkspacePlanStatusReadOnly)(workspacePlan.status)) return (0, result_1.err)(new authErrors_js_1.WorkspaceReadOnlyError()); return (0, result_1.ok)(); }; exports.ensureWorkspaceNotReadOnlyFragment = ensureWorkspaceNotReadOnlyFragment; /** * Ensure workspace can accept new project (not read-only, limits not reached). * If userId is specified, will also check for user role & seat */ const ensureWorkspaceProjectCanBeCreatedFragment = (loaders) => async ({ workspaceId, userId }) => { // First check user even has access if (userId) { // Is Member+ const isNotGuest = await (0, workspaceRole_js_1.hasMinimumWorkspaceRole)(loaders)({ userId, workspaceId, role: constants_js_1.Roles.Workspace.Member }); if (!isNotGuest) { return (0, result_1.err)(new authErrors_js_1.WorkspaceNotEnoughPermissionsError('Guests cannot create projects in the workspace')); } } const ensuredNotReadOnly = await (0, exports.ensureWorkspaceNotReadOnlyFragment)(loaders)({ workspaceId }); if (ensuredNotReadOnly.isErr) return (0, result_1.err)(ensuredNotReadOnly.error); const workspacePlan = await loaders.getWorkspacePlan({ workspaceId }); if (!workspacePlan) return (0, result_1.err)(new authErrors_js_1.WorkspaceNoAccessError()); // Now check editor seat if (userId) { const isEditor = await (0, workspaceSeat_js_1.hasEditorSeat)(loaders)({ userId, workspaceId }); if (!isEditor) return (0, result_1.err)(new authErrors_js_1.WorkspaceNoEditorSeatError()); } const workspaceLimits = await loaders.getWorkspaceLimits({ workspaceId }); if (!workspaceLimits) return (0, result_1.err)(new authErrors_js_1.WorkspaceNoAccessError()); // no limits imposed if (workspaceLimits.projectCount === null) return (0, result_1.ok)(); const currentProjectCount = await loaders.getWorkspaceProjectCount({ workspaceId }); // this will not happen in practice if (currentProjectCount === null) return (0, result_1.err)(new authErrors_js_1.WorkspaceNoAccessError()); return currentProjectCount < workspaceLimits.projectCount ? (0, result_1.ok)() : (0, result_1.err)(new authErrors_js_1.WorkspaceLimitsReachedError({ message: 'You have reached the maximum number of projects for your plan. Upgrade to increase it.', payload: { limit: 'projectCount' } })); }; exports.ensureWorkspaceProjectCanBeCreatedFragment = ensureWorkspaceProjectCanBeCreatedFragment; /** * Ensure model can be created (workspace not read-only, limits not reached). * If userId is specified, will also check for appropriate user role & seat */ const ensureModelCanBeCreatedFragment = (loaders) => async ({ projectId, userId, addedModelCount, workspaceId }) => { addedModelCount = addedModelCount ?? 1; const { FF_WORKSPACES_MODULE_ENABLED, FF_PERSONAL_PROJECTS_LIMITS_ENABLED } = await loaders.getEnv(); const project = await loaders.getProject({ projectId }); if (!project) return (0, result_1.err)(new authErrors_js_1.ProjectNotFoundError()); // Project may not be attached to a workspace yet, then we use the specified workspaceId workspaceId = workspaceId || project.workspaceId || undefined; // If workspace if (workspaceId && FF_WORKSPACES_MODULE_ENABLED) { if (userId) { // Has workspace role const isInWorkspace = await (0, workspaceRole_js_1.hasAnyWorkspaceRole)(loaders)({ userId, workspaceId }); if (!isInWorkspace) { return (0, result_1.err)(new authErrors_js_1.WorkspaceNoAccessError()); } } const ensuredNotReadOnly = await (0, exports.ensureWorkspaceNotReadOnlyFragment)(loaders)({ workspaceId }); if (ensuredNotReadOnly.isErr) return (0, result_1.err)(ensuredNotReadOnly.error); const workspacePlan = await loaders.getWorkspacePlan({ workspaceId }); if (!workspacePlan) return (0, result_1.err)(new authErrors_js_1.WorkspaceNoAccessError()); const workspaceLimits = await loaders.getWorkspaceLimits({ workspaceId }); if (!workspaceLimits) return (0, result_1.err)(new authErrors_js_1.WorkspaceNoAccessError()); if (workspaceLimits.modelCount === null) return (0, result_1.ok)(); const currentModelCount = await loaders.getWorkspaceModelCount({ workspaceId }); if (currentModelCount === null) return (0, result_1.err)(new authErrors_js_1.WorkspaceNoAccessError()); return currentModelCount + addedModelCount <= workspaceLimits.modelCount ? (0, result_1.ok)() : (0, result_1.err)(new authErrors_js_1.WorkspaceLimitsReachedError({ message: 'You have reached the maximum number of models for your plan. Upgrade to increase it.', payload: { limit: 'modelCount' } })); } else { // If not - check personal project limits if (FF_PERSONAL_PROJECTS_LIMITS_ENABLED) { return (0, result_1.err)(new authErrors_js_1.PersonalProjectsLimitedError('No new models can be added to personal projects')); } return (0, result_1.ok)(); } }; exports.ensureModelCanBeCreatedFragment = ensureModelCanBeCreatedFragment; //# sourceMappingURL=workspaces.js.map