buster/apps/server/src/api/v2/reports/[id]/GET.ts

120 lines
3.5 KiB
TypeScript
Raw Normal View History

2025-10-09 04:03:23 +08:00
import { screenshots_task_keys } from '@buster-app/trigger/task-keys';
2025-10-09 04:25:28 +08:00
import type { TakeReportScreenshotTrigger } from '@buster-app/trigger/task-schemas';
2025-09-25 04:32:50 +08:00
import { checkPermission } from '@buster/access-controls';
2025-10-09 04:03:23 +08:00
import {
type User,
getMetricIdsInReport,
getReportFileById,
getUserOrganizationId,
} from '@buster/database/queries';
import {
GetReportParamsSchema,
GetReportQuerySchema,
type GetReportResponse,
} from '@buster/server-shared/reports';
import { zValidator } from '@hono/zod-validator';
2025-10-09 06:11:56 +08:00
import { shouldTakeScreenshot } from '@shared-helpers/screenshots';
2025-10-09 04:03:23 +08:00
import { tasks } from '@trigger.dev/sdk';
import { Hono } from 'hono';
import { HTTPException } from 'hono/http-exception';
2025-09-27 05:04:45 +08:00
import { throwUnauthorizedError } from '../../../../shared-helpers/asset-public-access';
import { getMetricsInAncestorAssetFromMetricIds } from '../../../../shared-helpers/metric-helpers';
2025-08-05 09:27:18 +08:00
import { standardErrorHandler } from '../../../../utils/response';
2025-08-05 05:37:48 +08:00
export async function getReportHandler(
reportId: string,
user: User,
2025-09-21 01:15:53 +08:00
versionNumber?: number | undefined,
password?: string | undefined
2025-08-21 11:53:51 +08:00
): Promise<GetReportResponse> {
const [report, metricIds] = await Promise.all([
getReportFileById({
reportId,
userId: user.id,
versionNumber,
}),
getMetricIdsInReport({ reportId }),
]);
2025-08-08 06:42:04 +08:00
2025-09-25 04:32:50 +08:00
const permission = await checkPermission({
userId: user.id,
2025-09-21 01:05:10 +08:00
assetId: reportId,
assetType: 'report_file',
2025-09-25 04:32:50 +08:00
requiredRole: 'can_view',
2025-09-21 01:05:10 +08:00
workspaceSharing: report.workspace_sharing,
2025-09-25 04:32:50 +08:00
organizationId: report.organization_id,
publiclyAccessible: report.publicly_accessible,
publicExpiryDate: report.public_expiry_date ?? undefined,
publicPassword: report.public_password ?? undefined,
userSuppliedPassword: password,
2025-09-21 01:05:10 +08:00
});
2025-09-25 04:32:50 +08:00
if (!permission.hasAccess || !permission.effectiveRole) {
throwUnauthorizedError({
publiclyAccessible: report.publicly_accessible ?? false,
publicExpiryDate: report.public_expiry_date ?? undefined,
publicPassword: report.public_password ?? undefined,
userSuppliedPassword: password,
});
2025-09-25 04:32:50 +08:00
}
const metrics = await getMetricsInAncestorAssetFromMetricIds(metricIds, user);
2025-09-25 04:32:50 +08:00
const response: GetReportResponse = {
...report,
permission: permission.effectiveRole,
metrics,
2025-09-25 04:32:50 +08:00
};
return response;
}
2025-08-05 09:27:18 +08:00
const app = new Hono()
.get(
'/',
zValidator('param', GetReportParamsSchema),
zValidator('query', GetReportQuerySchema),
async (c) => {
const { id: reportId } = c.req.valid('param');
const query = c.req.valid('query');
2025-09-21 00:37:50 +08:00
const { password, version_number: versionNumber } = query;
const user = c.get('busterUser');
2025-08-03 10:15:48 +08:00
if (!reportId) {
throw new HTTPException(404, { message: 'Report ID is required' });
}
2025-08-03 10:15:48 +08:00
const response: GetReportResponse = await getReportHandler(
reportId,
user,
2025-09-21 00:37:50 +08:00
versionNumber,
password
);
2025-10-09 04:03:23 +08:00
2025-10-09 06:11:56 +08:00
const tag = `take-report-screenshot-${reportId}-${versionNumber}`;
if (
await shouldTakeScreenshot({
tag,
key: screenshots_task_keys.take_report_screenshot,
context: c,
})
) {
tasks.trigger(
screenshots_task_keys.take_report_screenshot,
{
reportId,
organizationId: (await getUserOrganizationId(user.id))?.organizationId || '',
accessToken: c.get('accessToken'),
} satisfies TakeReportScreenshotTrigger,
2025-10-09 06:24:30 +08:00
{ tags: [tag] }
2025-10-09 06:11:56 +08:00
);
}
2025-10-09 04:03:23 +08:00
return c.json(response);
}
)
2025-08-05 09:27:18 +08:00
.onError(standardErrorHandler);
export default app;