Add MVP version

This commit is contained in:
KMKoushik
2024-03-24 17:43:56 +11:00
parent 9032efa9b2
commit bbc64b5392
49 changed files with 3249 additions and 298 deletions

View File

@@ -0,0 +1,59 @@
import { ApiPermission } from "@prisma/client";
import { db } from "../db";
import { randomBytes } from "crypto";
import { hashToken } from "../auth";
export async function addApiKey({
name,
permission,
teamId,
}: {
name: string;
permission: ApiPermission;
teamId: number;
}) {
try {
const token = `us_${randomBytes(20).toString("hex")}`;
const hashedToken = hashToken(token);
await db.apiKey.create({
data: {
name,
permission: permission,
teamId,
tokenHash: hashedToken,
partialToken: `${token.slice(0, 8)}...${token.slice(-5)}`,
},
});
return token;
} catch (error) {
console.error("Error adding API key:", error);
throw error;
}
}
export async function retrieveApiKey(token: string) {
const hashedToken = hashToken(token);
try {
const apiKey = await db.apiKey.findUnique({
where: {
tokenHash: hashedToken,
},
select: {
id: true,
name: true,
permission: true,
teamId: true,
partialToken: true,
},
});
if (!apiKey) {
throw new Error("API Key not found");
}
return apiKey;
} catch (error) {
console.error("Error retrieving API key:", error);
throw error;
}
}

View File

@@ -0,0 +1,38 @@
import { db } from "../db";
import { JsonValue } from "@prisma/client/runtime/library";
export class AppSettingsService {
private static cache: Record<string, JsonValue> = {};
public static async getSetting(key: string) {
if (!this.cache[key]) {
const setting = await db.appSetting.findUnique({
where: { key },
});
if (setting) {
this.cache[key] = setting.value;
} else {
return null;
}
}
return this.cache[key];
}
public static async setSetting(key: string, value: string) {
await db.appSetting.upsert({
where: { key },
update: { value },
create: { key, value },
});
this.cache[key] = value;
return value;
}
public static async initializeCache(): Promise<void> {
const settings = await db.appSetting.findMany();
settings.forEach((setting) => {
this.cache[setting.key] = setting.value;
});
}
}

View File

@@ -0,0 +1,69 @@
import { addDomain, getDomainIdentity } from "~/server/ses";
import { db } from "~/server/db";
export async function createDomain(teamId: number, name: string) {
console.log("Creating domain:", name);
const publicKey = await addDomain(name);
const domain = await db.domain.create({
data: {
name,
publicKey,
teamId,
},
});
return domain;
}
export async function getDomain(id: number) {
let domain = await db.domain.findUnique({
where: {
id,
},
});
if (!domain) {
throw new Error("Domain not found");
}
if (domain.status !== "SUCCESS") {
const domainIdentity = await getDomainIdentity(domain.name, domain.region);
const dkimStatus = domainIdentity.DkimAttributes?.Status;
const spfDetails = domainIdentity.MailFromAttributes?.MailFromDomainStatus;
const verificationError = domainIdentity.VerificationInfo?.ErrorType;
const verificationStatus = domainIdentity.VerificationStatus;
const lastCheckedTime =
domainIdentity.VerificationInfo?.LastCheckedTimestamp;
console.log(domainIdentity);
if (
domain.dkimStatus !== dkimStatus ||
domain.spfDetails !== spfDetails ||
domain.status !== verificationStatus
) {
domain = await db.domain.update({
where: {
id,
},
data: {
dkimStatus,
spfDetails,
status: verificationStatus ?? "NOT_STARTED",
},
});
}
return {
...domain,
dkimStatus,
spfDetails,
verificationError,
lastCheckedTime,
};
}
return domain;
}

View File

@@ -0,0 +1,49 @@
import { EmailContent } from "~/types";
import { db } from "../db";
import { sendEmailThroughSes } from "../ses";
export async function sendEmail(
emailContent: EmailContent & { teamId: number }
) {
const { to, from, subject, text, html, teamId } = emailContent;
const domains = await db.domain.findMany({ where: { teamId } });
const fromDomain = from.split("@")[1];
if (!fromDomain) {
throw new Error("From email is not valid");
}
const domain = domains.find((domain) => domain.name === fromDomain);
if (!domain) {
throw new Error("Domain not found. Add domain to unsend first");
}
if (domain.status !== "SUCCESS") {
throw new Error("Domain is not verified");
}
const messageId = await sendEmailThroughSes({
to,
from,
subject,
text,
html,
region: domain.region,
});
if (messageId) {
return await db.email.create({
data: {
to,
from,
subject,
text,
html,
id: messageId,
teamId,
domainId: domain.id,
},
});
}
}