Add MVP version
This commit is contained in:
59
apps/web/src/server/service/api-service.ts
Normal file
59
apps/web/src/server/service/api-service.ts
Normal 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;
|
||||
}
|
||||
}
|
38
apps/web/src/server/service/app-settings-service.ts
Normal file
38
apps/web/src/server/service/app-settings-service.ts
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
69
apps/web/src/server/service/domain-service.ts
Normal file
69
apps/web/src/server/service/domain-service.ts
Normal 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;
|
||||
}
|
49
apps/web/src/server/service/email-service.ts
Normal file
49
apps/web/src/server/service/email-service.ts
Normal 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,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user