Skip to content

Commit cd5c000

Browse files
committed
[#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.
1 parent f19f526 commit cd5c000

File tree

4 files changed

+173
-16
lines changed

4 files changed

+173
-16
lines changed

server/controllers/aws.controller.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export function moveObjectToUserInS3(url, userId) {
124124
const objectKey = getObjectKey(url);
125125
const fileExtension = getExtension(objectKey);
126126
const newFilename = uuid.v4() + fileExtension;
127+
console.log(`${process.env.S3_BUCKET}/${objectKey}`);
127128
const params = {
128129
Bucket: `${process.env.S3_BUCKET}`,
129130
CopySource: `${process.env.S3_BUCKET}/${objectKey}`,

server/migrations/emailConsolidation.js

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import User from '../models/user';
33
import Project from '../models/project';
44
import Collection from '../models/collection';
55
import { moveObjectToUserInS3 } from '../controllers/aws.controller';
6+
import mail from '../utils/mail';
7+
import { renderAccountConsolidation } from '../views/mail';
68

79

810
const mongoConnectionString = process.env.MONGO_URL;
@@ -50,16 +52,31 @@ const agg = [
5052
}
5153
];
5254

55+
56+
// steps to make this work
57+
// iterate through the results
58+
// check if any files are on AWS
59+
// if so, move them to the right user bucket
60+
// then, update the user to currentUser
61+
// then, after updating all of the projects
62+
// also update the collections
63+
// delete other users
64+
// update user email so it is all lowercase
65+
// then, send the email
66+
// then, figure out how to iterate through all of the users.
67+
5368
let currentUser = null;
5469
let duplicates = null;
5570
User.aggregate(agg).then((result) => {
71+
console.log(result);
5672
const email = result[0]._id;
5773
return User.find({ email }).collation({ locale: 'en', strength: 2 })
5874
.sort({ createdAt: 1 }).exec();
5975
}).then((result) => {
6076
[currentUser, ...duplicates] = result;
77+
console.log('Current User: ', currentUser._id, ' ', currentUser.email);
6178
duplicates = duplicates.map(dup => dup._id);
62-
console.log(duplicates);
79+
console.log('Duplicates: ', duplicates);
6380
return Project.find({
6481
user: { $in: duplicates }
6582
}).exec();
@@ -68,7 +85,7 @@ User.aggregate(agg).then((result) => {
6885
sketches.forEach((sketch) => {
6986
const moveSketchFilesPromises = [];
7087
sketch.files.forEach((file) => {
71-
if (file.url.includes('assets.editor.p5js.org')) {
88+
if (file.url && file.url.includes(process.env.S3_BUCKET_URL_BASE)) {
7289
const fileSavePromise = moveObjectToUserInS3(file.url, currentUser._id)
7390
.then((newUrl) => {
7491
file.url = newUrl;
@@ -83,19 +100,38 @@ User.aggregate(agg).then((result) => {
83100
saveSketchPromises.push(sketchSavePromise);
84101
});
85102
return Promise.all(saveSketchPromises);
86-
// iterate through the results
87-
// check if any files are on AWS
88-
// if so, move them to the right user bucket
89-
// then, update the user to currentUser
90-
// then, after updating all of the projects
91-
// also update the collections
92-
// delete other users
93-
// update user email so it is all lowercase
94-
// then, send the email
95-
}).then(() => Collection.updateMany(
96-
{ owner: { $in: duplicates } },
97-
{ $set: { owner: ObjectId(currentUser.id) } }
98-
)).then(() => User.deleteMany({ _id: { $in: duplicates } })).catch((err) => {
99-
console.log(err);
103+
}).then(() => {
104+
console.log('Moved and updated all sketches.');
105+
return Collection.updateMany(
106+
{ owner: { $in: duplicates } },
107+
{ $set: { owner: ObjectId(currentUser.id) } }
108+
);
109+
}).then(() => {
110+
console.log('Moved and updated all collections.');
111+
return User.deleteMany({ _id: { $in: duplicates } });
112+
}).then(() => {
113+
console.log('Deleted other user accounts.');
114+
currentUser.email = currentUser.email.toLowerCase();
115+
return currentUser.save();
116+
}).then(() => {
117+
console.log('Migrated email to lowercase.');
118+
// const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
119+
const mailOptions = renderAccountConsolidation({
120+
body: {
121+
domain: 'https://editor.p5js.org',
122+
username: currentUser.username,
123+
email: currentUser.email
124+
},
125+
to: currentUser.email,
126+
});
127+
128+
mail.send(mailOptions, (mailErr, result) => {
129+
console.log('Sent email.');
130+
process.exit(0);
131+
});
100132
});
101133

134+
// ).then((result) => {
135+
// console.log(result);
136+
// });
137+
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
export default ({
2+
domain,
3+
headingText,
4+
greetingText,
5+
messageText,
6+
username,
7+
email,
8+
message2Text,
9+
resetPasswordLink,
10+
directLinkText,
11+
resetPasswordText,
12+
noteText,
13+
meta
14+
}) => (
15+
`
16+
<mjml>
17+
<mj-head>
18+
<mj-raw>
19+
<meta name="keywords" content="${meta.keywords}" />
20+
<meta name="description" content="${meta.description}" />
21+
</mj-raw>
22+
</mj-head>
23+
<mj-body>
24+
<mj-container>
25+
<mj-section>
26+
<mj-column>
27+
<mj-image width="192" src="${domain}/images/p5js-square-logo.png" alt="p5.js" />
28+
<mj-divider border-color="#ed225d"></mj-divider>
29+
</mj-column>
30+
</mj-section>
31+
32+
<mj-section>
33+
<mj-column>
34+
<mj-text font-size="20px" color="#333333" font-family="sans-serif">
35+
${headingText}
36+
</mj-text>
37+
</mj-column>
38+
</mj-section>
39+
40+
<mj-section>
41+
<mj-column>
42+
<mj-text color="#333333">
43+
${greetingText}
44+
</mj-text>
45+
<mj-text color="#333333">
46+
${messageText}
47+
</mj-text>
48+
<mj-text color="#333333">
49+
<span style="font-weight:bold;">Username:</span> ${username}
50+
</mj-text>
51+
<mj-text color="#333333">
52+
<span style="font-weight:bold;">Email:</span> ${email}
53+
</mj-text>
54+
<mj-text color="#333333">
55+
${message2Text}
56+
</mj-text>
57+
<mj-button background-color="#ed225d" href="${domain}/${resetPasswordLink}">
58+
${resetPasswordText}
59+
</mj-button>
60+
</mj-column>
61+
</mj-section>
62+
63+
<mj-section>
64+
<mj-column>
65+
<mj-text color="#333333">
66+
${directLinkText}
67+
</mj-text>
68+
<mj-text align="center" color="#333333"><a href="${domain}/${resetPasswordLink}">${domain}/${resetPasswordLink}</a></mj-text>
69+
<mj-text color="#333333">
70+
${noteText}
71+
</mj-text>
72+
</mj-column>
73+
</mj-section>
74+
</mj-container>
75+
</mj-body>
76+
</mjml>
77+
`
78+
);

server/views/mail.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,47 @@
11
import renderMjml from '../utils/renderMjml';
22
import mailLayout from './mailLayout';
3+
import consolidationMailLayout from './consolidationMailLayout';
4+
5+
export const renderAccountConsolidation = (data) => {
6+
const subject = 'p5.js Web Editor Account Consolidation';
7+
const templateOptions = {
8+
domain: data.body.domain,
9+
headingText: 'Account Consolidation',
10+
greetingText: 'Hello,',
11+
messageText: `You're receiving this message because you previous registered for the
12+
<a href="https://editor.p5js.org">p5.js Web Editor</a>
13+
using the same email address multiple times. In order to fix bugs and prevent future bugs,
14+
your accounts have been consolidated to the first account you created. You can login with
15+
the following email and username:`,
16+
username: data.body.username,
17+
email: data.body.email,
18+
message2Text: `All of your sketches and collections have been preserved and have not been modified.
19+
If you have forgotten your password you can reset it:`,
20+
resetPasswordLink: 'reset-password',
21+
resetPasswordText: 'Reset Password',
22+
directLinkText: 'Or copy and paste the following URL into your browser:',
23+
noteText: `We are grateful for your patience and understanding. Thank you for supporting p5.js and the
24+
p5.js Web Editor!`,
25+
meta: {
26+
keywords: 'p5.js, p5.js web editor, web editor, processing, code editor',
27+
description: 'A web editor for p5.js, a JavaScript library with the goal'
28+
+ ' of making coding accessible to artists, designers, educators, and beginners.'
29+
}
30+
};
31+
32+
// Return MJML string
33+
const template = consolidationMailLayout(templateOptions);
34+
35+
// Render MJML to HTML string
36+
const html = renderMjml(template);
37+
38+
// Return options to send mail
39+
return Object.assign(
40+
{},
41+
data,
42+
{ html, subject },
43+
);
44+
};
345

446
export const renderResetPassword = (data) => {
547
const subject = 'p5.js Web Editor Password Reset';

0 commit comments

Comments
 (0)