feat: add list emails api (#167)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
export const DEFAULT_QUERY_LIMIT = 30;
|
||||
export const DEFAULT_QUERY_LIMIT = 50;
|
||||
|
||||
/* Reputation constants */
|
||||
export const HARD_BOUNCE_WARNING_RATE = 5;
|
||||
|
170
apps/web/src/server/public-api/api/emails/list-emails.ts
Normal file
170
apps/web/src/server/public-api/api/emails/list-emails.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import { createRoute, z } from "@hono/zod-openapi";
|
||||
import { PublicAPIApp } from "~/server/public-api/hono";
|
||||
import { db } from "~/server/db";
|
||||
import { EmailStatus, Prisma } from "@prisma/client";
|
||||
import { DEFAULT_QUERY_LIMIT } from "~/lib/constants";
|
||||
|
||||
const EmailSchema = z.object({
|
||||
id: z.string(),
|
||||
to: z.string().or(z.array(z.string())),
|
||||
replyTo: z.string().or(z.array(z.string())).optional().nullable(),
|
||||
cc: z.string().or(z.array(z.string())).optional().nullable(),
|
||||
bcc: z.string().or(z.array(z.string())).optional().nullable(),
|
||||
from: z.string(),
|
||||
subject: z.string(),
|
||||
html: z.string().nullable(),
|
||||
text: z.string().nullable(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
latestStatus: z.nativeEnum(EmailStatus).nullable(),
|
||||
scheduledAt: z.string().datetime().nullable(),
|
||||
domainId: z.number().nullable(),
|
||||
});
|
||||
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
path: "/v1/emails",
|
||||
request: {
|
||||
query: z.object({
|
||||
page: z
|
||||
.string()
|
||||
.optional()
|
||||
.default("1")
|
||||
.transform(Number)
|
||||
.openapi({
|
||||
param: {
|
||||
name: "page",
|
||||
in: "query",
|
||||
},
|
||||
example: "1",
|
||||
}),
|
||||
limit: z
|
||||
.string()
|
||||
.optional()
|
||||
.default(String(DEFAULT_QUERY_LIMIT))
|
||||
.pipe(z.coerce.number().min(1).max(DEFAULT_QUERY_LIMIT))
|
||||
.openapi({
|
||||
param: {
|
||||
name: "limit",
|
||||
in: "query",
|
||||
},
|
||||
example: String(DEFAULT_QUERY_LIMIT),
|
||||
}),
|
||||
startDate: z
|
||||
.string()
|
||||
.datetime()
|
||||
.optional()
|
||||
.openapi({
|
||||
param: {
|
||||
name: "startDate",
|
||||
in: "query",
|
||||
},
|
||||
example: "2024-01-01T00:00:00Z",
|
||||
}),
|
||||
endDate: z
|
||||
.string()
|
||||
.datetime()
|
||||
.optional()
|
||||
.openapi({
|
||||
param: {
|
||||
name: "endDate",
|
||||
in: "query",
|
||||
},
|
||||
example: "2024-01-31T23:59:59Z",
|
||||
}),
|
||||
domainId: z
|
||||
.union([z.string(), z.array(z.string())])
|
||||
.optional()
|
||||
.transform((val) => {
|
||||
if (!val) return undefined;
|
||||
return (Array.isArray(val) ? val : [val]).map(Number);
|
||||
})
|
||||
.openapi({
|
||||
param: {
|
||||
name: "domainId",
|
||||
in: "query",
|
||||
},
|
||||
example: "123", // or ["123", "456"]
|
||||
}),
|
||||
}),
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
data: z.array(EmailSchema),
|
||||
count: z.number(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
description: "Retrieve a list of emails",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
function listEmails(app: PublicAPIApp) {
|
||||
app.openapi(route, async (c) => {
|
||||
const team = c.var.team;
|
||||
const { page, limit, startDate, endDate, domainId } = c.req.valid("query");
|
||||
|
||||
const whereClause: Prisma.EmailWhereInput = {
|
||||
teamId: team.id,
|
||||
};
|
||||
|
||||
if (startDate) {
|
||||
whereClause.createdAt = {
|
||||
gte: new Date(startDate),
|
||||
};
|
||||
}
|
||||
if (endDate) {
|
||||
whereClause.createdAt = {
|
||||
lte: new Date(endDate),
|
||||
};
|
||||
}
|
||||
|
||||
if (domainId && domainId.length > 0) {
|
||||
whereClause.domainId = { in: domainId };
|
||||
}
|
||||
|
||||
const [emails, count] = await db.$transaction([
|
||||
db.email.findMany({
|
||||
where: whereClause,
|
||||
select: {
|
||||
id: true,
|
||||
to: true,
|
||||
replyTo: true,
|
||||
cc: true,
|
||||
bcc: true,
|
||||
from: true,
|
||||
subject: true,
|
||||
html: true,
|
||||
text: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
latestStatus: true,
|
||||
scheduledAt: true,
|
||||
domainId: true,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
skip: (page - 1) * limit,
|
||||
take: limit,
|
||||
}),
|
||||
db.email.count({ where: whereClause }),
|
||||
]);
|
||||
|
||||
return c.json({
|
||||
data: emails.map((email) => ({
|
||||
...email,
|
||||
createdAt: email.createdAt.toISOString(),
|
||||
updatedAt: email.updatedAt.toISOString(),
|
||||
scheduledAt: email.scheduledAt ? email.scheduledAt.toISOString() : null,
|
||||
})),
|
||||
count,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default listEmails;
|
@@ -2,6 +2,7 @@ import { getApp } from "./hono";
|
||||
import getDomains from "./api/domains/get-domains";
|
||||
import sendEmail from "./api/emails/send-email";
|
||||
import getEmail from "./api/emails/get-email";
|
||||
import listEmails from "./api/emails/list-emails";
|
||||
import addContact from "./api/contacts/add-contact";
|
||||
import updateContactInfo from "./api/contacts/update-contact";
|
||||
import getContact from "./api/contacts/get-contact";
|
||||
@@ -23,6 +24,7 @@ verifyDomain(app);
|
||||
|
||||
/**Email related APIs */
|
||||
getEmail(app);
|
||||
listEmails(app);
|
||||
sendEmail(app);
|
||||
sendBatch(app);
|
||||
updateEmailScheduledAt(app);
|
||||
|
Reference in New Issue
Block a user