[#1317] Update email consolidation script

- Update the emailConsolidation script so that it will de-duplicate the
  first duplicated user
- Sends email to user alerting them that the consolidation has taken
  place.
This commit is contained in:
Cassie Tarakajian 2020-07-16 19:37:37 -04:00
parent f19f52683b
commit cd5c000d6d
4 changed files with 173 additions and 16 deletions

View file

@ -124,6 +124,7 @@ export function moveObjectToUserInS3(url, userId) {
const objectKey = getObjectKey(url); const objectKey = getObjectKey(url);
const fileExtension = getExtension(objectKey); const fileExtension = getExtension(objectKey);
const newFilename = uuid.v4() + fileExtension; const newFilename = uuid.v4() + fileExtension;
console.log(`${process.env.S3_BUCKET}/${objectKey}`);
const params = { const params = {
Bucket: `${process.env.S3_BUCKET}`, Bucket: `${process.env.S3_BUCKET}`,
CopySource: `${process.env.S3_BUCKET}/${objectKey}`, CopySource: `${process.env.S3_BUCKET}/${objectKey}`,

View file

@ -3,6 +3,8 @@ import User from '../models/user';
import Project from '../models/project'; import Project from '../models/project';
import Collection from '../models/collection'; import Collection from '../models/collection';
import { moveObjectToUserInS3 } from '../controllers/aws.controller'; import { moveObjectToUserInS3 } from '../controllers/aws.controller';
import mail from '../utils/mail';
import { renderAccountConsolidation } from '../views/mail';
const mongoConnectionString = process.env.MONGO_URL; const mongoConnectionString = process.env.MONGO_URL;
@ -50,16 +52,31 @@ const agg = [
} }
]; ];
// steps to make this work
// iterate through the results
// check if any files are on AWS
// if so, move them to the right user bucket
// then, update the user to currentUser
// then, after updating all of the projects
// also update the collections
// delete other users
// update user email so it is all lowercase
// then, send the email
// then, figure out how to iterate through all of the users.
let currentUser = null; let currentUser = null;
let duplicates = null; let duplicates = null;
User.aggregate(agg).then((result) => { User.aggregate(agg).then((result) => {
console.log(result);
const email = result[0]._id; const email = result[0]._id;
return User.find({ email }).collation({ locale: 'en', strength: 2 }) return User.find({ email }).collation({ locale: 'en', strength: 2 })
.sort({ createdAt: 1 }).exec(); .sort({ createdAt: 1 }).exec();
}).then((result) => { }).then((result) => {
[currentUser, ...duplicates] = result; [currentUser, ...duplicates] = result;
console.log('Current User: ', currentUser._id, ' ', currentUser.email);
duplicates = duplicates.map(dup => dup._id); duplicates = duplicates.map(dup => dup._id);
console.log(duplicates); console.log('Duplicates: ', duplicates);
return Project.find({ return Project.find({
user: { $in: duplicates } user: { $in: duplicates }
}).exec(); }).exec();
@ -68,7 +85,7 @@ User.aggregate(agg).then((result) => {
sketches.forEach((sketch) => { sketches.forEach((sketch) => {
const moveSketchFilesPromises = []; const moveSketchFilesPromises = [];
sketch.files.forEach((file) => { sketch.files.forEach((file) => {
if (file.url.includes('assets.editor.p5js.org')) { if (file.url && file.url.includes(process.env.S3_BUCKET_URL_BASE)) {
const fileSavePromise = moveObjectToUserInS3(file.url, currentUser._id) const fileSavePromise = moveObjectToUserInS3(file.url, currentUser._id)
.then((newUrl) => { .then((newUrl) => {
file.url = newUrl; file.url = newUrl;
@ -83,19 +100,38 @@ User.aggregate(agg).then((result) => {
saveSketchPromises.push(sketchSavePromise); saveSketchPromises.push(sketchSavePromise);
}); });
return Promise.all(saveSketchPromises); return Promise.all(saveSketchPromises);
// iterate through the results }).then(() => {
// check if any files are on AWS console.log('Moved and updated all sketches.');
// if so, move them to the right user bucket return Collection.updateMany(
// then, update the user to currentUser { owner: { $in: duplicates } },
// then, after updating all of the projects { $set: { owner: ObjectId(currentUser.id) } }
// also update the collections );
// delete other users }).then(() => {
// update user email so it is all lowercase console.log('Moved and updated all collections.');
// then, send the email return User.deleteMany({ _id: { $in: duplicates } });
}).then(() => Collection.updateMany( }).then(() => {
{ owner: { $in: duplicates } }, console.log('Deleted other user accounts.');
{ $set: { owner: ObjectId(currentUser.id) } } currentUser.email = currentUser.email.toLowerCase();
)).then(() => User.deleteMany({ _id: { $in: duplicates } })).catch((err) => { return currentUser.save();
console.log(err); }).then(() => {
console.log('Migrated email to lowercase.');
// const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
const mailOptions = renderAccountConsolidation({
body: {
domain: 'https://editor.p5js.org',
username: currentUser.username,
email: currentUser.email
},
to: currentUser.email,
});
mail.send(mailOptions, (mailErr, result) => {
console.log('Sent email.');
process.exit(0);
});
}); });
// ).then((result) => {
// console.log(result);
// });

View file

@ -0,0 +1,78 @@
export default ({
domain,
headingText,
greetingText,
messageText,
username,
email,
message2Text,
resetPasswordLink,
directLinkText,
resetPasswordText,
noteText,
meta
}) => (
`
<mjml>
<mj-head>
<mj-raw>
<meta name="keywords" content="${meta.keywords}" />
<meta name="description" content="${meta.description}" />
</mj-raw>
</mj-head>
<mj-body>
<mj-container>
<mj-section>
<mj-column>
<mj-image width="192" src="${domain}/images/p5js-square-logo.png" alt="p5.js" />
<mj-divider border-color="#ed225d"></mj-divider>
</mj-column>
</mj-section>
<mj-section>
<mj-column>
<mj-text font-size="20px" color="#333333" font-family="sans-serif">
${headingText}
</mj-text>
</mj-column>
</mj-section>
<mj-section>
<mj-column>
<mj-text color="#333333">
${greetingText}
</mj-text>
<mj-text color="#333333">
${messageText}
</mj-text>
<mj-text color="#333333">
<span style="font-weight:bold;">Username:</span> ${username}
</mj-text>
<mj-text color="#333333">
<span style="font-weight:bold;">Email:</span> ${email}
</mj-text>
<mj-text color="#333333">
${message2Text}
</mj-text>
<mj-button background-color="#ed225d" href="${domain}/${resetPasswordLink}">
${resetPasswordText}
</mj-button>
</mj-column>
</mj-section>
<mj-section>
<mj-column>
<mj-text color="#333333">
${directLinkText}
</mj-text>
<mj-text align="center" color="#333333"><a href="${domain}/${resetPasswordLink}">${domain}/${resetPasswordLink}</a></mj-text>
<mj-text color="#333333">
${noteText}
</mj-text>
</mj-column>
</mj-section>
</mj-container>
</mj-body>
</mjml>
`
);

View file

@ -1,5 +1,47 @@
import renderMjml from '../utils/renderMjml'; import renderMjml from '../utils/renderMjml';
import mailLayout from './mailLayout'; import mailLayout from './mailLayout';
import consolidationMailLayout from './consolidationMailLayout';
export const renderAccountConsolidation = (data) => {
const subject = 'p5.js Web Editor Account Consolidation';
const templateOptions = {
domain: data.body.domain,
headingText: 'Account Consolidation',
greetingText: 'Hello,',
messageText: `You're receiving this message because you previous registered for the
<a href="https://editor.p5js.org">p5.js Web Editor</a>
using the same email address multiple times. In order to fix bugs and prevent future bugs,
your accounts have been consolidated to the first account you created. You can login with
the following email and username:`,
username: data.body.username,
email: data.body.email,
message2Text: `All of your sketches and collections have been preserved and have not been modified.
If you have forgotten your password you can reset it:`,
resetPasswordLink: 'reset-password',
resetPasswordText: 'Reset Password',
directLinkText: 'Or copy and paste the following URL into your browser:',
noteText: `We are grateful for your patience and understanding. Thank you for supporting p5.js and the
p5.js Web Editor!`,
meta: {
keywords: 'p5.js, p5.js web editor, web editor, processing, code editor',
description: 'A web editor for p5.js, a JavaScript library with the goal'
+ ' of making coding accessible to artists, designers, educators, and beginners.'
}
};
// Return MJML string
const template = consolidationMailLayout(templateOptions);
// Render MJML to HTML string
const html = renderMjml(template);
// Return options to send mail
return Object.assign(
{},
data,
{ html, subject },
);
};
export const renderResetPassword = (data) => { export const renderResetPassword = (data) => {
const subject = 'p5.js Web Editor Password Reset'; const subject = 'p5.js Web Editor Password Reset';