From 7e32ed5158d6a39bdb72ccd9d4c4e7e7d6112459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Alby?= Date: Wed, 15 May 2019 09:19:03 +0200 Subject: [PATCH] Merge pull request #1766 from overleaf/ta-dropbox-duplicates-script Add Script to Unlink all Duplicate Dropbox uids GitOrigin-RevId: 6db73dee9f04e9006d0aec558cf370b5079df671 --- .../coffee/Features/Email/EmailBuilder.coffee | 11 +++ .../scripts/dropbox/remove_duplicate_uids.js | 72 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 services/web/scripts/dropbox/remove_duplicate_uids.js diff --git a/services/web/app/coffee/Features/Email/EmailBuilder.coffee b/services/web/app/coffee/Features/Email/EmailBuilder.coffee index e7b458d444..85a7b9f86b 100644 --- a/services/web/app/coffee/Features/Email/EmailBuilder.coffee +++ b/services/web/app/coffee/Features/Email/EmailBuilder.coffee @@ -130,6 +130,17 @@ templates.verifyEmailToJoinTeam = CTAEmailTemplate({ ctaURL: (opts) -> opts.acceptInviteUrl }) +templates.dropboxUnlinkedDuplicate = CTAEmailTemplate({ + subject: () -> "Your Dropbox Account has been Unlinked - #{settings.appName}" + message: (opts) -> """ +Our automated systems have detected that your Dropbox account was linked to more than one Overleaf accounts. This should not have been allowed and might be causing issues with the Dropbox sync feature. + +We have now unlinked all your Dropbox and Overleaf Accounts. To ensure your project will keep syncing you can link your Dropbox account to the Overleaf account of your choice now. +""" + ctaText: () -> "Link Dropbox Account" + ctaURL: (opts) -> "#{settings.siteUrl}/user/settings" +}) + templates.testEmail = CTAEmailTemplate({ subject: () -> "A Test Email from #{settings.appName}" title: () -> "A Test Email from #{settings.appName}" diff --git a/services/web/scripts/dropbox/remove_duplicate_uids.js b/services/web/scripts/dropbox/remove_duplicate_uids.js new file mode 100644 index 0000000000..078b5a189d --- /dev/null +++ b/services/web/scripts/dropbox/remove_duplicate_uids.js @@ -0,0 +1,72 @@ +const { db } = require('../../app/js/infrastructure/mongojs') +const DropboxHandler = require('../../modules/dropbox/app/js/DropboxHandler') +const EmailHandler = require('../../app/js/Features/Email/EmailHandler') +const async = require('async') +const minimist = require('minimist') + +const argv = minimist(process.argv.slice(2)) +const commit = argv.commit !== undefined + +if (!commit) { + console.log('DOING DRY RUN. TO SAVE CHANGES PASS --commit') +} + +db.users.aggregate( + [ + { + $group: { + // group by Dropbox access token uid and count distinct users + _id: '$dropbox.access_token.uid', + count: { $sum: 1 }, + _ids: { $addToSet: '$_id' } + } + }, + { + $match: { + // select only uids userd more than once + _id: { $ne: null }, + count: { $gt: 1 } + } + }, + { + $project: { + // filter output + _id: false, + dropbox_uid: '$_id', + _ids: '$_ids' + } + } + ], + { allowDiskUse: true }, + function(error, results) { + if (error) throw error + console.log('FOUND ' + results.length + ' DUPLICATES') + async.mapSeries(results, removeDuplicates, function(error) { + if (error) throw error + console.log('DONE') + process.exit() + }) + } +) + +function removeDuplicates(duplicate, callback) { + async.mapSeries(duplicate._ids, unlinkUser, function(error) { + callback(error) + }) +} + +function unlinkUser(_id, callback) { + db.users.findOne({ _id: _id }, function(error, user) { + if (error) return callback(error) + console.log('UNLINKING USER ' + _id + ' (' + user.email + ')') + if (!commit) return callback() + DropboxHandler.unlinkAccount(_id, function(error) { + if (error) return callback(error) + EmailHandler.sendEmail( + 'dropboxUnlinkedDuplicate', + { to: user.email }, + callback + ) + }) + }) +}