2014-03-18 20:03:56 -04:00
|
|
|
'use strict';
|
|
|
|
|
|
2013-12-21 19:42:07 -05:00
|
|
|
var winston = require('winston'),
|
|
|
|
|
nconf = require('nconf'),
|
|
|
|
|
async = require('async'),
|
|
|
|
|
|
|
|
|
|
db = require('./database'),
|
2013-11-27 11:27:20 -05:00
|
|
|
topics = require('./topics'),
|
|
|
|
|
categories = require('./categories'),
|
|
|
|
|
user = require('./user'),
|
|
|
|
|
notifications = require('./notifications'),
|
2013-08-08 11:40:31 -04:00
|
|
|
posts = require('./posts'),
|
2013-11-27 11:27:20 -05:00
|
|
|
meta = require('./meta'),
|
2014-01-09 20:13:17 -05:00
|
|
|
websockets = require('./socket.io'),
|
2014-02-19 21:06:30 -05:00
|
|
|
events = require('./events'),
|
2014-09-16 21:43:11 -04:00
|
|
|
plugins = require('./plugins'),
|
|
|
|
|
batch = require('./batch');
|
2013-12-21 19:42:07 -05:00
|
|
|
|
2013-05-23 12:52:16 -04:00
|
|
|
|
|
|
|
|
(function(ThreadTools) {
|
2013-07-05 16:44:11 -04:00
|
|
|
|
|
|
|
|
ThreadTools.exists = function(tid, callback) {
|
2014-02-22 18:56:37 -05:00
|
|
|
db.isSortedSetMember('topics:tid', tid, callback);
|
2014-03-18 20:03:56 -04:00
|
|
|
};
|
2013-08-23 13:14:36 -04:00
|
|
|
|
2014-01-01 14:15:53 -05:00
|
|
|
ThreadTools.delete = function(tid, uid, callback) {
|
2014-03-18 20:03:56 -04:00
|
|
|
toggleDelete(tid, uid, true, callback);
|
2014-02-17 22:53:01 -05:00
|
|
|
};
|
2013-06-20 16:19:17 -04:00
|
|
|
|
2014-01-01 14:15:53 -05:00
|
|
|
ThreadTools.restore = function(tid, uid, callback) {
|
2014-03-18 20:03:56 -04:00
|
|
|
toggleDelete(tid, uid, false, callback);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function toggleDelete(tid, uid, isDelete, callback) {
|
2014-11-07 17:46:03 -05:00
|
|
|
topics.getTopicFields(tid, ['tid', 'cid', 'deleted', 'title'], function(err, topicData) {
|
|
|
|
|
if (err) {
|
2014-01-22 23:58:21 -05:00
|
|
|
return callback(err);
|
|
|
|
|
}
|
2013-10-16 13:04:28 -04:00
|
|
|
|
2014-04-17 20:07:23 -04:00
|
|
|
var alreadyDeletedOrRestored = (parseInt(topicData.deleted, 10) && isDelete) || (!parseInt(topicData.deleted, 10) && !isDelete);
|
|
|
|
|
if (alreadyDeletedOrRestored) {
|
|
|
|
|
return callback(null, {tid: tid});
|
2014-01-22 23:58:21 -05:00
|
|
|
}
|
2013-12-21 19:42:07 -05:00
|
|
|
|
2014-03-18 20:03:56 -04:00
|
|
|
topics[isDelete ? 'delete' : 'restore'](tid, function(err) {
|
2014-04-24 20:05:05 -04:00
|
|
|
function emitTo(room) {
|
|
|
|
|
websockets.in(room).emit(isDelete ? 'event:topic_deleted' : 'event:topic_restored', {
|
|
|
|
|
tid: tid,
|
|
|
|
|
isDelete: isDelete
|
|
|
|
|
});
|
|
|
|
|
}
|
2014-11-07 17:46:03 -05:00
|
|
|
if (err) {
|
2014-02-17 22:53:01 -05:00
|
|
|
return callback(err);
|
|
|
|
|
}
|
2014-01-16 19:58:57 -05:00
|
|
|
|
2014-03-18 20:03:56 -04:00
|
|
|
ThreadTools[isDelete ? 'lock' : 'unlock'](tid);
|
2014-11-07 17:46:03 -05:00
|
|
|
if (isDelete) {
|
|
|
|
|
plugins.fireHook('action:topic.delete', tid);
|
|
|
|
|
} else {
|
|
|
|
|
plugins.fireHook('action:topic.restore', topicData);
|
|
|
|
|
}
|
2014-02-24 16:23:11 -05:00
|
|
|
|
2014-03-18 20:03:56 -04:00
|
|
|
events[isDelete ? 'logTopicDelete' : 'logTopicRestore'](uid, tid);
|
2014-01-22 23:58:21 -05:00
|
|
|
|
2014-02-17 22:53:01 -05:00
|
|
|
websockets.emitTopicPostStats();
|
2014-01-22 23:58:21 -05:00
|
|
|
|
2014-04-24 20:05:05 -04:00
|
|
|
emitTo('topic_' + tid);
|
|
|
|
|
emitTo('category_' + topicData.cid);
|
2014-01-22 23:58:21 -05:00
|
|
|
|
2014-02-17 22:53:01 -05:00
|
|
|
callback(null, {
|
2014-03-18 20:03:56 -04:00
|
|
|
tid: tid
|
2014-02-17 22:53:01 -05:00
|
|
|
});
|
2014-01-16 19:58:57 -05:00
|
|
|
});
|
2014-01-22 23:58:21 -05:00
|
|
|
});
|
2014-03-18 20:03:56 -04:00
|
|
|
}
|
2013-06-20 16:19:17 -04:00
|
|
|
|
2014-06-10 16:56:55 -04:00
|
|
|
ThreadTools.purge = function(tid, uid, callback) {
|
2014-10-31 22:04:09 -04:00
|
|
|
ThreadTools.exists(tid, function(err, exists) {
|
|
|
|
|
if (err || !exists) {
|
2014-06-10 16:56:55 -04:00
|
|
|
return callback(err);
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-31 22:04:09 -04:00
|
|
|
batch.processSortedSet('tid:' + tid + ':posts', function(pids, next) {
|
|
|
|
|
async.eachLimit(pids, 10, posts.purge, next);
|
|
|
|
|
}, {alwaysStartAt: 0}, function(err) {
|
2014-09-16 21:43:11 -04:00
|
|
|
if (err) {
|
|
|
|
|
return callback(err);
|
2014-06-10 16:56:55 -04:00
|
|
|
}
|
2014-10-31 22:04:09 -04:00
|
|
|
|
|
|
|
|
topics.getTopicField(tid, 'mainPid', function(err, mainPid) {
|
2014-09-16 21:43:11 -04:00
|
|
|
if (err) {
|
|
|
|
|
return callback(err);
|
|
|
|
|
}
|
2014-10-31 22:04:09 -04:00
|
|
|
posts.purge(mainPid, function(err) {
|
|
|
|
|
if (err) {
|
|
|
|
|
return callback(err);
|
|
|
|
|
}
|
|
|
|
|
topics.purge(tid, callback);
|
|
|
|
|
});
|
2014-09-16 21:43:11 -04:00
|
|
|
});
|
|
|
|
|
});
|
2014-06-10 16:56:55 -04:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2014-01-16 19:58:57 -05:00
|
|
|
ThreadTools.lock = function(tid, uid, callback) {
|
2014-03-18 20:03:56 -04:00
|
|
|
toggleLock(tid, uid, true, callback);
|
2014-02-24 16:23:11 -05:00
|
|
|
};
|
2014-01-10 10:46:26 -05:00
|
|
|
|
2014-01-16 19:58:57 -05:00
|
|
|
ThreadTools.unlock = function(tid, uid, callback) {
|
2014-03-18 20:03:56 -04:00
|
|
|
toggleLock(tid, uid, false, callback);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function toggleLock(tid, uid, lock, callback) {
|
2014-04-17 20:07:23 -04:00
|
|
|
topics.getTopicField(tid, 'cid', function(err, cid) {
|
2014-04-24 20:05:05 -04:00
|
|
|
function emitTo(room) {
|
|
|
|
|
websockets.in(room).emit(lock ? 'event:topic_locked' : 'event:topic_unlocked', {
|
|
|
|
|
tid: tid,
|
|
|
|
|
isLocked: lock
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-17 20:07:23 -04:00
|
|
|
if (err) {
|
|
|
|
|
return callback(err);
|
|
|
|
|
}
|
2014-01-10 10:46:26 -05:00
|
|
|
|
2014-04-17 20:07:23 -04:00
|
|
|
topics.setTopicField(tid, 'locked', lock ? 1 : 0);
|
|
|
|
|
|
2014-07-24 14:22:48 -04:00
|
|
|
plugins.fireHook('action:topic.lock', {
|
|
|
|
|
tid: tid,
|
2014-07-24 14:32:17 -04:00
|
|
|
isLocked: lock,
|
2014-08-14 17:46:58 -04:00
|
|
|
uid: uid
|
2014-07-24 14:22:48 -04:00
|
|
|
});
|
|
|
|
|
|
2014-04-24 20:05:05 -04:00
|
|
|
emitTo('topic_' + tid);
|
|
|
|
|
emitTo('category_' + cid);
|
2014-04-17 20:07:23 -04:00
|
|
|
|
|
|
|
|
if (typeof callback === 'function') {
|
|
|
|
|
callback(null, {
|
|
|
|
|
tid: tid,
|
|
|
|
|
isLocked: lock
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2014-01-10 10:46:26 -05:00
|
|
|
}
|
|
|
|
|
|
2014-01-16 19:58:57 -05:00
|
|
|
ThreadTools.pin = function(tid, uid, callback) {
|
2014-03-18 20:03:56 -04:00
|
|
|
togglePin(tid, uid, true, callback);
|
|
|
|
|
};
|
2013-06-20 16:19:17 -04:00
|
|
|
|
2014-01-16 19:58:57 -05:00
|
|
|
ThreadTools.unpin = function(tid, uid, callback) {
|
2014-03-18 20:03:56 -04:00
|
|
|
togglePin(tid, uid, false, callback);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function togglePin(tid, uid, pin, callback) {
|
2014-04-17 20:07:23 -04:00
|
|
|
topics.getTopicField(tid, 'cid', function(err, cid) {
|
2014-04-24 20:05:05 -04:00
|
|
|
function emitTo(room) {
|
|
|
|
|
websockets.in(room).emit(pin ? 'event:topic_pinned' : 'event:topic_unpinned', {
|
|
|
|
|
tid: tid,
|
|
|
|
|
isPinned: pin
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-17 20:07:23 -04:00
|
|
|
if (err) {
|
|
|
|
|
return callback(err);
|
|
|
|
|
}
|
2013-11-25 17:20:44 -05:00
|
|
|
|
2014-04-17 20:07:23 -04:00
|
|
|
topics.setTopicField(tid, 'pinned', pin ? 1 : 0);
|
|
|
|
|
topics.getTopicFields(tid, ['cid', 'lastposttime'], function(err, topicData) {
|
2014-11-07 17:15:01 -05:00
|
|
|
db.sortedSetAdd('cid:' + topicData.cid + ':tids', pin ? Math.pow(2, 53) : topicData.lastposttime, tid);
|
2014-04-17 20:07:23 -04:00
|
|
|
});
|
2014-01-10 10:46:26 -05:00
|
|
|
|
2014-07-24 14:22:48 -04:00
|
|
|
plugins.fireHook('action:topic.pin', {
|
|
|
|
|
tid: tid,
|
2014-07-24 14:32:17 -04:00
|
|
|
isPinned: pin,
|
2014-08-14 17:46:58 -04:00
|
|
|
uid: uid
|
2014-07-24 14:22:48 -04:00
|
|
|
});
|
|
|
|
|
|
2014-04-24 20:05:05 -04:00
|
|
|
emitTo('topic_' + tid);
|
|
|
|
|
emitTo('category_' + cid);
|
2014-04-17 20:07:23 -04:00
|
|
|
|
|
|
|
|
if (typeof callback === 'function') {
|
|
|
|
|
callback(null, {
|
|
|
|
|
tid: tid,
|
|
|
|
|
isPinned: pin
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2013-05-23 12:52:16 -04:00
|
|
|
}
|
|
|
|
|
|
2014-07-24 14:32:17 -04:00
|
|
|
ThreadTools.move = function(tid, cid, uid, callback) {
|
2014-02-02 15:43:33 -05:00
|
|
|
var topic;
|
|
|
|
|
async.waterfall([
|
|
|
|
|
function(next) {
|
2014-02-07 12:27:55 -05:00
|
|
|
topics.getTopicFields(tid, ['cid', 'lastposttime', 'pinned', 'deleted'], next);
|
2014-02-02 15:43:33 -05:00
|
|
|
},
|
|
|
|
|
function(topicData, next) {
|
|
|
|
|
topic = topicData;
|
2014-11-07 17:15:01 -05:00
|
|
|
db.sortedSetRemove('cid:' + topicData.cid + ':tids', tid, next);
|
2014-02-02 15:43:33 -05:00
|
|
|
},
|
2014-09-03 20:19:51 -04:00
|
|
|
function(next) {
|
2014-02-07 12:27:55 -05:00
|
|
|
var timestamp = parseInt(topic.pinned, 10) ? Math.pow(2, 53) : topic.lastposttime;
|
2014-11-07 17:15:01 -05:00
|
|
|
db.sortedSetAdd('cid:' + cid + ':tids', timestamp, tid, next);
|
2014-02-02 15:43:33 -05:00
|
|
|
}
|
2014-09-03 20:19:51 -04:00
|
|
|
], function(err) {
|
|
|
|
|
if (err) {
|
2014-01-25 22:43:49 -05:00
|
|
|
return callback(err);
|
|
|
|
|
}
|
2014-02-02 15:43:33 -05:00
|
|
|
var oldCid = topic.cid;
|
2014-01-25 22:43:49 -05:00
|
|
|
|
2014-02-02 15:43:33 -05:00
|
|
|
if(!parseInt(topic.deleted, 10)) {
|
|
|
|
|
categories.incrementCategoryFieldBy(oldCid, 'topic_count', -1);
|
|
|
|
|
categories.incrementCategoryFieldBy(cid, 'topic_count', 1);
|
|
|
|
|
}
|
2013-07-03 13:08:32 -04:00
|
|
|
|
2014-04-17 20:07:23 -04:00
|
|
|
categories.moveRecentReplies(tid, oldCid, cid);
|
|
|
|
|
|
|
|
|
|
topics.setTopicField(tid, 'cid', cid, callback);
|
2014-07-24 14:22:48 -04:00
|
|
|
|
2014-10-10 15:44:02 -04:00
|
|
|
events.logTopicMove(uid, tid);
|
|
|
|
|
|
2014-07-24 14:22:48 -04:00
|
|
|
plugins.fireHook('action:topic.move', {
|
|
|
|
|
tid: tid,
|
|
|
|
|
fromCid: oldCid,
|
2014-07-24 14:32:17 -04:00
|
|
|
toCid: cid,
|
2014-08-14 17:46:58 -04:00
|
|
|
uid: uid
|
2014-07-24 14:22:48 -04:00
|
|
|
});
|
2013-05-23 12:52:16 -04:00
|
|
|
});
|
2014-03-18 20:03:56 -04:00
|
|
|
};
|
2013-05-23 12:52:16 -04:00
|
|
|
|
2014-01-16 20:53:32 -05:00
|
|
|
ThreadTools.toggleFollow = function(tid, uid, callback) {
|
2014-07-24 16:12:53 -04:00
|
|
|
callback = callback || function() {};
|
|
|
|
|
async.waterfall([
|
|
|
|
|
function (next) {
|
|
|
|
|
ThreadTools.exists(tid, next);
|
|
|
|
|
},
|
|
|
|
|
function (exists, next) {
|
|
|
|
|
if (!exists) {
|
|
|
|
|
return next(new Error('[[error:no-topic]]'));
|
2014-01-16 20:53:32 -05:00
|
|
|
}
|
2014-07-24 16:12:53 -04:00
|
|
|
topics.isFollowing(tid, uid, next);
|
|
|
|
|
},
|
|
|
|
|
function (isFollowing, next) {
|
|
|
|
|
db[isFollowing ? 'setRemove' : 'setAdd']('tid:' + tid + ':followers', uid, function(err) {
|
|
|
|
|
next(err, !isFollowing);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
], callback);
|
2014-03-18 20:03:56 -04:00
|
|
|
};
|
2013-06-06 20:39:45 -04:00
|
|
|
|
2014-08-13 21:42:04 -04:00
|
|
|
ThreadTools.follow = function(tid, uid, callback) {
|
|
|
|
|
callback = callback || function() {};
|
|
|
|
|
async.waterfall([
|
|
|
|
|
function (next) {
|
|
|
|
|
ThreadTools.exists(tid, next);
|
|
|
|
|
},
|
|
|
|
|
function (exists, next) {
|
|
|
|
|
if (!exists) {
|
|
|
|
|
return next(new Error('[[error:no-topic]]'));
|
|
|
|
|
}
|
|
|
|
|
db.setAdd('tid:' + tid + ':followers', uid, next);
|
|
|
|
|
}
|
|
|
|
|
], callback);
|
|
|
|
|
};
|
|
|
|
|
|
2014-04-10 20:31:57 +01:00
|
|
|
}(exports));
|