Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
KMKoushik committed Nov 1, 2024
1 parent 4838657 commit 82b747c
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 109 deletions.
8 changes: 3 additions & 5 deletions apps/web/src/server/api/routers/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ export const apiRouter = createTRPCRouter({
return keys;
}),

deleteApiKey: teamProcedure
.input(z.object({ id: z.number() }))
.mutation(async ({ input }) => {
return deleteApiKey(input.id);
}),
deleteApiKey: apiKeyProcedure.mutation(async ({ input }) => {
return deleteApiKey(input.id);
}),
});
92 changes: 42 additions & 50 deletions apps/web/src/server/api/routers/domain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
createTRPCRouter,
teamProcedure,
protectedProcedure,
domainProcedure,
} from "~/server/api/trpc";
import { db } from "~/server/db";
import {
Expand All @@ -27,14 +28,12 @@ export const domainRouter = createTRPCRouter({
return createDomain(ctx.team.id, input.name, input.region);
}),

startVerification: teamProcedure
.input(z.object({ id: z.number() }))
.mutation(async ({ ctx, input }) => {
await ctx.db.domain.update({
where: { id: input.id },
data: { isVerifying: true },
});
}),
startVerification: domainProcedure.mutation(async ({ ctx, input }) => {
await ctx.db.domain.update({
where: { id: input.id },
data: { isVerifying: true },
});
}),

domains: teamProcedure.query(async ({ ctx }) => {
const domains = await db.domain.findMany({
Expand All @@ -49,16 +48,13 @@ export const domainRouter = createTRPCRouter({
return domains;
}),

getDomain: teamProcedure
.input(z.object({ id: z.number() }))
.query(async ({ input }) => {
return getDomain(input.id);
}),
getDomain: domainProcedure.query(async ({ input }) => {
return getDomain(input.id);
}),

updateDomain: teamProcedure
updateDomain: domainProcedure
.input(
z.object({
id: z.number(),
clickTracking: z.boolean().optional(),
openTracking: z.boolean().optional(),
})
Expand All @@ -70,43 +66,39 @@ export const domainRouter = createTRPCRouter({
});
}),

deleteDomain: teamProcedure
.input(z.object({ id: z.number() }))
.mutation(async ({ input }) => {
await deleteDomain(input.id);
return { success: true };
}),

sendTestEmailFromDomain: teamProcedure
.input(z.object({ id: z.number() }))
.mutation(
async ({
ctx: {
session: { user },
team,
},
input,
}) => {
const domain = await db.domain.findFirst({
where: { id: input.id, teamId: team.id },
});
deleteDomain: domainProcedure.mutation(async ({ input }) => {
await deleteDomain(input.id);
return { success: true };
}),

if (!domain) {
throw new Error("Domain not found");
}
sendTestEmailFromDomain: domainProcedure.mutation(
async ({
ctx: {
session: { user },
team,
},
input,
}) => {
const domain = await db.domain.findFirst({
where: { id: input.id, teamId: team.id },
});

if (!user.email) {
throw new Error("User email not found");
}
if (!domain) {
throw new Error("Domain not found");
}

return sendEmail({
teamId: team.id,
to: user.email,
from: `hello@${domain.name}`,
subject: "Unsend test email",
text: "hello,\n\nUnsend is the best open source sending platform\n\ncheck out https://unsend.dev",
html: "<p>hello,</p><p>Unsend is the best open source sending platform<p><p>check out <a href='https://unsend.dev'>unsend.dev</a>",
});
if (!user.email) {
throw new Error("User email not found");
}
),

return sendEmail({
teamId: team.id,
to: user.email,
from: `hello@${domain.name}`,
subject: "Unsend test email",
text: "hello,\n\nUnsend is the best open source sending platform\n\ncheck out https://unsend.dev",
html: "<p>hello,</p><p>Unsend is the best open source sending platform<p><p>check out <a href='https://unsend.dev'>unsend.dev</a>",
});
}
),
});
72 changes: 36 additions & 36 deletions apps/web/src/server/api/routers/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import { EmailStatus } from "@prisma/client";
import { format, subDays } from "date-fns";
import { z } from "zod";

import { createTRPCRouter, teamProcedure } from "~/server/api/trpc";
import {
createTRPCRouter,
emailProcedure,
teamProcedure,
} from "~/server/api/trpc";
import { db } from "~/server/db";
import { cancelEmail, updateEmail } from "~/server/service/email-service";

Expand Down Expand Up @@ -167,43 +171,39 @@ export const emailRouter = createTRPCRouter({
return { emailStatusCounts, totalCount, emailDailyStatusCounts };
}),

getEmail: teamProcedure
.input(z.object({ id: z.string() }))
.query(async ({ input }) => {
const email = await db.email.findUnique({
where: {
id: input.id,
},
select: {
emailEvents: {
orderBy: {
status: "desc",
},
getEmail: emailProcedure.query(async ({ input }) => {
const email = await db.email.findUnique({
where: {
id: input.id,
},
select: {
emailEvents: {
orderBy: {
status: "desc",
},
id: true,
createdAt: true,
latestStatus: true,
subject: true,
to: true,
from: true,
domainId: true,
text: true,
html: true,
scheduledAt: true,
},
});

return email;
}),

cancelEmail: teamProcedure
.input(z.object({ id: z.string() }))
.mutation(async ({ input }) => {
await cancelEmail(input.id);
}),

updateEmailScheduledAt: teamProcedure
.input(z.object({ id: z.string(), scheduledAt: z.string().datetime() }))
id: true,
createdAt: true,
latestStatus: true,
subject: true,
to: true,
from: true,
domainId: true,
text: true,
html: true,
scheduledAt: true,
},
});

return email;
}),

cancelEmail: emailProcedure.mutation(async ({ input }) => {
await cancelEmail(input.id);
}),

updateEmailScheduledAt: emailProcedure
.input(z.object({ scheduledAt: z.string().datetime() }))
.mutation(async ({ input }) => {
await updateEmail(input.id, { scheduledAt: input.scheduledAt });
}),
Expand Down
57 changes: 41 additions & 16 deletions apps/web/src/server/api/trpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,45 @@ export const teamProcedure = protectedProcedure.use(async ({ ctx, next }) => {
});
});

export const domainProcedure = teamProcedure
.input(z.object({ id: z.number() }))
.use(async ({ ctx, next, input }) => {
const domain = await db.domain.findUnique({
where: { id: input.id, teamId: ctx.team.id },
});
if (!domain) {
throw new TRPCError({ code: "NOT_FOUND", message: "Domain not found" });
}

return next({ ctx: { ...ctx, domain } });
});

export const emailProcedure = teamProcedure
.input(z.object({ id: z.string() }))
.use(async ({ ctx, next, input }) => {
const email = await db.email.findUnique({
where: { id: input.id, teamId: ctx.team.id },
});
if (!email) {
throw new TRPCError({ code: "NOT_FOUND", message: "Email not found" });
}

return next({ ctx: { ...ctx, email } });
});

export const apiKeyProcedure = teamProcedure
.input(z.object({ id: z.number() }))
.use(async ({ ctx, next, input }) => {
const apiKey = await db.apiKey.findUnique({
where: { id: input.id, teamId: ctx.team.id },
});
if (!apiKey) {
throw new TRPCError({ code: "NOT_FOUND", message: "API key not found" });
}

return next({ ctx: { ...ctx, apiKey } });
});

export const contactBookProcedure = teamProcedure
.input(
z.object({
Expand All @@ -133,7 +172,7 @@ export const contactBookProcedure = teamProcedure
)
.use(async ({ ctx, next, input }) => {
const contactBook = await db.contactBook.findUnique({
where: { id: input.contactBookId },
where: { id: input.contactBookId, teamId: ctx.team.id },
});
if (!contactBook) {
throw new TRPCError({
Expand All @@ -142,13 +181,6 @@ export const contactBookProcedure = teamProcedure
});
}

if (contactBook.teamId !== ctx.team.id) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this contact book",
});
}

return next({ ctx: { ...ctx, contactBook } });
});

Expand All @@ -160,7 +192,7 @@ export const campaignProcedure = teamProcedure
)
.use(async ({ ctx, next, input }) => {
const campaign = await db.campaign.findUnique({
where: { id: input.campaignId },
where: { id: input.campaignId, teamId: ctx.team.id },
});
if (!campaign) {
throw new TRPCError({
Expand All @@ -169,13 +201,6 @@ export const campaignProcedure = teamProcedure
});
}

if (campaign.teamId !== ctx.team.id) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this campaign",
});
}

