var RDB = require('./redis.js'), posts = require('./posts.js'), utils = require('./../public/src/utils.js'), user = require('./user.js'), async = require('async'), topics = require('./topics.js'); (function(Categories) { Categories.getCategoryById = function(category_id, current_user, callback) { RDB.smembers('categories:' + category_id + ':tid', function(err, tids) { Categories.getCategoryData(category_id, function(categoryData) { var category_name = categoryData.name; category_slug = categoryData.slug; RDB.smembers('cid:' + category_id + ':active_users', function(err, active_users) { if (category_name === null) { callback(false); } var categoryData = { 'category_name' : category_name, 'show_sidebar' : 'show', 'show_topic_button': 'show', 'no_topics_message': 'hidden', 'topic_row_size': 'span9', 'category_id': category_id, 'active_users': [], 'topics' : [], 'twitter-intent-url': 'https://twitter.com/intent/tweet?url=' + encodeURIComponent(global.config.url + 'category/' + category_slug) + '&text=' + encodeURIComponent(category_name), 'facebook-share-url': 'https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(global.config.url + 'category/' + category_slug), 'google-share-url': 'https://plus.google.com/share?url=' + encodeURIComponent(global.config.url + 'category/' + category_slug) }; function getTopics(next) { Categories.getTopicsByTids(tids, current_user, function(topics) { // Float pinned topics to the top topics = topics.sort(function(a, b) { if (a.pinned !== b.pinned) return b.pinned - a.pinned; else { return b.lastposttime - a.lastposttime; } }); next(null, topics); }, category_id); } function getModerators(next) { Categories.getModerators(category_id, function(moderators) { next(null, moderators); }); } function getActiveUsers(next) { user.getMultipleUserFields(active_users, ['username', 'userslug'], function(users) { var activeUserData = []; for(var uid in users) { activeUserData.push(users[uid]); } next(null, activeUserData); }); } if (tids.length === 0) { getModerators(function(err, moderators) { categoryData.moderator_block_class = moderators.length > 0 ? '' : 'none'; categoryData.moderators = moderators; categoryData.show_sidebar = 'hidden'; categoryData.no_topics_message = 'show'; callback(categoryData); }); } else { async.parallel([getTopics, getModerators, getActiveUsers], function(err, results) { categoryData.topics = results[0]; categoryData.moderator_block_class = results[1].length > 0 ? '' : 'none'; categoryData.moderators = results[1]; categoryData.active_users = results[2]; callback(categoryData); }); } }); }); }); } // not the permanent location for this function Categories.getLatestTopics = function(current_user, start, end, callback) { RDB.zrevrange('topics:recent', 0, -1, function(err, tids) { var latestTopics = { 'category_name' : 'Recent', 'show_sidebar' : 'hidden', 'show_topic_button' : 'hidden', 'no_topics_message' : 'hidden', 'topic_row_size': 'span12', 'category_id': false, 'topics' : [] }; if (!tids.length) { callback(latestTopics); return; } Categories.getTopicsByTids(tids, current_user, function(topicData) { latestTopics.topics = topicData; callback(latestTopics); }); }); } // not the permanent location for this function Categories.getTopicsByTids = function(tids, current_user, callback, category_id /*temporary*/) { var retrieved_topics = []; var topicCountToLoad = tids.length; function getTopicInfo(topicData, callback) { function getUserName(next) { user.getUserField(topicData.uid, 'username', function(username) { next(null, username); }); } function hasReadTopic(next) { topics.hasReadTopics([topicData.tid], current_user, function(hasRead) { next(null, hasRead); }); } function getTeaserInfo(next) { topics.getTeaser(topicData.tid, function(teaser) { next(null, teaser); }); } // temporary. I don't think this call should belong here function getPrivileges(next) { Categories.privileges(category_id, current_user, function(user_privs) { next(null, user_privs); }); } async.parallel([getUserName, hasReadTopic, getTeaserInfo, getPrivileges], function(err, results) { var username = results[0], hasReadTopic = results[1], teaserInfo = results[2], privileges = results[3]; callback({ username: username, hasread: hasReadTopic, teaserInfo: teaserInfo, privileges: privileges }); }); } for(var i=0; i<tids.length; ++i) { topics.getTopicData(tids[i], function(topicData) { getTopicInfo(topicData, function(topicInfo) { topicData['pin-icon'] = topicData.pinned === '1' ? 'icon-pushpin' : 'none'; topicData['lock-icon'] = topicData.locked === '1' ? 'icon-lock' : 'none'; topicData['deleted-class'] = topicData.deleted === '1' ? 'deleted' : ''; topicData.relativeTime = utils.relativeTime(topicData.timestamp); topicData.username = topicInfo.username; topicData.badgeclass = (topicInfo.hasread && current_user != 0) ? '' : 'badge-important'; topicData.teaser_text = topicInfo.teaserInfo.text, topicData.teaser_username = topicInfo.teaserInfo.username; topicData.teaser_timestamp = utils.relativeTime(topicInfo.teaserInfo.timestamp); if (!topicData.deleted || (topicData.deleted && topicInfo.privileges.view_deleted) || topicData.uid === current_user) retrieved_topics.push(topicData); else --topicCountToLoad; if(retrieved_topics.length === topicCountToLoad) callback(retrieved_topics); }); }); } } Categories.getAllCategories = function(callback, current_user) { RDB.lrange('categories:cid', 0, -1, function(err, cids) { RDB.handle(err); Categories.getCategories(cids, callback, current_user); }); } Categories.getModerators = function(cid, callback) { RDB.smembers('cid:' + cid + ':moderators', function(err, mods) { if (mods.length === 0) return callback([]); user.getMultipleUserFields(mods, ['username'], function(details) { var moderators = []; for(u in details) { if (details.hasOwnProperty(u)) { moderators.push({ username: details[u].username }); } } callback(moderators); }); }); } Categories.privileges = function(cid, uid, callback) { function isModerator(next) { user.isModerator(uid, cid, function(isMod) { next(null, isMod); }); } function isAdministrator(next) { user.isAdministrator(uid, function(isAdmin) { next(null, isAdmin); }); } async.parallel([isModerator, isAdministrator], function(err, results) { callback({ editable: results.indexOf(true) !== -1 ? true : false, view_deleted: results.indexOf(true) !== -1 ? true : false }); }); } Categories.isTopicsRead = function(cid, uid, callback) { RDB.smembers('categories:' + cid + ':tid', function(err, tids) { topics.hasReadTopics(tids, uid, function(hasRead) { var allread = true; for (var i=0, ii=tids.length; i<ii; i++) { if(hasRead[i] === 0) { allread = false; break; } } callback(allread); }); }); } Categories.markAsRead = function(cid, uid) { RDB.sadd('cid:' + cid + ':read_by_uid', uid); } Categories.hasReadCategories = function(cids, uid, callback) { var batch = RDB.multi(); for (var i=0, ii=cids.length; i<ii; i++) { batch.sismember('cid:' + cids[i] + ':read_by_uid', uid); } batch.exec(function(err, hasRead) { callback(hasRead); }); } Categories.hasReadCategory = function(cid, uid, callback) { RDB.sismember('cid:' + cid + ':read_by_uid', uid, function(err, hasRead) { RDB.handle(err); callback(hasRead); }); } Categories.getRecentReplies = function(cid, callback) { RDB.zrevrange('categories:recent_posts:cid:' + cid, 0, 4, function(err, pids) { if (pids.length == 0) { callback(false); return; } posts.getPostSummaryByPids(pids, function(posts) { callback(posts); }); }); } Categories.getCategoryData = function(cid, callback) { RDB.hgetall('category:' + cid, function(err, data) { if(err === null) callback(data); else console.log(err); }); } Categories.getCategories = function(cids, callback, current_user) { if (cids.length === 0) { callback({'categories' : []}); return; } var categories = []; for(var i=0; i<cids.length; ++i) { Categories.getCategoryData(cids[i], function(categoryData) { if(!categoryData) return; Categories.hasReadCategory(categoryData.cid, current_user, function(hasRead) { categoryData['badgeclass'] = (parseInt(categoryData.topic_count,10) === 0 || (hasRead && current_user != 0)) ? '' : 'badge-important'; categories.push(categoryData); if(categories.length === cids.length) callback({'categories': categories}); }) ; }); } }; }(exports));