Merge remote-tracking branch 'origin/master' into composer-revamp

v1.18.x
Julian Lam 11 years ago
commit c4623e2447

@ -20,7 +20,7 @@ case "$1" in
echo "Launching NodeBB in \"development\" mode." echo "Launching NodeBB in \"development\" mode."
echo "To run the production build of NodeBB, please use \"forever\"." echo "To run the production build of NodeBB, please use \"forever\"."
echo "More Information: https://github.com/designcreateplay/NodeBB/wiki/How-to-run-NodeBB" echo "More Information: https://github.com/designcreateplay/NodeBB/wiki/How-to-run-NodeBB"
NODE_ENV=development supervisor --extensions 'node|js|tpl' -- app $1 NODE_ENV=development supervisor -q --extensions 'node|js|tpl' -- app $1
;; ;;
language) language)

@ -32,5 +32,8 @@
"show_email": "Show My Email", "show_email": "Show My Email",
"has_no_follower": "This user doesn't have any followers :(", "has_no_follower": "This user doesn't have any followers :(",
"follows_no_one": "This user isn't following anyone :(" "follows_no_one": "This user isn't following anyone :(",
"email_hidden": "Email Hidden",
"hidden": "hidden"
} }

@ -211,6 +211,7 @@ define(['uploader'], function(uploader) {
var modal = $('#category-permissions-modal'), var modal = $('#category-permissions-modal'),
searchEl = modal.find('#permission-search'), searchEl = modal.find('#permission-search'),
resultsEl = modal.find('.search-results'), resultsEl = modal.find('.search-results'),
groupsResultsEl = modal.find('.groups-results'),
searchDelay; searchDelay;
searchEl.off().on('keyup', function() { searchEl.off().on('keyup', function() {
@ -263,6 +264,40 @@ define(['uploader'], function(uploader) {
searchEl.keyup(); searchEl.keyup();
}); });
// User Groups and privileges
socket.emit('api:admin.categories.groupsearch', cid, function(err, results) {
var groupsFrag = document.createDocumentFragment(),
liEl = document.createElement('li');
var numResults = results.length,
resultObj;
for(var x=0;x<numResults;x++) {
resultObj = results[x];
liEl.setAttribute('data-gid', resultObj.gid);
liEl.innerHTML = '<div class="pull-right">' +
'<div class="btn-group">' +
'<button type="button" data-gpriv="+gr" class="btn btn-default' + (resultObj.privileges['+gr'] ? ' active' : '') + '">Read</button>' +
'<button type="button" data-gpriv="+gw" class="btn btn-default' + (resultObj.privileges['+gw'] ? ' active' : '') + '">Write</button>' +
'</div>' +
'</div>' +
' '+resultObj.name;
groupsFrag.appendChild(liEl.cloneNode(true));
}
groupsResultsEl.html(groupsFrag);
});
groupsResultsEl.off().on('click', '[data-gpriv]', function(e) {
var btnEl = $(this),
gid = btnEl.parents('li[data-gid]').attr('data-gid'),
privilege = this.getAttribute('data-gpriv');
e.preventDefault();
socket.emit('api:admin.categories.setGroupPrivilege', cid, gid, privilege, !btnEl.hasClass('active'), function(err, privileges) {
btnEl.toggleClass('active', privileges[privilege]);
});
})
modal.modal(); modal.modal();
}; };

@ -102,7 +102,7 @@ define(function() {
var loadingEl = document.getElementById('categories-loading'); var loadingEl = document.getElementById('categories-loading');
if (loadingEl) { if (loadingEl) {
socket.once('api:categories.get', function(data) { socket.emit('api:categories.get', function(data) {
// Render categories // Render categories
var categoriesFrag = document.createDocumentFragment(), var categoriesFrag = document.createDocumentFragment(),
categoryEl = document.createElement('li'), categoryEl = document.createElement('li'),
@ -172,7 +172,6 @@ define(function() {
} }
}); });
}); });
socket.emit('api:categories.get');
} }
}); });
} }
@ -483,7 +482,21 @@ define(function() {
adjust_rep(-1, data.pid, data.uid); adjust_rep(-1, data.pid, data.uid);
}); });
socket.on('event:new_post', createNewPosts); socket.on('event:new_post', function(data) {
var posts = data.posts;
for (var p in posts) {
if (posts.hasOwnProperty(p)) {
var post = posts[p],
postcount = jQuery('.user_postcount_' + post.uid),
ptotal = parseInt(postcount.html(), 10);
ptotal += 1;
postcount.html(ptotal);
}
}
createNewPosts(data);
});
socket.on('event:topic_deleted', function(data) { socket.on('event:topic_deleted', function(data) {
if (data.tid === tid && data.status === 'ok') { if (data.tid === tid && data.status === 'ok') {

@ -20,34 +20,51 @@
<span class="label label-danger">[[user:banned]]</span> <span class="label label-danger">[[user:banned]]</span>
</div> </div>
<!-- ENDIF banned --> <!-- ENDIF banned -->
<div>
<a id="chat-btn" href="#" class="btn btn-default hide">Chat</a>
</div>
<div id="user-actions"> <div id="user-actions">
<a id="follow-btn" href="#" class="btn btn-default">Follow</a> <a id="follow-btn" href="#" class="btn btn-default hide">Follow</a>
<a id="unfollow-btn" href="#" class="btn btn-default">Unfollow</a> <a id="unfollow-btn" href="#" class="btn btn-default hide">Unfollow</a>
</div> </div>
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<div class="inline-block"> <div class="inline-block">
<div class="account-bio-block"> <div class="account-bio-block">
<span class="account-bio-label">[[user:email]]</span><i class="fa fa-eye-slash {emailClass}" title="Email hidden"></i> <span class="account-bio-label">[[user:email]]</span><i class="fa fa-eye-slash {emailClass}" title="[[user:email_hidden]]"></i>
<!-- IF email -->
<span>{email}</span> <span>{email}</span>
<!-- ELSE -->
<i class="fa fa-eye-slash" title="[[user:email_hidden]]"></i> [[user:hidden]]
<!-- ENDIF email -->
<br/> <br/>
<!-- IF fullname -->
<span class="account-bio-label">[[user:fullname]]</span> <span class="account-bio-label">[[user:fullname]]</span>
<span>{fullname}</span> <span>{fullname}</span>
<br/> <br/>
<!-- ENDIF fullname -->
<!-- IF website -->
<span class="account-bio-label">[[user:website]]</span> <span class="account-bio-label">[[user:website]]</span>
<span><a href="{website}">{websiteName}</a></span> <span><a href="{website}">{websiteName}</a></span>
<br/> <br/>
<!-- ENDIF website -->
<!-- IF location -->
<span class="account-bio-label">[[user:location]]</span> <span class="account-bio-label">[[user:location]]</span>
<span>{location}</span> <span>{location}</span>
<br/> <br/>
<!-- ENDIF location -->
<!-- IF age -->
<span class="account-bio-label">[[user:age]]</span> <span class="account-bio-label">[[user:age]]</span>
<span>{age}</span> <span>{age}</span>
<br/> <br/>
<!-- ENDIF age -->
<hr/> <hr/>
<span class="account-bio-label">[[user:joined]]</span> <span class="account-bio-label">[[user:joined]]</span>
<span class="timeago" title="{joindate}"></span> <span class="timeago" title="{joindate}"></span>
@ -74,10 +91,12 @@
<br/> <br/>
<hr/> <hr/>
<!-- IF signature -->
<span class="account-bio-label">[[user:signature]]</span> <span class="account-bio-label">[[user:signature]]</span>
<div class="post-signature"> <div class="post-signature">
<span id='signature'>{signature}</span> <span id='signature'>{signature}</span>
</div> </div>
<!-- ENDIF signature -->
</div> </div>
</div> </div>
</div> </div>

File diff suppressed because one or more lines are too long

@ -40,7 +40,8 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-lg-offset-2 col-lg-10"> <div class="col-lg-offset-2 col-lg-10">
<button class="btn btn-primary" id="login" type="submit">[[login:login]]</button> &nbsp; <a id="reset-link" class="hide" href="/reset">[[login:forgot_password]]</a> <hr />
<button class="btn btn-primary btn-lg btn-block" id="login" type="submit">[[login:login]]</button> &nbsp; <a id="reset-link" class="hide" href="/reset">[[login:forgot_password]]</a>
</div> </div>
</div> </div>
<input type="hidden" name="_csrf" value="{token}" id="csrf-token" /> <input type="hidden" name="_csrf" value="{token}" id="csrf-token" />

@ -15,12 +15,18 @@
<div class="category search"> <div class="category search">
<div class="{show_results}"> <div class="{show_results}">
<ul id="topics-container" data-search-query="{search_query}">
<h3>[[topic:topics]]</h3> <h3>[[topic:topics]]</h3>
<!-- IF topic_matches -->
<small>{topic_matches} result(s) matching "{search_query}"</small>
<!-- ENDIF topic_matches -->
<div class="alert alert-info {show_no_topics}">[[topic:no_topics_found]]</div> <div class="alert alert-info {show_no_topics}">[[topic:no_topics_found]]</div>
<ul id="topics-container" data-search-query="{search_query}">
<!-- BEGIN topics --> <!-- BEGIN topics -->
<a href="../../topic/{topics.slug}" id="tid-{topics.tid}">
<li class="category-item"> <li class="category-item">
<a href="../../topic/{topics.slug}" id="tid-{topics.tid}">
<div> <div>
<div class="col-md-12 img-thumbnail"> <div class="col-md-12 img-thumbnail">
<div class="search-result-post"> <div class="search-result-post">
@ -30,14 +36,21 @@
</div> </div>
</div> </div>
</li>
</a> </a>
</li>
<!-- END topics --> <!-- END topics -->
</ul>
<h3>Posts</h3> <h3>Posts</h3>
<!-- IF post_matches -->
<small>{post_matches} result(s) matching "{search_query}"</small>
<!-- ENDIF post_matches -->
<div class="alert alert-info {show_no_posts}">No posts found!</div> <div class="alert alert-info {show_no_posts}">No posts found!</div>
<ul id="topics-container" data-search-query="{search_query}">
<!-- BEGIN posts --> <!-- BEGIN posts -->
<a href="../../topic/{posts.topicSlug}#{posts.pid}" id="tid-{posts.tid}">
<li class="category-item"> <li class="category-item">
<a href="../../topic/{posts.topicSlug}#{posts.pid}" id="tid-{posts.tid}">
<div> <div>
<div class="col-md-12 img-thumbnail"> <div class="col-md-12 img-thumbnail">
<div class="search-result-post"> <div class="search-result-post">
@ -47,8 +60,8 @@
</div> </div>
</div> </div>
</li>
</a> </a>
</li>
<!-- END posts --> <!-- END posts -->
</ul> </ul>
</div> </div>

@ -109,7 +109,7 @@
<div class="post-info"> <div class="post-info">
<span class="pull-left"> <span class="pull-left">
[[topic:reputation]]: <i class='fa fa-star'></i> <span class='formatted-number'>{posts.user_rep}</span>&nbsp;|&nbsp;[[topic:posts]]: <i class='fa fa-pencil'></i> <span class='formatted-number'>{posts.user_postcount}</span> [[topic:reputation]]: <i class='fa fa-star'></i> <span class='formatted-number post_rep_{posts.uid}'>{posts.user_rep}</span>&nbsp;|&nbsp;[[topic:posts]]: <i class='fa fa-pencil'></i> <span class='formatted-number user_postcount_{posts.uid}'>{posts.user_postcount}</span>
{posts.additional_profile_info} {posts.additional_profile_info}
</span> </span>
<span class="pull-right"> <span class="pull-right">

@ -65,4 +65,56 @@ CategoryTools.privileges = function(cid, uid, callback) {
}); });
}; };
CategoryTools.groupPrivileges = function(cid, gid, callback) {
async.parallel({
"+gr": function(next) {
var key = 'cid:' + cid + ':privileges:+gr';
Groups.exists(key, function(err, exists) {
if (exists) {
async.parallel({
isMember: function(next) {
Groups.isMemberByGroupName(gid, key, next);
},
isEmpty: function(next) {
Groups.isEmptyByGroupName(key, next);
}
}, next);
} else {
next(null, {
isMember: false,
isEmpty: true
});
}
});
},
"+gw": function(next) {
var key = 'cid:' + cid + ':privileges:+gw';
Groups.exists(key, function(err, exists) {
if (exists) {
async.parallel({
isMember: function(next) {
Groups.isMemberByGroupName(gid, key, next);
},
isEmpty: function(next) {
Groups.isEmptyByGroupName(key, next);
}
}, next);
} else {
next(null, {
isMember: false,
isEmpty: true
});
}
});
}
}, function(err, privileges) {
callback(err, !privileges ? null : {
"+gr": privileges['+gr'].isMember,
"+gw": privileges['+gw'].isMember,
read: (privileges['+gr'].isMember || privileges['+gr'].isEmpty),
write: (privileges['+gw'].isMember || privileges['+gw'].isEmpty),
});
});
};
module.exports = CategoryTools; module.exports = CategoryTools;

@ -176,7 +176,6 @@
Groups.update = function(gid, values, callback) { Groups.update = function(gid, values, callback) {
db.exists('gid:' + gid, function (err, exists) { db.exists('gid:' + gid, function (err, exists) {
console.log('exists?', gid, exists, values);
if (!err && exists) { if (!err && exists) {
db.setObject('gid:' + gid, values, callback); db.setObject('gid:' + gid, values, callback);
} else { } else {
@ -199,7 +198,6 @@
Groups.getGidFromName(groupName, function(err, gid) { Groups.getGidFromName(groupName, function(err, gid) {
if (err || !gid) { if (err || !gid) {
Groups.create(groupName, '', function(err, groupObj) { Groups.create(groupName, '', function(err, groupObj) {
console.log('creating group, calling hide', groupObj.gid);
async.parallel([ async.parallel([
function(next) { function(next) {
Groups.hide(groupObj.gid, next); Groups.hide(groupObj.gid, next);
@ -263,4 +261,40 @@
}); });
}; };
Groups.getCategoryAccess = function(cid, uid, callback){
var access = false;
// check user group read access level
async.series([function(callback){
// get groups with read permission
db.getObjectField('group:gid', 'cid:' + cid + ':privileges:+gr', function(err, gid){
// get the user groups that belong to this read group
db.getSetMembers('gid:' + gid + ':members', function (err, gids) {
// check if user belong to any of these user groups
var groups_check = new Array();
gids.forEach(function(cgid){
groups_check.push(function(callback){
Groups.isMember(uid, cgid, function(err, isMember){
if (isMember){
access = true;
}
callback(null, gids);
})
});
});
// do a series check. We want to make sure we check all the groups before determining if the user
// has access or not.
async.series(groups_check, function(err, results){
callback(null, results);
});
});
});
}],
function(err, results){
// if the read group is empty we will asume that read access has been granted to ALL
if (results[0].length == 0){ access = true; }
callback(false, access);
});
};
}(module.exports)); }(module.exports));

@ -14,7 +14,8 @@ var db = require('./database'),
async = require('async'), async = require('async'),
nconf = require('nconf'), nconf = require('nconf'),
validator = require('validator'), validator = require('validator'),
winston = require('winston'); winston = require('winston'),
gravatar = require('gravatar');
(function(Posts) { (function(Posts) {
var customUserInfo = {}; var customUserInfo = {};
@ -202,12 +203,16 @@ var db = require('./database'),
} }
postTools.parseSignature(userData.signature, function(err, signature) { postTools.parseSignature(userData.signature, function(err, signature) {
if(err) {
return callback(err);
}
post.username = userData.username || 'anonymous'; post.username = userData.username || 'anonymous';
post.userslug = userData.userslug || ''; post.userslug = userData.userslug || '';
post.user_rep = userData.reputation || 0; post.user_rep = userData.reputation || 0;
post.user_postcount = userData.postcount || 0; post.user_postcount = userData.postcount || 0;
post.user_banned = parseInt(userData.banned, 10) === 1; post.user_banned = parseInt(userData.banned, 10) === 1;
post.picture = userData.picture || require('gravatar').url('', {}, https = nconf.get('https')); post.picture = userData.picture || gravatar.url('', {}, https = nconf.get('https'));
post.signature = signature; post.signature = signature;
for (var info in customUserInfo) { for (var info in customUserInfo) {
@ -217,11 +222,16 @@ var db = require('./database'),
} }
plugins.fireHook('filter:posts.custom_profile_info', {profile: "", uid: post.uid, pid: post.pid}, function(err, profile_info) { plugins.fireHook('filter:posts.custom_profile_info', {profile: "", uid: post.uid, pid: post.pid}, function(err, profile_info) {
if(err) {
return callback(err);
}
post.additional_profile_info = profile_info.profile; post.additional_profile_info = profile_info.profile;
if (post.editor !== '') { if (post.editor !== '') {
user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) { user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) {
if (err) return callback(); if (err) {
return callback(err);
}
post.editorname = editorData.username; post.editorname = editorData.username;
post.editorslug = editorData.userslug; post.editorslug = editorData.userslug;
@ -439,8 +449,9 @@ var db = require('./database'),
Posts.uploadPostImage = function(image, callback) { Posts.uploadPostImage = function(image, callback) {
if(!image) if(!image) {
return callback('invalid image', null); return callback('invalid image', null);
}
require('./imgur').upload(meta.config.imgurClientID, image.data, 'base64', function(err, data) { require('./imgur').upload(meta.config.imgurClientID, image.data, 'base64', function(err, data) {
if(err) { if(err) {
@ -455,22 +466,29 @@ var db = require('./database'),
} }
Posts.getPostsByUid = function(uid, start, end, callback) { Posts.getPostsByUid = function(uid, start, end, callback) {
user.getPostIds(uid, start, end, function(pids) { user.getPostIds(uid, start, end, function(err, pids) {
if(err) {
return callback(err);
}
if (pids && pids.length) { if (pids && pids.length) {
plugins.fireHook('filter:post.getTopic', pids, function(err, posts) { plugins.fireHook('filter:post.getTopic', pids, function(err, posts) {
if(err) {
return callback(err);
}
if (!err & 0 < posts.length) { if (posts && posts.length) {
Posts.getPostsByPids(pids, function(err, posts) { Posts.getPostsByPids(pids, function(err, posts) {
plugins.fireHook('action:post.gotTopic', posts); plugins.fireHook('action:post.gotTopic', posts);
callback(posts); callback(null, posts);
}); });
} else { } else {
callback(posts); callback(null, []);
} }
}); });
} else } else {
callback([]); callback(null, []);
}
}); });
} }

@ -244,7 +244,7 @@ var nconf = require('nconf'),
var custom_routes = { var custom_routes = {
'routes': [], 'routes': [],
'api_methods': [] 'api': []
}; };
plugins.ready(function() { plugins.ready(function() {
@ -264,6 +264,19 @@ var nconf = require('nconf'),
}(route)); }(route));
} }
} }
var apiRoutes = custom_routes.api;
for (var route in apiRoutes) {
if (apiRoutes.hasOwnProperty(route)) {
(function(route) {
app[apiRoutes[route].method || 'get']('/api/admin' + apiRoutes[route].route, function(req, res) {
apiRoutes[route].callback(req, res, function(data) {
res.json(data);
});
});
}(route));
}
}
}); });
}); });

@ -4,6 +4,7 @@ var path = require('path'),
db = require('../database'), db = require('../database'),
user = require('../user'), user = require('../user'),
groups = require('../groups'),
auth = require('./authentication'), auth = require('./authentication'),
topics = require('../topics'), topics = require('../topics'),
posts = require('../posts'), posts = require('../posts'),
@ -39,33 +40,26 @@ var path = require('path'),
res.json(200, config); res.json(200, config);
}); });
app.get('/home', function (req, res, next) { app.get('/home', function (req, res) {
var uid = (req.user) ? req.user.uid : 0; var uid = (req.user) ? req.user.uid : 0;
categories.getAllCategories(uid, function (err, data) { categories.getAllCategories(uid, function (err, data) {
data.categories = data.categories.filter(function (category) { data.categories = data.categories.filter(function (category) {
return (!category.disabled || parseInt(category.disabled, 10) === 0); return (!category.disabled || parseInt(category.disabled, 10) === 0);
}); });
function getRecentReplies(category, callback) { function iterator(category, callback) {
categories.getRecentReplies(category.cid, 2, function (err, posts) { categories.getRecentReplies(category.cid, 2, function (err, posts) {
if(err) {
return callback(err);
}
category.posts = posts; category.posts = posts;
category.post_count = posts.length > 2 ? 2 : posts.length; category.post_count = posts.length > 2 ? 2 : posts.length;
callback(null); callback(null);
}); });
} }
async.each(data.categories, getRecentReplies, function (err) { async.each(data.categories, iterator, function (err) {
if(err) {
return next(err);
}
data.motd_class = (parseInt(meta.config.show_motd, 10) === 1 || meta.config.show_motd === undefined) ? '' : ' none'; data.motd_class = (parseInt(meta.config.show_motd, 10) === 1 || meta.config.show_motd === undefined) ? '' : ' none';
data.motd_class += (meta.config.motd && meta.config.motd.length > 0 ? '' : ' default'); data.motd_class += (meta.config.motd && meta.config.motd.length > 0 ? '' : ' default');
data.motd = require('marked')(meta.config.motd || "<div class=\"pull-right btn-group\"><a target=\"_blank\" href=\"http://www.nodebb.org\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-comment\"></i><span class='hidden-mobile'>&nbsp;Get NodeBB</span></a> <a target=\"_blank\" href=\"https://github.com/designcreateplay/NodeBB\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-github\"></i><span class='hidden-mobile'>&nbsp;Fork us on Github</span></a> <a target=\"_blank\" href=\"https://twitter.com/dcplabs\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-twitter\"></i><span class='hidden-mobile'>&nbsp;@dcplabs</span></a></div>\n\n# NodeBB <span>v" + pkg.version + "</span>\nWelcome to NodeBB, the discussion platform of the future."); data.motd = require('marked')(meta.config.motd || "<div class=\"pull-right btn-group\"><a target=\"_blank\" href=\"http://www.nodebb.org\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-comment\"></i><span class='hidden-mobile'>&nbsp;Get NodeBB</span></a> <a target=\"_blank\" href=\"https://github.com/designcreateplay/NodeBB\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-github\"></i><span class='hidden-mobile'>&nbsp;Fork us on Github</span></a> <a target=\"_blank\" href=\"https://twitter.com/dcplabs\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-twitter\"></i><span class='hidden-mobile'>&nbsp;@NodeBB</span></a></div>\n\n# NodeBB <span>v" + pkg.version + "</span>\nWelcome to NodeBB, the discussion platform of the future.");
res.json(data); res.json(data);
}); });
}); });
@ -128,7 +122,15 @@ var path = require('path'),
if (parseInt(data.deleted, 10) === 1 && parseInt(data.expose_tools, 10) === 0) { if (parseInt(data.deleted, 10) === 1 && parseInt(data.expose_tools, 10) === 0) {
return res.json(404, {}); return res.json(404, {});
} }
// get the category this post belongs to and check category access
var cid = data.category_slug.split("/")[0];
groups.getCategoryAccess(cid, uid, function(err, access){
if (access){
res.json(data); res.json(data);
} else {
res.send(403);
}
})
} else next(); } else next();
}); });
}); });
@ -139,6 +141,8 @@ var path = require('path'),
// Category Whitelisting // Category Whitelisting
categoryTools.privileges(req.params.id, uid, function(err, privileges) { categoryTools.privileges(req.params.id, uid, function(err, privileges) {
if (!err && privileges.read) { if (!err && privileges.read) {
groups.getCategoryAccess(req.params.id, uid, function(err, access){
if (access){
categories.getCategoryById(req.params.id, uid, function (err, data) { categories.getCategoryById(req.params.id, uid, function (err, data) {
if (!err && data && parseInt(data.disabled, 10) === 0) { if (!err && data && parseInt(data.disabled, 10) === 0) {
res.json(data); res.json(data);
@ -149,6 +153,11 @@ var path = require('path'),
} else { } else {
res.send(403); res.send(403);
} }
});
} else {
res.send(403);
}
}); });
}); });
@ -244,10 +253,6 @@ var path = require('path'),
return callback(err, null); return callback(err, null);
} }
if(pids.length > 50) {
pids = pids.splice(0, 50);
}
posts.getPostSummaryByPids(pids, false, function (err, posts) { posts.getPostSummaryByPids(pids, false, function (err, posts) {
if (err){ if (err){
return callback(err, null); return callback(err, null);
@ -263,10 +268,6 @@ var path = require('path'),
return callback(err, null); return callback(err, null);
} }
if(tids.length > 50) {
tids = tids.splice(0, 50);
}
topics.getTopicsByTids(tids, 0, function (topics) { topics.getTopicsByTids(tids, 0, function (topics) {
callback(null, topics); callback(null, topics);
}, 0); }, 0);
@ -285,7 +286,9 @@ var path = require('path'),
show_results: '', show_results: '',
search_query: req.params.term, search_query: req.params.term,
posts: results[0], posts: results[0],
topics: results[1] topics: results[1],
post_matches : results[0].length,
topic_matches : results[1].length
}); });
}); });
} else { } else {
@ -313,7 +316,7 @@ var path = require('path'),
app.get('/500', function(req, res) { app.get('/500', function(req, res) {
res.json({errorMessage: 'testing'}); res.json({errorMessage: 'testing'});
}) });
}); });
} }
}(exports)); }(exports));

