Skip to content

Commit

Permalink
added webhooks for team create and delete (#140)
Browse files Browse the repository at this point in the history
* added webhooks for team create and delete

* moved to svix
  • Loading branch information
fomalhautb authored Jul 22, 2024
1 parent 8e2b864 commit ad2fd3e
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 224 deletions.
9 changes: 5 additions & 4 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
"@react-email/render": "^0.0.12",
"@react-email/tailwind": "^0.0.14",
"@sentry/nextjs": "^7.105.0",
"@stackframe/stack-shared": "workspace:*",
"@stackframe/stack-emails": "workspace:*",
"@stackframe/stack-shared": "workspace:*",
"@vercel/analytics": "^1.2.2",
"bcrypt": "^5.1.1",
"dotenv-cli": "^7.3.0",
Expand All @@ -48,18 +48,19 @@
"react-email": "2.1.0",
"server-only": "^0.0.1",
"sharp": "^0.32.6",
"svix": "^1.25.0",
"yaml": "^2.4.5",
"yup": "^1.4.0"
},
"devDependencies": {
"@types/bcrypt": "^5.0.2",
"@types/node": "^20.8.10",
"@types/nodemailer": "^6.4.14",
"chokidar-cli": "^3.0.0",
"@types/react": "^18.2.66",
"chokidar-cli": "^3.0.0",
"glob": "^10.4.1",
"prisma": "^5.9.1",
"rimraf": "^5.0.5",
"tsx": "^4.7.2",
"glob": "^10.4.1"
"tsx": "^4.7.2"
}
}
32 changes: 26 additions & 6 deletions apps/backend/src/app/api/v1/teams/crud.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ensureTeamMembershipExist } from "@/lib/db-checks";
import { isTeamSystemPermission, teamSystemPermissionStringToDBType } from "@/lib/permissions";
import { sendWebhooks } from "@/lib/webhooks";
import { prismaClient } from "@/prisma-client";
import { createCrudHandlers } from "@/route-handlers/crud-handler";
import { getIdFromUserIdOrMe } from "@/route-handlers/utils";
Expand All @@ -9,7 +10,8 @@ import { teamsCrud } from "@stackframe/stack-shared/dist/interface/crud/teams";
import { userIdOrMeSchema, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields";
import { StatusError, throwErr } from "@stackframe/stack-shared/dist/utils/errors";

function prismaToCrud(prisma: Prisma.TeamGetPayload<{}>) {

export function teamPrismaToCrud(prisma: Prisma.TeamGetPayload<{}>) {
return {
id: prisma.teamId,
display_name: prisma.displayName,
Expand Down Expand Up @@ -71,7 +73,17 @@ export const teamsCrudHandlers = createCrudHandlers(teamsCrud, {
return db;
});

return prismaToCrud(db);
await sendWebhooks({
type: "team.created",
projectId: auth.project.id,
data: {
team_id: db.teamId,
display_name: db.displayName,
by_user_id: auth.user?.id,
},
});

return teamPrismaToCrud(db);
},
onRead: async ({ params, auth }) => {
const db = await prismaClient.$transaction(async (tx) => {
Expand Down Expand Up @@ -99,7 +111,7 @@ export const teamsCrudHandlers = createCrudHandlers(teamsCrud, {
return db;
});

return prismaToCrud(db);
return teamPrismaToCrud(db);
},
onUpdate: async ({ params, auth, data }) => {
const db = await prismaClient.team.update({
Expand All @@ -115,17 +127,25 @@ export const teamsCrudHandlers = createCrudHandlers(teamsCrud, {
},
});

return prismaToCrud(db);
return teamPrismaToCrud(db);
},
onDelete: async ({ params, auth }) => {
const db = await prismaClient.team.delete({
await prismaClient.team.delete({
where: {
projectId_teamId: {
projectId: auth.project.id,
teamId: params.team_id,
},
},
});

await sendWebhooks({
type: "team.deleted",
projectId: auth.project.id,
data: {
team_id: params.team_id,
},
});
},
onList: async ({ query, auth }) => {
const userId = getIdFromUserIdOrMe(query.user_id, auth.user);
Expand All @@ -150,7 +170,7 @@ export const teamsCrudHandlers = createCrudHandlers(teamsCrud, {
});

return {
items: db.map(prismaToCrud),
items: db.map(teamPrismaToCrud),
is_paginated: false,
};
}
Expand Down
6 changes: 3 additions & 3 deletions apps/backend/src/app/api/v1/users/crud.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { getServerTeamFromDbType } from "@/lib/teams";
import { prismaClient } from "@/prisma-client";
import { createCrudHandlers } from "@/route-handlers/crud-handler";
import { BooleanTrue, Prisma } from "@prisma/client";
Expand All @@ -9,6 +8,7 @@ import { userIdOrMeSchema, yupObject, yupString } from "@stackframe/stack-shared
import { StackAssertionError, throwErr } from "@stackframe/stack-shared/dist/utils/errors";
import { hashPassword } from "@stackframe/stack-shared/dist/utils/password";
import { createLazyProxy } from "@stackframe/stack-shared/dist/utils/proxies";
import { teamPrismaToCrud } from "../teams/crud";

const fullInclude = {
projectUserOAuthAccounts: true,
Expand Down Expand Up @@ -46,7 +46,7 @@ const prismaToCrud = (prisma: Prisma.ProjectUserGetPayload<{ include: typeof ful
email: a.email,
})),
selected_team_id: selectedTeamMembers[0]?.teamId ?? null,
selected_team: selectedTeamMembers[0] ? getServerTeamFromDbType(selectedTeamMembers[0]?.team) : null,
selected_team: selectedTeamMembers[0] ? teamPrismaToCrud(selectedTeamMembers[0]?.team) : null,
};
};

Expand Down Expand Up @@ -177,7 +177,7 @@ export const usersCrudHandlers = createLazyProxy(() => createCrudHandlers(usersC
return prismaToCrud(db);
},
onDelete: async ({ auth, params }) => {
const db = await prismaClient.projectUser.delete({
await prismaClient.projectUser.delete({
where: {
projectId_projectUserId: {
projectId: auth.project.id,
Expand Down
166 changes: 0 additions & 166 deletions apps/backend/src/lib/teams.tsx

This file was deleted.

36 changes: 36 additions & 0 deletions apps/backend/src/lib/webhooks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { getEnvVariable } from "@stackframe/stack-shared/dist/utils/env";
import { captureError } from "@stackframe/stack-shared/dist/utils/errors";
import { Svix } from "svix";

export async function sendWebhooks(options: {
type: string,
projectId: string,
data: any,
}) {
try {
const dataString = getEnvVariable("STACK_WEBHOOK_DATA");
const apiKey = getEnvVariable("STACK_SVIX_API_KEY");
const svix = new Svix(apiKey);

if (!dataString) {
return;
}
const data = JSON.parse(dataString);
for (const { url, projectId } of data) {
if (projectId !== options.projectId) {
continue;
}

await svix.application.getOrCreate({ uid: projectId, name: projectId });
await svix.endpoint.create(projectId, { url });
await svix.message.create(projectId, {
eventType: options.type,
payload: {
data: options.data,
},
});
}
} catch (error) {
captureError("Failed to send webhook", error);
}
}
Loading

0 comments on commit ad2fd3e

Please sign in to comment.