Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions app-next/src/lib/email-templates/admin-upload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Email specific components
import { baseLayout } from "./layout";

export const generateAdminReviewEmail = (
userName: string,
datasetId: string,
datasetName: string,
logoUrl: string,
datasetUrl?: string,
) => {
const datasetLink = datasetUrl ?? `https://www.openml.org/datasets/${datasetId}`;

const content = `
<!-- Content for Admin Upload Review -->
<h1 style="color: #4338ca; margin: 0 0 20px 0; font-size: 24px; font-weight: 700; text-align: center;">New Dataset Uploaded</h1>

<div style="background: #ffffff; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.05);">
<h2 style="font-size: 18px; color: #1f2937; margin: 0 0 10px 0;">Upload Details</h2>
<table style="width: 100%; border-collapse: collapse; margin-bottom: 20px;">
<tr>
<td style="padding: 8px 0; color: #6b7280; width: 100px;">User:</td>
<td style="padding: 8px 0; color: #111827; font-weight: 500;">${userName}</td>
</tr>
<tr>
<td style="padding: 8px 0; color: #6b7280;">Dataset:</td>
<td style="padding: 8px 0; color: #111827; font-weight: 500;">${datasetName} (ID: ${datasetId})</td>
</tr>
<tr>
<td style="padding: 8px 0; color: #6b7280;">Time:</td>
<td style="padding: 8px 0; color: #111827;">${new Date().toLocaleString()}</td>
</tr>
</table>

<!-- CTA Button -->
<div style="text-align: center; margin: 20px 0;">
<a href="${datasetLink}" class="cta-button" style="background: linear-gradient(135deg, #6366f1, #8b5cf6, #ec4899); color: #ffffff; padding: 12px 24px; text-decoration: none; border-radius: 6px; display: inline-block; font-weight: 600; font-size: 14px;">Review Dataset</a>
</div>
</div>

<p style="color: #6b7280; font-size: 14px; margin-top: 20px; text-align: center;">
This is an automated notification for OpenML Admins.
</p>
`;

return baseLayout(content, logoUrl);
};
33 changes: 33 additions & 0 deletions app-next/src/lib/email-templates/confirm-email.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Email specific components
import { baseLayout } from "./layout";

export const generateConfirmEmail = (link: string, logoUrl: string) => {
const content = `
<!-- Content for Confirm Email -->
<h1 style="color: #111827; margin: 0 0 20px 0; font-size: 28px; font-weight: 700; text-align: center;">Welcome to OpenML!</h1>

<p style="color: #374151; font-size: 16px; line-height: 1.6; margin-bottom: 20px;">Hi there,</p>
<p style="color: #374151; font-size: 16px; line-height: 1.6; margin-bottom: 20px;">Thank you for signing up to OpenML, the collaborative machine learning platform.</p>
<p style="color: #374151; font-size: 16px; line-height: 1.6; margin-bottom: 30px;">To verify your email address and activate your account, please click the button below:</p>

<!-- CTA Button -->
<div style="text-align: center; margin: 40px 0;">
<a href="${link}" class="cta-button" style="background: linear-gradient(135deg, #6366f1, #8b5cf6, #ec4899); color: #ffffff; padding: 14px 30px; text-decoration: none; border-radius: 6px; display: inline-block; font-weight: 600; font-size: 16px; box-shadow: 0 4px 6px rgba(37, 99, 235, 0.2);">Confirm Email Address</a>
</div>

<!-- Alternative Link -->
<div style="background: #f3f4f6; padding: 20px; border-radius: 8px; margin: 30px 0;">
<p style="color: #6b7280; font-size: 14px; margin: 0 0 10px 0;">Or copy and paste this link into your browser:</p>
<p style="color: #233044; font-size: 14px; word-break: break-all; margin: 0;">${link}</p>
</div>

<p style="color: #6b7280; font-size: 14px; line-height: 1.6; margin-bottom: 10px; font-style: italic;">
⏱️ This confirmation link will expire in 24 hours.
</p>
<p style="color: #6b7280; font-size: 14px; line-height: 1.6; margin-bottom: 30px;">
If you didn't create an account with OpenML, you can safely ignore this email.
</p>
`;

return baseLayout(content, logoUrl);
};
48 changes: 48 additions & 0 deletions app-next/src/lib/email-templates/dataset-edit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Email specific components
import { baseLayout } from "./layout";

