2013-09-17 13:09:37 -04:00
var RDB = require ( './redis.js' ) ,
2013-05-23 12:52:16 -04:00
topics = require ( './topics.js' ) ,
categories = require ( './categories.js' ) ,
user = require ( './user.js' ) ,
2013-06-06 20:39:45 -04:00
async = require ( 'async' ) ,
2013-07-15 15:08:54 -04:00
notifications = require ( './notifications.js' ) ,
2013-08-08 11:40:31 -04:00
posts = require ( './posts' ) ,
reds = require ( 'reds' ) ,
2013-08-13 16:00:24 -04:00
topicSearch = reds . createSearch ( 'nodebbtopicsearch' ) ,
2013-08-23 13:14:36 -04:00
winston = require ( 'winston' ) ,
2013-09-17 15:38:50 -04:00
meta = require ( './meta' ) ,
nconf = require ( 'nconf' ) ;
2013-05-23 12:52:16 -04:00
( function ( ThreadTools ) {
2013-07-05 16:44:11 -04:00
ThreadTools . exists = function ( tid , callback ) {
RDB . sismember ( 'topics:tid' , tid , function ( err , ismember ) {
if ( err ) RDB . handle ( err ) ;
2013-09-17 13:09:37 -04:00
callback ( ! ! ismember || false ) ;
2013-07-05 16:44:11 -04:00
} ) ;
}
2013-08-23 13:14:36 -04:00
2013-05-23 12:52:16 -04:00
ThreadTools . privileges = function ( tid , uid , callback ) {
2013-08-23 13:14:36 -04:00
//todo: break early if one condition is true
2013-05-23 12:52:16 -04:00
function getCategoryPrivileges ( next ) {
2013-08-11 16:12:20 -04:00
topics . getTopicField ( tid , 'cid' , function ( err , cid ) {
2013-05-23 12:52:16 -04:00
categories . privileges ( cid , uid , function ( privileges ) {
next ( null , privileges ) ;
} ) ;
} ) ;
}
function hasEnoughRep ( next ) {
2013-08-23 14:55:25 -04:00
user . getUserField ( uid , 'reputation' , function ( err , reputation ) {
if ( err ) return next ( null , false ) ;
2013-08-23 13:14:36 -04:00
next ( null , reputation >= meta . config [ 'privileges:manage_topic' ] ) ;
2013-05-23 12:52:16 -04:00
} ) ;
}
2013-08-23 13:14:36 -04:00
2013-05-23 12:52:16 -04:00
async . parallel ( [ getCategoryPrivileges , hasEnoughRep ] , function ( err , results ) {
callback ( {
editable : results [ 0 ] . editable || ( results . slice ( 1 ) . indexOf ( true ) !== - 1 ? true : false ) ,
view _deleted : results [ 0 ] . view _deleted || ( results . slice ( 1 ) . indexOf ( true ) !== - 1 ? true : false )
} ) ;
} ) ;
}
ThreadTools . lock = function ( tid , uid , socket ) {
ThreadTools . privileges ( tid , uid , function ( privileges ) {
if ( privileges . editable ) {
2013-07-03 13:08:32 -04:00
topics . setTopicField ( tid , 'locked' , 1 ) ;
2013-05-23 12:52:16 -04:00
if ( socket ) {
2013-09-17 13:09:37 -04:00
io . sockets . in ( 'topic_' + tid ) . emit ( 'event:topic_locked' , {
2013-05-23 12:52:16 -04:00
tid : tid ,
status : 'ok'
} ) ;
2013-06-20 16:19:17 -04:00
socket . emit ( 'api:topic.lock' , {
status : 'ok' ,
tid : tid
} ) ;
2013-05-23 12:52:16 -04:00
}
}
} ) ;
}
ThreadTools . unlock = function ( tid , uid , socket ) {
ThreadTools . privileges ( tid , uid , function ( privileges ) {
if ( privileges . editable ) {
2013-07-03 14:36:52 -04:00
topics . setTopicField ( tid , 'locked' , 0 ) ;
2013-07-03 14:42:50 -04:00
2013-05-23 12:52:16 -04:00
if ( socket ) {
2013-09-17 13:09:37 -04:00
io . sockets . in ( 'topic_' + tid ) . emit ( 'event:topic_unlocked' , {
2013-05-23 12:52:16 -04:00
tid : tid ,
status : 'ok'
} ) ;
2013-06-20 16:19:17 -04:00
socket . emit ( 'api:topic.unlock' , {
status : 'ok' ,
tid : tid
} ) ;
2013-05-23 12:52:16 -04:00
}
}
} ) ;
}
2013-07-15 15:25:31 -04:00
ThreadTools . delete = function ( tid , uid , callback ) {
2013-05-23 12:52:16 -04:00
ThreadTools . privileges ( tid , uid , function ( privileges ) {
2013-07-15 15:25:31 -04:00
if ( privileges . editable || uid === - 1 ) {
2013-08-23 13:14:36 -04:00
2013-08-26 16:04:31 -04:00
topics . delete ( tid ) ;
2013-05-23 12:52:16 -04:00
ThreadTools . lock ( tid , uid ) ;
2013-08-08 11:40:31 -04:00
topicSearch . remove ( tid ) ;
2013-09-17 13:09:37 -04:00
io . sockets . in ( 'topic_' + tid ) . emit ( 'event:topic_deleted' , {
2013-07-15 15:25:31 -04:00
tid : tid ,
status : 'ok'
} ) ;
2013-06-20 16:19:17 -04:00
2013-07-15 15:25:31 -04:00
callback ( null ) ;
} else callback ( new Error ( 'not-enough-privs' ) ) ;
2013-05-23 12:52:16 -04:00
} ) ;
}
ThreadTools . restore = function ( tid , uid , socket ) {
ThreadTools . privileges ( tid , uid , function ( privileges ) {
if ( privileges . editable ) {
2013-07-03 13:08:32 -04:00
2013-08-26 16:04:31 -04:00
topics . restore ( tid ) ;
2013-05-23 12:52:16 -04:00
ThreadTools . unlock ( tid , uid ) ;
2013-09-17 13:09:37 -04:00
io . sockets . in ( 'topic_' + tid ) . emit ( 'event:topic_restored' , {
2013-08-23 13:14:36 -04:00
tid : tid ,
status : 'ok'
} ) ;
2013-06-20 16:19:17 -04:00
2013-08-23 13:14:36 -04:00
if ( socket ) {
2013-06-20 16:19:17 -04:00
socket . emit ( 'api:topic.restore' , {
status : 'ok' ,
tid : tid
} ) ;
2013-05-23 12:52:16 -04:00
}
2013-08-08 11:40:31 -04:00
2013-08-11 16:12:20 -04:00
topics . getTopicField ( tid , 'title' , function ( err , title ) {
2013-08-08 11:40:31 -04:00
topicSearch . index ( title , tid ) ;
} ) ;
2013-05-23 12:52:16 -04:00
}
} ) ;
}
ThreadTools . pin = function ( tid , uid , socket ) {
ThreadTools . privileges ( tid , uid , function ( privileges ) {
if ( privileges . editable ) {
2013-08-23 13:14:36 -04:00
2013-07-03 13:08:32 -04:00
topics . setTopicField ( tid , 'pinned' , 1 ) ;
2013-08-11 16:12:20 -04:00
topics . getTopicField ( tid , 'cid' , function ( err , cid ) {
2013-09-17 13:09:37 -04:00
RDB . zadd ( 'categories:' + cid + ':tid' , Math . pow ( 2 , 53 ) , tid ) ;
2013-08-09 20:03:19 -04:00
} ) ;
2013-08-23 13:14:36 -04:00
2013-05-23 12:52:16 -04:00
if ( socket ) {
2013-09-17 13:09:37 -04:00
io . sockets . in ( 'topic_' + tid ) . emit ( 'event:topic_pinned' , {
2013-05-23 12:52:16 -04:00
tid : tid ,
status : 'ok'
} ) ;
2013-06-20 16:19:17 -04:00
socket . emit ( 'api:topic.pin' , {
status : 'ok' ,
tid : tid
} ) ;
2013-05-23 12:52:16 -04:00
}
}
} ) ;
}
ThreadTools . unpin = function ( tid , uid , socket ) {
ThreadTools . privileges ( tid , uid , function ( privileges ) {
if ( privileges . editable ) {
2013-08-23 13:14:36 -04:00
2013-07-03 13:08:32 -04:00
topics . setTopicField ( tid , 'pinned' , 0 ) ;
2013-08-24 18:19:01 -04:00
topics . getTopicFields ( tid , [ 'cid' , 'lastposttime' ] , function ( err , topicData ) {
2013-08-09 20:03:19 -04:00
RDB . zadd ( 'categories:' + topicData . cid + ':tid' , topicData . lastposttime , tid ) ;
} ) ;
2013-05-23 12:52:16 -04:00
if ( socket ) {
2013-09-17 13:09:37 -04:00
io . sockets . in ( 'topic_' + tid ) . emit ( 'event:topic_unpinned' , {
2013-05-23 12:52:16 -04:00
tid : tid ,
status : 'ok'
} ) ;
2013-06-20 16:19:17 -04:00
socket . emit ( 'api:topic.unpin' , {
status : 'ok' ,
tid : tid
} ) ;
2013-05-23 12:52:16 -04:00
}
}
} ) ;
}
ThreadTools . move = function ( tid , cid , socket ) {
2013-08-23 13:14:36 -04:00
2013-08-24 18:19:01 -04:00
topics . getTopicFields ( tid , [ 'cid' , 'lastposttime' ] , function ( err , topicData ) {
2013-08-09 20:03:19 -04:00
var oldCid = topicData . cid ;
var multi = RDB . multi ( ) ;
multi . zrem ( 'categories:' + oldCid + ':tid' , tid ) ;
multi . zadd ( 'categories:' + cid + ':tid' , topicData . lastposttime , tid ) ;
2013-08-23 13:14:36 -04:00
2013-08-09 20:03:19 -04:00
multi . exec ( function ( err , result ) {
2013-05-23 12:52:16 -04:00
2013-08-23 13:14:36 -04:00
if ( ! err && result [ 0 ] === 1 && result [ 1 ] === 1 ) {
2013-07-03 13:08:32 -04:00
topics . setTopicField ( tid , 'cid' , cid ) ;
2013-08-09 20:03:19 -04:00
2013-07-22 12:07:05 -04:00
categories . moveRecentReplies ( tid , oldCid , cid , function ( err , data ) {
2013-09-17 13:09:37 -04:00
if ( err ) {
2013-08-13 16:00:24 -04:00
winston . err ( err ) ;
2013-07-22 12:07:05 -04:00
}
} ) ;
2013-08-27 13:32:43 -04:00
categories . moveActiveUsers ( tid , oldCid , cid , function ( err , data ) {
2013-09-17 13:09:37 -04:00
if ( err ) {
2013-08-27 13:32:43 -04:00
winston . err ( err ) ;
}
} ) ;
2013-07-04 13:29:29 -04:00
categories . incrementCategoryFieldBy ( oldCid , 'topic_count' , - 1 ) ;
categories . incrementCategoryFieldBy ( cid , 'topic_count' , 1 ) ;
2013-07-03 13:08:32 -04:00
2013-05-24 11:18:28 -04:00
socket . emit ( 'api:topic.move' , {
status : 'ok'
} ) ;
2013-08-27 13:32:43 -04:00
2013-09-17 13:09:37 -04:00
io . sockets . in ( 'topic_' + tid ) . emit ( 'event:topic_moved' , {
2013-05-24 11:18:28 -04:00
tid : tid
} ) ;
2013-05-23 12:52:16 -04:00
} else {
2013-05-24 11:18:28 -04:00
socket . emit ( 'api:topic.move' , {
status : 'error'
} ) ;
2013-05-23 12:52:16 -04:00
}
} ) ;
} ) ;
}
2013-06-06 20:39:45 -04:00
ThreadTools . isFollowing = function ( tid , current _user , callback ) {
RDB . sismember ( 'tid:' + tid + ':followers' , current _user , function ( err , following ) {
callback ( following ) ;
} ) ;
}
ThreadTools . toggleFollow = function ( tid , current _user , callback ) {
ThreadTools . isFollowing ( tid , current _user , function ( following ) {
if ( ! following ) {
RDB . sadd ( 'tid:' + tid + ':followers' , current _user , function ( err , success ) {
2013-06-07 14:41:21 -04:00
if ( callback ) {
if ( ! err ) {
callback ( {
status : 'ok' ,
follow : true
} ) ;
2013-09-17 13:09:37 -04:00
} else callback ( {
status : 'error'
} ) ;
2013-06-07 14:41:21 -04:00
}
2013-06-06 20:39:45 -04:00
} ) ;
} else {
RDB . srem ( 'tid:' + tid + ':followers' , current _user , function ( err , success ) {
2013-06-07 14:41:21 -04:00
if ( callback ) {
if ( ! err ) {
callback ( {
status : 'ok' ,
follow : false
} ) ;
2013-09-17 13:09:37 -04:00
} else callback ( {
status : 'error'
} ) ;
2013-06-07 14:41:21 -04:00
}
2013-06-06 20:39:45 -04:00
} ) ;
}
} ) ;
}
ThreadTools . get _followers = function ( tid , callback ) {
RDB . smembers ( 'tid:' + tid + ':followers' , function ( err , followers ) {
callback ( err , followers ) ;
} ) ;
}
ThreadTools . notify _followers = function ( tid , exceptUid ) {
async . parallel ( [
function ( next ) {
2013-08-23 13:14:36 -04:00
2013-08-11 16:12:20 -04:00
topics . getTopicField ( tid , 'title' , function ( err , title ) {
2013-07-15 15:03:42 -04:00
topics . getTeaser ( tid , function ( err , teaser ) {
if ( ! err ) {
2013-10-03 20:35:16 -04:00
notifications . create ( '<strong>' + teaser . username + '</strong> has posted a reply to: "<strong>' + title + '</strong>"' , nconf . get ( 'relative_path' ) + '/topic/' + tid , 'topic:' + tid , function ( nid ) {
2013-07-15 15:03:42 -04:00
next ( null , nid ) ;
} ) ;
} else next ( err ) ;
2013-06-06 20:39:45 -04:00
} ) ;
} ) ;
2013-08-23 13:14:36 -04:00
2013-06-06 20:39:45 -04:00
} ,
function ( next ) {
ThreadTools . get _followers ( tid , function ( err , followers ) {
if ( followers . indexOf ( exceptUid ) !== - 1 ) followers . splice ( followers . indexOf ( exceptUid ) , 1 ) ;
next ( null , followers ) ;
} ) ;
}
] , function ( err , results ) {
2013-07-15 15:03:42 -04:00
if ( ! err ) notifications . push ( results [ 0 ] , results [ 1 ] ) ;
// Otherwise, do nothing
2013-06-06 20:39:45 -04:00
} ) ;
}
2013-09-22 13:33:05 -04:00
ThreadTools . getLatestUndeletedPid = function ( tid , callback ) {
2013-09-22 12:55:03 -04:00
RDB . lrange ( 'tid:' + tid + ':posts' , 0 , - 1 , function ( err , pids ) {
if ( pids . length === 0 ) return callback ( new Error ( 'no-undeleted-pids-found' ) ) ;
pids . reverse ( ) ;
async . detectSeries ( pids , function ( pid , next ) {
RDB . hget ( 'post:' + pid , 'deleted' , function ( err , deleted ) {
2013-09-22 13:28:10 -04:00
if ( deleted === '0' ) next ( true ) ;
2013-09-22 12:55:03 -04:00
else next ( false ) ;
} ) ;
} , function ( pid ) {
if ( pid ) callback ( null , pid ) ;
else callback ( new Error ( 'no-undeleted-pids-found' ) ) ;
} ) ;
2013-08-14 13:32:07 -04:00
} ) ;
2013-07-15 15:08:54 -04:00
}
2013-05-23 12:52:16 -04:00
} ( exports ) ) ;