mirror of https://github.com/buster-so/buster.git
collection and assets queries
This commit is contained in:
parent
1a955d786b
commit
87ea87e963
|
@ -1,43 +1,17 @@
|
||||||
import type { User } from '@buster/database';
|
import { getReport } from '@buster/database';
|
||||||
import type {
|
import type { GetReportIndividualResponse } from '@buster/server-shared/reports';
|
||||||
GetReportIndividualResponse,
|
|
||||||
ReportIndividualResponse,
|
|
||||||
} from '@buster/server-shared/reports';
|
|
||||||
import { zValidator } from '@hono/zod-validator';
|
|
||||||
import { Hono } from 'hono';
|
import { Hono } from 'hono';
|
||||||
import { HTTPException } from 'hono/http-exception';
|
import { HTTPException } from 'hono/http-exception';
|
||||||
|
|
||||||
async function getReportHandler(
|
export async function getReportHandler(
|
||||||
reportId: string,
|
reportId: string,
|
||||||
user: User
|
user: { id: string }
|
||||||
): Promise<GetReportIndividualResponse> {
|
): Promise<GetReportIndividualResponse> {
|
||||||
return {
|
const report = await getReport({ reportId, userId: user.id });
|
||||||
id: reportId,
|
|
||||||
name: 'Sales Analysis Q4',
|
const response: GetReportIndividualResponse = report;
|
||||||
file_name: 'sales_analysis_q4.md',
|
|
||||||
description: 'Quarterly sales performance analysis',
|
return response;
|
||||||
created_by: user.id,
|
|
||||||
created_at: '2024-01-15T10:00:00Z',
|
|
||||||
updated_at: '2024-01-20T14:30:00Z',
|
|
||||||
deleted_at: null,
|
|
||||||
publicly_accessible: false,
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
type: 'h1',
|
|
||||||
children: [{ text: 'Sales Analysis Q4' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'p',
|
|
||||||
children: [{ text: 'This report analyzes our Q4 sales performance.' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'metric',
|
|
||||||
metricId: '123',
|
|
||||||
children: [{ text: '' }],
|
|
||||||
caption: [{ text: 'This is a metric' }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = new Hono().get('/', async (c) => {
|
const app = new Hono().get('/', async (c) => {
|
||||||
|
|
|
@ -1,46 +1,47 @@
|
||||||
import type { User } from '@buster/database';
|
import type { User } from '@buster/database';
|
||||||
|
import { getUserOrganizationId, updateReport } from '@buster/database';
|
||||||
import type { UpdateReportRequest, UpdateReportResponse } from '@buster/server-shared/reports';
|
import type { UpdateReportRequest, UpdateReportResponse } from '@buster/server-shared/reports';
|
||||||
import { UpdateReportRequestSchema } from '@buster/server-shared/reports';
|
import { UpdateReportRequestSchema } from '@buster/server-shared/reports';
|
||||||
import { zValidator } from '@hono/zod-validator';
|
import { zValidator } from '@hono/zod-validator';
|
||||||
import { Hono } from 'hono';
|
import { Hono } from 'hono';
|
||||||
import { HTTPException } from 'hono/http-exception';
|
import { HTTPException } from 'hono/http-exception';
|
||||||
|
import { getReportHandler } from './GET';
|
||||||
|
|
||||||
async function updateReportHandler(
|
async function updateReportHandler(
|
||||||
reportId: string,
|
reportId: string,
|
||||||
request: UpdateReportRequest,
|
request: UpdateReportRequest,
|
||||||
user: User
|
user: User
|
||||||
): Promise<UpdateReportResponse> {
|
): Promise<UpdateReportResponse> {
|
||||||
const existingReport: UpdateReportResponse = {
|
|
||||||
id: reportId,
|
|
||||||
name: 'Sales Analysis Q4',
|
|
||||||
file_name: 'sales_analysis_q4.md',
|
|
||||||
description: 'Quarterly sales performance analysis',
|
|
||||||
created_by: user.id,
|
|
||||||
created_at: '2024-01-15T10:00:00Z',
|
|
||||||
updated_at: '2024-01-20T14:30:00Z',
|
|
||||||
deleted_at: null,
|
|
||||||
publicly_accessible: false,
|
|
||||||
content: [
|
|
||||||
{
|
|
||||||
type: 'h1' as const,
|
|
||||||
children: [{ text: 'Sales Analysis Q4' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'p' as const,
|
|
||||||
children: [{ text: 'This report analyzes our Q4 sales performance.' }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!reportId || reportId === 'invalid') {
|
if (!reportId || reportId === 'invalid') {
|
||||||
throw new HTTPException(404, { message: 'Report not found' });
|
throw new HTTPException(404, { message: 'Report not found' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedReport: UpdateReportResponse = {
|
// Get user's organization ID
|
||||||
...existingReport,
|
const userOrg = await getUserOrganizationId(user.id);
|
||||||
...(request as Partial<UpdateReportResponse>),
|
|
||||||
updated_at: new Date().toISOString(),
|
if (!userOrg) {
|
||||||
};
|
throw new HTTPException(403, { message: 'User is not associated with an organization' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const _hasPermissionToEditAsset = true; //DALLIN: Check if user has permission to edit asset
|
||||||
|
|
||||||
|
if (!_hasPermissionToEditAsset) {
|
||||||
|
throw new HTTPException(403, { message: 'User does not have permission to edit asset' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name, content } = request;
|
||||||
|
|
||||||
|
// Update the report in the database
|
||||||
|
await updateReport({
|
||||||
|
reportId,
|
||||||
|
organizationId: userOrg.organizationId,
|
||||||
|
userId: user.id,
|
||||||
|
name,
|
||||||
|
content,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get and return the updated report
|
||||||
|
const updatedReport: UpdateReportResponse = await getReportHandler(reportId, user);
|
||||||
|
|
||||||
return updatedReport;
|
return updatedReport;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@ import { Hono } from 'hono';
|
||||||
import { requireAuth } from '../../../../middleware/auth';
|
import { requireAuth } from '../../../../middleware/auth';
|
||||||
import GET from './GET';
|
import GET from './GET';
|
||||||
import PUT from './PUT';
|
import PUT from './PUT';
|
||||||
|
import SHARING from './sharing';
|
||||||
|
|
||||||
const app = new Hono().route('/', GET).route('/', PUT);
|
const app = new Hono().route('/', GET).route('/', PUT).route('/sharing', SHARING);
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
import { getUserOrganizationId, updateReport } from '@buster/database';
|
||||||
|
import {
|
||||||
|
type ShareUpdateRequest,
|
||||||
|
ShareUpdateRequestSchema,
|
||||||
|
type ShareUpdateResponse,
|
||||||
|
type UpdateReportResponse,
|
||||||
|
} from '@buster/server-shared/reports';
|
||||||
|
import { zValidator } from '@hono/zod-validator';
|
||||||
|
import { Hono } from 'hono';
|
||||||
|
import { HTTPException } from 'hono/http-exception';
|
||||||
|
import { getReportHandler } from '../GET';
|
||||||
|
|
||||||
|
async function updateReportShareHandler(
|
||||||
|
reportId: string,
|
||||||
|
request: ShareUpdateRequest,
|
||||||
|
user: { id: string; organizationId: string }
|
||||||
|
) {
|
||||||
|
const _hasPermissionToEditAssetPermissions = true; //DALLIN: Check if user has permission to edit asset permissions
|
||||||
|
|
||||||
|
if (!_hasPermissionToEditAssetPermissions) {
|
||||||
|
throw new HTTPException(403, {
|
||||||
|
message: 'User does not have permission to edit asset permissions',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { publicly_accessible, public_expiry_date, public_password, workspace_sharing } = request;
|
||||||
|
|
||||||
|
if (publicly_accessible || public_expiry_date || public_password || workspace_sharing) {
|
||||||
|
//DALLIN: Check if user has permission to edit settings
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateReport({
|
||||||
|
reportId,
|
||||||
|
organizationId: user.organizationId,
|
||||||
|
userId: user.id,
|
||||||
|
publicly_accessible,
|
||||||
|
public_expiry_date,
|
||||||
|
public_password,
|
||||||
|
workspace_sharing,
|
||||||
|
});
|
||||||
|
|
||||||
|
const updatedReport: UpdateReportResponse = await getReportHandler(reportId, user);
|
||||||
|
|
||||||
|
return updatedReport;
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = new Hono().put('/', zValidator('json', ShareUpdateRequestSchema), async (c) => {
|
||||||
|
const reportId = c.req.param('id');
|
||||||
|
const request = c.req.valid('json');
|
||||||
|
const user = c.get('busterUser');
|
||||||
|
|
||||||
|
if (!reportId) {
|
||||||
|
throw new HTTPException(404, { message: 'Report not found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const userOrg = await getUserOrganizationId(user.id);
|
||||||
|
|
||||||
|
if (!userOrg) {
|
||||||
|
throw new HTTPException(403, { message: 'User is not associated with an organization' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedReport: ShareUpdateResponse = await updateReportShareHandler(reportId, request, {
|
||||||
|
id: user.id,
|
||||||
|
organizationId: userOrg.organizationId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return c.json(updatedReport);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default app;
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { Hono } from 'hono';
|
||||||
|
import PUT from './PUT';
|
||||||
|
|
||||||
|
const app = new Hono().route('/', PUT);
|
||||||
|
|
||||||
|
export default app;
|
|
@ -1 +0,0 @@
|
||||||
export * from './shareInterfaces';
|
|
|
@ -1,14 +0,0 @@
|
||||||
import type { ShareRole, WorkspaceShareRole } from '@buster/server-shared/share';
|
|
||||||
|
|
||||||
export type ShareDeleteRequest = string[];
|
|
||||||
|
|
||||||
export type ShareUpdateRequest = {
|
|
||||||
users?: {
|
|
||||||
email: string;
|
|
||||||
role: ShareRole;
|
|
||||||
}[];
|
|
||||||
workspace_sharing?: WorkspaceShareRole | null;
|
|
||||||
publicly_accessible?: boolean;
|
|
||||||
public_password?: string | null;
|
|
||||||
public_expiry_date?: string | null;
|
|
||||||
};
|
|
|
@ -80,10 +80,11 @@ export async function getReport(input: GetReportInput) {
|
||||||
// Individual permissions query - get users with direct permissions to this report
|
// Individual permissions query - get users with direct permissions to this report
|
||||||
const individualPermissionsQuery = db
|
const individualPermissionsQuery = db
|
||||||
.select({
|
.select({
|
||||||
|
id: users.id,
|
||||||
role: assetPermissions.role,
|
role: assetPermissions.role,
|
||||||
email: users.email,
|
email: users.email,
|
||||||
name: users.name,
|
name: users.name,
|
||||||
avatarUrl: users.avatarUrl,
|
avatar_url: users.avatarUrl,
|
||||||
})
|
})
|
||||||
.from(assetPermissions)
|
.from(assetPermissions)
|
||||||
.innerJoin(users, eq(users.id, assetPermissions.identityId))
|
.innerJoin(users, eq(users.id, assetPermissions.identityId))
|
||||||
|
|
|
@ -35,7 +35,11 @@ export type ReportListItem = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get paginated list of reports for the user's organization
|
* Get paginated list of reports for the user's organization
|
||||||
* with optional filtering by name, dates, and public accessibility
|
* with optional filtering by name, dates, and public accessibility.
|
||||||
|
*
|
||||||
|
* Security note: When deleted date filters (deleted_after/deleted_before) are provided,
|
||||||
|
* this function returns only deleted reports within that date range.
|
||||||
|
* Otherwise, it returns only non-deleted reports.
|
||||||
*/
|
*/
|
||||||
export async function getReportsList(
|
export async function getReportsList(
|
||||||
input: GetReportsListInput
|
input: GetReportsListInput
|
||||||
|
@ -64,20 +68,27 @@ export async function getReportsList(
|
||||||
const { organizationId } = userOrg;
|
const { organizationId } = userOrg;
|
||||||
|
|
||||||
// Build dynamic where conditions
|
// Build dynamic where conditions
|
||||||
// Only include the isNull check if no deleted date filters are provided
|
// Check if deleted date filters are provided
|
||||||
const hasDeletedFilters = deleted_after !== undefined || deleted_before !== undefined;
|
const hasDeletedFilters = deleted_after !== undefined || deleted_before !== undefined;
|
||||||
|
|
||||||
const whereConditions = and(
|
const whereConditions = and(
|
||||||
eq(reportFiles.organizationId, organizationId),
|
eq(reportFiles.organizationId, organizationId),
|
||||||
// Only exclude deleted reports if no deleted date filters are provided
|
// Security fix: Always apply proper deletion filtering
|
||||||
!hasDeletedFilters ? isNull(reportFiles.deletedAt) : undefined,
|
// If deleted date filters are provided, show only deleted reports in that range
|
||||||
|
// Otherwise, show only non-deleted reports
|
||||||
|
hasDeletedFilters
|
||||||
|
? and(
|
||||||
|
// Show only deleted reports within the specified date range
|
||||||
|
deleted_after ? gte(reportFiles.deletedAt, deleted_after) : undefined,
|
||||||
|
deleted_before ? lte(reportFiles.deletedAt, deleted_before) : undefined
|
||||||
|
)
|
||||||
|
: // Show only non-deleted reports
|
||||||
|
isNull(reportFiles.deletedAt),
|
||||||
name ? like(reportFiles.name, `%${name}%`) : undefined,
|
name ? like(reportFiles.name, `%${name}%`) : undefined,
|
||||||
created_after ? gte(reportFiles.createdAt, created_after) : undefined,
|
created_after ? gte(reportFiles.createdAt, created_after) : undefined,
|
||||||
created_before ? lte(reportFiles.createdAt, created_before) : undefined,
|
created_before ? lte(reportFiles.createdAt, created_before) : undefined,
|
||||||
updated_after ? gte(reportFiles.updatedAt, updated_after) : undefined,
|
updated_after ? gte(reportFiles.updatedAt, updated_after) : undefined,
|
||||||
updated_before ? lte(reportFiles.updatedAt, updated_before) : undefined,
|
updated_before ? lte(reportFiles.updatedAt, updated_before) : undefined,
|
||||||
deleted_after ? gte(reportFiles.deletedAt, deleted_after) : undefined,
|
|
||||||
deleted_before ? lte(reportFiles.deletedAt, deleted_before) : undefined,
|
|
||||||
publicly_accessible !== undefined
|
publicly_accessible !== undefined
|
||||||
? eq(reportFiles.publiclyAccessible, publicly_accessible)
|
? eq(reportFiles.publiclyAccessible, publicly_accessible)
|
||||||
: undefined
|
: undefined
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
export * from './get-report-title';
|
export * from './get-report-title';
|
||||||
export * from './get-reports-list';
|
export * from './get-reports-list';
|
||||||
export * from './get-report';
|
export * from './get-report';
|
||||||
|
export * from './update-report';
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
import { and, eq, isNull } from 'drizzle-orm';
|
||||||
|
import {} from 'drizzle-zod';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { db } from '../../connection';
|
||||||
|
import { reportFiles } from '../../schema';
|
||||||
|
import { workspaceSharingEnum } from '../../schema';
|
||||||
|
import { ReportElementSchema, type ReportElements } from '../../schema-types';
|
||||||
|
|
||||||
|
const WorkspaceSharingSchema = z.enum(workspaceSharingEnum.enumValues);
|
||||||
|
|
||||||
|
// Input validation schema for updating a report
|
||||||
|
const UpdateReportInputSchema = z.object({
|
||||||
|
reportId: z.string().uuid('Report ID must be a valid UUID'),
|
||||||
|
organizationId: z.string().uuid('Organization ID must be a valid UUID'),
|
||||||
|
userId: z.string().uuid('User ID must be a valid UUID'),
|
||||||
|
name: z.string().optional(),
|
||||||
|
publicly_accessible: z.boolean().optional(),
|
||||||
|
content: z.lazy(() => z.array(ReportElementSchema)).optional() as z.ZodOptional<
|
||||||
|
z.ZodType<ReportElements>
|
||||||
|
>,
|
||||||
|
public_expiry_date: z.string().optional(),
|
||||||
|
public_password: z.string().optional(),
|
||||||
|
workspace_sharing: WorkspaceSharingSchema.optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
type UpdateReportInput = z.infer<typeof UpdateReportInputSchema>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a report with the provided fields
|
||||||
|
* Only updates fields that are provided in the input
|
||||||
|
* Always updates the updatedAt timestamp
|
||||||
|
*/
|
||||||
|
export const updateReport = async (params: UpdateReportInput): Promise<void> => {
|
||||||
|
// Validate and destructure input
|
||||||
|
const {
|
||||||
|
reportId,
|
||||||
|
organizationId,
|
||||||
|
userId,
|
||||||
|
name,
|
||||||
|
publicly_accessible,
|
||||||
|
content,
|
||||||
|
public_expiry_date,
|
||||||
|
public_password,
|
||||||
|
workspace_sharing,
|
||||||
|
} = UpdateReportInputSchema.parse(params);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Build update data - only include fields that are provided
|
||||||
|
const updateData: {
|
||||||
|
updatedAt: string;
|
||||||
|
name?: string;
|
||||||
|
publiclyAccessible?: boolean;
|
||||||
|
publiclyEnabledBy?: string | null;
|
||||||
|
content?: ReportElements;
|
||||||
|
publicExpiryDate?: string;
|
||||||
|
publicPassword?: string;
|
||||||
|
workspaceSharing?: 'none' | 'can_view' | 'can_edit' | 'full_access';
|
||||||
|
workspaceSharingEnabledBy?: string | null;
|
||||||
|
workspaceSharingEnabledAt?: string | null;
|
||||||
|
} = {
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only add fields that are provided
|
||||||
|
if (name !== undefined) {
|
||||||
|
updateData.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (publicly_accessible !== undefined) {
|
||||||
|
updateData.publiclyAccessible = publicly_accessible;
|
||||||
|
// Set publiclyEnabledBy to userId when enabling, null when disabling
|
||||||
|
updateData.publiclyEnabledBy = publicly_accessible ? userId : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content !== undefined) {
|
||||||
|
updateData.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (public_expiry_date !== undefined) {
|
||||||
|
updateData.publicExpiryDate = public_expiry_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (public_password !== undefined) {
|
||||||
|
updateData.publicPassword = public_password;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workspace_sharing !== undefined) {
|
||||||
|
updateData.workspaceSharing = workspace_sharing;
|
||||||
|
|
||||||
|
if (workspace_sharing !== 'none') {
|
||||||
|
updateData.workspaceSharingEnabledBy = userId;
|
||||||
|
updateData.workspaceSharingEnabledAt = new Date().toISOString();
|
||||||
|
} else {
|
||||||
|
updateData.workspaceSharingEnabledBy = null;
|
||||||
|
updateData.workspaceSharingEnabledAt = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update report in database
|
||||||
|
await db
|
||||||
|
.update(reportFiles)
|
||||||
|
.set(updateData)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(reportFiles.id, reportId),
|
||||||
|
eq(reportFiles.organizationId, organizationId),
|
||||||
|
isNull(reportFiles.deletedAt)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating report:', {
|
||||||
|
reportId,
|
||||||
|
organizationId,
|
||||||
|
error: error instanceof Error ? error.message : error,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Re-throw with more context
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Failed to update report');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export const AssetCollectionSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
description: z.string().nullable().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type AssetCollection = z.infer<typeof AssetCollectionSchema>;
|
||||||
|
|
||||||
|
export const AssetCollectionsSchema = z.array(AssetCollectionSchema);
|
||||||
|
|
||||||
|
export type AssetCollections = z.infer<typeof AssetCollectionsSchema>;
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ReportElementsSchema } from '@buster/database';
|
||||||
import { AutoformatPlugin } from '@platejs/autoformat';
|
import { AutoformatPlugin } from '@platejs/autoformat';
|
||||||
import {
|
import {
|
||||||
BaseBasicBlocksPlugin,
|
BaseBasicBlocksPlugin,
|
||||||
|
@ -22,7 +23,6 @@ import {
|
||||||
BaseUnderlinePlugin,
|
BaseUnderlinePlugin,
|
||||||
} from '@platejs/basic-nodes';
|
} from '@platejs/basic-nodes';
|
||||||
import { createSlateEditor } from 'platejs';
|
import { createSlateEditor } from 'platejs';
|
||||||
import { ReportElementsSchema } from '../../../../database/src/schema-types/report-elements';
|
|
||||||
import { MarkdownPlugin } from './MarkdownPlugin';
|
import { MarkdownPlugin } from './MarkdownPlugin';
|
||||||
|
|
||||||
const serverNode = [
|
const serverNode = [
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { ReportElement } from '../../../database/src/schema-types/report-elements';
|
import type { ReportElement } from '@buster/database';
|
||||||
|
|
||||||
export const SAMPLE_REPORT_ELEMENTS = [
|
export const SAMPLE_REPORT_ELEMENTS = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import type { ReportElement, ReportElements } from '@buster/database';
|
import type { ReportElements } from '@buster/database';
|
||||||
import { ReportElementSchema } from '@buster/database';
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { AssetCollectionsSchema } from '../collections/shared-asset-collections';
|
||||||
|
import { IndividualPermissionsSchema } from '../shared-permissions';
|
||||||
|
import { VersionsSchema } from '../version-shared';
|
||||||
|
|
||||||
export const ReportListItemSchema = z.object({
|
export const ReportListItemSchema = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
|
@ -12,28 +14,20 @@ export const ReportListItemSchema = z.object({
|
||||||
publicly_accessible: z.boolean(),
|
publicly_accessible: z.boolean(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ReportIndividualResponseSchema: z.ZodType<{
|
export const ReportIndividualResponseSchema = z.object({
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
file_name: string;
|
|
||||||
description: string;
|
|
||||||
created_by: string;
|
|
||||||
created_at: string;
|
|
||||||
updated_at: string;
|
|
||||||
deleted_at: string | null;
|
|
||||||
publicly_accessible: boolean;
|
|
||||||
content: ReportElement[];
|
|
||||||
}> = z.object({
|
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
file_name: z.string(),
|
|
||||||
description: z.string(),
|
|
||||||
created_by: z.string(),
|
|
||||||
created_at: z.string(),
|
created_at: z.string(),
|
||||||
updated_at: z.string(),
|
updated_at: z.string(),
|
||||||
deleted_at: z.string().nullable(),
|
created_by_id: z.string(),
|
||||||
|
created_by_name: z.string().nullable(),
|
||||||
|
created_by_avatar: z.string().nullable(),
|
||||||
publicly_accessible: z.boolean(),
|
publicly_accessible: z.boolean(),
|
||||||
content: z.array(ReportElementSchema) as z.ZodType<ReportElements>,
|
version_number: z.number(),
|
||||||
|
version_history: VersionsSchema,
|
||||||
|
collections: AssetCollectionsSchema,
|
||||||
|
individual_permissions: IndividualPermissionsSchema,
|
||||||
|
content: z.any() as z.ZodType<ReportElements>, //we use any here because we don't know the type of the content, will be validated in the database
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ReportListItem = z.infer<typeof ReportListItemSchema>;
|
export type ReportListItem = z.infer<typeof ReportListItemSchema>;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { ReportElementSchema, type ReportElements } from '@buster/database';
|
import type { ReportElements } from '@buster/database';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { WorkspaceSharingSchema } from '../shared-permissions';
|
||||||
import { PaginatedRequestSchema } from '../type-utilities/pagination';
|
import { PaginatedRequestSchema } from '../type-utilities/pagination';
|
||||||
|
|
||||||
export const GetReportsListRequestSchema = PaginatedRequestSchema;
|
export const GetReportsListRequestSchema = PaginatedRequestSchema;
|
||||||
|
@ -8,13 +9,18 @@ export const GetReportsListRequestSchema = PaginatedRequestSchema;
|
||||||
export const UpdateReportRequestSchema = z
|
export const UpdateReportRequestSchema = z
|
||||||
.object({
|
.object({
|
||||||
name: z.string().optional(),
|
name: z.string().optional(),
|
||||||
description: z.string().optional(),
|
content: z.any().optional() as z.ZodOptional<z.ZodType<ReportElements>>, //we use any here because we don't know the type of the content, will be validated in the database
|
||||||
publicly_accessible: z.boolean().optional(),
|
|
||||||
content: z.lazy(() => z.array(ReportElementSchema)).optional() as z.ZodOptional<
|
|
||||||
z.ZodType<ReportElements>
|
|
||||||
>,
|
|
||||||
})
|
})
|
||||||
.partial();
|
.partial();
|
||||||
|
|
||||||
export type UpdateReportRequest = z.infer<typeof UpdateReportRequestSchema>;
|
export type UpdateReportRequest = z.infer<typeof UpdateReportRequestSchema>;
|
||||||
export type GetReportsListRequest = z.infer<typeof GetReportsListRequestSchema>;
|
export type GetReportsListRequest = z.infer<typeof GetReportsListRequestSchema>;
|
||||||
|
|
||||||
|
export const ShareUpdateRequestSchema = z.object({
|
||||||
|
publicly_accessible: z.boolean().optional(),
|
||||||
|
public_expiry_date: z.string().optional(),
|
||||||
|
public_password: z.string().optional(),
|
||||||
|
workspace_sharing: WorkspaceSharingSchema.optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type ShareUpdateRequest = z.infer<typeof ShareUpdateRequestSchema>;
|
||||||
|
|
|
@ -4,7 +4,9 @@ import { ReportIndividualResponseSchema, ReportListItemSchema } from './reports.
|
||||||
|
|
||||||
export const GetReportsListResponseSchema = PaginatedResponseSchema(ReportListItemSchema);
|
export const GetReportsListResponseSchema = PaginatedResponseSchema(ReportListItemSchema);
|
||||||
export const UpdateReportResponseSchema = ReportIndividualResponseSchema;
|
export const UpdateReportResponseSchema = ReportIndividualResponseSchema;
|
||||||
|
export const ShareUpdateResponseSchema = ReportIndividualResponseSchema;
|
||||||
|
|
||||||
export type GetReportsListResponse = z.infer<typeof GetReportsListResponseSchema>;
|
export type GetReportsListResponse = z.infer<typeof GetReportsListResponseSchema>;
|
||||||
export type UpdateReportResponse = z.infer<typeof UpdateReportResponseSchema>;
|
export type UpdateReportResponse = z.infer<typeof UpdateReportResponseSchema>;
|
||||||
export type GetReportIndividualResponse = z.infer<typeof ReportIndividualResponseSchema>;
|
export type GetReportIndividualResponse = z.infer<typeof ReportIndividualResponseSchema>;
|
||||||
|
export type ShareUpdateResponse = z.infer<typeof ShareUpdateResponseSchema>;
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import type { assetPermissionRoleEnum, workspaceSharingEnum } from '@buster/database';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
type AssetPermissionRoleBase = (typeof assetPermissionRoleEnum.enumValues)[number];
|
||||||
|
const AssetPermissionRoleEnums: Record<AssetPermissionRoleBase, AssetPermissionRoleBase> =
|
||||||
|
Object.freeze({
|
||||||
|
owner: 'owner',
|
||||||
|
viewer: 'viewer',
|
||||||
|
full_access: 'full_access',
|
||||||
|
can_edit: 'can_edit',
|
||||||
|
can_filter: 'can_filter',
|
||||||
|
can_view: 'can_view',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const AssetPermissionRoleSchema = z.enum(
|
||||||
|
Object.values(AssetPermissionRoleEnums) as [AssetPermissionRoleBase, ...AssetPermissionRoleBase[]]
|
||||||
|
);
|
||||||
|
|
||||||
|
export const IndividualPermissionSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string().nullable(),
|
||||||
|
email: z.string(),
|
||||||
|
avatar_url: z.string().nullable(),
|
||||||
|
role: AssetPermissionRoleSchema,
|
||||||
|
});
|
||||||
|
|
||||||
|
export type IndividualPermission = z.infer<typeof IndividualPermissionSchema>;
|
||||||
|
|
||||||
|
export const IndividualPermissionsSchema = z.array(IndividualPermissionSchema);
|
||||||
|
|
||||||
|
export type IndividualPermissions = z.infer<typeof IndividualPermissionsSchema>;
|
||||||
|
|
||||||
|
type WorkspaceSharingBase = (typeof workspaceSharingEnum.enumValues)[number];
|
||||||
|
const WorkspaceSharingEnums: Record<WorkspaceSharingBase, WorkspaceSharingBase> = Object.freeze({
|
||||||
|
none: 'none',
|
||||||
|
can_view: 'can_view',
|
||||||
|
can_edit: 'can_edit',
|
||||||
|
full_access: 'full_access',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WorkspaceSharingSchema = z.enum(
|
||||||
|
Object.values(WorkspaceSharingEnums) as [WorkspaceSharingBase, ...WorkspaceSharingBase[]]
|
||||||
|
);
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export const VersionSchema = z.object({
|
||||||
|
version_number: z.number(),
|
||||||
|
updated_at: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Version = z.infer<typeof VersionSchema>;
|
||||||
|
|
||||||
|
export const VersionsSchema = z.array(VersionSchema);
|
||||||
|
|
||||||
|
export type Versions = z.infer<typeof VersionsSchema>;
|
Loading…
Reference in New Issue