return next({ ctx: { ...ctx, campaign } });
});

Expand Down
8 changes: 8 additions & 0 deletions apps/web/src/server/public-api/api-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,11 @@ export const getContactBook = async (c: Context, teamId: number) => {

return contactBook;
};

export const checkIsValidEmailId = async (emailId: string, teamId: number) => {
const email = await db.email.findUnique({ where: { id: emailId, teamId } });

if (!email) {
throw new UnsendApiError({ code: "NOT_FOUND", message: "Email not found" });
}
};
4 changes: 3 additions & 1 deletion apps/web/src/server/public-api/api/emails/cancel-email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createRoute, z } from "@hono/zod-openapi";
import { PublicAPIApp } from "~/server/public-api/hono";
import { getTeamFromToken } from "~/server/public-api/auth";
import { cancelEmail } from "~/server/service/email-service";
import { checkIsValidEmailId } from "../../api-utils";

const route = createRoute({
method: "post",
Expand Down Expand Up @@ -34,8 +35,9 @@ const route = createRoute({

function cancelScheduledEmail(app: PublicAPIApp) {
app.openapi(route, async (c) => {
await getTeamFromToken(c);
const team = await getTeamFromToken(c);
const emailId = c.req.param("emailId");
await checkIsValidEmailId(emailId, team.id);

await cancelEmail(emailId);

Expand Down
5 changes: 4 additions & 1 deletion apps/web/src/server/public-api/api/emails/update-email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createRoute, z } from "@hono/zod-openapi";
import { PublicAPIApp } from "~/server/public-api/hono";
import { getTeamFromToken } from "~/server/public-api/auth";
import { updateEmail } from "~/server/service/email-service";
import { checkIsValidEmailId } from "../../api-utils";

const route = createRoute({
method: "patch",
Expand Down Expand Up @@ -44,9 +45,11 @@ const route = createRoute({

function updateEmailScheduledAt(app: PublicAPIApp) {
app.openapi(route, async (c) => {
await getTeamFromToken(c);
const team = await getTeamFromToken(c);
const emailId = c.req.param("emailId");

await checkIsValidEmailId(emailId, team.id);

await updateEmail(emailId, {
scheduledAt: c.req.valid("json").scheduledAt,
});
Expand Down

0 comments on commit 82b747c

Please sign in to comment.