blob: 3a6e453d4a2b73b055f00ad2fca24548ec149fd8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const _ = require('lodash');
const log = require('./migration-utils').log;
function deduplicateAccounts(model) {
const accountsModel = model('Account');
const spaceModel = model('Space');
return accountsModel.aggregate([
{$group: {_id: '$email', count: {$sum: 1}}},
{$match: {count: {$gt: 1}}}
]).exec()
.then((accounts) => _.map(accounts, '_id'))
.then((emails) => Promise.all(
_.map(emails, (email) => accountsModel.find({email}, {_id: 1, email: 1, lastActivity: 1, lastLogin: 1}).lean().exec())
))
.then((promises) => {
const duplicates = _.flatMap(promises, (accounts) => _.sortBy(accounts, [(a) => a.lastActivity || '', 'lastLogin']).slice(0, -1));
if (_.isEmpty(duplicates))
log('Duplicates not found!');
else {
log(`Duplicates found: ${_.size(duplicates)}`);
_.forEach(duplicates, (dup) => log(` ID: ${dup._id}, e-mail: ${dup.email}`));
}
return _.map(duplicates, '_id');
})
.then((accountIds) => {
if (_.isEmpty(accountIds))
return Promise.resolve();
return spaceModel.find({owner: {$in: accountIds}}, {_id: 1}).lean().exec()
.then((spaces) => _.map(spaces, '_id'))
.then((spaceIds) =>
Promise.all([
model('Cluster').deleteMany({space: {$in: spaceIds}}).exec(),
model('Cache').deleteMany({space: {$in: spaceIds}}).exec(),
model('DomainModel').deleteMany({space: {$in: spaceIds}}).exec(),
model('Igfs').deleteMany({space: {$in: spaceIds}}).exec(),
model('Notebook').deleteMany({space: {$in: spaceIds}}).exec(),
model('Activities').deleteMany({owner: accountIds}).exec(),
model('Notifications').deleteMany({owner: accountIds}).exec(),
spaceModel.deleteMany({owner: accountIds}).exec(),
accountsModel.deleteMany({_id: accountIds}).exec()
])
)
.then(() => {
const conditions = _.map(accountIds, (accountId) => ({session: {$regex: `"${accountId}"`}}));
return accountsModel.db.collection('sessions').deleteMany({$or: conditions});
});
});
}
exports.up = function up(done) {
deduplicateAccounts((name) => this(name))
.then(() => this('Account').collection.createIndex({email: 1}, {unique: true, background: false}))
.then(() => done())
.catch(done);
};
exports.down = function down(done) {
log('Account migration can not be reverted');
done();
};