export const generateDatasetEditEmail = (
userName: string,
datasetId: string,
datasetName: string,
changes: string[],
logoUrl: string,
datasetUrl?: string,
) => {
const datasetLink = datasetUrl ?? `https://www.openml.org/datasets/${datasetId}`;

const content = `
<!-- Content for Dataset Edit -->
<h1 style="color: #4338ca; margin: 0 0 20px 0; font-size: 24px; font-weight: 700; text-align: center;">Dataset Updated</h1>

<div style="background: #ffffff; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.05);">
<h2 style="font-size: 18px; color: #1f2937; margin: 0 0 10px 0;">Dataset Details</h2>
<table style="width: 100%; border-collapse: collapse; margin-bottom: 20px;">
<tr>
<td style="padding: 8px 0; color: #6b7280; width: 100px;">User:</td>
<td style="padding: 8px 0; color: #111827; font-weight: 500;">${userName}</td>
</tr>
<tr>
<td style="padding: 8px 0; color: #6b7280;">Dataset:</td>
<td style="padding: 8px 0; color: #111827; font-weight: 500;">${datasetName} (ID: ${datasetId})</td>
</tr>
</table>

<h3 style="font-size: 16px; color: #1f2937; margin: 15px 0 10px 0;">Changes Made:</h3>
<ul style="color: #374151; font-size: 14px; margin: 0; padding-left: 20px;">
${changes.map((change) => `<li>${change}</li>`).join("")}
</ul>

<!-- CTA Button -->
<div style="text-align: center; margin: 20px 0;">
<a href="${datasetLink}" class="cta-button" style="background: linear-gradient(135deg, #6366f1, #8b5cf6, #ec4899); color: #ffffff; padding: 12px 24px; text-decoration: none; border-radius: 6px; display: inline-block; font-weight: 600; font-size: 14px;">View Dataset</a>
</div>
</div>

<p style="color: #6b7280; font-size: 14px; margin-top: 20px; text-align: center;">
This is an automated notification for OpenML Admins/Owners.
</p>
`;

return baseLayout(content, logoUrl);
};
51 changes: 51 additions & 0 deletions app-next/src/lib/email-templates/entity-created.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { baseLayout } from "./layout";

type EntityType = "dataset" | "task" | "collection";

const ENTITY_LABELS: Record<EntityType, string> = {
dataset: "Dataset",
task: "Task",
collection: "Collection",
};

export const generateEntityCreatedEmail = (
entityType: EntityType,
entityName: string,
entityId: string,
entityUrl: string,
logoUrl: string,
) => {
const label = ENTITY_LABELS[entityType];

const content = `
<h1 style="color: #4338ca; margin: 0 0 20px 0; font-size: 24px; font-weight: 700; text-align: center;">${label} Created Successfully</h1>

<div style="background: #ffffff; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.05);">
<h2 style="font-size: 18px; color: #1f2937; margin: 0 0 10px 0;">${label} Details</h2>
<table style="width: 100%; border-collapse: collapse; margin-bottom: 20px;">
<tr>
<td style="padding: 8px 0; color: #6b7280; width: 100px;">${label}:</td>
<td style="padding: 8px 0; color: #111827; font-weight: 500;">${entityName}</td>
</tr>
<tr>
<td style="padding: 8px 0; color: #6b7280;">ID:</td>
<td style="padding: 8px 0; color: #111827; font-weight: 500;">${entityId}</td>
</tr>
</table>

<p style="color: #374151; font-size: 14px; margin: 0 0 20px 0;">
Your ${label.toLowerCase()} has been submitted to OpenML and will be available shortly.
</p>

<div style="text-align: center; margin: 20px 0;">
<a href="${entityUrl}" class="cta-button" style="background: linear-gradient(135deg, #6366f1, #8b5cf6, #ec4899); color: #ffffff; padding: 12px 24px; text-decoration: none; border-radius: 6px; display: inline-block; font-weight: 600; font-size: 14px;">View ${label}</a>
</div>
</div>

<p style="color: #6b7280; font-size: 14px; margin-top: 20px; text-align: center;">
This is an automated confirmation from OpenML.
</p>
`;

return baseLayout(content, logoUrl);
};
64 changes: 64 additions & 0 deletions app-next/src/lib/email-templates/layout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
export const baseLayout = (content: string, logoUrl: string) => `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenML Email</title>
<style>
/* Global link hover */
a:hover {
text-decoration: underline!important;
}

/* CTA Button class for hover states */
.cta-button {
background: linear-gradient(135deg, #6366f1, #8b5cf6, #ec4899) !important;
color: #ffffff !important;
text-decoration: none !important;
font-weight: 600 !important;
display: inline-block !important;
padding: 14px 30px !important;
border-radius: 6px !important;
box-shadow: 0 4px 6px rgba(37, 99, 235, 0.2) !important;
}
.cta-button:hover {
background: rgba(37, 99, 235, 0.2) !important;
color: #ffffff !important;
opacity: 0.9 !important;
box-shadow: 0 6px 8px rgba(37, 99, 235, 0.3) !important;
transform: translateY(-1px);
}
</style>
</head>
<body style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background: #f3f4f6; margin: 0; padding: 20px;">
<div style="max-width: 670px margin: 0 auto; background: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);">

<!-- Header -->
<div style="background: rgba(37, 99, 235, 0.2); background: linear-gradient(135deg, #6366f1, #8b5cf6, #ec4899); padding: 40px 20px; text-align: center;">
<img src="${logoUrl}" alt="OpenML Logo" style="max-width: 300px; height: auto; margin: 0px auto;" />
</div>

<!-- Main Content -->
<div style="padding: 25px; background:transparent;">
${content}

<!-- Support Info -->
<div style="border-top: 2px solid #e5e7eb; padding-top: 20px; margin-top: 30px;">
<p style="color: #6b7280; font-size: 14px; line-height: 1.6; margin-bottom: 10px;">
Need help? Contact us at <a href="mailto:openmachinelearning@gmail.com" style="color: #233044; text-decoration: none;">openmachinelearning@gmail.com</a>
</p>
<p style="color: #374151; font-size: 15px; line-height: 1.6; margin-bottom: 5px;">Best regards,</p>
<p style="color: #233044; font-size: 15px; font-weight: 600; margin: 0;">The OpenML Team</p>
</div>
</div>

<!-- Footer -->
<div style="background: #233044; padding: 20px 30px; text-align: center; border-top: 1px solid #e5e7eb;">
<p style="color: #e5e7eb; font-size: 12px; margin: 0;">© ${new Date().getFullYear()} OpenML. Open Machine Learning Platform.</p>
</div>

</div>
</body>
</html>
`;
37 changes: 37 additions & 0 deletions app-next/src/lib/email-templates/profile-update.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Email specific components
import { baseLayout } from "./layout";

