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.getTopicById = function(tid, current_user, callback) { function getTopicData(next) { RDB.multi() .get(schema.topics(tid).title) .get(schema.topics(tid).locked) .get(schema.topics(tid).category_name) .get(schema.topics(tid).category_slug) .get(schema.topics(tid).deleted) .get(schema.topics(tid).pinned) .get(schema.topics(tid).slug) .exec(function(err, replies) { next(null, { topic_name: replies[0], locked: replies[1] || 0, category_name: replies[2], category_slug: replies[3], deleted: replies[4] || 0, pinned: replies[5] || 0, slug: replies[6] }); }); } function getTopicPosts(next) { posts.getPostsByTid(tid, current_user, 0, 9, function(postData) { next(null, postData); }); } function getPrivileges(next) { threadTools.privileges(tid, current_user, function(privData) { next(null, privData); }); } async.parallel([getTopicData, getTopicPosts, getPrivileges], function(err, results) { var topicData = results[0], privileges = results[2]; postTools.constructPostObject(results[1], tid, current_user, privileges, function(postObj) { if (postObj.length) { var main_posts = postObj.splice(0, 1); callback({ 'topic_name':topicData.topic_name, 'category_name':topicData.category_name, 'category_slug':topicData.category_slug, 'locked': parseInt(topicData.locked) || 0, 'deleted': parseInt(topicData.deleted) || 0, 'pinned': parseInt(topicData.pinned) || 0, 'slug': topicData.slug, 'topic_id': tid, 'expose_tools': privileges.editable ? 1 : 0, 'posts': postObj, 'main_posts': main_posts }); } else { return callback(false); } }); }); } Topics.get_topic = function(tid, uid, callback) { var topicData = {}; function get_topic_data(next) { RDB.mget([ schema.topics(tid).title, schema.topics(tid).uid, schema.topics(tid).timestamp, schema.topics(tid).slug, schema.topics(tid).postcount, schema.topics(tid).locked, schema.topics(tid).pinned, schema.topics(tid).deleted ], function(err, topic) { if (err) { throw new Error(err); } topicData.title = topic[0]; topicData.uid = topic[1]; topicData.timestamp = topic[2]; topicData.relativeTime = utils.relativeTime(topic[2]), topicData.slug = topic[3]; topicData.post_count = topic[4]; topicData.locked = topic[5]; topicData.pinned = topic[6]; topicData.deleted = topic[7]; user.getUserField(topic[1], 'username', function(username) { topicData.username = username; next(); }); }); } function get_read_status(next) { // posts.create calls this function - should be an option to skip this because its always true if (uid && parseInt(uid) > 0) { RDB.sismember(schema.topics(tid).read_by_uid, uid, function(err, read) { topicData.badgeclass = read ? '' : 'badge-important'; next(); }); } else { next(); } } function get_teaser(next) { Topics.get_teaser(tid, function(teaser) { topicData.teaser_text = teaser.text; topicData.teaser_username = teaser.username; next(); }); } async.parallel([get_topic_data, get_read_status, get_teaser], function(err) { if (err) { throw new Error(err); } topicData.tid = tid; 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.get_cid_by_tid = function(tid, callback) { RDB.get(schema.topics(tid).cid, function(err, cid) { if (cid && parseInt(cid) > 0) { callback(cid); } else { callback(false); } }); } Topics.getTitle = function(tid, callback) { RDB.get('tid:' + tid + ':title', function(err, title) { callback(title); }); } Topics.getSlug = function(tid, callback) { RDB.get('tid:' + tid + ':slug', function(err, slug) { callback(slug); }); } Topics.getTitleByPid = function(pid, callback) { RDB.get('pid:' + pid + ':tid', function(err, tid) { if (!err) { Topics.getTitle(tid, function(title) { callback(title); }); } else callback('Could not grab title'); }); } Topics.markAsRead = function(tid, uid) { RDB.sadd(schema.topics(tid).read_by_uid, uid); Topics.get_cid_by_tid(tid, 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 Details - move this out later RDB.lpush('uid:' + uid + ':topics', tid); socket.emit('event:alert', { title: 'Thank you for posting', message: 'You have successfully posted. Click here to view your post.', type: 'notify', timeout: 2000 }); // 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); }); RDB.zadd(schema.topics().recent, Date.now(), tid); //RDB.zadd('topics:active', tid); // 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); RDB.set(schema.topics(tid).cid, category_id); categories.getCategories([category_id], function(data) { RDB.set(schema.topics(tid).category_name, data.categories[0].name); RDB.set(schema.topics(tid).category_slug, data.categories[0].slug); }); RDB.incr('cid:' + category_id + ':topiccount'); RDB.incr('totaltopiccount'); feed.updateCategory(category_id); }); }); }; }(exports));