var RDB = require('./redis.js') schema = require('./schema.js'), posts = require('./posts.js'), utils = require('./../public/src/utils.js'), user = require('./user.js'), categories = require('./categories.js'), posts = require('./posts.js'), marked = require('marked'), threadTools = require('./threadTools.js'), postTools = require('./postTools'), async = require('async'), feed = require('./feed.js'); marked.setOptions({ breaks: true }); (function(Topics) { Topics.getTopicData = function(tid, callback) { RDB.hgetall('topic:' + tid, function(err, data) { if(err === null) callback(data); else console.log(err); }); } Topics.getTopicPosts = function(tid, callback) { posts.getPostsByTid(tid, 0, -1, function(postData) { callback(postData); }); } function constructPosts(topicPosts, callback) { var done = 0; for(var i=0, ii=topicPosts.length; i 0) { RDB.sismember(schema.topics(tid).read_by_uid, uid, function(err, read) { next(null, read); }); } else { next(null, null); } } function get_teaser(next) { Topics.get_teaser(tid, function(teaser) { next(null, teaser); }); } async.parallel([get_topic_data, get_read_status, get_teaser], function(err, results) { if (err) { throw new Error(err); } var topicData = results[0]; topicData.relativeTime = utils.relativeTime(results[0].timestamp); topicData.badgeclass = results[1] ? '' : 'badge-important'; topicData.teaser_text = results[2].text; topicData.teaser_username = results[2].username; callback(topicData); }); } Topics.getAllTopics = function(limit, after, callback) { RDB.smembers('topics:tid', function(err, tids) { var topics = [], numTids, x; // Sort into ascending order tids.sort(function(a, b) { return a - b; }); // Eliminate everything after the "after" tid if (after) { for(x=0,numTids=tids.length;x= after) { tids = tids.slice(0, x); break; } } } if (limit) { if (limit > 0 && limit < tids.length) { tids = tids.slice(tids.length - limit); } } // Sort into descending order tids.sort(function(a, b) { return b - a; }); async.each(tids, function(tid, next) { Topics.get_topic(tid, 0, function(topicData) { topics.push(topicData); next(); }); }, function(err) { callback(topics); }); }); } Topics.getTitleByPid = function(pid, callback) { posts.getPostField(pid, 'tid', function(tid) { Topics.getTopicField(tid, 'title', function(title) { callback(title); }); }); } Topics.markAsRead = function(tid, uid) { RDB.sadd(schema.topics(tid).read_by_uid, uid); Topics.getTopicField(tid, 'cid', function(cid) { categories.isTopicsRead(cid, uid, function(read) { if(read) { categories.markAsRead(cid, uid); } }); }); } Topics.hasReadTopics = function(tids, uid, callback) { var batch = RDB.multi(); for (var i=0, ii=tids.length; i 0) { RDB.lpush(schema.topics(tid).posts, pid); // Auto-subscribe the post creator to the newly created topic threadTools.toggleFollow(tid, uid); // Notify any users looking at the category that a new topic has arrived Topics.get_topic(tid, uid, function(topicData) { io.sockets.in('category_' + category_id).emit('event:new_topic', topicData); io.sockets.in('recent_posts').emit('event:new_topic', topicData); }); posts.getTopicPostStats(socket); } }); user.addTopicIdToUser(uid, tid); // let everyone know that there is an unread topic in this category RDB.del('cid:' + category_id + ':read_by_uid', function(err, data) { Topics.markAsRead(tid, uid); }); // in future it may be possible to add topics to several categories, so leaving the door open here. RDB.sadd('categories:' + category_id + ':tid', tid); categories.getCategories([category_id], function(data) { Topics.setTopicField(tid, 'category_name', data.categories[0].name); Topics.setTopicField(tid, 'category_slug', data.categories[0].slug); }); RDB.incr('cid:' + category_id + ':topiccount'); RDB.incr('totaltopiccount'); feed.updateCategory(category_id); socket.emit('event:alert', { title: 'Thank you for posting', message: 'You have successfully posted. Click here to view your post.', type: 'notify', timeout: 2000 }); }); }); }; Topics.getTopicField = function(tid, field, callback) { RDB.hget('topic:' + tid, field, function(err, data) { if(err === null) callback(data); else console.log(err); }); } Topics.setTopicField = function(tid, field, value) { RDB.hset('topic:' + tid, field, value); } Topics.increasePostCount = function(tid) { RDB.hincrby('topic:' + tid, 'postcount', 1); } Topics.isLocked = function(tid, callback) { Topics.getTopicField(tid, 'locked', function(locked) { callback(locked); }); } Topics.addToRecent = function(tid, timestamp) { RDB.zadd(schema.topics().recent, timestamp, tid); } }(exports));