export const generateProfileUpdateEmail = (
name: string,
fields: string[],
logoUrl: string,
) => {
const content = `
<!-- Content for Profile Update -->
<h1 style="color: #111827; margin: 0 0 20px 0; font-size: 28px; font-weight: 700; text-align: center;">Security Alert: Profile Updated</h1>

<p style="color: #374151; font-size: 16px; line-height: 1.6; margin-bottom: 20px;">Hi ${name},</p>
<p style="color: #374151; font-size: 16px; line-height: 1.6; margin-bottom: 20px;">
This email is to notify you that your OpenML profile was recently updated.
</p>

<!-- Changed Fields -->
<div style="background: #f3f4f6; padding: 20px; border-radius: 8px; margin: 30px 0;">
<p style="color: #233044; font-size: 14px; font-weight: 600; margin: 0 0 10px 0;">The following items were changed:</p>
<ul style="color: #374151; font-size: 14px; margin: 0; padding-left: 20px;">
${fields.map((field) => `<li>${field}</li>`).join("")}
</ul>
</div>

<p style="color: #374151; font-size: 16px; line-height: 1.6; margin-bottom: 20px;">
If you made these changes, you can safely ignore this email.
</p>

<!-- Security Warning -->
<div style="background-color: #fef3c7; border-left: 4px solid #f59e0b; padding: 15px; border-radius: 4px; margin: 20px 0;">
<p style="color: #92400e; font-size: 14px; margin: 0; line-height: 1.6;"><strong>🔒 Was this not you?</strong> Please <a href="https://www.openml.org/auth/reset-password" style="color: #92400e; text-decoration: underline;">reset your password</a> immediately or contact support.</p>
</div>
`;

return baseLayout(content, logoUrl);
};
35 changes: 35 additions & 0 deletions app-next/src/lib/email-templates/reset-password.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { baseLayout } from "./layout";

export const generateResetPasswordEmail = (link: string, logoUrl: string) => {
const content = `
<!-- Content for Reset Password -->
<h1 style="color: #111827; margin: 0 0 20px 0; font-size: 28px; font-weight: 700; text-align: center;">Reset Your Password</h1>

<p style="color: #374151; font-size: 16px; line-height: 1.6; margin-bottom: 20px;">Hi there,</p>
<p style="color: #374151; font-size: 16px; line-height: 1.6; margin-bottom: 20px;">We received a request to reset your password for your OpenML account.</p>
<p style="color: #374151; font-size: 16px; line-height: 1.6; margin-bottom: 30px;">Click the button below to create a new password:</p>

<!-- CTA Button -->
<div style="text-align: center; margin: 40px 0;">
<a href="${link}" class="cta-button" style="background: linear-gradient(135deg, #6366f1, #8b5cf6, #ec4899); color: #ffffff; padding: 14px 30px; text-decoration: none; border-radius: 6px; display: inline-block; font-weight: 600; font-size: 16px; box-shadow: 0 4px 6px rgba(37, 99, 235, 0.2);">Reset Password</a>
</div>


<!-- Alternative Link -->
<div style="background: #f3f4f6; padding: 20px; border-radius: 8px; margin: 30px 0;">
<p style="color: #6b7280; font-size: 14px; margin: 0 0 10px 0;">Or copy and paste this link into your browser:</p>
<p style="color: #233044; font-size: 14px; word-break: break-all; margin: 0;">${link}</p>
</div>

<p style="color: #6b7280; font-size: 14px; line-height: 1.6; margin-bottom: 10px; font-style: italic;">
⏱️ This reset link will expire in 1 hour.
</p>

<!-- Security Notice -->
<div style="background-color: rgba(255, 167, 38, .2); border-left: 4px solid rgb(255, 167, 38); padding: 15px; border-radius: 4px; margin: 20px 0;">
<p style="color: #92400e; font-size: 14px; margin: 0; line-height: 1.6;"><strong>🔒 Security Notice:</strong> If you didn't request a password reset, please ignore this email. Your password will remain unchanged.</p>
</div>
`;

return baseLayout(content, logoUrl);
};
Loading