This commit is contained in:
Carl-Gerhard Lindesvärd
2024-09-03 21:17:40 +02:00
parent 4cdfe3aed2
commit 8e06bacdb0
13 changed files with 326 additions and 54 deletions

View File

@@ -5,6 +5,8 @@ import { hashPassword, stripTrailingSlash } from '@openpanel/common';
import type { Prisma } from '@openpanel/db';
import { db } from '@openpanel/db';
import { getClientAccess } from '../access';
import { TRPCAccessError } from '../errors';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const clientRouter = createTRPCRouter({
@@ -17,7 +19,16 @@ export const clientRouter = createTRPCRouter({
crossDomain: z.boolean().optional(),
})
)
.mutation(({ input }) => {
.mutation(async ({ input, ctx }) => {
const access = await getClientAccess({
userId: ctx.session.userId,
clientId: input.id,
});
if (!access) {
throw TRPCAccessError('You do not have access to this client');
}
return db.client.update({
where: {
id: input.id,
@@ -66,7 +77,16 @@ export const clientRouter = createTRPCRouter({
id: z.string(),
})
)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
const access = await getClientAccess({
userId: ctx.session.userId,
clientId: input.id,
});
if (!access) {
throw TRPCAccessError('You do not have access to this client');
}
await db.client.delete({
where: {
id: input.id,

View File

@@ -1,9 +1,16 @@
import { PrismaError } from 'prisma-error-enum';
import { z } from 'zod';
import { db, getDashboardsByProjectId, getId } from '@openpanel/db';
import {
db,
getDashboardsByProjectId,
getId,
getProjectById,
} from '@openpanel/db';
import type { Prisma } from '@openpanel/db';
import { getProjectAccess } from '../access';
import { TRPCAccessError, TRPCNotFoundError } from '../errors';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const dashboardRouter = createTRPCRouter({
@@ -13,7 +20,7 @@ export const dashboardRouter = createTRPCRouter({
projectId: z.string(),
})
)
.query(async ({ input }) => {
.query(({ input }) => {
return getDashboardsByProjectId(input.projectId);
}),
create: protectedProcedure
@@ -21,17 +28,31 @@ export const dashboardRouter = createTRPCRouter({
z.object({
name: z.string(),
projectId: z.string(),
organizationSlug: z.string(),
})
)
.mutation(async ({ input: { organizationSlug, projectId, name } }) => {
.mutation(async ({ input, ctx }) => {
const access = await getProjectAccess({
projectId: input.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
const project = await getProjectById(input.projectId);
if (!project) {
throw TRPCNotFoundError('Project not found');
}
return db.dashboard.create({
data: {
id: await getId('dashboard', name),
projectId: projectId,
organizationSlug: organizationSlug,
organizationId: organizationSlug,
name,
id: await getId('dashboard', input.name),
projectId: input.projectId,
organizationSlug: project.organizationId!,
organizationId: project.organizationId,
name: input.name,
},
});
}),
@@ -42,7 +63,22 @@ export const dashboardRouter = createTRPCRouter({
name: z.string(),
})
)
.mutation(({ input }) => {
.mutation(async ({ input, ctx }) => {
const dashboard = await db.dashboard.findUniqueOrThrow({
where: {
id: input.id,
},
});
const access = await getProjectAccess({
projectId: dashboard.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this dashboard');
}
return db.dashboard.update({
where: {
id: input.id,
@@ -59,18 +95,33 @@ export const dashboardRouter = createTRPCRouter({
forceDelete: z.boolean().optional(),
})
)
.mutation(async ({ input: { id, forceDelete } }) => {
.mutation(async ({ input, ctx }) => {
const dashboard = await db.dashboard.findUniqueOrThrow({
where: {
id: input.id,
},
});
const access = await getProjectAccess({
projectId: dashboard.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this dashboard');
}
try {
if (forceDelete) {
if (input.forceDelete) {
await db.report.deleteMany({
where: {
dashboardId: id,
dashboardId: input.id,
},
});
}
await db.dashboard.delete({
where: {
id,
id: input.id,
},
});
} catch (e) {

View File

@@ -27,18 +27,20 @@ export const eventRouter = createTRPCRouter({
conversion: z.boolean().optional(),
})
)
.mutation(({ input: { projectId, name, icon, color, conversion } }) => {
return db.eventMeta.upsert({
where: {
name_projectId: {
name,
projectId,
.mutation(
async ({ input: { projectId, name, icon, color, conversion } }) => {
return db.eventMeta.upsert({
where: {
name_projectId: {
name,
projectId,
},
},
},
create: { projectId, name, icon, color, conversion },
update: { icon, color, conversion },
});
}),
create: { projectId, name, icon, color, conversion },
update: { icon, color, conversion },
});
}
),
byId: protectedProcedure
.input(
@@ -78,8 +80,10 @@ export const eventRouter = createTRPCRouter({
profile: z.boolean().optional(),
})
)
.query(async ({ input }) => getEventList(input)),
conversions: publicProcedure
.query(async ({ input }) => {
return getEventList(input);
}),
conversions: protectedProcedure
.input(
z.object({
projectId: z.string(),

View File

@@ -5,6 +5,8 @@ import { z } from 'zod';
import { db } from '@openpanel/db';
import { zInviteUser } from '@openpanel/validation';
import { getOrganizationAccess, getOrganizationAccessCached } from '../access';
import { TRPCAccessError } from '../errors';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const organizationRouter = createTRPCRouter({
@@ -15,7 +17,16 @@ export const organizationRouter = createTRPCRouter({
name: z.string(),
})
)
.mutation(({ input }) => {
.mutation(async ({ input, ctx }) => {
const access = await getOrganizationAccess({
userId: ctx.session.userId,
organizationId: input.id,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
return db.organization.update({
where: {
id: input.id,
@@ -29,6 +40,15 @@ export const organizationRouter = createTRPCRouter({
inviteUser: protectedProcedure
.input(zInviteUser)
.mutation(async ({ input, ctx }) => {
const access = await getOrganizationAccess({
userId: ctx.session.userId,
organizationId: input.organizationSlug,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
const email = input.email.toLowerCase();
const userExists = await db.user.findFirst({
where: {
@@ -68,12 +88,22 @@ export const organizationRouter = createTRPCRouter({
memberId: z.string(),
})
)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
const member = await db.member.findUniqueOrThrow({
where: {
id: input.memberId,
},
});
const access = await getOrganizationAccess({
userId: ctx.session.userId,
organizationId: member.organizationId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
const invitationId = pathOr<string | undefined>(
undefined,
['meta', 'invitationId'],
@@ -107,6 +137,15 @@ export const organizationRouter = createTRPCRouter({
throw new Error('You cannot remove yourself from the organization');
}
const access = await getOrganizationAccess({
userId: ctx.session.userId,
organizationId: input.organizationId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
await db.$transaction([
db.member.deleteMany({
where: {
@@ -131,7 +170,16 @@ export const organizationRouter = createTRPCRouter({
access: z.array(z.string()),
})
)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
const access = await getOrganizationAccess({
userId: ctx.session.userId,
organizationId: input.organizationSlug,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
return db.$transaction([
db.projectAccess.deleteMany({
where: {

View File

@@ -2,6 +2,8 @@ import { z } from 'zod';
import { db, getId, getProjectsByOrganizationSlug } from '@openpanel/db';
import { getProjectAccess } from '../access';
import { TRPCAccessError } from '../errors';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const projectRouter = createTRPCRouter({
@@ -23,7 +25,16 @@ export const projectRouter = createTRPCRouter({
name: z.string(),
})
)
.mutation(({ input }) => {
.mutation(async ({ input, ctx }) => {
const access = await getProjectAccess({
userId: ctx.session.userId,
projectId: input.id,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
return db.project.update({
where: {
id: input.id,
@@ -56,7 +67,16 @@ export const projectRouter = createTRPCRouter({
id: z.string(),
})
)
.mutation(async ({ input }) => {
.mutation(async ({ input, ctx }) => {
const access = await getProjectAccess({
userId: ctx.session.userId,
projectId: input.id,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
await db.project.delete({
where: {
id: input.id,

View File

@@ -3,6 +3,8 @@ import { z } from 'zod';
import { db, getReferences } from '@openpanel/db';
import { zCreateReference, zRange } from '@openpanel/validation';
import { getProjectAccess } from '../access';
import { TRPCAccessError } from '../errors';
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
import { getChartStartEndDate } from './chart.helpers';
@@ -23,7 +25,22 @@ export const referenceRouter = createTRPCRouter({
),
delete: protectedProcedure
.input(z.object({ id: z.string() }))
.mutation(async ({ input: { id } }) => {
.mutation(async ({ input: { id }, ctx }) => {
const reference = await db.reference.findUniqueOrThrow({
where: {
id,
},
});
const access = await getProjectAccess({
userId: ctx.session.userId,
projectId: reference.projectId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
return db.reference.delete({
where: {
id,

View File

@@ -3,6 +3,8 @@ import { z } from 'zod';
import { db } from '@openpanel/db';
import { zReportInput } from '@openpanel/validation';
import { getProjectAccess } from '../access';
import { TRPCAccessError } from '../errors';
import { createTRPCRouter, protectedProcedure } from '../trpc';
export const reportRouter = createTRPCRouter({
@@ -13,12 +15,22 @@ export const reportRouter = createTRPCRouter({
dashboardId: z.string(),
})
)
.mutation(async ({ input: { report, dashboardId } }) => {
.mutation(async ({ input: { report, dashboardId }, ctx }) => {
const dashboard = await db.dashboard.findUniqueOrThrow({
where: {
id: dashboardId,
},
});
const access = await getProjectAccess({
userId: ctx.session.userId,
projectId: dashboard.projectId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
return db.report.create({
data: {
projectId: dashboard.projectId,
@@ -42,7 +54,22 @@ export const reportRouter = createTRPCRouter({
report: zReportInput.omit({ projectId: true }),
})
)
.mutation(({ input: { report, reportId } }) => {
.mutation(async ({ input: { report, reportId }, ctx }) => {
const dbReport = await db.report.findUniqueOrThrow({
where: {
id: reportId,
},
});
const access = await getProjectAccess({
userId: ctx.session.userId,
projectId: dbReport.projectId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
return db.report.update({
where: {
id: reportId,
@@ -66,7 +93,22 @@ export const reportRouter = createTRPCRouter({
reportId: z.string(),
})
)
.mutation(({ input: { reportId } }) => {
.mutation(async ({ input: { reportId }, ctx }) => {
const report = await db.report.findUniqueOrThrow({
where: {
id: reportId,
},
});
const access = await getProjectAccess({
userId: ctx.session.userId,
projectId: report.projectId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
return db.report.delete({
where: {
id: reportId,

View File

@@ -10,7 +10,7 @@ const uid = new ShortUniqueId({ length: 6 });
export const shareRouter = createTRPCRouter({
shareOverview: protectedProcedure
.input(zShareOverview)
.mutation(({ input }) => {
.mutation(async ({ input }) => {
return db.shareOverview.upsert({
where: {
projectId: input.projectId,