mirror of
https://github.com/wassname/talk.git
synced 2026-06-29 12:08:41 +08:00
Merge branch 'gdpr-delete' of github.com:coralproject/talk into gdpr-delete
* 'gdpr-delete' of github.com:coralproject/talk: added emails around account deletion
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
const path = require('path');
|
||||
const moment = require('moment');
|
||||
const { CronJob } = require('cron');
|
||||
const { get } = require('lodash');
|
||||
const { ErrMissingEmail } = require('errors');
|
||||
|
||||
module.exports = connectors => {
|
||||
const {
|
||||
services: { Mailer },
|
||||
services: { Mailer, I18n },
|
||||
models: { User },
|
||||
graph: { Context },
|
||||
} = connectors;
|
||||
@@ -28,6 +30,13 @@ module.exports = connectors => {
|
||||
// Create the context we'll use to perform user deletions.
|
||||
const ctx = Context.forSystem();
|
||||
|
||||
// Grab some settings.
|
||||
const { loaders: { Settings } } = ctx;
|
||||
const {
|
||||
organizationName,
|
||||
organizationContactEmail,
|
||||
} = await Settings.load(['organizationName', 'organizationContactEmail']);
|
||||
|
||||
// rescheduledDeletionDate is the date in the future that we'll set the
|
||||
// user's account to be deleted on if this delete fails.
|
||||
const rescheduledDeletionDate = moment()
|
||||
@@ -61,6 +70,26 @@ module.exports = connectors => {
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the user's email address.
|
||||
const reply = await ctx.graphql(
|
||||
`
|
||||
query GetUserEmailAddress($user_id: ID!) {
|
||||
user(id: $user_id) {
|
||||
email
|
||||
}
|
||||
}
|
||||
`,
|
||||
{ user_id: user.id }
|
||||
);
|
||||
if (reply.errors) {
|
||||
throw reply.errors;
|
||||
}
|
||||
|
||||
const email = get(reply, 'data.user.email');
|
||||
if (!email) {
|
||||
throw new ErrMissingEmail();
|
||||
}
|
||||
|
||||
ctx.log.info(
|
||||
{
|
||||
userID: user.id,
|
||||
@@ -91,6 +120,20 @@ module.exports = connectors => {
|
||||
}
|
||||
|
||||
ctx.log.info({ userID: user.id }, 'user was deleted successfully');
|
||||
|
||||
// Send the download link via the user's attached email account.
|
||||
await Mailer.send({
|
||||
template: 'plain',
|
||||
locals: {
|
||||
body: I18n.t(
|
||||
'email.deleted.body',
|
||||
organizationName,
|
||||
organizationContactEmail
|
||||
),
|
||||
},
|
||||
subject: I18n.t('email.deleted.subject'),
|
||||
email,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
ctx.log.error({ err }, 'could not handle user deletions');
|
||||
|
||||
@@ -104,31 +104,64 @@ async function sendDownloadLink(ctx) {
|
||||
// requestDeletion will schedule the current user to have their account deleted
|
||||
// by setting the `scheduledDeletionDate` on the user
|
||||
// ${scheduledDeletionDelayHours} hours from now.
|
||||
async function requestDeletion({ user, connectors: { models: { User } } }) {
|
||||
async function requestDeletion({
|
||||
user,
|
||||
loaders: { Settings },
|
||||
connectors: { models: { User }, services: { Users, I18n } },
|
||||
}) {
|
||||
// Ensure the user doesn't already have a deletion scheduled.
|
||||
if (get(user, 'metadata.scheduledDeletionDate')) {
|
||||
throw new ErrDeletionAlreadyScheduled();
|
||||
}
|
||||
|
||||
// Get the date in the future ${scheduledDeletionDelayHours} hours from now.
|
||||
const scheduledDeletionDate = moment()
|
||||
.add(scheduledDeletionDelayHours, 'hours')
|
||||
.toDate();
|
||||
const scheduledDeletionDate = moment().add(
|
||||
scheduledDeletionDelayHours,
|
||||
'hours'
|
||||
);
|
||||
|
||||
// Amend the scheduledDeletionDate on the user.
|
||||
await User.update(
|
||||
{ id: user.id },
|
||||
{ $set: { 'metadata.scheduledDeletionDate': scheduledDeletionDate } }
|
||||
{
|
||||
$set: {
|
||||
'metadata.scheduledDeletionDate': scheduledDeletionDate.toDate(),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return scheduledDeletionDate;
|
||||
const { organizationName } = await Settings.load('organizationName');
|
||||
|
||||
// Send the download link via the user's attached email account.
|
||||
await Users.sendEmail(user, {
|
||||
template: 'plain',
|
||||
locals: {
|
||||
body: I18n.t(
|
||||
'email.delete.body',
|
||||
organizationName,
|
||||
scheduledDeletionDate.format('MMM Do YYYY, h:mm:ss a')
|
||||
),
|
||||
},
|
||||
subject: I18n.t('email.delete.subject'),
|
||||
});
|
||||
|
||||
return scheduledDeletionDate.toDate();
|
||||
}
|
||||
|
||||
// cancelDeletion will unset the scheduled deletion date on the user account
|
||||
// that is used to indicate that the user was scheduled for deletion.
|
||||
async function cancelDeletion({ user, connectors: { models: { User } } }) {
|
||||
async function cancelDeletion({
|
||||
user,
|
||||
loaders: { Settings },
|
||||
connectors: { models: { User }, services: { I18n, Users } },
|
||||
}) {
|
||||
// Ensure the user has a deletion scheduled.
|
||||
if (!get(user, 'metadata.scheduledDeletionDate', null)) {
|
||||
const scheduledDeletionDate = get(
|
||||
user,
|
||||
'metadata.scheduledDeletionDate',
|
||||
null
|
||||
);
|
||||
if (!scheduledDeletionDate) {
|
||||
throw new ErrDeletionNotScheduled();
|
||||
}
|
||||
|
||||
@@ -137,6 +170,21 @@ async function cancelDeletion({ user, connectors: { models: { User } } }) {
|
||||
{ id: user.id },
|
||||
{ $unset: { 'metadata.scheduledDeletionDate': 1 } }
|
||||
);
|
||||
|
||||
const { organizationName } = await Settings.load('organizationName');
|
||||
|
||||
// Send the download link via the user's attached email account.
|
||||
await Users.sendEmail(user, {
|
||||
template: 'plain',
|
||||
locals: {
|
||||
body: I18n.t(
|
||||
'email.cancelDelete.body',
|
||||
organizationName,
|
||||
moment(scheduledDeletionDate).format('MMM Do YYYY, h:mm:ss a')
|
||||
),
|
||||
},
|
||||
subject: I18n.t('email.cancelDelete.subject'),
|
||||
});
|
||||
}
|
||||
|
||||
// downloadUser will return the download file url that can be used to directly
|
||||
|
||||
@@ -14,5 +14,17 @@ en:
|
||||
subject: "Your comments are ready for download from {0}"
|
||||
download_link_ready: "Click here to download your comments from {0} as of {1}:"
|
||||
download_archive: "Download Archive"
|
||||
delete:
|
||||
subject: "Commenter Account Deletion Request"
|
||||
body: "You have submitted a request to delete your commenter account on {0}. Your account will be deleted on {1}. If you change your mind, you can reactivate your account by logging in and cancelling the request."
|
||||
deleted:
|
||||
subject: "Commenter Account Deleted"
|
||||
body: |
|
||||
Your commenter account for {0} is now deleted. We’re sorry to see you go!
|
||||
If you’d like to re-join the discussion in the future, you can sign up for a new account.
|
||||
If you’d like to give us feedback on why you left and what we can do to make the commenting experience better, please email us at {1}.
|
||||
cancelDelete:
|
||||
subject: "Commenter Account Reactivated"
|
||||
body: "You have cancelled your account deletion request for {0}. Your account is now reactivated."
|
||||
error:
|
||||
DOWNLOAD_TOKEN_INVALID: "Your download link is not valid."
|
||||
|
||||
Reference in New Issue
Block a user