Files
NodeBB/src/user/delete.js

305 lines
8.3 KiB
JavaScript
Raw Normal View History

'use strict';
2016-10-08 19:09:48 +03:00
var async = require('async');
2017-06-25 20:00:05 -04:00
var _ = require('lodash');
2018-04-12 12:35:05 -04:00
var path = require('path');
var nconf = require('nconf');
2016-10-08 19:09:48 +03:00
var db = require('../database');
var posts = require('../posts');
var topics = require('../topics');
var groups = require('../groups');
2018-02-07 15:46:11 -05:00
var messaging = require('../messaging');
2016-10-08 19:09:48 +03:00
var plugins = require('../plugins');
var batch = require('../batch');
var file = require('../file');
module.exports = function (User) {
var deletesInProgress = {};
User.delete = function (callerUid, uid, callback) {
2018-11-12 00:20:44 -05:00
if (parseInt(uid, 10) <= 0) {
return setImmediate(callback, new Error('[[error:invalid-uid]]'));
2014-12-29 15:11:52 -05:00
}
if (deletesInProgress[uid]) {
return setImmediate(callback, new Error('[[error:already-deleting]]'));
}
deletesInProgress[uid] = 'user.delete';
async.waterfall([
function (next) {
removeFromSortedSets(uid, next);
},
function (next) {
2016-03-12 17:29:33 +02:00
deletePosts(callerUid, uid, next);
},
function (next) {
2016-03-12 17:29:33 +02:00
deleteTopics(callerUid, uid, next);
2014-08-08 17:42:03 -04:00
},
function (next) {
deleteUploads(uid, next);
},
function (next) {
2014-08-26 13:47:48 -04:00
User.deleteAccount(uid, next);
2017-02-17 19:31:21 -07:00
},
2014-08-08 17:42:03 -04:00
], callback);
};
2016-03-12 17:29:33 +02:00
function deletePosts(callerUid, uid, callback) {
batch.processSortedSet('uid:' + uid + ':posts', function (ids, next) {
async.eachSeries(ids, function (pid, next) {
2016-03-12 17:29:33 +02:00
posts.purge(pid, callerUid, next);
}, next);
2017-02-18 12:30:49 -07:00
}, { alwaysStartAt: 0 }, callback);
}
2016-03-12 17:29:33 +02:00
function deleteTopics(callerUid, uid, callback) {
batch.processSortedSet('uid:' + uid + ':topics', function (ids, next) {
async.eachSeries(ids, function (tid, next) {
2016-03-12 17:29:33 +02:00
topics.purge(tid, callerUid, next);
}, next);
2017-02-18 12:30:49 -07:00
}, { alwaysStartAt: 0 }, callback);
}
function deleteUploads(uid, callback) {
2018-04-12 12:35:05 -04:00
batch.processSortedSet('uid:' + uid + ':uploads', function (uploadNames, next) {
async.waterfall([
function (next) {
2018-04-12 12:35:05 -04:00
async.each(uploadNames, function (uploadName, next) {
file.delete(path.join(nconf.get('upload_path'), uploadName), next);
}, next);
},
function (next) {
2018-04-12 12:35:05 -04:00
db.sortedSetRemove('uid:' + uid + ':uploads', uploadNames, next);
},
], next);
}, { alwaysStartAt: 0 }, callback);
}
function removeFromSortedSets(uid, callback) {
db.sortedSetsRemove([
'users:joindate',
'users:postcount',
'users:reputation',
'users:banned',
'users:banned:expire',
'users:flags',
'users:online',
'users:notvalidated',
'digest:day:uids',
'digest:week:uids',
'digest:month:uids',
], uid, callback);
}
User.deleteAccount = function (uid, callback) {
if (deletesInProgress[uid] === 'user.deleteAccount') {
return setImmediate(callback, new Error('[[error:already-deleting]]'));
}
deletesInProgress[uid] = 'user.deleteAccount';
2015-11-11 00:00:02 -05:00
var userData;
async.waterfall([
function (next) {
removeFromSortedSets(uid, next);
},
2015-11-11 00:00:02 -05:00
function (next) {
db.getObject('user:' + uid, next);
2016-11-23 17:15:31 +03:00
},
function (_userData, next) {
2018-03-16 20:58:11 -04:00
if (!_userData || !_userData.username) {
delete deletesInProgress[uid];
return callback(new Error('[[error:no-user]]'));
2016-11-23 17:15:31 +03:00
}
2015-11-11 00:00:02 -05:00
userData = _userData;
2017-02-18 12:30:49 -07:00
plugins.fireHook('static:user.delete', { uid: uid }, next);
2015-11-11 00:00:02 -05:00
},
function (next) {
deleteVotes(uid, next);
},
2015-12-16 09:30:55 +02:00
function (next) {
deleteChats(uid, next);
},
2015-12-24 12:20:27 +02:00
function (next) {
User.auth.revokeAllSessions(uid, next);
},
2015-11-11 00:00:02 -05:00
function (next) {
async.parallel([
function (next) {
db.sortedSetRemove('username:uid', userData.username, next);
},
function (next) {
db.sortedSetRemove('username:sorted', userData.username.toLowerCase() + ':' + uid, next);
},
function (next) {
db.sortedSetRemove('userslug:uid', userData.userslug, next);
},
function (next) {
db.sortedSetRemove('fullname:uid', userData.fullname, next);
},
function (next) {
if (userData.email) {
async.parallel([
async.apply(db.sortedSetRemove, 'email:uid', userData.email.toLowerCase()),
2017-02-17 19:31:21 -07:00
async.apply(db.sortedSetRemove, 'email:sorted', userData.email.toLowerCase() + ':' + uid),
], next);
} else {
next();
}
},
function (next) {
db.decrObjectField('global', 'userCount', next);
},
function (next) {
var keys = [
2016-05-18 19:02:43 +03:00
'uid:' + uid + ':notifications:read',
'uid:' + uid + ':notifications:unread',
2016-10-08 19:09:48 +03:00
'uid:' + uid + ':bookmarks',
2016-05-18 19:02:43 +03:00
'uid:' + uid + ':followed_tids',
'uid:' + uid + ':ignored_tids',
'user:' + uid + ':settings',
2019-03-25 11:46:29 -04:00
'user:' + uid + ':usernames',
'user:' + uid + ':emails',
'uid:' + uid + ':topics', 'uid:' + uid + ':posts',
'uid:' + uid + ':chats', 'uid:' + uid + ':chats:unread',
2015-12-16 09:30:55 +02:00
'uid:' + uid + ':chat:rooms', 'uid:' + uid + ':chat:rooms:unread',
'uid:' + uid + ':upvote', 'uid:' + uid + ':downvote',
'uid:' + uid + ':flag:pids',
2017-02-17 19:31:21 -07:00
'uid:' + uid + ':sessions', 'uid:' + uid + ':sessionUUID:sessionId',
2019-02-28 10:20:07 -05:00
'invitation:uid:' + uid,
];
db.deleteAll(keys, next);
},
2019-02-28 10:20:07 -05:00
function (next) {
db.setRemove('invitation:uids', uid, next);
},
function (next) {
deleteUserIps(uid, next);
},
function (next) {
deleteBans(uid, next);
},
function (next) {
deleteUserFromFollowers(uid, next);
},
function (next) {
groups.leaveAllGroups(uid, next);
2017-02-17 19:31:21 -07:00
},
2015-11-11 00:00:02 -05:00
], next);
},
function (results, next) {
db.deleteAll(['followers:' + uid, 'following:' + uid, 'user:' + uid], next);
2017-02-17 19:31:21 -07:00
},
], function (err) {
delete deletesInProgress[uid];
callback(err, userData);
});
2015-11-11 00:00:02 -05:00
};
2015-11-11 00:00:02 -05:00
function deleteVotes(uid, callback) {
async.waterfall([
function (next) {
async.parallel({
upvotedPids: async.apply(db.getSortedSetRange, 'uid:' + uid + ':upvote', 0, -1),
2017-02-17 19:31:21 -07:00
downvotedPids: async.apply(db.getSortedSetRange, 'uid:' + uid + ':downvote', 0, -1),
2015-11-11 00:00:02 -05:00
}, next);
},
function (pids, next) {
2017-06-25 20:00:05 -04:00
pids = _.uniq(pids.upvotedPids.concat(pids.downvotedPids).filter(Boolean));
2015-11-11 00:00:02 -05:00
async.eachSeries(pids, function (pid, next) {
2016-10-08 19:09:48 +03:00
posts.unvote(pid, uid, next);
2015-11-11 00:00:02 -05:00
}, next);
2017-02-17 19:31:21 -07:00
},
], function (err) {
2015-11-11 00:00:02 -05:00
callback(err);
});
2015-11-11 00:00:02 -05:00
}
2015-12-16 09:30:55 +02:00
function deleteChats(uid, callback) {
async.waterfall([
function (next) {
db.getSortedSetRange('uid:' + uid + ':chat:rooms', 0, -1, next);
},
function (roomIds, next) {
var userKeys = roomIds.map(function (roomId) {
2015-12-16 09:30:55 +02:00
return 'uid:' + uid + ':chat:room:' + roomId + ':mids';
});
async.parallel([
2018-02-07 15:46:11 -05:00
async.apply(messaging.leaveRooms, uid, roomIds),
2017-02-17 19:31:21 -07:00
async.apply(db.deleteAll, userKeys),
2015-12-16 09:30:55 +02:00
], next);
2017-02-17 19:31:21 -07:00
},
], function (err) {
2015-12-16 09:30:55 +02:00
callback(err);
});
}
function deleteUserIps(uid, callback) {
2015-10-22 15:16:31 -04:00
async.waterfall([
function (next) {
db.getSortedSetRange('uid:' + uid + ':ip', 0, -1, next);
},
function (ips, next) {
var keys = ips.map(function (ip) {
2015-10-22 15:16:31 -04:00
return 'ip:' + ip + ':uid';
});
db.sortedSetsRemove(keys, uid, next);
},
function (next) {
db.delete('uid:' + uid + ':ip', next);
2017-02-17 19:31:21 -07:00
},
2015-10-22 15:16:31 -04:00
], callback);
}
function deleteBans(uid, callback) {
async.waterfall([
function (next) {
db.getSortedSetRange('uid:' + uid + ':bans:timestamp', 0, -1, next);
},
function (bans, next) {
db.deleteAll(bans, next);
},
function (next) {
db.delete('uid:' + uid + ':bans:timestamp', next);
},
], callback);
}
function deleteUserFromFollowers(uid, callback) {
2015-04-09 15:37:20 -04:00
async.parallel({
followers: async.apply(db.getSortedSetRange, 'followers:' + uid, 0, -1),
2017-02-17 19:31:21 -07:00
following: async.apply(db.getSortedSetRange, 'following:' + uid, 0, -1),
}, function (err, results) {
2015-04-09 15:37:20 -04:00
function updateCount(uids, name, fieldName, next) {
async.each(uids, function (uid, next) {
db.sortedSetCard(name + uid, function (err, count) {
2015-04-09 15:37:20 -04:00
if (err) {
return next(err);
}
count = parseInt(count, 10) || 0;
db.setObjectField('user:' + uid, fieldName, count, next);
});
}, next);
}
if (err) {
return callback(err);
}
var followingSets = results.followers.map(function (uid) {
2014-09-16 22:25:12 -04:00
return 'following:' + uid;
});
var followerSets = results.following.map(function (uid) {
2015-04-09 15:37:20 -04:00
return 'followers:' + uid;
});
async.parallel([
async.apply(db.sortedSetsRemove, followerSets.concat(followingSets), uid),
async.apply(updateCount, results.following, 'followers:', 'followerCount'),
2017-02-17 19:31:21 -07:00
async.apply(updateCount, results.followers, 'following:', 'followingCount'),
2015-04-09 15:37:20 -04:00
], callback);
});
}
2014-03-23 23:34:04 -04:00
};