mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-07-13 00:21:51 +02:00
Merge branch 'master' into acp-paper
This commit is contained in:
8
Dockerfile
Normal file
8
Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
||||
FROM node:0.10-onbuild
|
||||
|
||||
ENV NODE_ENV=production \
|
||||
daemon=false \
|
||||
silent=false
|
||||
|
||||
CMD node app --setup && npm start
|
||||
EXPOSE 4567
|
||||
18
nodebb
18
nodebb
@@ -5,8 +5,7 @@ var colors = require('colors'),
|
||||
argv = require('minimist')(process.argv.slice(2)),
|
||||
fs = require('fs'),
|
||||
async = require('async'),
|
||||
touch = require('touch'),
|
||||
npm = require('npm');
|
||||
touch = require('touch');
|
||||
|
||||
var getRunningPid = function(callback) {
|
||||
fs.readFile(__dirname + '/pidfile', {
|
||||
@@ -119,15 +118,12 @@ switch(process.argv[2]) {
|
||||
case 'upgrade':
|
||||
async.series([
|
||||
function(next) {
|
||||
process.stdout.write('1. '.bold + 'Bringing base dependencies up to date\n'.yellow);
|
||||
npm.load({
|
||||
loglevel: 'silent'
|
||||
}, function() {
|
||||
npm.commands.install(next);
|
||||
});
|
||||
process.stdout.write('1. '.bold + 'Bringing base dependencies up to date... '.yellow);
|
||||
require('child_process').execFile('/usr/bin/env', ['npm', 'i', '--production'], next);
|
||||
},
|
||||
function(next) {
|
||||
process.stdout.write('2. '.bold + 'Updating NodeBB data store schema\n'.yellow);
|
||||
process.stdout.write('OK\n'.green);
|
||||
process.stdout.write('2. '.bold + 'Updating NodeBB data store schema.\n'.yellow);
|
||||
var upgradeProc = cproc.fork('app.js', ['--upgrade'], {
|
||||
cwd: __dirname,
|
||||
silent: false
|
||||
@@ -136,7 +132,7 @@ switch(process.argv[2]) {
|
||||
upgradeProc.on('close', next)
|
||||
},
|
||||
function(next) {
|
||||
process.stdout.write('3. '.bold + 'Storing upgrade date in "package.json"\n'.yellow);
|
||||
process.stdout.write('3. '.bold + 'Storing upgrade date in "package.json"... '.yellow);
|
||||
touch(__dirname + '/package.json', {}, next);
|
||||
}
|
||||
], function(err) {
|
||||
@@ -145,6 +141,8 @@ switch(process.argv[2]) {
|
||||
} else {
|
||||
var message = 'NodeBB Upgrade Complete!',
|
||||
spaces = new Array(Math.floor(process.stdout.columns / 2) - (message.length / 2) + 1).join(' ');
|
||||
|
||||
process.stdout.write('OK\n'.green);
|
||||
process.stdout.write('\n' + spaces + message.green.bold + '\n\n'.reset);
|
||||
}
|
||||
});
|
||||
|
||||
26
package.json
26
package.json
@@ -14,14 +14,14 @@
|
||||
"test": "mocha ./tests -t 10000"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~0.9.0",
|
||||
"bcryptjs": "~2.1.0",
|
||||
"async": "~1.4.2",
|
||||
"bcryptjs": "~2.2.1",
|
||||
"body-parser": "^1.9.0",
|
||||
"colors": "^1.1.0",
|
||||
"compression": "^1.1.0",
|
||||
"connect-ensure-login": "^0.1.1",
|
||||
"connect-flash": "^0.1.1",
|
||||
"connect-multiparty": "^1.2.4",
|
||||
"connect-multiparty": "^2.0.0",
|
||||
"cookie-parser": "^1.3.3",
|
||||
"cron": "^1.0.5",
|
||||
"csurf": "^1.6.1",
|
||||
@@ -43,37 +43,37 @@
|
||||
"nodebb-plugin-composer-default": "1.0.9",
|
||||
"nodebb-plugin-dbsearch": "0.2.15",
|
||||
"nodebb-plugin-emoji-extended": "0.4.9",
|
||||
"nodebb-plugin-markdown": "4.0.2",
|
||||
"nodebb-plugin-markdown": "4.0.4",
|
||||
"nodebb-plugin-mentions": "1.0.0",
|
||||
"nodebb-plugin-soundpack-default": "0.1.2",
|
||||
"nodebb-plugin-spam-be-gone": "0.4.1",
|
||||
"nodebb-rewards-essentials": "0.0.3",
|
||||
"nodebb-theme-lavender": "1.0.49",
|
||||
"nodebb-theme-persona": "2.0.13",
|
||||
"nodebb-theme-vanilla": "3.0.7",
|
||||
"nodebb-theme-persona": "2.0.15",
|
||||
"nodebb-theme-vanilla": "3.0.8",
|
||||
"nodebb-widget-essentials": "1.0.4",
|
||||
"npm": "^2.1.4",
|
||||
"passport": "^0.2.1",
|
||||
"passport-local": "1.0.0",
|
||||
"prompt": "^0.2.14",
|
||||
"request": "^2.44.0",
|
||||
"rimraf": "~2.3.2",
|
||||
"rimraf": "~2.4.2",
|
||||
"rss": "^1.0.0",
|
||||
"semver": "^4.3.3",
|
||||
"semver": "^5.0.1",
|
||||
"serve-favicon": "^2.1.5",
|
||||
"sitemap": "^0.8.1",
|
||||
"sitemap": "^1.0.0",
|
||||
"socket.io": "^1.2.1",
|
||||
"socket.io-client": "^1.2.1",
|
||||
"socket.io-redis": "^0.1.3",
|
||||
"socketio-wildcard": "~0.1.1",
|
||||
"string": "^3.0.0",
|
||||
"templates.js": "0.2.8",
|
||||
"touch": "0.0.3",
|
||||
"templates.js": "0.2.10",
|
||||
"touch": "1.0.0",
|
||||
"uglify-js": "^2.4.23",
|
||||
"underscore": "~1.8.3",
|
||||
"underscore.deep": "^0.5.1",
|
||||
"validator": "^3.30.0",
|
||||
"winston": "^0.9.0",
|
||||
"validator": "^4.0.5",
|
||||
"winston": "^1.0.1",
|
||||
"xregexp": "~2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -50,11 +50,11 @@ define('admin/manage/category', [
|
||||
|
||||
function enableColorPicker(idx, inputEl) {
|
||||
var $inputEl = $(inputEl),
|
||||
previewEl = $inputEl.parents('[data-cid]').find('.preview-box');
|
||||
previewEl = $inputEl.parents('[data-cid]').find('.category-preview');
|
||||
|
||||
colorpicker.enable($inputEl, function(hsb, hex) {
|
||||
if ($inputEl.attr('data-name') === 'bgColor') {
|
||||
previewEl.css('background', '#' + hex);
|
||||
previewEl.css('background-color', '#' + hex);
|
||||
} else if ($inputEl.attr('data-name') === 'color') {
|
||||
previewEl.css('color', '#' + hex);
|
||||
}
|
||||
@@ -83,6 +83,11 @@ define('admin/manage/category', [
|
||||
modified(ev.target);
|
||||
});
|
||||
|
||||
// Update preview image size on change
|
||||
$('[data-name="imageClass"]').on('change', function(ev) {
|
||||
$('.category-preview').css('background-size', $(this).val());
|
||||
});
|
||||
|
||||
// Colour Picker
|
||||
$('[data-name="bgColor"], [data-name="color"]').each(enableColorPicker);
|
||||
|
||||
@@ -113,8 +118,7 @@ define('admin/manage/category', [
|
||||
uploader.open(RELATIVE_PATH + '/api/admin/category/uploadpicture', { cid: cid }, 0, function(imageUrlOnServer) {
|
||||
inputEl.val(imageUrlOnServer);
|
||||
var previewBox = inputEl.parent().parent().siblings('.category-preview');
|
||||
previewBox.css('background', 'url(' + imageUrlOnServer + '?' + new Date().getTime() + ')')
|
||||
.css('background-size', 'cover');
|
||||
previewBox.css('background', 'url(' + imageUrlOnServer + '?' + new Date().getTime() + ')');
|
||||
modified(inputEl[0]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -92,7 +92,7 @@ app.cacheBuster = null;
|
||||
|
||||
switch(url_parts[0]) {
|
||||
case 'user':
|
||||
room = 'user/' + ajaxify.data ? ajaxify.data.theirid : 0;
|
||||
room = 'user/' + (ajaxify.data ? ajaxify.data.theirid : 0);
|
||||
break;
|
||||
case 'topic':
|
||||
room = 'topic_' + url_parts[1];
|
||||
@@ -503,7 +503,7 @@ app.cacheBuster = null;
|
||||
|
||||
app.load = function() {
|
||||
$('document').ready(function () {
|
||||
var url = ajaxify.start(window.location.pathname.slice(1), true, window.location.search);
|
||||
var url = ajaxify.start(window.location.pathname.slice(1) + window.location.search, true);
|
||||
ajaxify.end(url, app.template);
|
||||
|
||||
handleStatusChange();
|
||||
|
||||
@@ -103,10 +103,10 @@ var async = require('async'),
|
||||
});
|
||||
};
|
||||
|
||||
Categories.getCategoriesByPrivilege = function(uid, privilege, callback) {
|
||||
Categories.getCategoriesByPrivilege = function(set, uid, privilege, callback) {
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
db.getSortedSetRange('categories:cid', 0, -1, next);
|
||||
db.getSortedSetRange(set, 0, -1, next);
|
||||
},
|
||||
function(cids, next) {
|
||||
privileges.categories.filterCids(privilege, cids, uid, next);
|
||||
@@ -273,6 +273,7 @@ var async = require('async'),
|
||||
if (!category) {
|
||||
return;
|
||||
}
|
||||
|
||||
var postCount = parseInt(category.post_count, 10) || 0;
|
||||
var topicCount = parseInt(category.topic_count, 10) || 0;
|
||||
if (!Array.isArray(category.children) || !category.children.length) {
|
||||
@@ -282,9 +283,11 @@ var async = require('async'),
|
||||
}
|
||||
|
||||
category.children.forEach(function(child) {
|
||||
postCount += parseInt(child.post_count, 10) || 0;
|
||||
topicCount += parseInt(child.topic_count, 10) || 0;
|
||||
calculateTopicPostCount(child);
|
||||
postCount += parseInt(child.totalPostCount, 10) || 0;
|
||||
topicCount += parseInt(child.totalTopicCount, 10) || 0;
|
||||
});
|
||||
|
||||
category.totalPostCount = postCount;
|
||||
category.totalTopicCount = topicCount;
|
||||
}
|
||||
@@ -308,22 +311,57 @@ var async = require('async'),
|
||||
};
|
||||
|
||||
Categories.getChildren = function(cids, uid, callback) {
|
||||
var categories = cids.map(function(cid) {
|
||||
return {cid: cid};
|
||||
});
|
||||
|
||||
async.each(categories, function(category, next) {
|
||||
getChildrenRecursive(category, uid, next);
|
||||
}, function (err) {
|
||||
callback(err, categories.map(function(c) {
|
||||
return c && c.children;
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
function getChildrenRecursive(category, uid, callback) {
|
||||
async.waterfall([
|
||||
async.apply(db.getSortedSetRange, 'categories:cid', 0, -1),
|
||||
function(cids, next) {
|
||||
privileges.categories.filterCids('find', cids, uid, next);
|
||||
function (next) {
|
||||
db.getSortedSetRange('cid:' + category.cid + ':children', 0, -1, next);
|
||||
},
|
||||
function (cids, next) {
|
||||
Categories.getCategoriesData(cids, next);
|
||||
function (children, next) {
|
||||
privileges.categories.filterCids('find', children, uid, next);
|
||||
},
|
||||
function (categories, next) {
|
||||
async.map(cids, function(cid, next) {
|
||||
next(null, categories.filter(function(category) {
|
||||
return category && parseInt(category.parentCid, 10) === parseInt(cid, 10);
|
||||
}));
|
||||
function (children, next) {
|
||||
if (!children.length) {
|
||||
category.children = [];
|
||||
return callback();
|
||||
}
|
||||
Categories.getCategoriesData(children, next);
|
||||
},
|
||||
function (childrenData, next) {
|
||||
category.children = childrenData;
|
||||
async.each(category.children, function(child, next) {
|
||||
getChildrenRecursive(child, uid, next);
|
||||
}, next);
|
||||
}
|
||||
], callback);
|
||||
}
|
||||
|
||||
Categories.flattenCategories = function(allCategories, categoryData) {
|
||||
categoryData.forEach(function(category) {
|
||||
if (!category) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!category.parent) {
|
||||
allCategories.push(category);
|
||||
}
|
||||
|
||||
if (Array.isArray(category.children) && category.children.length) {
|
||||
Categories.flattenCategories(allCategories, category.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -335,13 +373,13 @@ var async = require('async'),
|
||||
Categories.getTree = function(categories, parentCid) {
|
||||
var tree = [], i = 0, len = categories.length, category;
|
||||
|
||||
for(i; i < len; ++i) {
|
||||
for (i; i < len; ++i) {
|
||||
category = categories[i];
|
||||
if (!category.hasOwnProperty('parentCid')) {
|
||||
category.parentCid = 0;
|
||||
}
|
||||
|
||||
if(category.parentCid == parentCid){
|
||||
if (category.parentCid == parentCid){
|
||||
tree.push(category);
|
||||
category.children = Categories.getTree(categories, category.cid);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ module.exports = function(Categories) {
|
||||
|
||||
Categories.create = function(data, callback) {
|
||||
var category;
|
||||
var parentCid = data.parentCid ? data.parentCid : 0;
|
||||
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
db.incrObjectField('global', 'nextCid', next);
|
||||
@@ -27,7 +29,7 @@ module.exports = function(Categories) {
|
||||
bgColor: data.bgColor || colours[0],
|
||||
color: data.color || colours[1],
|
||||
slug: slug,
|
||||
parentCid: ( data.parentCid ? data.parentCid : 0 ),
|
||||
parentCid: parentCid,
|
||||
topic_count: 0,
|
||||
post_count: 0,
|
||||
disabled: 0,
|
||||
@@ -48,6 +50,7 @@ module.exports = function(Categories) {
|
||||
async.series([
|
||||
async.apply(db.setObject, 'category:' + category.cid, category),
|
||||
async.apply(db.sortedSetAdd, 'categories:cid', category.order, category.cid),
|
||||
async.apply(db.sortedSetAdd, 'cid:' + parentCid + ':children', category.order, category.cid),
|
||||
async.apply(privileges.categories.give, defaultPrivileges, category.cid, 'administrators'),
|
||||
async.apply(privileges.categories.give, defaultPrivileges, category.cid, 'registered-users'),
|
||||
async.apply(privileges.categories.give, ['find', 'read'], category.cid, 'guests')
|
||||
|
||||
@@ -30,15 +30,32 @@ module.exports = function(Categories) {
|
||||
function(next) {
|
||||
db.sortedSetRemove('categories:cid', cid, next);
|
||||
},
|
||||
function(next) {
|
||||
removeFromParent(cid, next);
|
||||
},
|
||||
function(next) {
|
||||
db.deleteAll([
|
||||
'cid:' + cid + ':tids',
|
||||
'cid:' + cid + ':tids:posts',
|
||||
'cid:' + cid + ':pids',
|
||||
'cid:' + cid + ':read_by_uid',
|
||||
'cid:' + cid + ':children',
|
||||
'category:' + cid
|
||||
], next);
|
||||
}
|
||||
], callback);
|
||||
}
|
||||
|
||||
function removeFromParent(cid, callback) {
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
Categories.getCategoryField(cid, 'parentCid', next);
|
||||
},
|
||||
function(parentCid, next) {
|
||||
parentCid = parseInt(parentCid, 10) || 0;
|
||||
db.sortedSetRemove('cid:' + parentCid + ':children', cid, next);
|
||||
}
|
||||
], callback);
|
||||
|
||||
}
|
||||
};
|
||||
@@ -56,9 +56,10 @@ module.exports = function(Categories) {
|
||||
}
|
||||
},
|
||||
function(posts, next) {
|
||||
categoryData.forEach(function(category) {
|
||||
assignPostsToCategory(category, posts);
|
||||
});
|
||||
assignPostsToCategories(categoryData, posts);
|
||||
|
||||
bubbleUpChildrenPosts(categoryData);
|
||||
|
||||
next();
|
||||
}
|
||||
], callback);
|
||||
@@ -87,13 +88,33 @@ module.exports = function(Categories) {
|
||||
], callback);
|
||||
}
|
||||
|
||||
function assignPostsToCategory(category, posts) {
|
||||
category.posts = posts.filter(function(post) {
|
||||
return post.category && (parseInt(post.category.cid, 10) === parseInt(category.cid, 10) ||
|
||||
parseInt(post.category.parentCid, 10) === parseInt(category.cid, 10));
|
||||
}).sort(function(a, b) {
|
||||
return b.timestamp - a.timestamp;
|
||||
}).slice(0, parseInt(category.numRecentReplies, 10));
|
||||
function bubbleUpChildrenPosts(categoryData) {
|
||||
categoryData.forEach(function(category) {
|
||||
if (category.posts.length) {
|
||||
return;
|
||||
}
|
||||
var latestPost;
|
||||
category.children.forEach(function(children) {
|
||||
if (children.posts.length && (!latestPost || (latestPost && latestPost.timestamp < children.posts[0].timestamp))) {
|
||||
latestPost = children.posts[0];
|
||||
}
|
||||
});
|
||||
|
||||
if (latestPost) {
|
||||
category.posts = [latestPost];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function assignPostsToCategories(categories, posts) {
|
||||
categories.forEach(function(category) {
|
||||
category.posts = posts.filter(function(post) {
|
||||
return post.category && (parseInt(post.category.cid, 10) === parseInt(category.cid, 10) ||
|
||||
parseInt(post.category.parentCid, 10) === parseInt(category.cid, 10));
|
||||
}).sort(function(a, b) {
|
||||
return b.timestamp - a.timestamp;
|
||||
}).slice(0, parseInt(category.numRecentReplies, 10));
|
||||
});
|
||||
}
|
||||
|
||||
function getRecentTopicPids(category, callback) {
|
||||
|
||||
@@ -50,17 +50,63 @@ module.exports = function(Categories) {
|
||||
};
|
||||
|
||||
function updateCategoryField(cid, key, value, callback) {
|
||||
if (key === 'parentCid') {
|
||||
return updateParent(cid, value, callback);
|
||||
}
|
||||
|
||||
db.setObjectField('category:' + cid, key, value, function(err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (key === 'order') {
|
||||
db.sortedSetAdd('categories:cid', value, cid, callback);
|
||||
updateOrder(cid, value, callback);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateParent(cid, newParent, callback) {
|
||||
Categories.getCategoryField(cid, 'parentCid', function(err, oldParent) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
async.series([
|
||||
function (next) {
|
||||
oldParent = parseInt(oldParent, 10) || 0;
|
||||
db.sortedSetRemove('cid:' + oldParent + ':children', cid, next);
|
||||
},
|
||||
function (next) {
|
||||
newParent = parseInt(newParent, 10) || 0;
|
||||
db.sortedSetAdd('cid:' + newParent + ':children', cid, cid, next);
|
||||
},
|
||||
function (next) {
|
||||
db.setObjectField('category:' + cid, 'parentCid', newParent, next);
|
||||
}
|
||||
], function(err, results) {
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function updateOrder(cid, order, callback) {
|
||||
Categories.getCategoryField(cid, 'parentCid', function(err, parentCid) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
async.parallel([
|
||||
function (next) {
|
||||
db.sortedSetAdd('categories:cid', order, cid, next);
|
||||
},
|
||||
function (next) {
|
||||
parentCid = parseInt(parentCid, 10) || 0;
|
||||
db.sortedSetAdd('cid:' + parentCid + ':children', order, cid, next);
|
||||
}
|
||||
], callback);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@ categoriesController.list = function(req, res, next) {
|
||||
content: 'website'
|
||||
}];
|
||||
|
||||
if(meta.config['brand:logo']) {
|
||||
if (meta.config['brand:logo']) {
|
||||
res.locals.metaTags.push({
|
||||
property: 'og:image',
|
||||
content: meta.config['brand:logo']
|
||||
@@ -46,22 +46,13 @@ categoriesController.list = function(req, res, next) {
|
||||
var categoryData;
|
||||
async.waterfall([
|
||||
function(next) {
|
||||
categories.getCategoriesByPrivilege(req.uid, 'find', next);
|
||||
categories.getCategoriesByPrivilege('cid:0:children', req.uid, 'find', next);
|
||||
},
|
||||
function(_categoryData, next) {
|
||||
categoryData = _categoryData;
|
||||
|
||||
var allCategories = [];
|
||||
|
||||
categoryData = categoryData.filter(function(category) {
|
||||
if (!category.parent) {
|
||||
allCategories.push(category);
|
||||
}
|
||||
|
||||
if (Array.isArray(category.children) && category.children.length) {
|
||||
allCategories.push.apply(allCategories, category.children);
|
||||
}
|
||||
return category && !category.parent;
|
||||
});
|
||||
categories.flattenCategories(allCategories, categoryData);
|
||||
|
||||
categories.getRecentTopicReplies(allCategories, req.uid, next);
|
||||
}
|
||||
@@ -200,7 +191,9 @@ categoriesController.get = function(req, res, next) {
|
||||
});
|
||||
},
|
||||
function(categoryData, next) {
|
||||
categories.getRecentTopicReplies(categoryData.children, req.uid, function(err) {
|
||||
var allCategories = [];
|
||||
categories.flattenCategories(allCategories, [categoryData]);
|
||||
categories.getRecentTopicReplies(allCategories, req.uid, function(err) {
|
||||
next(err, categoryData);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -42,9 +42,9 @@ Controllers.home = function(req, res, next) {
|
||||
if (route === 'categories') {
|
||||
Controllers.categories.list(req, res, next);
|
||||
} else if (route === 'recent') {
|
||||
Controllers.categories.recent(req, res, next);
|
||||
Controllers.recent.get(req, res, next);
|
||||
} else if (route === 'popular') {
|
||||
Controllers.categories.popular(req, res, next);
|
||||
Controllers.popular.get(req, res, next);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ searchController.search = function(req, res, next) {
|
||||
|
||||
var breadcrumbs = helpers.buildBreadcrumbs([{text: '[[global:search]]'}]);
|
||||
|
||||
categories.getCategoriesByPrivilege(req.uid, 'read', function(err, categories) {
|
||||
categories.getCategoriesByPrivilege('categories:cid', req.uid, 'read', function(err, categories) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
@@ -157,6 +157,7 @@ usersController.getMap = function(req, res, next) {
|
||||
}
|
||||
data.room = validator.escape(categoryData.name);
|
||||
data.link = '/category/' + categoryData.slug;
|
||||
data.core = false;
|
||||
next(null, data);
|
||||
});
|
||||
} else if (roomName.startsWith('topic_')) {
|
||||
@@ -167,13 +168,18 @@ usersController.getMap = function(req, res, next) {
|
||||
}
|
||||
data.room = validator.escape(topicData.title);
|
||||
data.link = '/topic/' + topicData.slug;
|
||||
data.core = false;
|
||||
next(null, data);
|
||||
});
|
||||
} else {
|
||||
data.core = true;
|
||||
next(null, data);
|
||||
}
|
||||
});
|
||||
}, function(err, data) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
data.sort(function(a, b) {
|
||||
return b.total - a.total;
|
||||
});
|
||||
|
||||
@@ -71,6 +71,7 @@ var fs = require('fs'),
|
||||
Plugins.fireHook('action:email.send', {
|
||||
to: email,
|
||||
from: meta.config['email:from'] || 'no-reply@localhost.lan',
|
||||
from_name: meta.config['email:from_name'] || 'NodeBB',
|
||||
subject: translated[2],
|
||||
html: translated[0],
|
||||
plaintext: translated[1],
|
||||
|
||||
10
src/image.js
10
src/image.js
@@ -18,12 +18,16 @@ image.resizeImage = function(path, extension, width, height, callback) {
|
||||
});
|
||||
} else {
|
||||
lwip.open(path, function(err, image) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
image.batch()
|
||||
.cover(width, height)
|
||||
.crop(width, height)
|
||||
.writeFile(path, function(err) {
|
||||
callback(err)
|
||||
})
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -41,7 +45,7 @@ image.normalise = function(path, extension, callback) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
image.writeFile(path, 'png', callback)
|
||||
image.writeFile(path, 'png', callback);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ module.exports = function(Meta) {
|
||||
var pkgData = JSON.parse(pkgData),
|
||||
ok = semver.satisfies(pkgData.version, pkg.dependencies[module]);
|
||||
|
||||
if (ok) {
|
||||
if (ok || pkgData._resolved.indexOf('//github.com') != -1) {
|
||||
next(true);
|
||||
} else {
|
||||
process.stdout.write('[' + 'outdated'.yellow + '] ' + module.bold + ' v' + pkgData.version + ', requires ' + pkg.dependencies[module] + '\n')
|
||||
@@ -44,4 +44,4 @@ module.exports = function(Meta) {
|
||||
callback(!ok && global.env !== 'development' ? new Error('dependencies-out-of-date') : null);
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -111,7 +111,24 @@ module.exports = function(Meta) {
|
||||
|
||||
Meta.js.minify = function(minify, callback) {
|
||||
if (nconf.get('isPrimary') === 'true') {
|
||||
var minifier = Meta.js.minifierProc = fork('minifier.js'),
|
||||
/**
|
||||
* Check if the parent process is running with the debug option --debug (or --debug-brk)
|
||||
*/
|
||||
var forkProcessParams = {};
|
||||
if(global.v8debug) {
|
||||
/**
|
||||
* use the line below if you want to debug minifier.js script too (or even --debug-brk option, but
|
||||
* you'll have to setup your debugger and connect to the forked process)
|
||||
*/
|
||||
//forkProcessParams = {execArgv: ['--debug=' + (global.process.debugPort + 1), '--nolazy']};
|
||||
|
||||
/**
|
||||
* otherwise, just clean up --debug/--debug-brk options which are set up by default from the parent one
|
||||
*/
|
||||
forkProcessParams = {execArgv: []};
|
||||
}
|
||||
|
||||
var minifier = Meta.js.minifierProc = fork('minifier.js', [], forkProcessParams),
|
||||
onComplete = function(err) {
|
||||
if (err) {
|
||||
winston.error('[meta/js] Minification failed: ' + err.message);
|
||||
|
||||
@@ -186,6 +186,9 @@ middleware.buildHeader = function(req, res, next) {
|
||||
},
|
||||
footer: function(next) {
|
||||
app.render('footer', {loggedIn: (req.user ? parseInt(req.user.uid, 10) !== 0 : false)}, next);
|
||||
},
|
||||
plugins: function(next) {
|
||||
plugins.fireHook('filter:middleware.buildHeader', {req: req, locals: res.locals}, next);
|
||||
}
|
||||
}, function(err, results) {
|
||||
if (err) {
|
||||
@@ -297,12 +300,18 @@ middleware.renderHeader = function(req, res, callback) {
|
||||
templateValues.customCSS = results.customCSS;
|
||||
templateValues.customJS = results.customJS;
|
||||
templateValues.maintenanceHeader = parseInt(meta.config.maintenanceMode, 10) === 1 && !results.isAdmin;
|
||||
templateValues.defaultLang = res.locals.config.defaultLang;
|
||||
templateValues.defaultLang = meta.config.defaultLang || 'en_GB';
|
||||
|
||||
templateValues.template = {name: res.locals.template};
|
||||
templateValues.template[res.locals.template] = true;
|
||||
|
||||
app.render('header', templateValues, callback);
|
||||
plugins.fireHook('filter:middleware.renderHeader', {templateValues: templateValues, req: req, res: res}, function(err, data) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
app.render('header', data.templateValues, callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -520,4 +529,4 @@ module.exports = function(webserver) {
|
||||
middleware.admin = require('./admin')(webserver);
|
||||
|
||||
return middleware;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -417,11 +417,14 @@ function getChildrenCids(cids, uid, callback) {
|
||||
}
|
||||
|
||||
var childrenCids = [];
|
||||
var allCategories = [];
|
||||
|
||||
childrenCategories.forEach(function(childrens) {
|
||||
childrenCids = childrenCids.concat(childrens.map(function(category) {
|
||||
return category && category.cid;
|
||||
}));
|
||||
});
|
||||
categories.flattenCategories(allCategories, childrens);
|
||||
childrenCids = childrenCids.concat(allCategories.map(function(category) {
|
||||
return category && category.cid;
|
||||
}));
|
||||
});
|
||||
|
||||
callback(null, childrenCids);
|
||||
});
|
||||
|
||||
@@ -61,7 +61,7 @@ sitemap.getDynamicUrls = function(callback) {
|
||||
async.parallel({
|
||||
categoryUrls: function(next) {
|
||||
var categoryUrls = [];
|
||||
categories.getCategoriesByPrivilege(0, 'find', function(err, categoriesData) {
|
||||
categories.getCategoriesByPrivilege('categories:cid', 0, 'find', function(err, categoriesData) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ Categories.create = function(socket, data, callback) {
|
||||
|
||||
Categories.getAll = function(socket, data, callback) {
|
||||
async.waterfall([
|
||||
async.apply(db.getSortedSetRangeByScore, 'categories:cid', 0, -1, 0, Date.now()),
|
||||
async.apply(db.getSortedSetRange, 'categories:cid', 0, -1),
|
||||
async.apply(categories.getCategoriesData),
|
||||
function(categories, next) {
|
||||
//Hook changes, there is no req, and res
|
||||
|
||||
@@ -15,7 +15,7 @@ SocketCategories.getRecentReplies = function(socket, cid, callback) {
|
||||
};
|
||||
|
||||
SocketCategories.get = function(socket, data, callback) {
|
||||
categories.getCategoriesByPrivilege(socket.uid, 'find', callback);
|
||||
categories.getCategoriesByPrivilege('categories:cid', socket.uid, 'find', callback);
|
||||
};
|
||||
|
||||
SocketCategories.getWatchedCategories = function(socket, data, callback) {
|
||||
@@ -117,7 +117,7 @@ SocketCategories.getUsersInCategory = function(socket, cid, callback) {
|
||||
};
|
||||
|
||||
SocketCategories.getCategoriesByPrivilege = function(socket, privilege, callback) {
|
||||
categories.getCategoriesByPrivilege(socket.uid, privilege, callback);
|
||||
categories.getCategoriesByPrivilege('categories:cid', socket.uid, privilege, callback);
|
||||
};
|
||||
|
||||
SocketCategories.watch = function(socket, cid, callback) {
|
||||
|
||||
@@ -59,6 +59,10 @@ SocketMeta.rooms.enter = function(socket, data, callback) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
|
||||
if (data.enter) {
|
||||
data.enter = data.enter.toString();
|
||||
}
|
||||
|
||||
if (data.enter && data.enter.startsWith('uid_') && data.enter !== 'uid_' + socket.uid) {
|
||||
return callback(new Error('[[error:not-allowed]]'));
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ var db = require('./database'),
|
||||
schemaDate, thisSchemaDate,
|
||||
|
||||
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema
|
||||
latestSchema = Date.UTC(2015, 6, 3);
|
||||
latestSchema = Date.UTC(2015, 7, 18);
|
||||
|
||||
Upgrade.check = function(callback) {
|
||||
db.get('schemaDate', function(err, value) {
|
||||
@@ -446,6 +446,46 @@ Upgrade.upgrade = function(callback) {
|
||||
winston.info('[2015/07/03] Enabling default composer plugin skipped');
|
||||
next();
|
||||
}
|
||||
},
|
||||
function(next) {
|
||||
thisSchemaDate = Date.UTC(2015, 7, 18);
|
||||
if (schemaDate < thisSchemaDate) {
|
||||
updatesMade = true;
|
||||
winston.info('[2015/08/18] Creating children category sorted sets');
|
||||
|
||||
db.getSortedSetRange('categories:cid', 0, -1, function(err, cids) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
async.each(cids, function(cid, next) {
|
||||
db.getObjectFields('category:' + cid, ['parentCid', 'order'], function(err, category) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (!category) {
|
||||
return next();
|
||||
}
|
||||
if (parseInt(category.parentCid, 10)) {
|
||||
db.sortedSetAdd('cid:' + category.parentCid + ':children', parseInt(category.order, 10), cid, next);
|
||||
} else {
|
||||
db.sortedSetAdd('cid:0:children', parseInt(category.order, 10), cid, next);
|
||||
}
|
||||
});
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
winston.info('[2015/08/18] Creating children category sorted sets done');
|
||||
Upgrade.update(thisSchemaDate, next);
|
||||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
winston.info('[2015/08/18] Creating children category sorted sets skipped');
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
</div>
|
||||
<div class="col-sm-4 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="cid-{category.cid}-imageClass">Image Class</label>
|
||||
<label for="cid-{category.cid}-imageClass">Background Image Size</label>
|
||||
<select id="cid-{category.cid}-imageClass" class="form-control" data-name="imageClass" data-value="{category.imageClass}">
|
||||
<option value="auto">auto</option>
|
||||
<option value="cover">cover</option>
|
||||
@@ -97,8 +97,8 @@
|
||||
<div class="category-preview" style="
|
||||
<!-- IF category.backgroundImage -->background-image: url({category.backgroundImage});<!-- ENDIF category.backgroundImage -->
|
||||
<!-- IF category.bgColor -->background-color: {category.bgColor};<!-- ENDIF category.bgColor -->
|
||||
<!-- IF category.imageClass -->background-size: {category.imageClass};<!-- ENDIF category.imageClass -->
|
||||
color: {category.color};
|
||||
background-size:cover;
|
||||
">
|
||||
<div class="icon">
|
||||
<i data-name="icon" value="{category.icon}" class="fa {category.icon} fa-2x"></i>
|
||||
|
||||
@@ -14,6 +14,13 @@
|
||||
</p>
|
||||
<input type="text" class="form-control input-lg" id="email:from" data-field="email:from" placeholder="info@example.org" /><br />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email:from_name"><strong>From Name</strong></label>
|
||||
<p class="help-block">
|
||||
The from name to display in the email.
|
||||
</p>
|
||||
<input type="text" class="form-control input-lg" id="email:from_name" data-field="email:from_name" placeholder="NodeBB" /><br />
|
||||
</div>
|
||||
<button class="btn btn-block btn-default" type="button" data-action="email.test">Send Test Email</button>
|
||||
<p class="help-block">
|
||||
The test email will be sent to the currently logged in user's email address.
|
||||
|
||||
Reference in New Issue
Block a user