feat(server): supplement team email remind (#9483)

fix PD-2047 AF-1996
This commit is contained in:
darkskygit
2025-01-21 05:18:02 +00:00
parent 42428fbf99
commit 1116a1d74e
13 changed files with 345 additions and 17 deletions

View File

@@ -17,6 +17,7 @@ export interface WorkspaceEvents {
}>;
ownerTransferred: Payload<{ email: string; workspaceId: Workspace['id'] }>;
updated: Payload<{ workspaceId: Workspace['id']; count: number }>;
removed: Payload<{ workspaceId: Workspace['id']; userId: User['id'] }>;
};
deleted: Payload<Workspace['id']>;
blob: {

View File

@@ -276,7 +276,39 @@ export class MailService {
}
// =================== Team Workspace Mails ===================
async sendReviewRequestMail(
async sendTeamWorkspaceUpgradedEmail(
to: string,
ws: { id: string; name: string; isOwner: boolean }
) {
const { id: workspaceId, name: workspaceName, isOwner } = ws;
const baseContent = {
subject: `${workspaceName} has been upgraded to team workspace! 🎉`,
title: 'Welcome to the team workspace!',
content: `Great news! ${workspaceName} has been upgraded to team workspace by the workspace owner. You now have access to the following enhanced features:`,
};
if (isOwner) {
baseContent.subject =
'Your workspace has been upgraded to team workspace! 🎉';
baseContent.title = 'Welcome to the team workspace!';
baseContent.content = `${workspaceName} has been upgraded to team workspace with the following benefits:`;
}
const html = emailTemplate({
title: baseContent.title,
content: `${baseContent.content}
✓ 100 GB initial storage + 20 GB per seat
✓ 500 MB of maximum file size
✓ Unlimited team members (10+ seats)
✓ Multiple admin roles
✓ Priority customer support`,
buttonContent: 'Open Workspace',
buttonUrl: this.url.link(`/workspace/${workspaceId}`),
});
return this.sendMail({ to, subject: baseContent.subject, html });
}
async sendReviewRequestEmail(
to: string,
invitee: string,
ws: { id: string; name: string }
@@ -324,7 +356,7 @@ export class MailService {
return this.sendMail({ to, subject, html });
}
async sendOwnerTransferred(to: string, ws: { name: string }) {
async sendOwnershipTransferredEmail(to: string, ws: { name: string }) {
const { name: workspaceName } = ws;
const title = `Your ownership of ${workspaceName} has been transferred`;
@@ -334,4 +366,83 @@ export class MailService {
});
return this.sendMail({ to, subject: title, html });
}
async sendMemberRemovedEmail(to: string, ws: { name: string }) {
const { name: workspaceName } = ws;
const title = `You have been removed from ${workspaceName}`;
const html = emailTemplate({
title: 'Workspace access removed',
content: `You have been removed from {workspace name}. You no longer have access to this workspace.`,
});
return this.sendMail({ to, subject: title, html });
}
async sendWorkspaceExpireRemindEmail(
to: string,
ws: {
id: string;
name: string;
expirationDate: Date;
deletionDate?: Date;
}
) {
const {
id: workspaceId,
name: workspaceName,
expirationDate,
deletionDate,
} = ws;
const baseContent: {
subject: string;
title: string;
content: string;
button?: { buttonContent: string; buttonUrl: string };
} = {
subject: `[Action Required] Your ${workspaceName} team workspace is expiring soon`,
title: 'Team workspace expiring soon',
content: `Your ${workspaceName} team workspace will expire on ${expirationDate}. After expiration, you won't be able to sync or collaborate with team members. Please renew your subscription to continue using all team features.`,
button: {
buttonContent: 'Go to Billing',
// TODO(@darkskygit): use real billing path
buttonUrl: this.url.link(`/workspace/${workspaceId}`),
},
};
if (deletionDate) {
if (deletionDate.getTime() > Date.now()) {
// in 24 hours
if (deletionDate.getTime() - Date.now() < 24 * 60 * 60 * 1000) {
baseContent.subject = `[Action Required] Final warning: Your ${workspaceName} data will be deleted in 24 hours`;
baseContent.title = 'Urgent: Last chance to prevent data loss';
baseContent.content = `Your ${workspaceName} team workspace data will be permanently deleted in 24 hours on ${deletionDate}. To prevent data loss, please take immediate action:
<li>Renew your subscription to restore team features</li>
<li>Export your workspace data from Workspace Settings > Export Workspace</li>`;
} else {
baseContent.subject = `[Action Required] Important: Your ${workspaceName} data will be deleted soon`;
baseContent.title = 'Take action to prevent data loss';
baseContent.content = `Your ${workspaceName} team workspace expired on ${expirationDate}. All workspace data will be permanently deleted on ${deletionDate} (180 days after expiration). To prevent data loss, please either:
<li>Renew your subscription to restore team features</li>
<li>Export your workspace data from Workspace Settings > Export Workspace</li>`;
}
} else {
baseContent.subject = `Data deletion completed for ${workspaceName}`;
baseContent.title = 'Workspace data deleted';
baseContent.content = `All data in ${workspaceName} has been permanently deleted as the workspace remained expired for 180 days. This action cannot be undone.
Thank you for your support of AFFiNE. We hope to see you again in the future.`;
baseContent.button = undefined;
}
} else if (expirationDate.getTime() < Date.now()) {
baseContent.subject = `Your ${workspaceName} team workspace has expired`;
baseContent.title = 'Team workspace expired';
baseContent.content = `Your ${workspaceName} team workspace expired on ${expirationDate}. Your workspace can't sync or collaborate with team members. Please renew your subscription to restore all team features.`;
}
const html = emailTemplate({
title: baseContent.title,
content: baseContent.content,
...baseContent.button,
});
return this.sendMail({ to, subject: baseContent.subject, html });
}
}