2013-12-02 21:20:55 -05:00
var db = require ( './database' ) ,
2013-11-27 11:27:20 -05:00
topics = require ( './topics' ) ,
categories = require ( './categories' ) ,
CategoryTools = require ( './categoryTools' ) ,
user = require ( './user' ) ,
2013-06-06 20:39:45 -04:00
async = require ( 'async' ) ,
2013-11-27 11:27:20 -05:00
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' ) ,
websockets = require ( './websockets' ) ;
2013-08-23 13:14:36 -04:00
winston = require ( 'winston' ) ,
2013-11-26 19:09:32 -05:00
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 ) {
2013-12-04 23:36:52 -05:00
2013-12-02 21:20:55 -05:00
db . isSetMember ( 'topics:tid' , tid , function ( err , ismember ) {
2013-12-04 23:36:52 -05:00
2013-12-02 21:20:55 -05:00
if ( err ) {
callback ( false ) ;
}
2013-12-04 15:11:17 -05:00
callback ( ismember ) ;
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-11-27 11:27:20 -05:00
async . parallel ( {
categoryPrivs : function ( next ) {
topics . getTopicField ( tid , 'cid' , function ( err , cid ) {
CategoryTools . privileges ( cid , uid , next ) ;
2013-05-23 12:52:16 -04:00
} ) ;
2013-11-27 11:27:20 -05:00
} ,
hasEnoughRep : function ( next ) {
2013-12-08 10:49:42 -05:00
if ( meta . config [ 'privileges:disabled' ] ) {
return next ( null , false ) ;
} else {
user . getUserField ( uid , 'reputation' , function ( err , reputation ) {
if ( err ) return next ( null , false ) ;
next ( null , parseInt ( reputation , 10 ) >= parseInt ( meta . config [ 'privileges:manage_topic' ] , 10 ) ) ;
} ) ;
}
2013-11-27 11:27:20 -05:00
}
} , function ( err , results ) {
callback ( err , ! results ? undefined : {
read : results . categoryPrivs . read ,
write : results . categoryPrivs . write ,
editable : results . categoryPrivs . editable || results . hasEnoughRep ,
view _deleted : results . categoryPrivs . view _deleted || results . hasEnoughRep
2013-05-23 12:52:16 -04:00
} ) ;
} ) ;
}
2013-11-25 17:20:44 -05:00
ThreadTools . lock = function ( tid , socket ) {
topics . setTopicField ( tid , 'locked' , 1 ) ;
2013-06-20 16:19:17 -04:00
2013-11-25 17:20:44 -05:00
if ( socket ) {
2013-11-26 19:09:32 -05:00
websockets . in ( 'topic_' + tid ) . emit ( 'event:topic_locked' , {
2013-11-25 17:20:44 -05:00
tid : tid ,
status : 'ok'
} ) ;
2013-11-25 17:49:17 -05:00
if ( socket ) {
socket . emit ( 'api:topic.lock' , {
status : 'ok' ,
tid : tid
} ) ;
}
2013-11-25 17:20:44 -05:00
}
2013-05-23 12:52:16 -04:00
}
2013-11-25 17:20:44 -05:00
ThreadTools . unlock = function ( tid , socket ) {
topics . setTopicField ( tid , 'locked' , 0 ) ;
2013-07-03 14:42:50 -04:00
2013-11-25 17:20:44 -05:00
if ( socket ) {
2013-11-26 19:09:32 -05:00
websockets . in ( 'topic_' + tid ) . emit ( 'event:topic_unlocked' , {
2013-11-25 17:20:44 -05:00
tid : tid ,
status : 'ok'
} ) ;
2013-06-20 16:19:17 -04:00
2013-11-25 17:49:17 -05:00
if ( socket ) {
socket . emit ( 'api:topic.unlock' , {
status : 'ok' ,
tid : tid
} ) ;
}
2013-11-25 17:20:44 -05:00
}
2013-05-23 12:52:16 -04:00
}
2013-11-25 17:20:44 -05:00
ThreadTools . delete = function ( tid , callback ) {
topics . delete ( tid ) ;
2013-10-16 13:04:28 -04:00
2013-12-02 21:20:55 -05:00
db . decrObjectField ( 'global' , 'topicCount' ) ;
2013-05-23 12:52:16 -04:00
2013-11-25 17:20:44 -05:00
ThreadTools . lock ( tid ) ;
2013-08-08 11:40:31 -04:00
2013-12-05 20:06:36 -05:00
db . searchRemove ( 'topic' , tid ) ;
2013-06-20 16:19:17 -04:00
2013-11-26 19:09:32 -05:00
websockets . in ( 'topic_' + tid ) . emit ( 'event:topic_deleted' , {
2013-11-25 17:20:44 -05:00
tid : tid ,
status : 'ok'
2013-05-23 12:52:16 -04:00
} ) ;
2013-11-25 17:20:44 -05:00
if ( callback ) {
callback ( null ) ;
}
}
2013-06-20 16:19:17 -04:00
2013-11-25 17:20:44 -05:00
ThreadTools . restore = function ( tid , socket , callback ) {
topics . restore ( tid ) ;
2013-12-02 21:20:55 -05:00
db . incrObjectField ( 'global' , 'topicCount' ) ;
2013-11-25 17:20:44 -05:00
ThreadTools . unlock ( tid ) ;
2013-10-16 13:04:28 -04:00
2013-11-26 19:09:32 -05:00
websockets . in ( 'topic_' + tid ) . emit ( 'event:topic_restored' , {
2013-11-25 17:20:44 -05:00
tid : tid ,
status : 'ok'
2013-05-23 12:52:16 -04:00
} ) ;
2013-11-25 17:20:44 -05:00
topics . getTopicField ( tid , 'title' , function ( err , title ) {
2013-12-05 20:06:36 -05:00
db . searchIndex ( 'topic' , title , tid ) ;
2013-11-25 17:20:44 -05:00
} ) ;
2013-08-23 13:14:36 -04:00
2013-11-25 17:20:44 -05:00
if ( callback ) {
callback ( null ) ;
}
}
2013-06-20 16:19:17 -04:00
2013-11-25 17:20:44 -05:00
ThreadTools . pin = function ( tid , socket ) {
topics . setTopicField ( tid , 'pinned' , 1 ) ;
topics . getTopicField ( tid , 'cid' , function ( err , cid ) {
2013-12-02 21:20:55 -05:00
db . sortedSetAdd ( 'categories:' + cid + ':tid' , Math . pow ( 2 , 53 ) , tid ) ;
2013-05-23 12:52:16 -04:00
} ) ;
2013-11-25 17:20:44 -05:00
if ( socket ) {
2013-11-26 19:09:32 -05:00
websockets . in ( 'topic_' + tid ) . emit ( 'event:topic_pinned' , {
2013-11-25 17:20:44 -05:00
tid : tid ,
status : 'ok'
} ) ;
2013-08-23 13:14:36 -04:00
2013-11-25 17:49:17 -05:00
if ( socket ) {
socket . emit ( 'api:topic.pin' , {
status : 'ok' ,
tid : tid
} ) ;
}
2013-11-25 17:20:44 -05:00
}
}
2013-06-20 16:19:17 -04:00
2013-11-25 17:20:44 -05:00
ThreadTools . unpin = function ( tid , socket ) {
topics . setTopicField ( tid , 'pinned' , 0 ) ;
topics . getTopicFields ( tid , [ 'cid' , 'lastposttime' ] , function ( err , topicData ) {
2013-12-02 21:20:55 -05:00
db . sortedSetAdd ( 'categories:' + topicData . cid + ':tid' , topicData . lastposttime , tid ) ;
2013-05-23 12:52:16 -04:00
} ) ;
2013-11-25 17:20:44 -05:00
if ( socket ) {
2013-11-26 19:09:32 -05:00
websockets . in ( 'topic_' + tid ) . emit ( 'event:topic_unpinned' , {
2013-11-25 17:20:44 -05:00
tid : tid ,
status : 'ok'
} ) ;
2013-11-25 17:49:17 -05:00
if ( socket ) {
socket . emit ( 'api:topic.unpin' , {
status : 'ok' ,
tid : tid
} ) ;
}
2013-11-25 17:20:44 -05:00
}
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 ;
2013-12-04 16:58:06 -05:00
db . sortedSetRemove ( 'categories:' + oldCid + ':tid' , tid , function ( err , result ) {
db . sortedSetAdd ( 'categories:' + cid + ':tid' , topicData . lastposttime , tid , function ( err , result ) {
2013-08-23 13:14:36 -04:00
2013-12-04 16:58:06 -05:00
if ( err ) {
socket . emit ( 'api:topic.move' , {
status : 'error'
} ) ;
return ;
}
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-11-26 19:09:32 -05:00
websockets . in ( 'topic_' + tid ) . emit ( 'event:topic_moved' , {
2013-05-24 11:18:28 -04:00
tid : tid
} ) ;
2013-12-04 16:58:06 -05:00
} ) ;
2013-05-23 12:52:16 -04:00
} ) ;
} ) ;
}
2013-06-06 20:39:45 -04:00
ThreadTools . isFollowing = function ( tid , current _user , callback ) {
2013-12-02 21:20:55 -05:00
db . isSetMember ( 'tid:' + tid + ':followers' , current _user , function ( err , following ) {
2013-06-06 20:39:45 -04:00
callback ( following ) ;
} ) ;
}
ThreadTools . toggleFollow = function ( tid , current _user , callback ) {
ThreadTools . isFollowing ( tid , current _user , function ( following ) {
if ( ! following ) {
2013-12-02 21:20:55 -05:00
db . setAdd ( '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 {
2013-12-02 21:20:55 -05:00
db . setRemove ( '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
} ) ;
}
} ) ;
}
2013-11-01 13:04:15 -04:00
ThreadTools . getFollowers = function ( tid , callback ) {
2013-12-02 21:20:55 -05:00
db . getSetMembers ( 'tid:' + tid + ':followers' , function ( err , followers ) {
2013-10-03 21:18:59 -04:00
callback ( err , followers . map ( function ( follower ) {
return parseInt ( follower , 10 ) ;
} ) ) ;
2013-06-06 20:39:45 -04:00
} ) ;
}
2013-11-01 13:04:15 -04:00
ThreadTools . notifyFollowers = function ( tid , exceptUid ) {
2013-06-06 20:39:45 -04:00
async . parallel ( [
function ( next ) {
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
} ) ;
} ) ;
} ,
function ( next ) {
2013-11-01 13:04:15 -04:00
ThreadTools . getFollowers ( tid , function ( err , followers ) {
2013-10-03 21:18:59 -04:00
exceptUid = parseInt ( exceptUid , 10 ) ;
2013-06-06 20:39:45 -04:00
if ( followers . indexOf ( exceptUid ) !== - 1 ) followers . splice ( followers . indexOf ( exceptUid ) , 1 ) ;
next ( null , followers ) ;
} ) ;
}
] , function ( err , results ) {
2013-12-02 21:20:55 -05:00
if ( ! err ) {
notifications . push ( results [ 0 ] , results [ 1 ] ) ;
}
2013-06-06 20:39:45 -04:00
} ) ;
}
2013-09-22 13:33:05 -04:00
ThreadTools . getLatestUndeletedPid = function ( tid , callback ) {
2013-12-02 21:20:55 -05:00
db . getListRange ( 'tid:' + tid + ':posts' , 0 , - 1 , function ( err , pids ) {
if ( pids . length === 0 ) {
return callback ( new Error ( 'no-undeleted-pids-found' ) ) ;
}
2013-09-22 12:55:03 -04:00
pids . reverse ( ) ;
async . detectSeries ( pids , function ( pid , next ) {
2013-11-15 14:57:50 -05:00
posts . getPostField ( pid , 'deleted' , function ( err , deleted ) {
2013-12-05 13:11:27 -05:00
if ( parseInt ( deleted , 10 ) === 0 ) {
2013-12-02 21:20:55 -05:00
next ( true ) ;
} else {
next ( false ) ;
}
2013-09-22 12:55:03 -04:00
} ) ;
} , function ( pid ) {
2013-12-02 21:20:55 -05:00
if ( pid ) {
callback ( null , pid ) ;
} else {
callback ( new Error ( 'no-undeleted-pids-found' ) ) ;
}
2013-09-22 12:55:03 -04:00
} ) ;
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 ) ) ;