@ -72,7 +72,7 @@
login_strategies.push({ login_strategies.push({
name: 'google', name: 'google',
url: '/auth/google', url: '/auth/google',
callbackURL: nconf.get('url') + '/auth/google/callback', callbackURL: '/auth/google/callback',
icon: 'google-plus', icon: 'google-plus',
scope: 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email' scope: 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email'
}); });
@ -95,7 +95,7 @@
login_strategies.push({ login_strategies.push({
name: 'facebook', name: 'facebook',
url: '/auth/facebook', url: '/auth/facebook',
callbackURL: nconf.get('url') + '/auth/facebook/callback', callbackURL: '/auth/facebook/callback',
icon: 'facebook', icon: 'facebook',
scope: 'email' scope: 'email'
}); });

@ -393,18 +393,24 @@ var fs = require('fs'),
}); });
}); });
app.get('/api/user/:userslug', function (req, res) { app.get('/api/user/:userslug', function (req, res, next) {
var callerUID = req.user ? req.user.uid : '0'; var callerUID = req.user ? req.user.uid : '0';
getUserDataByUserSlug(req.params.userslug, callerUID, function (userData) { getUserDataByUserSlug(req.params.userslug, callerUID, function (userData) {
if (userData) { if (userData) {
user.isFollowing(callerUID, userData.theirid, function (isFollowing) { user.isFollowing(callerUID, userData.theirid, function (isFollowing) {
posts.getPostsByUid(userData.theirid, 0, 9, function (posts) { posts.getPostsByUid(userData.theirid, 0, 9, function (err, posts) {
if(err) {
return next(err);
}
userData.posts = posts.filter(function (p) { userData.posts = posts.filter(function (p) {
return p && parseInt(p.deleted, 10) !== 1; return p && parseInt(p.deleted, 10) !== 1;
}); });
userData.isFollowing = isFollowing; userData.isFollowing = isFollowing;
if (!userData.profileviews) { if (!userData.profileviews) {
userData.profileviews = 1; userData.profileviews = 1;
} }

@ -444,21 +444,18 @@ var bcrypt = require('bcrypt'),
User.getPostIds = function(uid, start, stop, callback) { User.getPostIds = function(uid, start, stop, callback) {
db.getListRange('uid:' + uid + ':posts', start, stop, function(err, pids) { db.getListRange('uid:' + uid + ':posts', start, stop, function(err, pids) {
if (!err) { if(err) {
if (pids && pids.length) { return callback(err);
callback(pids);
} else {
callback([]);
} }
if (pids && pids.length) {
callback(null, pids);
} else { } else {
console.log(err); callback(null, []);
callback([]);
} }
}); });
}; };
User.follow = function(uid, followid, callback) { User.follow = function(uid, followid, callback) {
db.setAdd('following:' + uid, followid, function(err, data) { db.setAdd('following:' + uid, followid, function(err, data) {
if (!err) { if (!err) {

@ -591,9 +591,9 @@ websockets.init = function(io) {
threadTools.move(data.tid, data.cid, socket); threadTools.move(data.tid, data.cid, socket);
}); });
socket.on('api:categories.get', function() { socket.on('api:categories.get', function(callback) {
categories.getAllCategories(0, function(err, categories) { categories.getAllCategories(0, function(err, categories) {
socket.emit('api:categories.get', categories); callback(categories);
}); });
}); });
@ -714,10 +714,10 @@ websockets.init = function(io) {
return; return;
} }
var finalMessage = username + ' : ' + msg, var username = usersData[0].username,
notifText = 'New message from <strong>' + username + '</strong>', toUsername = usersData[1].username,
username = usersData[0].username, finalMessage = username + ' : ' + msg,
toUsername = usersData[1].username; notifText = 'New message from <strong>' + username + '</strong>';
if (!isUserOnline(touid)) { if (!isUserOnline(touid)) {
notifications.create(notifText, 'javascript:app.openChat(&apos;' + username + '&apos;, ' + uid + ');', 'notification_' + uid + '_' + touid, function(nid) { notifications.create(notifText, 'javascript:app.openChat(&apos;' + username + '&apos;, ' + uid + ');', 'notification_' + uid + '_' + touid, function(nid) {
@ -1084,6 +1084,37 @@ websockets.init = function(io) {
}); });
}); });
socket.on('api:admin.categories.setGroupPrivilege', function(cid, gid, privilege, set, callback) {
var cb = function(err) {
CategoryTools.groupPrivileges(cid, gid, callback);
};
if (set) {
groups.joinByGroupName('cid:' + cid + ':privileges:' + privilege, gid, cb);
} else {
groups.leaveByGroupName('cid:' + cid + ':privileges:' + privilege, gid, cb);
}
});
socket.on('api:admin.categories.groupsearch', function(cid, callback) {
groups.list({expand:false}, function(err, data){
async.map(data, function(groupObj, next) {
CategoryTools.groupPrivileges(cid, groupObj.gid, function(err, privileges) {
if (!err) {
groupObj.privileges = privileges;
} else {
winston.error('[socket api:admin.categories.groupsearch] Could not retrieve permissions');
}
next(null, groupObj);
});
}, function(err, data) {
if (!callback) socket.emit('api:admin.categories.groupsearch', data);
else callback(null, data);
});
});
});
socket.on('api:admin.themes.getInstalled', function(callback) { socket.on('api:admin.themes.getInstalled', function(callback) {
meta.themes.get(function(err, themeArr) { meta.themes.get(function(err, themeArr) {
callback(themeArr); callback(themeArr);

Loading…
Cancel
Save