1. Update dependencies 2. Use cssnano for production 3. Assign an environment variable to Sentry's environment settings 4. `Pill` now accepts React Nodes so we can pass translations using Trans component 5. Switch to mailpit API during tests 6. Do not require Email Sender to be of type email and add proper error messages
89 lines
2.2 KiB
TypeScript
89 lines
2.2 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
import { getLogger } from '@kit/shared/logger';
|
|
import { Database } from '@kit/supabase/database';
|
|
|
|
type Account = Database['public']['Tables']['accounts']['Row'];
|
|
|
|
export function createAccountWebhooksService() {
|
|
return new AccountWebhooksService();
|
|
}
|
|
|
|
class AccountWebhooksService {
|
|
private readonly namespace = 'accounts.webhooks';
|
|
|
|
async handleAccountDeletedWebhook(account: Account) {
|
|
const logger = await getLogger();
|
|
|
|
const ctx = {
|
|
accountId: account.id,
|
|
namespace: this.namespace,
|
|
};
|
|
|
|
logger.info(ctx, 'Received account deleted webhook. Processing...');
|
|
|
|
if (account.is_personal_account) {
|
|
logger.info(ctx, `Account is personal. We send an email to the user.`);
|
|
|
|
await this.sendDeleteAccountEmail(account);
|
|
}
|
|
}
|
|
|
|
private async sendDeleteAccountEmail(account: Account) {
|
|
const userEmail = account.email;
|
|
const userDisplayName = account.name ?? userEmail;
|
|
|
|
const emailSettings = this.getEmailSettings();
|
|
|
|
if (userEmail) {
|
|
await this.sendAccountDeletionEmail({
|
|
fromEmail: emailSettings.fromEmail,
|
|
productName: emailSettings.productName,
|
|
userDisplayName,
|
|
userEmail,
|
|
});
|
|
}
|
|
}
|
|
|
|
private async sendAccountDeletionEmail(params: {
|
|
fromEmail: string;
|
|
userEmail: string;
|
|
userDisplayName: string;
|
|
productName: string;
|
|
}) {
|
|
const { renderAccountDeleteEmail } = await import('@kit/email-templates');
|
|
const { getMailer } = await import('@kit/mailers');
|
|
|
|
const mailer = await getMailer();
|
|
|
|
const { html, subject } = await renderAccountDeleteEmail({
|
|
userDisplayName: params.userDisplayName,
|
|
productName: params.productName,
|
|
});
|
|
|
|
return mailer.sendEmail({
|
|
to: params.userEmail,
|
|
from: params.fromEmail,
|
|
subject,
|
|
html,
|
|
});
|
|
}
|
|
|
|
private getEmailSettings() {
|
|
const productName = process.env.NEXT_PUBLIC_PRODUCT_NAME;
|
|
const fromEmail = process.env.EMAIL_SENDER;
|
|
|
|
return z
|
|
.object({
|
|
productName: z.string(),
|
|
fromEmail: z.string({
|
|
required_error: 'EMAIL_SENDER is required',
|
|
}).min(1),
|
|
})
|
|
.parse({
|
|
productName,
|
|
fromEmail,
|
|
});
|
|
}
|
|
}
|