mirror of
https://github.com/wassname/talk.git
synced 2026-06-28 23:58:38 +08:00
149 lines
4.3 KiB
JavaScript
149 lines
4.3 KiB
JavaScript
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, I18n },
|
|
models: { User },
|
|
graph: { Context },
|
|
} = connectors;
|
|
|
|
// Setup the mail templates.
|
|
['txt', 'html'].forEach(format => {
|
|
Mailer.templates.register(
|
|
path.join(__dirname, 'emails', `download.${format}.ejs`),
|
|
'download',
|
|
format
|
|
);
|
|
});
|
|
|
|
// Setup the cron job that will scan for accounts to delete every 30 minutes.
|
|
new CronJob({
|
|
cronTime: '0,30 * * * *',
|
|
timeZone: 'America/New_York',
|
|
start: true,
|
|
runOnInit: true,
|
|
onTick: async () => {
|
|
// Create the context we'll use to perform user deletions.
|
|
const ctx = Context.forSystem();
|
|
|
|
try {
|
|
// Grab some settings.
|
|
const {
|
|
loaders: { Settings },
|
|
} = ctx;
|
|
const {
|
|
organizationName,
|
|
organizationContactEmail,
|
|
} = await Settings.select(
|
|
'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()
|
|
.add(1, 'hours')
|
|
.toDate();
|
|
|
|
// Keep running for each user we can pull.
|
|
while (true) {
|
|
// We'll find any user that has an account deletion date before now
|
|
// and update the user such that their deletion time is 1 hour from
|
|
// now. This will ensure that only one instance can pull the same
|
|
// user at a time, and if the delete fails, it will be retried an
|
|
// hour from now. If the deletion was successful, well, it can't be
|
|
// retried because the reference to the scheduledDeletionDate will
|
|
// get deleted along with the user.
|
|
const user = await User.findOneAndUpdate(
|
|
{
|
|
'metadata.scheduledDeletionDate': { $lte: new Date() },
|
|
},
|
|
{
|
|
$set: {
|
|
'metadata.scheduledDeletionDate': rescheduledDeletionDate,
|
|
},
|
|
}
|
|
);
|
|
if (!user) {
|
|
// There are no more users that meet the search criteria! We're
|
|
// done!
|
|
ctx.log.info('no more users are scheduled for deletion');
|
|
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,
|
|
scheduledDeletionDate: user.metadata.scheduledDeletionDate,
|
|
},
|
|
'starting user delete'
|
|
);
|
|
|
|
// Delete the user using the existing graph call.
|
|
const { data, errors } = await ctx.graphql(
|
|
`
|
|
mutation DeleteUser($user_id: ID!) {
|
|
delUser(id: $user_id) {
|
|
errors {
|
|
translation_key
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
{ user_id: user.id }
|
|
);
|
|
if (errors) {
|
|
throw errors;
|
|
}
|
|
|
|
if (data.errors) {
|
|
throw data.errors;
|
|
}
|
|
|
|
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', organizationName),
|
|
email,
|
|
});
|
|
}
|
|
} catch (err) {
|
|
ctx.log.error({ err }, 'could not handle user deletions');
|
|
}
|
|
},
|
|
});
|
|
};
|