import _ from "underscore"; import type { EntityId } from "metabase/admin/permissions/types"; import { DataPermission, DataPermissionValue, } from "metabase/admin/permissions/types"; import { isTableEntityId, isSchemaEntityId, } from "metabase/admin/permissions/utils/data-entity-id"; import { getEntityPermission, getSchemasPermission, hasPermissionValueInSubgraph, updateEntityPermission, } from "metabase/admin/permissions/utils/graph"; import type Database from "metabase-lib/v1/metadata/Database"; import type { GroupsPermissions, NativePermissions } from "metabase-types/api"; export function shouldRestrictNativeQueryPermissions( permissions: GroupsPermissions, groupId: number, entityId: EntityId, _permission: DataPermission, value: DataPermissionValue, _database: Database, ) { const currDbNativePermission = getSchemasPermission( permissions, groupId, { databaseId: entityId.databaseId }, DataPermission.CREATE_QUERIES, ); if (isTableEntityId(entityId)) { return ( (value === DataPermissionValue.SANDBOXED || value === DataPermissionValue.BLOCKED) && currDbNativePermission === DataPermissionValue.QUERY_BUILDER_AND_NATIVE ); } if (isSchemaEntityId(entityId)) { return ( value === DataPermissionValue.BLOCKED && currDbNativePermission === DataPermissionValue.QUERY_BUILDER_AND_NATIVE ); } return false; } export function upgradeViewPermissionsIfNeeded( permissions: GroupsPermissions, groupId: number, entityId: EntityId, value: NativePermissions, database: Database, ) { // get permission for item up one level or db if we're already at the top most entity: // table -> schema, schema -> database, database -> database const parentOrDbEntityId = isTableEntityId(entityId) ? _.pick(entityId, ["databaseId", "schemaName"]) : _.pick(entityId, ["databaseId"]); const parentOrDbPermission = getEntityPermission( permissions, groupId, parentOrDbEntityId, DataPermission.VIEW_DATA, ); const isGrantingNativeQueryAccessWithoutProperViewAccess = value === DataPermissionValue.QUERY_BUILDER_AND_NATIVE && parentOrDbPermission !== DataPermissionValue.UNRESTRICTED && parentOrDbPermission !== DataPermissionValue.IMPERSONATED; const isGrantingQueryAccessWithBlockedChild = value !== DataPermissionValue.NO && !isTableEntityId(entityId) && hasPermissionValueInSubgraph( permissions, groupId, entityId, database, DataPermission.VIEW_DATA, DataPermissionValue.BLOCKED, ); if ( isGrantingNativeQueryAccessWithoutProperViewAccess || isGrantingQueryAccessWithBlockedChild ) { permissions = updateEntityPermission( permissions, groupId, parentOrDbEntityId, DataPermissionValue.UNRESTRICTED, database, DataPermission.VIEW_DATA, ); } return permissions; }