diff --git a/app/scenes/CollectionExport.tsx b/app/scenes/CollectionExport.tsx index cf8458684..b1148dd49 100644 --- a/app/scenes/CollectionExport.tsx +++ b/app/scenes/CollectionExport.tsx @@ -25,7 +25,9 @@ function CollectionExport({ collection, onSubmit }: Props) { setIsLoading(false); showToast( - t("Export started, you will receive an email when it’s complete.") + t( + "Export started. If you have notifications enabled, you will receive an email when it's complete." + ) ); onSubmit(); }, diff --git a/app/scenes/Settings/Export.tsx b/app/scenes/Settings/Export.tsx index 160f44b97..05b8d3907 100644 --- a/app/scenes/Settings/Export.tsx +++ b/app/scenes/Settings/Export.tsx @@ -56,7 +56,7 @@ function Export() { {t("Export")} { + protected async beforeSend({ userId, teamId }: Props) { + const notificationSetting = await NotificationSetting.findOne({ + where: { + userId, + teamId, + event: "emails.export_completed", + }, + }); + + return notificationSetting !== null; + } + protected subject() { return "Your requested export"; } diff --git a/server/emails/templates/ExportSuccessEmail.tsx b/server/emails/templates/ExportSuccessEmail.tsx index f39381990..a992790f9 100644 --- a/server/emails/templates/ExportSuccessEmail.tsx +++ b/server/emails/templates/ExportSuccessEmail.tsx @@ -1,4 +1,5 @@ import * as React from "react"; +import { NotificationSetting } from "@server/models"; import BaseEmail from "./BaseEmail"; import Body from "./components/Body"; import Button from "./components/Button"; @@ -10,8 +11,10 @@ import Heading from "./components/Heading"; type Props = { to: string; + userId: string; id: string; teamUrl: string; + teamId: string; }; /** @@ -19,6 +22,18 @@ type Props = { * for download in the settings section. */ export default class ExportSuccessEmail extends BaseEmail { + protected async beforeSend({ userId, teamId }: Props) { + const notificationSetting = await NotificationSetting.findOne({ + where: { + userId, + teamId, + event: "emails.export_completed", + }, + }); + + return notificationSetting !== null; + } + protected subject() { return "Your requested export"; } diff --git a/server/models/NotificationSetting.ts b/server/models/NotificationSetting.ts index f42f98f6e..461503a3c 100644 --- a/server/models/NotificationSetting.ts +++ b/server/models/NotificationSetting.ts @@ -41,6 +41,7 @@ class NotificationSetting extends Model { "emails.invite_accepted", "emails.onboarding", "emails.features", + "emails.export_completed", ], ]) @Column(DataType.STRING) diff --git a/server/models/User.ts b/server/models/User.ts index 2497107c5..dd907c954 100644 --- a/server/models/User.ts +++ b/server/models/User.ts @@ -497,7 +497,9 @@ class User extends ParanoidModel { }; // By default when a user signs up we subscribe them to email notifications - // when documents they created are edited by other team members and onboarding + // when documents they created are edited by other team members and onboarding. + // If the user is an admin, they will also be subscribed to export_completed + // notifications. @AfterCreate static subscribeToNotifications = async ( model: User, @@ -537,6 +539,17 @@ class User extends ParanoidModel { transaction: options.transaction, }), ]); + + if (model.isAdmin) { + await NotificationSetting.findOrCreate({ + where: { + userId: model.id, + teamId: model.teamId, + event: "emails.export_completed", + }, + transaction: options.transaction, + }); + } }; static getCounts = async function (teamId: string) { diff --git a/server/queues/tasks/ExportMarkdownZipTask.ts b/server/queues/tasks/ExportMarkdownZipTask.ts index 1f5c4c651..d5d562a65 100644 --- a/server/queues/tasks/ExportMarkdownZipTask.ts +++ b/server/queues/tasks/ExportMarkdownZipTask.ts @@ -72,8 +72,10 @@ export default class ExportMarkdownZipTask extends BaseTask { await ExportSuccessEmail.schedule({ to: user.email, + userId: user.id, id: fileOperation.id, teamUrl: team.url, + teamId: team.id, }); } catch (error) { await this.updateFileOperation(fileOperation, { @@ -82,7 +84,9 @@ export default class ExportMarkdownZipTask extends BaseTask { }); await ExportFailureEmail.schedule({ to: user.email, + userId: user.id, teamUrl: team.url, + teamId: team.id, }); throw error; } diff --git a/shared/i18n/locales/en_US/translation.json b/shared/i18n/locales/en_US/translation.json index 1cc80c1f8..f67953cb3 100644 --- a/shared/i18n/locales/en_US/translation.json +++ b/shared/i18n/locales/en_US/translation.json @@ -343,7 +343,7 @@ "Sort": "Sort", "Saving": "Saving", "Save": "Save", - "Export started, you will receive an email when it’s complete.": "Export started, you will receive an email when it’s complete.", + "Export started. If you have notifications enabled, you will receive an email when it's complete.": "Export started. If you have notifications enabled, you will receive an email when it's complete.", "Exporting the collection {{collectionName}} may take a few seconds. Your documents will be a zip of folders with files in Markdown format. Please visit the Export section on settings to get the zip.": "Exporting the collection {{collectionName}} may take a few seconds. Your documents will be a zip of folders with files in Markdown format. Please visit the Export section on settings to get the zip.", "Exporting": "Exporting", "Export Collection": "Export Collection", @@ -620,7 +620,7 @@ "This is the screen that team members will first see when they sign in.": "This is the screen that team members will first see when they sign in.", "Export in progress…": "Export in progress…", "Export deleted": "Export deleted", - "A full export might take some time, consider exporting a single document or collection. The exported data is a zip of your documents in Markdown format. You may leave this page once the export has started – we will email a link to {{ userEmail }} when it’s complete.": "A full export might take some time, consider exporting a single document or collection. The exported data is a zip of your documents in Markdown format. You may leave this page once the export has started – we will email a link to {{ userEmail }} when it’s complete.", + "A full export might take some time, consider exporting a single document or collection. The exported data is a zip of your documents in Markdown format. You may leave this page once the export has started – if you have notifications enabled, we will email a link to {{ userEmail }} when it’s complete.": "A full export might take some time, consider exporting a single document or collection. The exported data is a zip of your documents in Markdown format. You may leave this page once the export has started – if you have notifications enabled, we will email a link to {{ userEmail }} when it’s complete.", "Export Requested": "Export Requested", "Requesting Export": "Requesting Export", "Export Data": "Export Data", @@ -650,6 +650,8 @@ "Receive a notification whenever a new collection is created": "Receive a notification whenever a new collection is created", "Invite accepted": "Invite accepted", "Receive a notification when someone you invited creates an account": "Receive a notification when someone you invited creates an account", + "Export completed": "Export completed", + "Receive a notification when an export you requested has been completed": "Receive a notification when an export you requested has been completed", "Getting started": "Getting started", "Tips on getting started with Outline’s features and functionality": "Tips on getting started with Outline’s features and functionality", "New features": "New features",