159 lines
3.8 KiB
TypeScript
159 lines
3.8 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
import {
|
|
db,
|
|
getClientById,
|
|
getClientByIdCached,
|
|
getId,
|
|
getProjectByIdCached,
|
|
getProjectsByOrganizationId,
|
|
} from '@openpanel/db';
|
|
|
|
import { stripTrailingSlash } from '@openpanel/common';
|
|
import { zProject } from '@openpanel/validation';
|
|
import { addDays, addHours } from 'date-fns';
|
|
import { getProjectAccess } from '../access';
|
|
import { TRPCAccessError } from '../errors';
|
|
import { createTRPCRouter, protectedProcedure } from '../trpc';
|
|
|
|
export const projectRouter = createTRPCRouter({
|
|
list: protectedProcedure
|
|
.input(
|
|
z.object({
|
|
organizationId: z.string().nullable(),
|
|
}),
|
|
)
|
|
.query(async ({ input: { organizationId } }) => {
|
|
if (organizationId === null) return [];
|
|
return getProjectsByOrganizationId(organizationId);
|
|
}),
|
|
|
|
update: protectedProcedure
|
|
.input(zProject.partial())
|
|
.mutation(async ({ input, ctx }) => {
|
|
if (!input.id) {
|
|
throw new Error('Project ID is required to update a project');
|
|
}
|
|
|
|
const access = await getProjectAccess({
|
|
userId: ctx.session.userId,
|
|
projectId: input.id,
|
|
});
|
|
|
|
if (!access) {
|
|
throw TRPCAccessError('You do not have access to this project');
|
|
}
|
|
|
|
const res = await db.project.update({
|
|
where: {
|
|
id: input.id,
|
|
},
|
|
data: {
|
|
name: input.name,
|
|
crossDomain: input.crossDomain,
|
|
filters:
|
|
input.filters === undefined ? undefined : input.filters || [],
|
|
domain:
|
|
input.domain === undefined
|
|
? undefined
|
|
: input.domain
|
|
? stripTrailingSlash(input.domain)
|
|
: null,
|
|
cors:
|
|
input.cors === undefined
|
|
? undefined
|
|
: input.cors.map((c) => stripTrailingSlash(c)) || [],
|
|
},
|
|
include: {
|
|
clients: {
|
|
select: {
|
|
id: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
await Promise.all([
|
|
getProjectByIdCached.clear(input.id),
|
|
res.clients.map((client) => {
|
|
getClientByIdCached.clear(client.id);
|
|
}),
|
|
]);
|
|
return res;
|
|
}),
|
|
create: protectedProcedure
|
|
.input(
|
|
zProject.omit({ id: true }).merge(
|
|
z.object({
|
|
organizationId: z.string(),
|
|
}),
|
|
),
|
|
)
|
|
.mutation(async ({ input }) => {
|
|
return db.project.create({
|
|
data: {
|
|
id: await getId('project', input.name),
|
|
organizationId: input.organizationId,
|
|
name: input.name,
|
|
domain: input.domain,
|
|
cors: input.cors,
|
|
crossDomain: input.crossDomain,
|
|
filters: [],
|
|
},
|
|
});
|
|
}),
|
|
delete: protectedProcedure
|
|
.input(
|
|
z.object({
|
|
projectId: z.string(),
|
|
}),
|
|
)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const access = await getProjectAccess({
|
|
userId: ctx.session.userId,
|
|
projectId: input.projectId,
|
|
});
|
|
|
|
if (!access) {
|
|
throw TRPCAccessError('You do not have access to this project');
|
|
}
|
|
|
|
await db.project.update({
|
|
where: {
|
|
id: input.projectId,
|
|
},
|
|
data: {
|
|
deleteAt: addHours(new Date(), 24),
|
|
},
|
|
});
|
|
|
|
return true;
|
|
}),
|
|
cancelDeletion: protectedProcedure
|
|
.input(
|
|
z.object({
|
|
projectId: z.string(),
|
|
}),
|
|
)
|
|
.mutation(async ({ input, ctx }) => {
|
|
const access = await getProjectAccess({
|
|
userId: ctx.session.userId,
|
|
projectId: input.projectId,
|
|
});
|
|
|
|
if (!access) {
|
|
throw TRPCAccessError('You do not have access to this project');
|
|
}
|
|
|
|
await db.project.update({
|
|
where: {
|
|
id: input.projectId,
|
|
},
|
|
data: {
|
|
deleteAt: null,
|
|
},
|
|
});
|
|
|
|
return true;
|
|
}),
|
|
});
|