refactor(server): remove files
2
apps/dokploy/emails/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
/node_modules
|
|
||||||
/dist
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
import {
|
|
||||||
Body,
|
|
||||||
Button,
|
|
||||||
Container,
|
|
||||||
Head,
|
|
||||||
Heading,
|
|
||||||
Html,
|
|
||||||
Img,
|
|
||||||
Link,
|
|
||||||
Preview,
|
|
||||||
Section,
|
|
||||||
Tailwind,
|
|
||||||
Text,
|
|
||||||
} from "@react-email/components";
|
|
||||||
import * as React from "react";
|
|
||||||
|
|
||||||
export type TemplateProps = {
|
|
||||||
projectName: string;
|
|
||||||
applicationName: string;
|
|
||||||
applicationType: string;
|
|
||||||
errorMessage: string;
|
|
||||||
buildLink: string;
|
|
||||||
date: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const BuildFailedEmail = ({
|
|
||||||
projectName = "dokploy",
|
|
||||||
applicationName = "frontend",
|
|
||||||
applicationType = "application",
|
|
||||||
errorMessage = "Error array.length is not a function",
|
|
||||||
buildLink = "https://dokploy.com/projects/dokploy-test/applications/dokploy-test",
|
|
||||||
date = "2023-05-01T00:00:00.000Z",
|
|
||||||
}: TemplateProps) => {
|
|
||||||
const previewText = `Build failed for ${applicationName}`;
|
|
||||||
return (
|
|
||||||
<Html>
|
|
||||||
<Head />
|
|
||||||
<Preview>{previewText}</Preview>
|
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: {
|
|
||||||
brand: "#007291",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="bg-white my-auto mx-auto font-sans px-2">
|
|
||||||
<Container className="border border-solid border-[#eaeaea] rounded-lg my-[40px] mx-auto p-[20px] max-w-[465px]">
|
|
||||||
<Section className="mt-[32px]">
|
|
||||||
<Img
|
|
||||||
src={
|
|
||||||
"https://raw.githubusercontent.com/Dokploy/dokploy/canary/logo.png"
|
|
||||||
}
|
|
||||||
width="100"
|
|
||||||
height="50"
|
|
||||||
alt="Dokploy"
|
|
||||||
className="my-0 mx-auto"
|
|
||||||
/>
|
|
||||||
</Section>
|
|
||||||
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
|
|
||||||
Build failed for <strong>{applicationName}</strong>
|
|
||||||
</Heading>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
Hello,
|
|
||||||
</Text>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
Your build for <strong>{applicationName}</strong> failed. Please
|
|
||||||
check the error message below.
|
|
||||||
</Text>
|
|
||||||
<Section className="flex text-black text-[14px] leading-[24px] bg-[#F4F4F5] rounded-lg p-2">
|
|
||||||
<Text className="!leading-3 font-bold">Details: </Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Project Name: <strong>{projectName}</strong>
|
|
||||||
</Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Application Name: <strong>{applicationName}</strong>
|
|
||||||
</Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Application Type: <strong>{applicationType}</strong>
|
|
||||||
</Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Date: <strong>{date}</strong>
|
|
||||||
</Text>
|
|
||||||
</Section>
|
|
||||||
<Section className="flex text-black text-[14px] mt-4 leading-[24px] bg-[#F4F4F5] rounded-lg p-2">
|
|
||||||
<Text className="!leading-3 font-bold">Reason: </Text>
|
|
||||||
<Text className="text-[12px] leading-[24px]">{errorMessage}</Text>
|
|
||||||
</Section>
|
|
||||||
<Section className="text-center mt-[32px] mb-[32px]">
|
|
||||||
<Button
|
|
||||||
href={buildLink}
|
|
||||||
className="bg-[#000000] rounded text-white text-[12px] font-semibold no-underline text-center px-5 py-3"
|
|
||||||
>
|
|
||||||
View build
|
|
||||||
</Button>
|
|
||||||
</Section>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
or copy and paste this URL into your browser:{" "}
|
|
||||||
<Link href={buildLink} className="text-blue-600 no-underline">
|
|
||||||
{buildLink}
|
|
||||||
</Link>
|
|
||||||
</Text>
|
|
||||||
</Container>
|
|
||||||
</Body>
|
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default BuildFailedEmail;
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
import {
|
|
||||||
Body,
|
|
||||||
Button,
|
|
||||||
Container,
|
|
||||||
Head,
|
|
||||||
Heading,
|
|
||||||
Html,
|
|
||||||
Img,
|
|
||||||
Link,
|
|
||||||
Preview,
|
|
||||||
Section,
|
|
||||||
Tailwind,
|
|
||||||
Text,
|
|
||||||
} from "@react-email/components";
|
|
||||||
import * as React from "react";
|
|
||||||
|
|
||||||
export type TemplateProps = {
|
|
||||||
projectName: string;
|
|
||||||
applicationName: string;
|
|
||||||
applicationType: string;
|
|
||||||
buildLink: string;
|
|
||||||
date: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const BuildSuccessEmail = ({
|
|
||||||
projectName = "dokploy",
|
|
||||||
applicationName = "frontend",
|
|
||||||
applicationType = "application",
|
|
||||||
buildLink = "https://dokploy.com/projects/dokploy-test/applications/dokploy-test",
|
|
||||||
date = "2023-05-01T00:00:00.000Z",
|
|
||||||
}: TemplateProps) => {
|
|
||||||
const previewText = `Build success for ${applicationName}`;
|
|
||||||
return (
|
|
||||||
<Html>
|
|
||||||
<Head />
|
|
||||||
<Preview>{previewText}</Preview>
|
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: {
|
|
||||||
brand: "#007291",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="bg-white my-auto mx-auto font-sans px-2">
|
|
||||||
<Container className="border border-solid border-[#eaeaea] rounded-lg my-[40px] mx-auto p-[20px] max-w-[465px]">
|
|
||||||
<Section className="mt-[32px]">
|
|
||||||
<Img
|
|
||||||
src={
|
|
||||||
"https://raw.githubusercontent.com/Dokploy/dokploy/canary/logo.png"
|
|
||||||
}
|
|
||||||
width="100"
|
|
||||||
height="50"
|
|
||||||
alt="Dokploy"
|
|
||||||
className="my-0 mx-auto"
|
|
||||||
/>
|
|
||||||
</Section>
|
|
||||||
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
|
|
||||||
Build success for <strong>{applicationName}</strong>
|
|
||||||
</Heading>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
Hello,
|
|
||||||
</Text>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
Your build for <strong>{applicationName}</strong> was successful
|
|
||||||
</Text>
|
|
||||||
<Section className="flex text-black text-[14px] leading-[24px] bg-[#F4F4F5] rounded-lg p-2">
|
|
||||||
<Text className="!leading-3 font-bold">Details: </Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Project Name: <strong>{projectName}</strong>
|
|
||||||
</Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Application Name: <strong>{applicationName}</strong>
|
|
||||||
</Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Application Type: <strong>{applicationType}</strong>
|
|
||||||
</Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Date: <strong>{date}</strong>
|
|
||||||
</Text>
|
|
||||||
</Section>
|
|
||||||
<Section className="text-center mt-[32px] mb-[32px]">
|
|
||||||
<Button
|
|
||||||
href={buildLink}
|
|
||||||
className="bg-[#000000] rounded text-white text-[12px] font-semibold no-underline text-center px-5 py-3"
|
|
||||||
>
|
|
||||||
View build
|
|
||||||
</Button>
|
|
||||||
</Section>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
or copy and paste this URL into your browser:{" "}
|
|
||||||
<Link href={buildLink} className="text-blue-600 no-underline">
|
|
||||||
{buildLink}
|
|
||||||
</Link>
|
|
||||||
</Text>
|
|
||||||
</Container>
|
|
||||||
</Body>
|
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default BuildSuccessEmail;
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
import {
|
|
||||||
Body,
|
|
||||||
Container,
|
|
||||||
Head,
|
|
||||||
Heading,
|
|
||||||
Html,
|
|
||||||
Img,
|
|
||||||
Preview,
|
|
||||||
Section,
|
|
||||||
Tailwind,
|
|
||||||
Text,
|
|
||||||
} from "@react-email/components";
|
|
||||||
import * as React from "react";
|
|
||||||
|
|
||||||
export type TemplateProps = {
|
|
||||||
projectName: string;
|
|
||||||
applicationName: string;
|
|
||||||
databaseType: "postgres" | "mysql" | "mongodb" | "mariadb";
|
|
||||||
type: "error" | "success";
|
|
||||||
errorMessage?: string;
|
|
||||||
date: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DatabaseBackupEmail = ({
|
|
||||||
projectName = "dokploy",
|
|
||||||
applicationName = "frontend",
|
|
||||||
databaseType = "postgres",
|
|
||||||
type = "success",
|
|
||||||
errorMessage,
|
|
||||||
date = "2023-05-01T00:00:00.000Z",
|
|
||||||
}: TemplateProps) => {
|
|
||||||
const previewText = `Database backup for ${applicationName} was ${type === "success" ? "successful ✅" : "failed ❌"}`;
|
|
||||||
return (
|
|
||||||
<Html>
|
|
||||||
<Preview>{previewText}</Preview>
|
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: {
|
|
||||||
brand: "#007291",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Head />
|
|
||||||
|
|
||||||
<Body className="bg-white my-auto mx-auto font-sans px-2">
|
|
||||||
<Container className="border border-solid border-[#eaeaea] rounded-lg my-[40px] mx-auto p-[20px] max-w-[465px]">
|
|
||||||
<Section className="mt-[32px]">
|
|
||||||
<Img
|
|
||||||
src={
|
|
||||||
"https://raw.githubusercontent.com/Dokploy/dokploy/canary/logo.png"
|
|
||||||
}
|
|
||||||
width="100"
|
|
||||||
height="50"
|
|
||||||
alt="Dokploy"
|
|
||||||
className="my-0 mx-auto"
|
|
||||||
/>
|
|
||||||
</Section>
|
|
||||||
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
|
|
||||||
Database backup for <strong>{applicationName}</strong>
|
|
||||||
</Heading>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
Hello,
|
|
||||||
</Text>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
Your database backup for <strong>{applicationName}</strong> was{" "}
|
|
||||||
{type === "success"
|
|
||||||
? "successful ✅"
|
|
||||||
: "failed Please check the error message below. ❌"}
|
|
||||||
.
|
|
||||||
</Text>
|
|
||||||
<Section className="flex text-black text-[14px] leading-[24px] bg-[#F4F4F5] rounded-lg p-2">
|
|
||||||
<Text className="!leading-3 font-bold">Details: </Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Project Name: <strong>{projectName}</strong>
|
|
||||||
</Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Application Name: <strong>{applicationName}</strong>
|
|
||||||
</Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Database Type: <strong>{databaseType}</strong>
|
|
||||||
</Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Date: <strong>{date}</strong>
|
|
||||||
</Text>
|
|
||||||
</Section>
|
|
||||||
{type === "error" && errorMessage ? (
|
|
||||||
<Section className="flex text-black text-[14px] mt-4 leading-[24px] bg-[#F4F4F5] rounded-lg p-2">
|
|
||||||
<Text className="!leading-3 font-bold">Reason: </Text>
|
|
||||||
<Text className="text-[12px] leading-[24px]">
|
|
||||||
{errorMessage || "Error message not provided"}
|
|
||||||
</Text>
|
|
||||||
</Section>
|
|
||||||
) : null}
|
|
||||||
</Container>
|
|
||||||
</Body>
|
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DatabaseBackupEmail;
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
import {
|
|
||||||
Body,
|
|
||||||
Button,
|
|
||||||
Container,
|
|
||||||
Head,
|
|
||||||
Heading,
|
|
||||||
Html,
|
|
||||||
Img,
|
|
||||||
Preview,
|
|
||||||
Section,
|
|
||||||
Tailwind,
|
|
||||||
Text,
|
|
||||||
} from "@react-email/components";
|
|
||||||
import * as React from "react";
|
|
||||||
|
|
||||||
export type TemplateProps = {
|
|
||||||
message: string;
|
|
||||||
date: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DockerCleanupEmail = ({
|
|
||||||
message = "Docker cleanup for dokploy",
|
|
||||||
date = "2023-05-01T00:00:00.000Z",
|
|
||||||
}: TemplateProps) => {
|
|
||||||
const previewText = "Docker cleanup for dokploy";
|
|
||||||
return (
|
|
||||||
<Html>
|
|
||||||
<Preview>{previewText}</Preview>
|
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: {
|
|
||||||
brand: "#007291",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Head />
|
|
||||||
|
|
||||||
<Body className="bg-white my-auto mx-auto font-sans px-2">
|
|
||||||
<Container className="border border-solid border-[#eaeaea] rounded-lg my-[40px] mx-auto p-[20px] max-w-[465px]">
|
|
||||||
<Section className="mt-[32px]">
|
|
||||||
<Img
|
|
||||||
src={
|
|
||||||
"https://raw.githubusercontent.com/Dokploy/dokploy/canary/logo.png"
|
|
||||||
}
|
|
||||||
width="100"
|
|
||||||
height="50"
|
|
||||||
alt="Dokploy"
|
|
||||||
className="my-0 mx-auto"
|
|
||||||
/>
|
|
||||||
</Section>
|
|
||||||
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
|
|
||||||
Docker cleanup for <strong>dokploy</strong>
|
|
||||||
</Heading>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
Hello,
|
|
||||||
</Text>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
The docker cleanup for <strong>dokploy</strong> was successful ✅
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Section className="flex text-black text-[14px] leading-[24px] bg-[#F4F4F5] rounded-lg p-2">
|
|
||||||
<Text className="!leading-3 font-bold">Details: </Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Message: <strong>{message}</strong>
|
|
||||||
</Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Date: <strong>{date}</strong>
|
|
||||||
</Text>
|
|
||||||
</Section>
|
|
||||||
</Container>
|
|
||||||
</Body>
|
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DockerCleanupEmail;
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
import {
|
|
||||||
Body,
|
|
||||||
Container,
|
|
||||||
Head,
|
|
||||||
Heading,
|
|
||||||
Html,
|
|
||||||
Img,
|
|
||||||
Preview,
|
|
||||||
Section,
|
|
||||||
Tailwind,
|
|
||||||
Text,
|
|
||||||
} from "@react-email/components";
|
|
||||||
import * as React from "react";
|
|
||||||
|
|
||||||
export type TemplateProps = {
|
|
||||||
date: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DokployRestartEmail = ({
|
|
||||||
date = "2023-05-01T00:00:00.000Z",
|
|
||||||
}: TemplateProps) => {
|
|
||||||
const previewText = "Your dokploy server was restarted";
|
|
||||||
return (
|
|
||||||
<Html>
|
|
||||||
<Preview>{previewText}</Preview>
|
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: {
|
|
||||||
brand: "#007291",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Head />
|
|
||||||
|
|
||||||
<Body className="bg-white my-auto mx-auto font-sans px-2">
|
|
||||||
<Container className="border border-solid border-[#eaeaea] rounded-lg my-[40px] mx-auto p-[20px] max-w-[465px]">
|
|
||||||
<Section className="mt-[32px]">
|
|
||||||
<Img
|
|
||||||
src={
|
|
||||||
"https://raw.githubusercontent.com/Dokploy/dokploy/canary/logo.png"
|
|
||||||
}
|
|
||||||
width="100"
|
|
||||||
height="50"
|
|
||||||
alt="Dokploy"
|
|
||||||
className="my-0 mx-auto"
|
|
||||||
/>
|
|
||||||
</Section>
|
|
||||||
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
|
|
||||||
Dokploy Server Restart
|
|
||||||
</Heading>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
Hello,
|
|
||||||
</Text>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
Your dokploy server was restarted ✅
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Section className="flex text-black text-[14px] leading-[24px] bg-[#F4F4F5] rounded-lg p-2">
|
|
||||||
<Text className="!leading-3 font-bold">Details: </Text>
|
|
||||||
<Text className="!leading-3">
|
|
||||||
Date: <strong>{date}</strong>
|
|
||||||
</Text>
|
|
||||||
</Section>
|
|
||||||
</Container>
|
|
||||||
</Body>
|
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DokployRestartEmail;
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
import {
|
|
||||||
Body,
|
|
||||||
Button,
|
|
||||||
Container,
|
|
||||||
Head,
|
|
||||||
Heading,
|
|
||||||
Hr,
|
|
||||||
Html,
|
|
||||||
Img,
|
|
||||||
Link,
|
|
||||||
Preview,
|
|
||||||
Section,
|
|
||||||
Tailwind,
|
|
||||||
Text,
|
|
||||||
} from "@react-email/components";
|
|
||||||
|
|
||||||
export type TemplateProps = {
|
|
||||||
email: string;
|
|
||||||
name: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface VercelInviteUserEmailProps {
|
|
||||||
inviteLink: string;
|
|
||||||
toEmail: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const InvitationEmail = ({
|
|
||||||
inviteLink,
|
|
||||||
toEmail,
|
|
||||||
}: VercelInviteUserEmailProps) => {
|
|
||||||
const previewText = "Join to Dokploy";
|
|
||||||
return (
|
|
||||||
<Html>
|
|
||||||
<Head />
|
|
||||||
<Preview>{previewText}</Preview>
|
|
||||||
<Tailwind
|
|
||||||
config={{
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
colors: {
|
|
||||||
brand: "#007291",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Body className="bg-white my-auto mx-auto font-sans px-2">
|
|
||||||
<Container className="border border-solid border-[#eaeaea] rounded-lg my-[40px] mx-auto p-[20px] max-w-[465px]">
|
|
||||||
<Section className="mt-[32px]">
|
|
||||||
<Img
|
|
||||||
src={
|
|
||||||
"https://raw.githubusercontent.com/Dokploy/dokploy/canary/logo.png"
|
|
||||||
}
|
|
||||||
width="100"
|
|
||||||
height="50"
|
|
||||||
alt="Dokploy"
|
|
||||||
className="my-0 mx-auto"
|
|
||||||
/>
|
|
||||||
</Section>
|
|
||||||
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
|
|
||||||
Join to <strong>Dokploy</strong>
|
|
||||||
</Heading>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
Hello,
|
|
||||||
</Text>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
You have been invited to join <strong>Dokploy</strong>, a platform
|
|
||||||
that helps for deploying your apps to the cloud.
|
|
||||||
</Text>
|
|
||||||
<Section className="text-center mt-[32px] mb-[32px]">
|
|
||||||
<Button
|
|
||||||
href={inviteLink}
|
|
||||||
className="bg-[#000000] rounded text-white text-[12px] font-semibold no-underline text-center px-5 py-3"
|
|
||||||
>
|
|
||||||
Join the team 🚀
|
|
||||||
</Button>
|
|
||||||
</Section>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
or copy and paste this URL into your browser:{" "}
|
|
||||||
<Link href={inviteLink} className="text-blue-600 no-underline">
|
|
||||||
https://dokploy.com
|
|
||||||
</Link>
|
|
||||||
</Text>
|
|
||||||
<Hr className="border border-solid border-[#eaeaea] my-[26px] mx-0 w-full" />
|
|
||||||
<Text className="text-[#666666] text-[12px] leading-[24px]">
|
|
||||||
This invitation was intended for {toEmail}. This invite was sent
|
|
||||||
from <strong className="text-black">dokploy.com</strong>. If you
|
|
||||||
were not expecting this invitation, you can ignore this email. If
|
|
||||||
you are concerned about your account's safety, please reply to
|
|
||||||
</Text>
|
|
||||||
</Container>
|
|
||||||
</Body>
|
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default InvitationEmail;
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
import {
|
|
||||||
Body,
|
|
||||||
Container,
|
|
||||||
Head,
|
|
||||||
Heading,
|
|
||||||
Html,
|
|
||||||
Img,
|
|
||||||
Link,
|
|
||||||
Preview,
|
|
||||||
Text,
|
|
||||||
} from "@react-email/components";
|
|
||||||
import * as React from "react";
|
|
||||||
|
|
||||||
interface NotionMagicLinkEmailProps {
|
|
||||||
loginCode?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseUrl = process.env.VERCEL_URL
|
|
||||||
? `https://${process.env.VERCEL_URL}`
|
|
||||||
: "";
|
|
||||||
|
|
||||||
export const NotionMagicLinkEmail = ({
|
|
||||||
loginCode,
|
|
||||||
}: NotionMagicLinkEmailProps) => (
|
|
||||||
<Html>
|
|
||||||
<Head />
|
|
||||||
<Preview>Log in with this magic link</Preview>
|
|
||||||
<Body style={main}>
|
|
||||||
<Container style={container}>
|
|
||||||
<Heading style={h1}>Login</Heading>
|
|
||||||
<Link
|
|
||||||
href="https://notion.so"
|
|
||||||
target="_blank"
|
|
||||||
style={{
|
|
||||||
...link,
|
|
||||||
display: "block",
|
|
||||||
marginBottom: "16px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Click here to log in with this magic link
|
|
||||||
</Link>
|
|
||||||
<Text style={{ ...text, marginBottom: "14px" }}>
|
|
||||||
Or, copy and paste this temporary login code:
|
|
||||||
</Text>
|
|
||||||
<code style={code}>{loginCode}</code>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
...text,
|
|
||||||
color: "#ababab",
|
|
||||||
marginTop: "14px",
|
|
||||||
marginBottom: "16px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
If you didn't try to login, you can safely ignore this email.
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
style={{
|
|
||||||
...text,
|
|
||||||
color: "#ababab",
|
|
||||||
marginTop: "12px",
|
|
||||||
marginBottom: "38px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Hint: You can set a permanent password in Settings & members → My
|
|
||||||
account.
|
|
||||||
</Text>
|
|
||||||
<Img
|
|
||||||
src={`${baseUrl}/static/notion-logo.png`}
|
|
||||||
width="32"
|
|
||||||
height="32"
|
|
||||||
alt="Notion's Logo"
|
|
||||||
/>
|
|
||||||
<Text style={footer}>
|
|
||||||
<Link
|
|
||||||
href="https://notion.so"
|
|
||||||
target="_blank"
|
|
||||||
style={{ ...link, color: "#898989" }}
|
|
||||||
>
|
|
||||||
Notion.so
|
|
||||||
</Link>
|
|
||||||
, the all-in-one-workspace
|
|
||||||
<br />
|
|
||||||
for your notes, tasks, wikis, and databases.
|
|
||||||
</Text>
|
|
||||||
</Container>
|
|
||||||
</Body>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
|
|
||||||
NotionMagicLinkEmail.PreviewProps = {
|
|
||||||
loginCode: "sparo-ndigo-amurt-secan",
|
|
||||||
} as NotionMagicLinkEmailProps;
|
|
||||||
|
|
||||||
export default NotionMagicLinkEmail;
|
|
||||||
|
|
||||||
const main = {
|
|
||||||
backgroundColor: "#ffffff",
|
|
||||||
};
|
|
||||||
|
|
||||||
const container = {
|
|
||||||
paddingLeft: "12px",
|
|
||||||
paddingRight: "12px",
|
|
||||||
margin: "0 auto",
|
|
||||||
};
|
|
||||||
|
|
||||||
const h1 = {
|
|
||||||
color: "#333",
|
|
||||||
fontFamily:
|
|
||||||
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
|
|
||||||
fontSize: "24px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
margin: "40px 0",
|
|
||||||
padding: "0",
|
|
||||||
};
|
|
||||||
|
|
||||||
const link = {
|
|
||||||
color: "#2754C5",
|
|
||||||
fontFamily:
|
|
||||||
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
|
|
||||||
fontSize: "14px",
|
|
||||||
textDecoration: "underline",
|
|
||||||
};
|
|
||||||
|
|
||||||
const text = {
|
|
||||||
color: "#333",
|
|
||||||
fontFamily:
|
|
||||||
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
|
|
||||||
fontSize: "14px",
|
|
||||||
margin: "24px 0",
|
|
||||||
};
|
|
||||||
|
|
||||||
const footer = {
|
|
||||||
color: "#898989",
|
|
||||||
fontFamily:
|
|
||||||
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
|
|
||||||
fontSize: "12px",
|
|
||||||
lineHeight: "22px",
|
|
||||||
marginTop: "12px",
|
|
||||||
marginBottom: "24px",
|
|
||||||
};
|
|
||||||
|
|
||||||
const code = {
|
|
||||||
display: "inline-block",
|
|
||||||
padding: "16px 4.5%",
|
|
||||||
width: "90.5%",
|
|
||||||
backgroundColor: "#f4f4f4",
|
|
||||||
borderRadius: "5px",
|
|
||||||
border: "1px solid #eee",
|
|
||||||
color: "#333",
|
|
||||||
};
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
import {
|
|
||||||
Body,
|
|
||||||
Container,
|
|
||||||
Head,
|
|
||||||
Heading,
|
|
||||||
Html,
|
|
||||||
Img,
|
|
||||||
Link,
|
|
||||||
Section,
|
|
||||||
Text,
|
|
||||||
} from "@react-email/components";
|
|
||||||
import * as React from "react";
|
|
||||||
|
|
||||||
interface PlaidVerifyIdentityEmailProps {
|
|
||||||
validationCode?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseUrl = process.env.VERCEL_URL
|
|
||||||
? `https://${process.env.VERCEL_URL}`
|
|
||||||
: "";
|
|
||||||
|
|
||||||
export const PlaidVerifyIdentityEmail = ({
|
|
||||||
validationCode,
|
|
||||||
}: PlaidVerifyIdentityEmailProps) => (
|
|
||||||
<Html>
|
|
||||||
<Head />
|
|
||||||
<Body style={main}>
|
|
||||||
<Container style={container}>
|
|
||||||
<Img
|
|
||||||
src={`${baseUrl}/static/plaid-logo.png`}
|
|
||||||
width="212"
|
|
||||||
height="88"
|
|
||||||
alt="Plaid"
|
|
||||||
style={logo}
|
|
||||||
/>
|
|
||||||
<Text style={tertiary}>Verify Your Identity</Text>
|
|
||||||
<Heading style={secondary}>
|
|
||||||
Enter the following code to finish linking Venmo.
|
|
||||||
</Heading>
|
|
||||||
<Section style={codeContainer}>
|
|
||||||
<Text style={code}>{validationCode}</Text>
|
|
||||||
</Section>
|
|
||||||
<Text style={paragraph}>Not expecting this email?</Text>
|
|
||||||
<Text style={paragraph}>
|
|
||||||
Contact{" "}
|
|
||||||
<Link href="mailto:login@plaid.com" style={link}>
|
|
||||||
login@plaid.com
|
|
||||||
</Link>{" "}
|
|
||||||
if you did not request this code.
|
|
||||||
</Text>
|
|
||||||
</Container>
|
|
||||||
<Text style={footer}>Securely powered by Plaid.</Text>
|
|
||||||
</Body>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
|
|
||||||
PlaidVerifyIdentityEmail.PreviewProps = {
|
|
||||||
validationCode: "144833",
|
|
||||||
} as PlaidVerifyIdentityEmailProps;
|
|
||||||
|
|
||||||
export default PlaidVerifyIdentityEmail;
|
|
||||||
|
|
||||||
const main = {
|
|
||||||
backgroundColor: "#ffffff",
|
|
||||||
fontFamily: "HelveticaNeue,Helvetica,Arial,sans-serif",
|
|
||||||
};
|
|
||||||
|
|
||||||
const container = {
|
|
||||||
backgroundColor: "#ffffff",
|
|
||||||
border: "1px solid #eee",
|
|
||||||
borderRadius: "5px",
|
|
||||||
boxShadow: "0 5px 10px rgba(20,50,70,.2)",
|
|
||||||
marginTop: "20px",
|
|
||||||
maxWidth: "360px",
|
|
||||||
margin: "0 auto",
|
|
||||||
padding: "68px 0 130px",
|
|
||||||
};
|
|
||||||
|
|
||||||
const logo = {
|
|
||||||
margin: "0 auto",
|
|
||||||
};
|
|
||||||
|
|
||||||
const tertiary = {
|
|
||||||
color: "#0a85ea",
|
|
||||||
fontSize: "11px",
|
|
||||||
fontWeight: 700,
|
|
||||||
fontFamily: "HelveticaNeue,Helvetica,Arial,sans-serif",
|
|
||||||
height: "16px",
|
|
||||||
letterSpacing: "0",
|
|
||||||
lineHeight: "16px",
|
|
||||||
margin: "16px 8px 8px 8px",
|
|
||||||
textTransform: "uppercase" as const,
|
|
||||||
textAlign: "center" as const,
|
|
||||||
};
|
|
||||||
|
|
||||||
const secondary = {
|
|
||||||
color: "#000",
|
|
||||||
display: "inline-block",
|
|
||||||
fontFamily: "HelveticaNeue-Medium,Helvetica,Arial,sans-serif",
|
|
||||||
fontSize: "20px",
|
|
||||||
fontWeight: 500,
|
|
||||||
lineHeight: "24px",
|
|
||||||
marginBottom: "0",
|
|
||||||
marginTop: "0",
|
|
||||||
textAlign: "center" as const,
|
|
||||||
};
|
|
||||||
|
|
||||||
const codeContainer = {
|
|
||||||
background: "rgba(0,0,0,.05)",
|
|
||||||
borderRadius: "4px",
|
|
||||||
margin: "16px auto 14px",
|
|
||||||
verticalAlign: "middle",
|
|
||||||
width: "280px",
|
|
||||||
};
|
|
||||||
|
|
||||||
const code = {
|
|
||||||
color: "#000",
|
|
||||||
display: "inline-block",
|
|
||||||
fontFamily: "HelveticaNeue-Bold",
|
|
||||||
fontSize: "32px",
|
|
||||||
fontWeight: 700,
|
|
||||||
letterSpacing: "6px",
|
|
||||||
lineHeight: "40px",
|
|
||||||
paddingBottom: "8px",
|
|
||||||
paddingTop: "8px",
|
|
||||||
margin: "0 auto",
|
|
||||||
width: "100%",
|
|
||||||
textAlign: "center" as const,
|
|
||||||
};
|
|
||||||
|
|
||||||
const paragraph = {
|
|
||||||
color: "#444",
|
|
||||||
fontSize: "15px",
|
|
||||||
fontFamily: "HelveticaNeue,Helvetica,Arial,sans-serif",
|
|
||||||
letterSpacing: "0",
|
|
||||||
lineHeight: "23px",
|
|
||||||
padding: "0 40px",
|
|
||||||
margin: "0",
|
|
||||||
textAlign: "center" as const,
|
|
||||||
};
|
|
||||||
|
|
||||||
const link = {
|
|
||||||
color: "#444",
|
|
||||||
textDecoration: "underline",
|
|
||||||
};
|
|
||||||
|
|
||||||
const footer = {
|
|
||||||
color: "#000",
|
|
||||||
fontSize: "12px",
|
|
||||||
fontWeight: 800,
|
|
||||||
letterSpacing: "0",
|
|
||||||
lineHeight: "23px",
|
|
||||||
margin: "0",
|
|
||||||
marginTop: "20px",
|
|
||||||
fontFamily: "HelveticaNeue,Helvetica,Arial,sans-serif",
|
|
||||||
textAlign: "center" as const,
|
|
||||||
textTransform: "uppercase" as const,
|
|
||||||
};
|
|
||||||
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 426 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 54 KiB |
@@ -1,152 +0,0 @@
|
|||||||
import {
|
|
||||||
Body,
|
|
||||||
Button,
|
|
||||||
Container,
|
|
||||||
Head,
|
|
||||||
Hr,
|
|
||||||
Html,
|
|
||||||
Img,
|
|
||||||
Link,
|
|
||||||
Preview,
|
|
||||||
Section,
|
|
||||||
Text,
|
|
||||||
} from "@react-email/components";
|
|
||||||
import * as React from "react";
|
|
||||||
|
|
||||||
const baseUrl = process.env.VERCEL_URL
|
|
||||||
? `https://${process.env.VERCEL_URL}`
|
|
||||||
: "";
|
|
||||||
|
|
||||||
export const StripeWelcomeEmail = () => (
|
|
||||||
<Html>
|
|
||||||
<Head />
|
|
||||||
<Preview>You're now ready to make live transactions with Stripe!</Preview>
|
|
||||||
<Body style={main}>
|
|
||||||
<Container style={container}>
|
|
||||||
<Section style={box}>
|
|
||||||
<Img
|
|
||||||
src={`${baseUrl}/static/stripe-logo.png`}
|
|
||||||
width="49"
|
|
||||||
height="21"
|
|
||||||
alt="Stripe"
|
|
||||||
/>
|
|
||||||
<Hr style={hr} />
|
|
||||||
<Text style={paragraph}>
|
|
||||||
Thanks for submitting your account information. You're now ready to
|
|
||||||
make live transactions with Stripe!
|
|
||||||
</Text>
|
|
||||||
<Text style={paragraph}>
|
|
||||||
You can view your payments and a variety of other information about
|
|
||||||
your account right from your dashboard.
|
|
||||||
</Text>
|
|
||||||
<Button style={button} href="https://dashboard.stripe.com/login">
|
|
||||||
View your Stripe Dashboard
|
|
||||||
</Button>
|
|
||||||
<Hr style={hr} />
|
|
||||||
<Text style={paragraph}>
|
|
||||||
If you haven't finished your integration, you might find our{" "}
|
|
||||||
<Link style={anchor} href="https://stripe.com/docs">
|
|
||||||
docs
|
|
||||||
</Link>{" "}
|
|
||||||
handy.
|
|
||||||
</Text>
|
|
||||||
<Text style={paragraph}>
|
|
||||||
Once you're ready to start accepting payments, you'll just need to
|
|
||||||
use your live{" "}
|
|
||||||
<Link
|
|
||||||
style={anchor}
|
|
||||||
href="https://dashboard.stripe.com/login?redirect=%2Fapikeys"
|
|
||||||
>
|
|
||||||
API keys
|
|
||||||
</Link>{" "}
|
|
||||||
instead of your test API keys. Your account can simultaneously be
|
|
||||||
used for both test and live requests, so you can continue testing
|
|
||||||
while accepting live payments. Check out our{" "}
|
|
||||||
<Link style={anchor} href="https://stripe.com/docs/dashboard">
|
|
||||||
tutorial about account basics
|
|
||||||
</Link>
|
|
||||||
.
|
|
||||||
</Text>
|
|
||||||
<Text style={paragraph}>
|
|
||||||
Finally, we've put together a{" "}
|
|
||||||
<Link
|
|
||||||
style={anchor}
|
|
||||||
href="https://stripe.com/docs/checklist/website"
|
|
||||||
>
|
|
||||||
quick checklist
|
|
||||||
</Link>{" "}
|
|
||||||
to ensure your website conforms to card network standards.
|
|
||||||
</Text>
|
|
||||||
<Text style={paragraph}>
|
|
||||||
We'll be here to help you with any step along the way. You can find
|
|
||||||
answers to most questions and get in touch with us on our{" "}
|
|
||||||
<Link style={anchor} href="https://support.stripe.com/">
|
|
||||||
support site
|
|
||||||
</Link>
|
|
||||||
.
|
|
||||||
</Text>
|
|
||||||
<Text style={paragraph}>— The Stripe team</Text>
|
|
||||||
<Hr style={hr} />
|
|
||||||
<Text style={footer}>
|
|
||||||
Stripe, 354 Oyster Point Blvd, South San Francisco, CA 94080
|
|
||||||
</Text>
|
|
||||||
</Section>
|
|
||||||
</Container>
|
|
||||||
</Body>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default StripeWelcomeEmail;
|
|
||||||
|
|
||||||
const main = {
|
|
||||||
backgroundColor: "#f6f9fc",
|
|
||||||
fontFamily:
|
|
||||||
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
|
||||||
};
|
|
||||||
|
|
||||||
const container = {
|
|
||||||
backgroundColor: "#ffffff",
|
|
||||||
margin: "0 auto",
|
|
||||||
padding: "20px 0 48px",
|
|
||||||
marginBottom: "64px",
|
|
||||||
};
|
|
||||||
|
|
||||||
const box = {
|
|
||||||
padding: "0 48px",
|
|
||||||
};
|
|
||||||
|
|
||||||
const hr = {
|
|
||||||
borderColor: "#e6ebf1",
|
|
||||||
margin: "20px 0",
|
|
||||||
};
|
|
||||||
|
|
||||||
const paragraph = {
|
|
||||||
color: "#525f7f",
|
|
||||||
|
|
||||||
fontSize: "16px",
|
|
||||||
lineHeight: "24px",
|
|
||||||
textAlign: "left" as const,
|
|
||||||
};
|
|
||||||
|
|
||||||
const anchor = {
|
|
||||||
color: "#556cd6",
|
|
||||||
};
|
|
||||||
|
|
||||||
const button = {
|
|
||||||
backgroundColor: "#656ee8",
|
|
||||||
borderRadius: "5px",
|
|
||||||
color: "#fff",
|
|
||||||
fontSize: "16px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
textDecoration: "none",
|
|
||||||
textAlign: "center" as const,
|
|
||||||
display: "block",
|
|
||||||
width: "100%",
|
|
||||||
padding: "10px",
|
|
||||||
};
|
|
||||||
|
|
||||||
const footer = {
|
|
||||||
color: "#8898aa",
|
|
||||||
fontSize: "12px",
|
|
||||||
lineHeight: "16px",
|
|
||||||
};
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
import {
|
|
||||||
Body,
|
|
||||||
Button,
|
|
||||||
Column,
|
|
||||||
Container,
|
|
||||||
Head,
|
|
||||||
Heading,
|
|
||||||
Hr,
|
|
||||||
Html,
|
|
||||||
Img,
|
|
||||||
Link,
|
|
||||||
Preview,
|
|
||||||
Row,
|
|
||||||
Section,
|
|
||||||
Tailwind,
|
|
||||||
Text,
|
|
||||||
} from "@react-email/components";
|
|
||||||
import * as React from "react";
|
|
||||||
|
|
||||||
interface VercelInviteUserEmailProps {
|
|
||||||
username?: string;
|
|
||||||
userImage?: string;
|
|
||||||
invitedByUsername?: string;
|
|
||||||
invitedByEmail?: string;
|
|
||||||
teamName?: string;
|
|
||||||
teamImage?: string;
|
|
||||||
inviteLink?: string;
|
|
||||||
inviteFromIp?: string;
|
|
||||||
inviteFromLocation?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseUrl = process.env.VERCEL_URL
|
|
||||||
? `https://${process.env.VERCEL_URL}`
|
|
||||||
: "";
|
|
||||||
|
|
||||||
export const VercelInviteUserEmail = ({
|
|
||||||
username,
|
|
||||||
userImage,
|
|
||||||
invitedByUsername,
|
|
||||||
invitedByEmail,
|
|
||||||
teamName,
|
|
||||||
teamImage,
|
|
||||||
inviteLink,
|
|
||||||
inviteFromIp,
|
|
||||||
inviteFromLocation,
|
|
||||||
}: VercelInviteUserEmailProps) => {
|
|
||||||
const previewText = `Join ${invitedByUsername} on Vercel`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Html>
|
|
||||||
<Head />
|
|
||||||
<Preview>{previewText}</Preview>
|
|
||||||
<Tailwind>
|
|
||||||
<Body className="bg-white my-auto mx-auto font-sans px-2">
|
|
||||||
<Container className="border border-solid border-[#eaeaea] rounded my-[40px] mx-auto p-[20px] max-w-[465px]">
|
|
||||||
<Section className="mt-[32px]">
|
|
||||||
<Img
|
|
||||||
src={`${baseUrl}/static/vercel-logo.png`}
|
|
||||||
width="40"
|
|
||||||
height="37"
|
|
||||||
alt="Vercel"
|
|
||||||
className="my-0 mx-auto"
|
|
||||||
/>
|
|
||||||
</Section>
|
|
||||||
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
|
|
||||||
Join <strong>{teamName}</strong> on <strong>Vercel</strong>
|
|
||||||
</Heading>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
Hello {username},
|
|
||||||
</Text>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
<strong>{invitedByUsername}</strong> (
|
|
||||||
<Link
|
|
||||||
href={`mailto:${invitedByEmail}`}
|
|
||||||
className="text-blue-600 no-underline"
|
|
||||||
>
|
|
||||||
{invitedByEmail}
|
|
||||||
</Link>
|
|
||||||
) has invited you to the <strong>{teamName}</strong> team on{" "}
|
|
||||||
<strong>Vercel</strong>.
|
|
||||||
</Text>
|
|
||||||
<Section>
|
|
||||||
<Row>
|
|
||||||
<Column align="right">
|
|
||||||
<Img
|
|
||||||
className="rounded-full"
|
|
||||||
src={userImage}
|
|
||||||
width="64"
|
|
||||||
height="64"
|
|
||||||
/>
|
|
||||||
</Column>
|
|
||||||
<Column align="center">
|
|
||||||
<Img
|
|
||||||
src={`${baseUrl}/static/vercel-arrow.png`}
|
|
||||||
width="12"
|
|
||||||
height="9"
|
|
||||||
alt="invited you to"
|
|
||||||
/>
|
|
||||||
</Column>
|
|
||||||
<Column align="left">
|
|
||||||
<Img
|
|
||||||
className="rounded-full"
|
|
||||||
src={teamImage}
|
|
||||||
width="64"
|
|
||||||
height="64"
|
|
||||||
/>
|
|
||||||
</Column>
|
|
||||||
</Row>
|
|
||||||
</Section>
|
|
||||||
<Section className="text-center mt-[32px] mb-[32px]">
|
|
||||||
<Button
|
|
||||||
className="bg-[#000000] rounded text-white text-[12px] font-semibold no-underline text-center px-5 py-3"
|
|
||||||
href={inviteLink}
|
|
||||||
>
|
|
||||||
Join the team
|
|
||||||
</Button>
|
|
||||||
</Section>
|
|
||||||
<Text className="text-black text-[14px] leading-[24px]">
|
|
||||||
or copy and paste this URL into your browser:{" "}
|
|
||||||
<Link href={inviteLink} className="text-blue-600 no-underline">
|
|
||||||
{inviteLink}
|
|
||||||
</Link>
|
|
||||||
</Text>
|
|
||||||
<Hr className="border border-solid border-[#eaeaea] my-[26px] mx-0 w-full" />
|
|
||||||
<Text className="text-[#666666] text-[12px] leading-[24px]">
|
|
||||||
This invitation was intended for{" "}
|
|
||||||
<span className="text-black">{username}</span>. This invite was
|
|
||||||
sent from <span className="text-black">{inviteFromIp}</span>{" "}
|
|
||||||
located in{" "}
|
|
||||||
<span className="text-black">{inviteFromLocation}</span>. If you
|
|
||||||
were not expecting this invitation, you can ignore this email. If
|
|
||||||
you are concerned about your account's safety, please reply to
|
|
||||||
this email to get in touch with us.
|
|
||||||
</Text>
|
|
||||||
</Container>
|
|
||||||
</Body>
|
|
||||||
</Tailwind>
|
|
||||||
</Html>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
VercelInviteUserEmail.PreviewProps = {
|
|
||||||
username: "alanturing",
|
|
||||||
userImage: `${baseUrl}/static/vercel-user.png`,
|
|
||||||
invitedByUsername: "Alan",
|
|
||||||
invitedByEmail: "alan.turing@example.com",
|
|
||||||
teamName: "Enigma",
|
|
||||||
teamImage: `${baseUrl}/static/vercel-team.png`,
|
|
||||||
inviteLink: "https://vercel.com/teams/invite/foo",
|
|
||||||
inviteFromIp: "204.13.186.218",
|
|
||||||
inviteFromLocation: "São Paulo, Brazil",
|
|
||||||
} as VercelInviteUserEmailProps;
|
|
||||||
|
|
||||||
export default VercelInviteUserEmail;
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "emails",
|
|
||||||
"version": "0.0.19",
|
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
|
||||||
"build": "email build",
|
|
||||||
"dev": "email dev",
|
|
||||||
"export": "email export"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@react-email/components": "0.0.21",
|
|
||||||
"react-email": "2.1.5",
|
|
||||||
"react": "^18.2.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/react": "18.2.33",
|
|
||||||
"@types/react-dom": "18.2.14"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
4209
apps/dokploy/emails/pnpm-lock.yaml
generated
@@ -1,27 +0,0 @@
|
|||||||
# React Email Starter
|
|
||||||
|
|
||||||
A live preview right in your browser so you don't need to keep sending real emails during development.
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
First, install the dependencies:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm install
|
|
||||||
# or
|
|
||||||
yarn
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, run the development server:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run dev
|
|
||||||
# or
|
|
||||||
yarn dev
|
|
||||||
```
|
|
||||||
|
|
||||||
Open [localhost:3000](http://localhost:3000) with your browser to see the result.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
@@ -1,15 +1,8 @@
|
|||||||
import { type PostgresJsDatabase, drizzle } from "drizzle-orm/postgres-js";
|
import { type PostgresJsDatabase, drizzle } from "drizzle-orm/postgres-js";
|
||||||
import postgres from "postgres";
|
import postgres from "postgres";
|
||||||
// import { sc } from "@dokploy/schema";
|
|
||||||
// import * as schema from "@dokploy/schema";
|
|
||||||
// schema
|
|
||||||
import * as schema from "./schema";
|
import * as schema from "./schema";
|
||||||
|
|
||||||
// type Schema = typeof schema;
|
|
||||||
|
|
||||||
// type Schema = typeof schema;
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line no-var -- only var works here
|
|
||||||
var db: PostgresJsDatabase<typeof schema> | undefined;
|
var db: PostgresJsDatabase<typeof schema> | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,157 +0,0 @@
|
|||||||
import BuildFailedEmail from "@/emails/emails/build-failed";
|
|
||||||
import { db } from "@/server/db";
|
|
||||||
import { notifications } from "@/server/db/schema";
|
|
||||||
import { renderAsync } from "@react-email/components";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import {
|
|
||||||
sendDiscordNotification,
|
|
||||||
sendEmailNotification,
|
|
||||||
sendSlackNotification,
|
|
||||||
sendTelegramNotification,
|
|
||||||
} from "./utils";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
projectName: string;
|
|
||||||
applicationName: string;
|
|
||||||
applicationType: string;
|
|
||||||
errorMessage: string;
|
|
||||||
buildLink: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sendBuildErrorNotifications = async ({
|
|
||||||
projectName,
|
|
||||||
applicationName,
|
|
||||||
applicationType,
|
|
||||||
errorMessage,
|
|
||||||
buildLink,
|
|
||||||
}: Props) => {
|
|
||||||
const date = new Date();
|
|
||||||
const notificationList = await db.query.notifications.findMany({
|
|
||||||
where: eq(notifications.appBuildError, true),
|
|
||||||
with: {
|
|
||||||
email: true,
|
|
||||||
discord: true,
|
|
||||||
telegram: true,
|
|
||||||
slack: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const notification of notificationList) {
|
|
||||||
const { email, discord, telegram, slack } = notification;
|
|
||||||
if (email) {
|
|
||||||
const template = await renderAsync(
|
|
||||||
BuildFailedEmail({
|
|
||||||
projectName,
|
|
||||||
applicationName,
|
|
||||||
applicationType,
|
|
||||||
errorMessage: errorMessage,
|
|
||||||
buildLink,
|
|
||||||
date: date.toLocaleString(),
|
|
||||||
}),
|
|
||||||
).catch();
|
|
||||||
await sendEmailNotification(email, "Build failed for dokploy", template);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (discord) {
|
|
||||||
await sendDiscordNotification(discord, {
|
|
||||||
title: "⚠️ Build Failed",
|
|
||||||
color: 0xff0000,
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: "Project",
|
|
||||||
value: projectName,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Application",
|
|
||||||
value: applicationName,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Type",
|
|
||||||
value: applicationType,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Error",
|
|
||||||
value: errorMessage,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Build Link",
|
|
||||||
value: buildLink,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
timestamp: date.toISOString(),
|
|
||||||
footer: {
|
|
||||||
text: "Dokploy Build Notification",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (telegram) {
|
|
||||||
await sendTelegramNotification(
|
|
||||||
telegram,
|
|
||||||
`
|
|
||||||
<b>⚠️ Build Failed</b>
|
|
||||||
|
|
||||||
<b>Project:</b> ${projectName}
|
|
||||||
<b>Application:</b> ${applicationName}
|
|
||||||
<b>Type:</b> ${applicationType}
|
|
||||||
<b>Time:</b> ${date.toLocaleString()}
|
|
||||||
|
|
||||||
<b>Error:</b>
|
|
||||||
<pre>${errorMessage}</pre>
|
|
||||||
|
|
||||||
<b>Build Details:</b> ${buildLink}
|
|
||||||
`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slack) {
|
|
||||||
const { channel } = slack;
|
|
||||||
await sendSlackNotification(slack, {
|
|
||||||
channel: channel,
|
|
||||||
attachments: [
|
|
||||||
{
|
|
||||||
color: "#FF0000",
|
|
||||||
pretext: ":warning: *Build Failed*",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
title: "Project",
|
|
||||||
value: projectName,
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Application",
|
|
||||||
value: applicationName,
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Type",
|
|
||||||
value: applicationType,
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Time",
|
|
||||||
value: date.toLocaleString(),
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Error",
|
|
||||||
value: `\`\`\`${errorMessage}\`\`\``,
|
|
||||||
short: false,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
type: "button",
|
|
||||||
text: "View Build Details",
|
|
||||||
url: buildLink,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
import BuildSuccessEmail from "@/emails/emails/build-success";
|
|
||||||
import { db } from "@/server/db";
|
|
||||||
import { notifications } from "@/server/db/schema";
|
|
||||||
import { renderAsync } from "@react-email/components";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import {
|
|
||||||
sendDiscordNotification,
|
|
||||||
sendEmailNotification,
|
|
||||||
sendSlackNotification,
|
|
||||||
sendTelegramNotification,
|
|
||||||
} from "./utils";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
projectName: string;
|
|
||||||
applicationName: string;
|
|
||||||
applicationType: string;
|
|
||||||
buildLink: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sendBuildSuccessNotifications = async ({
|
|
||||||
projectName,
|
|
||||||
applicationName,
|
|
||||||
applicationType,
|
|
||||||
buildLink,
|
|
||||||
}: Props) => {
|
|
||||||
const date = new Date();
|
|
||||||
const notificationList = await db.query.notifications.findMany({
|
|
||||||
where: eq(notifications.appDeploy, true),
|
|
||||||
with: {
|
|
||||||
email: true,
|
|
||||||
discord: true,
|
|
||||||
telegram: true,
|
|
||||||
slack: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const notification of notificationList) {
|
|
||||||
const { email, discord, telegram, slack } = notification;
|
|
||||||
|
|
||||||
if (email) {
|
|
||||||
const template = await renderAsync(
|
|
||||||
BuildSuccessEmail({
|
|
||||||
projectName,
|
|
||||||
applicationName,
|
|
||||||
applicationType,
|
|
||||||
buildLink,
|
|
||||||
date: date.toLocaleString(),
|
|
||||||
}),
|
|
||||||
).catch();
|
|
||||||
await sendEmailNotification(email, "Build success for dokploy", template);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (discord) {
|
|
||||||
await sendDiscordNotification(discord, {
|
|
||||||
title: "✅ Build Success",
|
|
||||||
color: 0x00ff00,
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: "Project",
|
|
||||||
value: projectName,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Application",
|
|
||||||
value: applicationName,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Type",
|
|
||||||
value: applicationType,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Build Link",
|
|
||||||
value: buildLink,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
timestamp: date.toISOString(),
|
|
||||||
footer: {
|
|
||||||
text: "Dokploy Build Notification",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (telegram) {
|
|
||||||
await sendTelegramNotification(
|
|
||||||
telegram,
|
|
||||||
`
|
|
||||||
<b>✅ Build Success</b>
|
|
||||||
|
|
||||||
<b>Project:</b> ${projectName}
|
|
||||||
<b>Application:</b> ${applicationName}
|
|
||||||
<b>Type:</b> ${applicationType}
|
|
||||||
<b>Time:</b> ${date.toLocaleString()}
|
|
||||||
|
|
||||||
<b>Build Details:</b> ${buildLink}
|
|
||||||
`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slack) {
|
|
||||||
const { channel } = slack;
|
|
||||||
await sendSlackNotification(slack, {
|
|
||||||
channel: channel,
|
|
||||||
attachments: [
|
|
||||||
{
|
|
||||||
color: "#00FF00",
|
|
||||||
pretext: ":white_check_mark: *Build Success*",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
title: "Project",
|
|
||||||
value: projectName,
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Application",
|
|
||||||
value: applicationName,
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Type",
|
|
||||||
value: applicationType,
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Time",
|
|
||||||
value: date.toLocaleString(),
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
type: "button",
|
|
||||||
text: "View Build Details",
|
|
||||||
url: buildLink,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,177 +0,0 @@
|
|||||||
import DatabaseBackupEmail from "@/emails/emails/database-backup";
|
|
||||||
import { db } from "@/server/db";
|
|
||||||
import { notifications } from "@/server/db/schema";
|
|
||||||
import { renderAsync } from "@react-email/components";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import {
|
|
||||||
sendDiscordNotification,
|
|
||||||
sendEmailNotification,
|
|
||||||
sendSlackNotification,
|
|
||||||
sendTelegramNotification,
|
|
||||||
} from "./utils";
|
|
||||||
|
|
||||||
export const sendDatabaseBackupNotifications = async ({
|
|
||||||
projectName,
|
|
||||||
applicationName,
|
|
||||||
databaseType,
|
|
||||||
type,
|
|
||||||
errorMessage,
|
|
||||||
}: {
|
|
||||||
projectName: string;
|
|
||||||
applicationName: string;
|
|
||||||
databaseType: "postgres" | "mysql" | "mongodb" | "mariadb";
|
|
||||||
type: "error" | "success";
|
|
||||||
errorMessage?: string;
|
|
||||||
}) => {
|
|
||||||
const date = new Date();
|
|
||||||
const notificationList = await db.query.notifications.findMany({
|
|
||||||
where: eq(notifications.databaseBackup, true),
|
|
||||||
with: {
|
|
||||||
email: true,
|
|
||||||
discord: true,
|
|
||||||
telegram: true,
|
|
||||||
slack: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const notification of notificationList) {
|
|
||||||
const { email, discord, telegram, slack } = notification;
|
|
||||||
|
|
||||||
if (email) {
|
|
||||||
const template = await renderAsync(
|
|
||||||
DatabaseBackupEmail({
|
|
||||||
projectName,
|
|
||||||
applicationName,
|
|
||||||
databaseType,
|
|
||||||
type,
|
|
||||||
errorMessage,
|
|
||||||
date: date.toLocaleString(),
|
|
||||||
}),
|
|
||||||
).catch();
|
|
||||||
await sendEmailNotification(
|
|
||||||
email,
|
|
||||||
"Database backup for dokploy",
|
|
||||||
template,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (discord) {
|
|
||||||
await sendDiscordNotification(discord, {
|
|
||||||
title:
|
|
||||||
type === "success"
|
|
||||||
? "✅ Database Backup Successful"
|
|
||||||
: "❌ Database Backup Failed",
|
|
||||||
color: type === "success" ? 0x00ff00 : 0xff0000,
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: "Project",
|
|
||||||
value: projectName,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Application",
|
|
||||||
value: applicationName,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Type",
|
|
||||||
value: databaseType,
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Time",
|
|
||||||
value: date.toLocaleString(),
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Type",
|
|
||||||
value: type,
|
|
||||||
},
|
|
||||||
...(type === "error" && errorMessage
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
name: "Error Message",
|
|
||||||
value: errorMessage,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
],
|
|
||||||
timestamp: date.toISOString(),
|
|
||||||
footer: {
|
|
||||||
text: "Dokploy Database Backup Notification",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (telegram) {
|
|
||||||
const statusEmoji = type === "success" ? "✅" : "❌";
|
|
||||||
const messageText = `
|
|
||||||
<b>${statusEmoji} Database Backup ${type === "success" ? "Successful" : "Failed"}</b>
|
|
||||||
|
|
||||||
<b>Project:</b> ${projectName}
|
|
||||||
<b>Application:</b> ${applicationName}
|
|
||||||
<b>Type:</b> ${databaseType}
|
|
||||||
<b>Time:</b> ${date.toLocaleString()}
|
|
||||||
|
|
||||||
<b>Status:</b> ${type === "success" ? "Successful" : "Failed"}
|
|
||||||
${type === "error" && errorMessage ? `<b>Error:</b> ${errorMessage}` : ""}
|
|
||||||
`;
|
|
||||||
await sendTelegramNotification(telegram, messageText);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slack) {
|
|
||||||
const { channel } = slack;
|
|
||||||
await sendSlackNotification(slack, {
|
|
||||||
channel: channel,
|
|
||||||
attachments: [
|
|
||||||
{
|
|
||||||
color: type === "success" ? "#00FF00" : "#FF0000",
|
|
||||||
pretext:
|
|
||||||
type === "success"
|
|
||||||
? ":white_check_mark: *Database Backup Successful*"
|
|
||||||
: ":x: *Database Backup Failed*",
|
|
||||||
fields: [
|
|
||||||
...(type === "error" && errorMessage
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
title: "Error Message",
|
|
||||||
value: errorMessage,
|
|
||||||
short: false,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
{
|
|
||||||
title: "Project",
|
|
||||||
value: projectName,
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Application",
|
|
||||||
value: applicationName,
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Type",
|
|
||||||
value: databaseType,
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Time",
|
|
||||||
value: date.toLocaleString(),
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Type",
|
|
||||||
value: type,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Status",
|
|
||||||
value: type === "success" ? "Successful" : "Failed",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
import DockerCleanupEmail from "@/emails/emails/docker-cleanup";
|
|
||||||
import { db } from "@/server/db";
|
|
||||||
import { notifications } from "@/server/db/schema";
|
|
||||||
import { renderAsync } from "@react-email/components";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import {
|
|
||||||
sendDiscordNotification,
|
|
||||||
sendEmailNotification,
|
|
||||||
sendSlackNotification,
|
|
||||||
sendTelegramNotification,
|
|
||||||
} from "./utils";
|
|
||||||
|
|
||||||
export const sendDockerCleanupNotifications = async (
|
|
||||||
message = "Docker cleanup for dokploy",
|
|
||||||
) => {
|
|
||||||
const date = new Date();
|
|
||||||
const notificationList = await db.query.notifications.findMany({
|
|
||||||
where: eq(notifications.dockerCleanup, true),
|
|
||||||
with: {
|
|
||||||
email: true,
|
|
||||||
discord: true,
|
|
||||||
telegram: true,
|
|
||||||
slack: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const notification of notificationList) {
|
|
||||||
const { email, discord, telegram, slack } = notification;
|
|
||||||
|
|
||||||
if (email) {
|
|
||||||
const template = await renderAsync(
|
|
||||||
DockerCleanupEmail({ message, date: date.toLocaleString() }),
|
|
||||||
).catch();
|
|
||||||
|
|
||||||
await sendEmailNotification(
|
|
||||||
email,
|
|
||||||
"Docker cleanup for dokploy",
|
|
||||||
template,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (discord) {
|
|
||||||
await sendDiscordNotification(discord, {
|
|
||||||
title: "✅ Docker Cleanup",
|
|
||||||
color: 0x00ff00,
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: "Message",
|
|
||||||
value: message,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
timestamp: date.toISOString(),
|
|
||||||
footer: {
|
|
||||||
text: "Dokploy Docker Cleanup Notification",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (telegram) {
|
|
||||||
await sendTelegramNotification(
|
|
||||||
telegram,
|
|
||||||
`
|
|
||||||
<b>✅ Docker Cleanup</b>
|
|
||||||
<b>Message:</b> ${message}
|
|
||||||
<b>Time:</b> ${date.toLocaleString()}
|
|
||||||
`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slack) {
|
|
||||||
const { channel } = slack;
|
|
||||||
await sendSlackNotification(slack, {
|
|
||||||
channel: channel,
|
|
||||||
attachments: [
|
|
||||||
{
|
|
||||||
color: "#00FF00",
|
|
||||||
pretext: ":white_check_mark: *Docker Cleanup*",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
title: "Message",
|
|
||||||
value: message,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Time",
|
|
||||||
value: date.toLocaleString(),
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
import DokployRestartEmail from "@/emails/emails/dokploy-restart";
|
|
||||||
import { db } from "@/server/db";
|
|
||||||
import { notifications } from "@/server/db/schema";
|
|
||||||
import { renderAsync } from "@react-email/components";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import {
|
|
||||||
sendDiscordNotification,
|
|
||||||
sendEmailNotification,
|
|
||||||
sendSlackNotification,
|
|
||||||
sendTelegramNotification,
|
|
||||||
} from "./utils";
|
|
||||||
|
|
||||||
export const sendDokployRestartNotifications = async () => {
|
|
||||||
const date = new Date();
|
|
||||||
const notificationList = await db.query.notifications.findMany({
|
|
||||||
where: eq(notifications.dokployRestart, true),
|
|
||||||
with: {
|
|
||||||
email: true,
|
|
||||||
discord: true,
|
|
||||||
telegram: true,
|
|
||||||
slack: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const notification of notificationList) {
|
|
||||||
const { email, discord, telegram, slack } = notification;
|
|
||||||
|
|
||||||
if (email) {
|
|
||||||
const template = await renderAsync(
|
|
||||||
DokployRestartEmail({ date: date.toLocaleString() }),
|
|
||||||
).catch();
|
|
||||||
await sendEmailNotification(email, "Dokploy Server Restarted", template);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (discord) {
|
|
||||||
await sendDiscordNotification(discord, {
|
|
||||||
title: "✅ Dokploy Server Restarted",
|
|
||||||
color: 0x00ff00,
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: "Time",
|
|
||||||
value: date.toLocaleString(),
|
|
||||||
inline: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
timestamp: date.toISOString(),
|
|
||||||
footer: {
|
|
||||||
text: "Dokploy Restart Notification",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (telegram) {
|
|
||||||
await sendTelegramNotification(
|
|
||||||
telegram,
|
|
||||||
`
|
|
||||||
<b>✅ Dokploy Serverd Restarted</b>
|
|
||||||
<b>Time:</b> ${date.toLocaleString()}
|
|
||||||
`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slack) {
|
|
||||||
const { channel } = slack;
|
|
||||||
await sendSlackNotification(slack, {
|
|
||||||
channel: channel,
|
|
||||||
attachments: [
|
|
||||||
{
|
|
||||||
color: "#00FF00",
|
|
||||||
pretext: ":white_check_mark: *Dokploy Server Restarted*",
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
title: "Time",
|
|
||||||
value: date.toLocaleString(),
|
|
||||||
short: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
import type { discord, email, slack, telegram } from "@/server/db/schema";
|
|
||||||
import nodemailer from "nodemailer";
|
|
||||||
|
|
||||||
export const sendEmailNotification = async (
|
|
||||||
connection: typeof email.$inferInsert,
|
|
||||||
subject: string,
|
|
||||||
htmlContent: string,
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
const {
|
|
||||||
smtpServer,
|
|
||||||
smtpPort,
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
fromAddress,
|
|
||||||
toAddresses,
|
|
||||||
} = connection;
|
|
||||||
const transporter = nodemailer.createTransport({
|
|
||||||
host: smtpServer,
|
|
||||||
port: smtpPort,
|
|
||||||
auth: { user: username, pass: password },
|
|
||||||
});
|
|
||||||
|
|
||||||
await transporter.sendMail({
|
|
||||||
from: fromAddress,
|
|
||||||
to: toAddresses.join(", "),
|
|
||||||
subject,
|
|
||||||
html: htmlContent,
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sendDiscordNotification = async (
|
|
||||||
connection: typeof discord.$inferInsert,
|
|
||||||
embed: any,
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
await fetch(connection.webhookUrl, {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({ embeds: [embed] }),
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sendTelegramNotification = async (
|
|
||||||
connection: typeof telegram.$inferInsert,
|
|
||||||
messageText: string,
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
const url = `https://api.telegram.org/bot${connection.botToken}/sendMessage`;
|
|
||||||
await fetch(url, {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({
|
|
||||||
chat_id: connection.chatId,
|
|
||||||
text: messageText,
|
|
||||||
parse_mode: "HTML",
|
|
||||||
disable_web_page_preview: true,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sendSlackNotification = async (
|
|
||||||
connection: typeof slack.$inferInsert,
|
|
||||||
message: any,
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
await fetch(connection.webhookUrl, {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify(message),
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -33,37 +33,6 @@ export * from "./services/auth";
|
|||||||
export * from "./services/gitlab";
|
export * from "./services/gitlab";
|
||||||
export * from "./services/server";
|
export * from "./services/server";
|
||||||
export * from "./services/application";
|
export * from "./services/application";
|
||||||
// export * from "./db/schema/application";
|
|
||||||
// export * from "./db/schema/postgres";
|
|
||||||
// export * from "./db/schema/user";
|
|
||||||
// export * from "./db/schema/admin";
|
|
||||||
// export * from "./db/schema/auth";
|
|
||||||
// export * from "./db/schema/project";
|
|
||||||
// export * from "./db/schema/domain";
|
|
||||||
// export * from "./db/schema/mariadb";
|
|
||||||
// export * from "./db/schema/mongo";
|
|
||||||
// export * from "./db/schema/mysql";
|
|
||||||
// export * from "./db/schema/backups";
|
|
||||||
// export * from "./db/schema/destination";
|
|
||||||
// export * from "./db/schema/deployment";
|
|
||||||
// export * from "./db/schema/mount";
|
|
||||||
// export * from "./db/schema/certificate";
|
|
||||||
// export * from "./db/schema/session";
|
|
||||||
// export * from "./db/schema/redirects";
|
|
||||||
// export * from "./db/schema/security";
|
|
||||||
// export * from "./db/schema/port";
|
|
||||||
// export * from "./db/schema/redis";
|
|
||||||
// export * from "./db/schema/shared";
|
|
||||||
// export * from "./db/schema/compose";
|
|
||||||
// export * from "./db/schema/registry";
|
|
||||||
// export * from "./db/schema/notification";
|
|
||||||
// export * from "./db/schema/ssh-key";
|
|
||||||
// export * from "./db/schema/git-provider";
|
|
||||||
// export * from "./db/schema/bitbucket";
|
|
||||||
// export * from "./db/schema/github";
|
|
||||||
// export * from "./db/schema/gitlab";
|
|
||||||
// export * from "./db/schema/server";
|
|
||||||
// export * from "./db/schema/utils";
|
|
||||||
|
|
||||||
export * from "./setup/config-paths";
|
export * from "./setup/config-paths";
|
||||||
export * from "./setup/postgres-setup";
|
export * from "./setup/postgres-setup";
|
||||||
@@ -146,3 +115,6 @@ export * from "./utils/access-log/utils";
|
|||||||
export * from "./constants/index";
|
export * from "./constants/index";
|
||||||
|
|
||||||
export * from "./monitoring/utilts";
|
export * from "./monitoring/utilts";
|
||||||
|
|
||||||
|
export * from "./db/validations/domain";
|
||||||
|
export * from "./db/validations/index";
|
||||||
|
|||||||