From cd5c000d6db3790920e3c551d5fd91645e6af550 Mon Sep 17 00:00:00 2001 From: Cassie Tarakajian Date: Thu, 16 Jul 2020 19:37:37 -0400 Subject: [PATCH] [#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. --- server/controllers/aws.controller.js | 1 + server/migrations/emailConsolidation.js | 68 ++++++++++++++++----- server/views/consolidationMailLayout.js | 78 +++++++++++++++++++++++++ server/views/mail.js | 42 +++++++++++++ 4 files changed, 173 insertions(+), 16 deletions(-) create mode 100644 server/views/consolidationMailLayout.js diff --git a/server/controllers/aws.controller.js b/server/controllers/aws.controller.js index 32122c71..a331a98c 100644 --- a/server/controllers/aws.controller.js +++ b/server/controllers/aws.controller.js @@ -124,6 +124,7 @@ export function moveObjectToUserInS3(url, userId) { const objectKey = getObjectKey(url); const fileExtension = getExtension(objectKey); const newFilename = uuid.v4() + fileExtension; + console.log(`${process.env.S3_BUCKET}/${objectKey}`); const params = { Bucket: `${process.env.S3_BUCKET}`, CopySource: `${process.env.S3_BUCKET}/${objectKey}`, diff --git a/server/migrations/emailConsolidation.js b/server/migrations/emailConsolidation.js index 7b8dd1d8..d259d918 100644 --- a/server/migrations/emailConsolidation.js +++ b/server/migrations/emailConsolidation.js @@ -3,6 +3,8 @@ import User from '../models/user'; import Project from '../models/project'; import Collection from '../models/collection'; import { moveObjectToUserInS3 } from '../controllers/aws.controller'; +import mail from '../utils/mail'; +import { renderAccountConsolidation } from '../views/mail'; 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 duplicates = null; User.aggregate(agg).then((result) => { + console.log(result); const email = result[0]._id; return User.find({ email }).collation({ locale: 'en', strength: 2 }) .sort({ createdAt: 1 }).exec(); }).then((result) => { [currentUser, ...duplicates] = result; + console.log('Current User: ', currentUser._id, ' ', currentUser.email); duplicates = duplicates.map(dup => dup._id); - console.log(duplicates); + console.log('Duplicates: ', duplicates); return Project.find({ user: { $in: duplicates } }).exec(); @@ -68,7 +85,7 @@ User.aggregate(agg).then((result) => { sketches.forEach((sketch) => { const moveSketchFilesPromises = []; 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) .then((newUrl) => { file.url = newUrl; @@ -83,19 +100,38 @@ User.aggregate(agg).then((result) => { saveSketchPromises.push(sketchSavePromise); }); return Promise.all(saveSketchPromises); - // 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(() => Collection.updateMany( - { owner: { $in: duplicates } }, - { $set: { owner: ObjectId(currentUser.id) } } -)).then(() => User.deleteMany({ _id: { $in: duplicates } })).catch((err) => { - console.log(err); +}).then(() => { + console.log('Moved and updated all sketches.'); + return Collection.updateMany( + { owner: { $in: duplicates } }, + { $set: { owner: ObjectId(currentUser.id) } } + ); +}).then(() => { + console.log('Moved and updated all collections.'); + return User.deleteMany({ _id: { $in: duplicates } }); +}).then(() => { + console.log('Deleted other user accounts.'); + currentUser.email = currentUser.email.toLowerCase(); + return currentUser.save(); +}).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); +// }); + diff --git a/server/views/consolidationMailLayout.js b/server/views/consolidationMailLayout.js new file mode 100644 index 00000000..fa986024 --- /dev/null +++ b/server/views/consolidationMailLayout.js @@ -0,0 +1,78 @@ +export default ({ + domain, + headingText, + greetingText, + messageText, + username, + email, + message2Text, + resetPasswordLink, + directLinkText, + resetPasswordText, + noteText, + meta +}) => ( + ` + + + + + + + + + + + + + + + + + + + + ${headingText} + + + + + + + + ${greetingText} + + + ${messageText} + + + Username: ${username} + + + Email: ${email} + + + ${message2Text} + + + ${resetPasswordText} + + + + + + + + ${directLinkText} + + ${domain}/${resetPasswordLink} + + ${noteText} + + + + + + +` +); diff --git a/server/views/mail.js b/server/views/mail.js index 43aaf3cb..07e5c5e5 100644 --- a/server/views/mail.js +++ b/server/views/mail.js @@ -1,5 +1,47 @@ import renderMjml from '../utils/renderMjml'; 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 + p5.js Web Editor + 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) => { const subject = 'p5.js Web Editor Password Reset';