mirror of https://github.com/buster-so/buster.git
workspace permissions
This commit is contained in:
parent
73d68fa27f
commit
beb332f01a
|
@ -1,4 +1,4 @@
|
|||
import { type AssetPermissionCheck, checkPermission } from '@buster/access-controls';
|
||||
import { hasAssetPermission } from '@buster/access-controls';
|
||||
import { executeMetricQuery, getCachedMetricData, setCachedMetricData } from '@buster/data-source';
|
||||
import type { Credentials } from '@buster/data-source';
|
||||
import type { User } from '@buster/database';
|
||||
|
@ -49,18 +49,38 @@ export async function getMetricDataHandler(
|
|||
|
||||
const { organizationId } = userOrg;
|
||||
|
||||
// Retrieve metric definition from database with data source info
|
||||
const metric = await getMetricWithDataSource({ metricId, versionNumber });
|
||||
|
||||
if (!metric) {
|
||||
throw new HTTPException(404, {
|
||||
message: 'Metric not found',
|
||||
});
|
||||
}
|
||||
|
||||
// Verify metric belongs to user's organization
|
||||
if (metric.organizationId !== organizationId) {
|
||||
throw new HTTPException(403, {
|
||||
message: 'You do not have permission to view this metric',
|
||||
});
|
||||
}
|
||||
|
||||
// Check if user has permission to view this metric file
|
||||
const permissionCheck: AssetPermissionCheck = {
|
||||
// This follows the same pattern as report-files.ts - hasAssetPermission handles all the logic including:
|
||||
// - Direct permissions
|
||||
// - Workspace sharing permissions
|
||||
// - Cascading permissions (dashboard, chat, collection)
|
||||
// - Admin permissions
|
||||
const hasAccess = await hasAssetPermission({
|
||||
userId: user.id,
|
||||
assetId: metricId,
|
||||
assetType: 'metric_file',
|
||||
requiredRole: 'can_view',
|
||||
organizationId,
|
||||
};
|
||||
workspaceSharing: metric.workspaceSharing ?? 'none',
|
||||
});
|
||||
|
||||
const permissionResult = await checkPermission(permissionCheck);
|
||||
|
||||
if (!permissionResult.hasAccess) {
|
||||
if (!hasAccess) {
|
||||
throw new HTTPException(403, {
|
||||
message: 'You do not have permission to view this metric',
|
||||
});
|
||||
|
@ -100,22 +120,6 @@ export async function getMetricDataHandler(
|
|||
// Ensure limit is within bounds
|
||||
const queryLimit = Math.min(Math.max(limit, 1), 5000);
|
||||
|
||||
// Retrieve metric definition from database with data source info
|
||||
const metric = await getMetricWithDataSource({ metricId, versionNumber });
|
||||
|
||||
if (!metric) {
|
||||
throw new HTTPException(404, {
|
||||
message: 'Metric not found',
|
||||
});
|
||||
}
|
||||
|
||||
// Verify metric belongs to user's organization
|
||||
if (metric.organizationId !== organizationId) {
|
||||
throw new HTTPException(403, {
|
||||
message: 'You do not have permission to view this metric',
|
||||
});
|
||||
}
|
||||
|
||||
// Extract SQL query from metric content
|
||||
const sql = extractSqlFromMetricContent(metric.content);
|
||||
|
||||
|
|
|
@ -12,10 +12,14 @@ export {
|
|||
listPermissions,
|
||||
// From checks.ts
|
||||
checkPermission,
|
||||
computeEffectivePermission,
|
||||
type AssetPermissionCheck,
|
||||
type AssetPermissionResult,
|
||||
// From cascading-permissions.ts
|
||||
checkCascadingPermissions,
|
||||
checkMetricDashboardAccess,
|
||||
checkMetricChatAccess,
|
||||
checkMetricCollectionAccess,
|
||||
} from './assets';
|
||||
|
||||
// Export dataset permissions
|
||||
|
|
|
@ -43,6 +43,13 @@ export const MetricWithDataSourceSchema = z.object({
|
|||
secretId: z.string(),
|
||||
dataSourceType: z.string(),
|
||||
versionNumber: z.number().optional(),
|
||||
workspaceSharing: z.enum(['none', 'can_view', 'can_edit', 'full_access']).nullable(),
|
||||
workspaceSharingEnabledBy: z.string().nullable(),
|
||||
workspaceSharingEnabledAt: z.string().nullable(),
|
||||
publiclyAccessible: z.boolean(),
|
||||
publiclyEnabledBy: z.string().nullable(),
|
||||
publicExpiryDate: z.string().nullable(),
|
||||
publicPassword: z.string().nullable(),
|
||||
});
|
||||
|
||||
export type MetricWithDataSource = z.infer<typeof MetricWithDataSourceSchema>;
|
||||
|
@ -68,6 +75,13 @@ export async function getMetricWithDataSource(
|
|||
versionHistory: metricFiles.versionHistory,
|
||||
secretId: dataSources.secretId,
|
||||
dataSourceType: dataSources.type,
|
||||
workspaceSharing: metricFiles.workspaceSharing,
|
||||
workspaceSharingEnabledBy: metricFiles.workspaceSharingEnabledBy,
|
||||
workspaceSharingEnabledAt: metricFiles.workspaceSharingEnabledAt,
|
||||
publiclyAccessible: metricFiles.publiclyAccessible,
|
||||
publiclyEnabledBy: metricFiles.publiclyEnabledBy,
|
||||
publicExpiryDate: metricFiles.publicExpiryDate,
|
||||
publicPassword: metricFiles.publicPassword,
|
||||
})
|
||||
.from(metricFiles)
|
||||
.innerJoin(dataSources, eq(metricFiles.dataSourceId, dataSources.id))
|
||||
|
@ -134,6 +148,13 @@ export async function getMetricWithDataSource(
|
|||
versionHistory,
|
||||
secretId: result.secretId,
|
||||
dataSourceType: result.dataSourceType,
|
||||
workspaceSharing: result.workspaceSharing,
|
||||
workspaceSharingEnabledBy: result.workspaceSharingEnabledBy,
|
||||
workspaceSharingEnabledAt: result.workspaceSharingEnabledAt,
|
||||
publiclyAccessible: result.publiclyAccessible,
|
||||
publiclyEnabledBy: result.publiclyEnabledBy,
|
||||
publicExpiryDate: result.publicExpiryDate,
|
||||
publicPassword: result.publicPassword,
|
||||
...(versionNumber !== undefined && { versionNumber }),
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue