Merge remote-tracking branch 'origin/master' into user-icons

v1.18.x
Julian Lam 10 years ago
commit 97dd5500a1

6
.gitignore vendored

@ -40,4 +40,8 @@ pidfile
## File-based project format:
*.ipr
*.iws
*.iws
## Transifex
tx.exe
.transifexrc

@ -24,7 +24,7 @@
// "single" : require single quotes
// "double" : require double quotes
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
"unused" : false, // true: Require all defined variables be used TODO: Set this to true, update codebase.
"unused" : true, // true: Require all defined variables be used
"strict" : true, // true: Requires all functions run in ES5 Strict Mode
"trailing" : false, // true: Prohibit trailing whitespaces
"maxparams" : false, // {int} Max number of formal params allowed per function

@ -4,7 +4,7 @@ First of all, thank you! Please consider this [style guide](https://docs.nodebb.
## Contributor License Agreement
Thank you for considering contributing to NodeBB. **Before we can accept any pull requests, please take a moment to read and sign our [license agreement](https://www.clahub.com/agreements/NodeBB/NodeBB)**. In summary, signing this document means that 1) you own the code that you are contributing and 2) you give permission to NodeBB Inc. to license the code to others. This agreement applies to any repository under the NodeBB organization.
Thank you for considering contributing to NodeBB. **Before you are able to submit a pull request, please take a moment to read our [contributor license agreement](https://gist.github.com/psychobunny/65946d7aa8854b12fab9)** and agree to it on the pull request page on GitHub. In summary, signing this document means that 1) you own the code that you are contributing and 2) you give permission to NodeBB Inc. to license the code to others. This agreement applies to any repository under the NodeBB organization.
If you are writing contributions as part of employment from another company / individual, then your employer will need to sign a separate agreement. Please [contact us](mailto:accounts@nodebb.org) so that we can send this additional agreement to your employer.

@ -23,14 +23,14 @@
var nconf = require('nconf');
nconf.argv().env('__');
var fs = require('fs'),
url = require('url'),
var url = require('url'),
async = require('async'),
semver = require('semver'),
winston = require('winston'),
colors = require('colors'),
path = require('path'),
pkg = require('./package.json'),
file = require('./src/file'),
utils = require('./public/src/utils.js');
global.env = process.env.NODE_ENV || 'production';
@ -53,7 +53,7 @@ if (nconf.get('config')) {
configFile = path.resolve(__dirname, nconf.get('config'));
}
var configExists = fs.existsSync(configFile);
var configExists = file.existsSync(configFile);
loadConfig();

@ -8,7 +8,7 @@ var nconf = require('nconf'),
async = require('async'),
logrotate = require('logrotate-stream'),
file = require('./src/file'),
pkg = require('./package.json');
nconf.argv().env().file({
@ -243,7 +243,7 @@ Loader.notifyWorkers = function(msg, worker_pid) {
fs.open(path.join(__dirname, 'config.json'), 'r', function(err) {
if (!err) {
if (nconf.get('daemon') !== 'false' && nconf.get('daemon') !== false) {
if (fs.existsSync(pidFilePath)) {
if (file.existsSync(pidFilePath)) {
try {
var pid = fs.readFileSync(pidFilePath, { encoding: 'utf-8' });
process.kill(pid, 0);

@ -4,6 +4,7 @@ var uglifyjs = require('uglify-js'),
less = require('less'),
async = require('async'),
fs = require('fs'),
file = require('./src/file'),
crypto = require('crypto'),
utils = require('./public/src/utils'),
@ -14,16 +15,16 @@ var uglifyjs = require('uglify-js'),
/* Javascript */
Minifier.js.minify = function (scripts, minify, callback) {
scripts = scripts.filter(function(file) {
return fs.existsSync(file) && file.endsWith('.js');
return file && file.endsWith('.js');
});
if (minify) {
minifyScripts(scripts, function() {
callback.apply(this, arguments);
});
} else {
concatenateScripts(scripts, callback);
}
async.filter(scripts, file.exists, function(scripts) {
if (minify) {
minifyScripts(scripts, callback);
} else {
concatenateScripts(scripts, callback);
}
});
};
process.on('message', function(payload) {

@ -48,10 +48,10 @@
"nodebb-plugin-soundpack-default": "0.1.4",
"nodebb-plugin-spam-be-gone": "0.4.2",
"nodebb-rewards-essentials": "0.0.5",
"nodebb-theme-lavender": "2.0.4",
"nodebb-theme-persona": "3.0.23",
"nodebb-theme-vanilla": "4.0.15",
"nodebb-widget-essentials": "2.0.1",
"nodebb-theme-lavender": "2.0.5",
"nodebb-theme-persona": "3.0.29",
"nodebb-theme-vanilla": "4.0.17",
"nodebb-widget-essentials": "2.0.2",
"npm": "^2.1.4",
"passport": "^0.3.0",
"passport-local": "1.0.0",

@ -29,7 +29,7 @@
"flag": "Flag",
"locked": "Locked",
"bookmark_instructions" : "Click here to return to your last position or close to discard.",
"bookmark_instructions" : "Click here to return to the last unread post in this thread.",
"flag_title": "Flag this post for moderation",
"flag_confirm": "Are you sure you want to flag this post?",

@ -54,6 +54,7 @@
"confirm_password": "Confirm Password",
"password": "Password",
"username_taken_workaround": "The username you requested was already taken, so we have altered it slightly. You are now known as <strong>%1</strong>",
"password_same_as_username": "Your password is the same as your username, please select another password.",
"upload_picture": "Upload picture",
"upload_a_picture": "Upload a picture",

@ -25,7 +25,7 @@
"tools": "Tools",
"flag": "Flag",
"locked": "Locked",
"bookmark_instructions": "Click here to return to your last position or close to discard.",
"bookmark_instructions" : "Click here to return to the last unread post in this thread.",
"flag_title": "Flag this post for moderation",
"flag_confirm": "Are you sure you want to flag this post?",
"flag_success": "This post has been flagged for moderation.",

@ -82,4 +82,11 @@ div.categories {
.description {
margin: 0;
}
.children-placeholder{
border: 1px dashed #ddd;
min-height: 20px;
height: 20px;
}
}

@ -94,19 +94,18 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri
}
};
Categories.toggle = function(cid, state) {
Categories.toggle = function(cid, disabled) {
var payload = {};
payload[cid] = {
disabled: !state | 0
disabled: disabled ? 1 : 0
};
socket.emit('admin.categories.update', payload, function(err, result) {
if (err) {
return app.alertError(err.message);
} else {
ajaxify.refresh();
}
ajaxify.refresh();
});
};
@ -114,8 +113,9 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri
newCategoryId = e.to.dataset.cid;
}
function itemDragDidEnd(e){
function itemDragDidEnd(e) {
var isCategoryUpdate = (newCategoryId != -1);
//Update needed?
if((e.newIndex != undefined && e.oldIndex != e.newIndex) || isCategoryUpdate){
var parentCategory = isCategoryUpdate ? sortables[newCategoryId] : sortables[e.from.dataset.cid],
@ -153,9 +153,7 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri
// Handle and children categories in this level have
for(var x=0,numCategories=categories.length;x<numCategories;x++) {
if (categories[x].hasOwnProperty('children') && categories[x].children.length > 0) {
renderList(categories[x].children, $('li[data-cid="' + categories[x].cid + '"]'), categories[x].cid);
}
renderList(categories[x].children, $('li[data-cid="' + categories[x].cid + '"]'), categories[x].cid);
}
// Make list sortable

@ -307,6 +307,9 @@ $(document).ready(function() {
}
app.load();
templates.cache['500'] = $('.tpl-500').html();
$('[data-template]').each(function() {
templates.cache[$(this).attr('data-template')] = $(this).html();
});
});

@ -176,6 +176,8 @@ define('forum/register', ['csrf', 'translator'], function(csrf, translator) {
showError(password_notify, '[[user:change_password_error_length]]');
} else if (!utils.isPasswordValid(password)) {
showError(password_notify, '[[user:change_password_error]]');
} else if (password === $('#username').val()) {
showError(password_notify, '[[user:password_same_as_username]]');
} else {
showSuccess(password_notify, successIcon);
}

@ -57,11 +57,13 @@ define('forum/topic', [
addBlockQuoteHandler();
addParentHandler();
handleBookmark(tid);
handleKeys();
navigator.init('[component="post"]', ajaxify.data.postcount, Topic.toTop, Topic.toBottom, Topic.navigatorCallback, Topic.calculateIndex);
navigator.init('[component="post/anchor"]', ajaxify.data.postcount, Topic.toTop, Topic.toBottom, Topic.navigatorCallback, Topic.calculateIndex);
$(window).on('scroll', updateTopicTitle);
@ -191,6 +193,26 @@ define('forum/topic', [
});
}
function addParentHandler() {
components.get('topic').on('click', '[component="post/parent"]', function() {
var toPid = $(this).attr('data-topid');
var toPost = $('[component="post"][data-pid="' + toPid + '"]');
if (toPost.length) {
return navigator.scrollToPost(toPost.attr('data-index'), true);
}
socket.emit('posts.getPidIndex', {pid: toPid, tid: ajaxify.data.tid, topicPostSort: config.topicPostSort}, function(err, index) {
if (err) {
return app.alertError(err.message);
}
if (utils.isNumber(index)) {
navigator.scrollToPost(index, true);
}
});
});
}
function enableInfiniteLoadingOrPagination() {
if (!config.usePagination) {
@ -219,43 +241,30 @@ define('forum/topic', [
return index;
};
Topic.navigatorCallback = function(topPostIndex, bottomPostIndex, elementCount) {
Topic.navigatorCallback = function(index, elementCount) {
var path = ajaxify.removeRelativePath(window.location.pathname.slice(1));
if (!path.startsWith('topic')) {
return 1;
}
var postIndex = topPostIndex;
var index = bottomPostIndex;
if (config.topicPostSort !== 'oldest_to_newest') {
if (bottomPostIndex === 0) {
index = 1;
} else {
index = Math.max(elementCount - bottomPostIndex + 2, 1);
}
}
var bookmarkKey = 'topic:' + ajaxify.data.tid + ':bookmark';
var currentBookmark = ajaxify.data.bookmark || localStorage.getItem(bookmarkKey);
if (!currentBookmark || parseInt(postIndex, 10) > parseInt(currentBookmark, 10)) {
if (!currentBookmark || parseInt(index, 10) > parseInt(currentBookmark, 10)) {
if (app.user.uid) {
var payload = {
socket.emit('topics.bookmark', {
'tid': ajaxify.data.tid,
'index': postIndex
};
socket.emit('topics.bookmark', payload, function(err) {
if (err) {
console.warn('Error saving bookmark:', err);
}
ajaxify.data.bookmark = postIndex;
'index': index
}, function(err) {
ajaxify.data.bookmark = index;
});
} else {
localStorage.setItem(bookmarkKey, postIndex);
localStorage.setItem(bookmarkKey, index);
}
}
// removes the bookmark alert when we get to / past the bookmark
if (!currentBookmark || parseInt(postIndex, 10) >= parseInt(currentBookmark, 10)) {
if (!currentBookmark || parseInt(index, 10) >= parseInt(currentBookmark, 10)) {
app.removeAlert('bookmark');
}
@ -264,14 +273,15 @@ define('forum/topic', [
var topicId = parts[1],
slug = parts[2];
var newUrl = 'topic/' + topicId + '/' + (slug ? slug : '');
if (postIndex > 1) {
newUrl += '/' + postIndex;
if (index > 1) {
newUrl += '/' + index;
}
if (newUrl !== currentUrl) {
if (Topic.replaceURLTimeout) {
clearTimeout(Topic.replaceURLTimeout);
}
Topic.replaceURLTimeout = setTimeout(function() {
Topic.replaceURLTimeout = 0;
if (history.replaceState) {
@ -284,7 +294,6 @@ define('forum/topic', [
}, 500);
}
}
return index;
};

@ -13,15 +13,20 @@ define('forum/topic/posts', [
var Posts = {};
Posts.onNewPost = function(data) {
var tid = ajaxify.data.tid;
if (data && data.posts && data.posts.length && parseInt(data.posts[0].tid, 10) !== parseInt(tid, 10)) {
if (!data || !data.posts || !data.posts.length) {
return;
}
if (!data || !data.posts || !data.posts.length) {
if (parseInt(data.posts[0].tid, 10) !== parseInt(ajaxify.data.tid, 10)) {
return;
}
data.posts.forEach(function(post) {
post.selfPost = !!app.user.uid && parseInt(post.uid, 10) === parseInt(app.user.uid, 10);
post.display_moderator_tools = post.selfPost || ajaxify.data.isAdminOrMod;
post.display_move_tools = ajaxify.data.isAdminOrMod;
});
updatePostCounts(data.posts);
if (config.usePagination) {
@ -152,56 +157,16 @@ define('forum/topic/posts', [
components.get('topic').append(html);
}
infinitescroll.removeExtra(components.get('posts'), direction, 40);
infinitescroll.removeExtra(components.get('post'), direction, 40);
html.hide().fadeIn('slow');
$(window).trigger('action:posts.loaded', {posts: data.posts});
var pids = [];
for(var i=0; i<data.posts.length; ++i) {
pids.push(data.posts[i].pid);
}
Posts.processPage(html);
$(window).trigger('action:posts.loaded', {posts: data.posts});
onNewPostsLoaded(html, pids);
callback(html);
});
}
function onNewPostsLoaded(html, pids) {
if (app.user.uid) {
socket.emit('posts.getPrivileges', pids, function(err, privileges) {
if(err) {
return app.alertError(err.message);
}
for(var i=0; i<pids.length; ++i) {
toggleModTools(pids[i], privileges[i]);
}
});
} else {
for(var i=0; i<pids.length; ++i) {
toggleModTools(pids[i], {editable: false, move: false});
}
}
Posts.processPage(html);
}
function toggleModTools(pid, privileges) {
var postEl = components.get('post', 'pid', pid),
isSelfPost = parseInt(postEl.attr('data-uid'), 10) === parseInt(app.user.uid, 10);
if (!privileges.editable) {
postEl.find('[component="post/edit"], [component="post/delete"], [component="post/purge"]').remove();
}
if (!privileges.move) {
postEl.find('[component="post/move"]').remove();
}
postEl.find('[component="user/chat"], [component="post/flag"]').toggleClass('hidden', isSelfPost || !app.user.uid);
}
Posts.loadMorePosts = function(direction) {
if (!components.get('topic').length || navigator.scrollActive) {
return;

@ -90,30 +90,22 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com
navigator.update = function() {
toggle(!!count);
var topIndex = 0;
var bottomIndex = 0;
$(navigator.selector).each(function() {
var el = $(this);
var middleOfViewport = $(window).scrollTop() + $(window).height() / 2;
index = parseInt($(navigator.selector).first().attr('data-index'), 10);
if (elementInView(el)) {
if (!topIndex) {
topIndex = parseInt(el.attr('data-index'), 10) + 1;
} else {
bottomIndex = parseInt(el.attr('data-index'), 10) + 1;
}
} else if (topIndex && bottomIndex) {
$(navigator.selector).each(function() {
index++;
if ($(this).offset().top > middleOfViewport) {
return false;
}
});
if (topIndex && !bottomIndex) {
bottomIndex = topIndex;
if (typeof navigator.callback === 'function') {
navigator.callback(index, count);
}
if (typeof navigator.callback === 'function' && topIndex && bottomIndex) {
index = navigator.callback(topIndex, bottomIndex, count);
navigator.updateTextAndProgressBar();
}
navigator.updateTextAndProgressBar();
};
navigator.updateTextAndProgressBar = function() {
@ -155,27 +147,16 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com
}
};
function elementInView(el) {
var scrollTop = $(window).scrollTop() + $('#header-menu').height();
var scrollBottom = scrollTop + $(window).height();
var elTop = el.offset().top;
var elBottom = elTop + Math.floor(el.height());
return (elTop >= scrollTop && elBottom < scrollBottom) || (elTop < scrollTop && elBottom > scrollTop);
}
navigator.scrollToPost = function(postIndex, highlight, duration, offset) {
navigator.scrollToPost = function(postIndex, highlight, duration) {
if (!utils.isNumber(postIndex) || !components.get('topic').length) {
return;
}
offset = offset || 0;
duration = duration !== undefined ? duration : 400;
navigator.scrollActive = true;
if (components.get('post/anchor', postIndex).length) {
return navigator.scrollToPostIndex(postIndex, highlight, duration, offset);
return navigator.scrollToPostIndex(postIndex, highlight, duration);
}
if (config.usePagination) {
@ -183,10 +164,10 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com
if (parseInt(page, 10) !== pagination.currentPage) {
pagination.loadPage(page, function() {
navigator.scrollToPostIndex(postIndex, highlight, duration, offset);
navigator.scrollToPostIndex(postIndex, highlight, duration);
});
} else {
navigator.scrollToPostIndex(postIndex, highlight, duration, offset);
navigator.scrollToPostIndex(postIndex, highlight, duration);
}
} else {
navigator.scrollActive = false;
@ -195,19 +176,20 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com
}
};
navigator.scrollToPostIndex = function(postIndex, highlight, duration, offset) {
navigator.scrollToPostIndex = function(postIndex, highlight, duration) {
var scrollTo = components.get('post/anchor', postIndex);
if (!scrollTo.length) {
navigator.scrollActive = false;
return;
}
offset = offset || 0;
duration = duration !== undefined ? duration : 400;
navigator.scrollActive = true;
var done = false;
function animateScroll() {
var scrollTop = (scrollTo.offset().top - ($(window).height() / 2) - offset) + 'px';
var scrollTop = (scrollTo.offset().top - ($(window).height() / 2)) + 'px';
$('html, body').animate({
scrollTop: scrollTop

@ -264,11 +264,12 @@
var fs = require('fs'),
path = require('path'),
winston = require('winston'),
file = require('../../../src/file'),
meta = require('../../../src/meta');
language = language || meta.config.defaultLang || 'en_GB';
if (!fs.existsSync(path.join(__dirname, '../../language', language))) {
if (!file.existsSync(path.join(__dirname, '../../language', language))) {
winston.warn('[translator] Language \'' + meta.config.defaultLang + '\' not found. Defaulting to \'en_GB\'');
language = 'en_GB';
}

@ -10,44 +10,51 @@ module.exports = function(Categories) {
Categories.update = function(modified, callback) {
function updateCategory(cid, next) {
Categories.exists(cid, function(err, exists) {
if (err || !exists) {
return next(err);
}
var cids = Object.keys(modified);
async.each(cids, function(cid, next) {
updateCategory(cid, modified[cid], next);
}, function(err) {
callback(err, cids);
});
};
var modifiedFields = modified[cid];
function updateCategory(cid, modifiedFields, callback) {
Categories.exists(cid, function(err, exists) {
if (err || !exists) {
return callback(err);
}
if (modifiedFields.hasOwnProperty('name')) {
modifiedFields.slug = cid + '/' + utils.slugify(modifiedFields.name);
}
if (modifiedFields.hasOwnProperty('name')) {
modifiedFields.slug = cid + '/' + utils.slugify(modifiedFields.name);
plugins.fireHook('filter:category.update', {category: modifiedFields}, function(err, categoryData) {
if (err) {
return callback(err);
}
plugins.fireHook('filter:category.update', {category: modifiedFields}, function(err, categoryData) {
var category = categoryData.category;
var fields = Object.keys(category);
// move parent to front, so its updated first
var parentCidIndex = fields.indexOf('parentCid');
if (parentCidIndex !== -1 && fields.length > 1) {
fields.splice(0, 0, fields.splice(parentCidIndex, 1)[0]);
}
async.eachSeries(fields, function(key, next) {
updateCategoryField(cid, key, category[key], next);
}, function(err) {
if (err) {
return next(err);
return callback(err);
}
var category = categoryData.category;
var fields = Object.keys(category);
async.each(fields, function(key, next) {
updateCategoryField(cid, key, category[key], next);
}, function(err) {
if (err) {
return next(err);
}
plugins.fireHook('action:category.update', {cid: cid, modified: category});
next();
});
plugins.fireHook('action:category.update', {cid: cid, modified: category});
callback();
});
});
}
var cids = Object.keys(modified);
async.each(cids, updateCategory, function(err) {
callback(err, cids);
});
};
}
function updateCategoryField(cid, key, value, callback) {
if (key === 'parentCid') {

@ -1,24 +1,24 @@
'use strict';
var path = require('path');
var fs = require('fs');
var file = require('../../file');
var themesController = {};
themesController.get = function(req, res, next) {
var themeDir = path.join(__dirname, '../../../node_modules/' + req.params.theme);
fs.exists(themeDir, function(exists) {
if (exists) {
var themeConfig = require(path.join(themeDir, 'theme.json')),
screenshotPath = path.join(themeDir, themeConfig.screenshot);
if (themeConfig.screenshot && fs.existsSync(screenshotPath)) {
res.sendFile(screenshotPath);
} else {
res.sendFile(path.join(__dirname, '../../../public/images/themes/default.png'));
}
} else {
file.exists(themeDir, function(exists) {
if (!exists) {
return next();
}
var themeConfig = require(path.join(themeDir, 'theme.json')),
screenshotPath = path.join(themeDir, themeConfig.screenshot);
if (themeConfig.screenshot && file.existsSync(screenshotPath)) {
res.sendFile(screenshotPath);
} else {
res.sendFile(path.join(__dirname, '../../../public/images/themes/default.png'));
}
});
};

@ -253,9 +253,10 @@ categoriesController.get = function(req, res, callback) {
data.pageCount = pageCount;
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
data.rssFeedUrl = nconf.get('relative_path') + '/category/' + data.cid + '.rss';
data.pagination = pagination.create(data.currentPage, data.pageCount);
data.title = data.name;
data.pagination = pagination.create(data.currentPage, data.pageCount);
data.pagination.rel.forEach(function(rel) {
rel.href = nconf.get('url') + '/category/' + data.slug + rel.href;
res.locals.linkTags.push(rel);
});

@ -263,6 +263,7 @@ topicsController.get = function(req, res, callback) {
data.rssFeedUrl = nconf.get('relative_path') + '/topic/' + data.tid + '.rss';
data.pagination = pagination.create(data.currentPage, data.pageCount);
data.pagination.rel.forEach(function(rel) {
rel.href = nconf.get('url') + '/topic/' + data.slug + rel.href;
res.locals.linkTags.push(rel);
});

@ -68,7 +68,7 @@ module.exports = function(db, module) {
return callback(err, null);
}
callback(null, item[field] || null);
callback(null, item.hasOwnProperty(field) ? item[field] : null);
});
};

@ -8,7 +8,6 @@ var fs = require('fs'),
Magic = mmmagic.Magic,
mime = require('mime'),
meta = require('./meta'),
utils = require('../public/src/utils');
var file = {};
@ -63,6 +62,7 @@ file.isFileTypeAllowed = function(path, allowedExtensions, callback) {
};
file.allowedExtensions = function() {
var meta = require('./meta');
var allowedExtensions = (meta.config.allowedFileExtensions || '').trim();
if (!allowedExtensions) {
return [];
@ -80,4 +80,21 @@ file.allowedExtensions = function() {
return allowedExtensions;
};
file.exists = function(path, callback) {
fs.stat(path, function(err, stat) {
callback(!err && stat);
});
};
file.existsSync = function(path) {
var exists = false;
try {
exists = fs.statSync(path);
} catch(err) {
exists = false;
}
return !!exists;
};
module.exports = file;

@ -10,6 +10,7 @@ var fs = require('fs'),
winston = require('winston'),
util = require('util'),
socketio = require('socket.io'),
file = require('./file'),
meta = require('./meta'),
morgan = require('morgan');
@ -76,7 +77,7 @@ var opts = {
/* Open the streams to log to: either a path or stdout */
var stream;
if(value) {
if(fs.existsSync(value)) {
if(file.existsSync(value)) {
var stats = fs.statSync(value);
if(stats) {
if(stats.isDirectory()) {

@ -11,6 +11,7 @@ var winston = require('winston'),
plugins = require('../plugins'),
emitter = require('../emitter'),
db = require('../database'),
file = require('../file'),
utils = require('../../public/src/utils');
module.exports = function(Meta) {
@ -149,24 +150,25 @@ module.exports = function(Meta) {
Meta.css.getFromFile = function(callback) {
var cachePath = path.join(__dirname, '../../public/stylesheet.css'),
acpCachePath = path.join(__dirname, '../../public/admin.css');
fs.exists(cachePath, function(exists) {
if (exists) {
if (nconf.get('isPrimary') === 'true') {
winston.verbose('[meta/css] Reading stylesheets from file');
async.map([cachePath, acpCachePath], fs.readFile, function(err, files) {
Meta.css.cache = files[0];
Meta.css.acpCache = files[1];
emitter.emit('meta:css.compiled');
callback();
});
} else {
callback();
}
} else {
file.exists(cachePath, function(exists) {
if (!exists) {
winston.warn('[meta/css] No stylesheets found on disk, re-minifying');
Meta.css.minify.apply(Meta.css, arguments);
Meta.css.minify(callback);
return;
}
if (nconf.get('isPrimary') !== 'true') {
return callback();
}
winston.verbose('[meta/css] Reading stylesheets from file');
async.map([cachePath, acpCachePath], fs.readFile, function(err, files) {
Meta.css.cache = files[0];
Meta.css.acpCache = files[1];
emitter.emit('meta:css.compiled');
callback();
});
});
};
@ -197,10 +199,10 @@ module.exports = function(Meta) {
}
function filterMissingFiles(files) {
return files.filter(function(file) {
var exists = fs.existsSync(path.join(__dirname, '../../node_modules', file));
return files.filter(function(filePath) {
var exists = file.existsSync(path.join(__dirname, '../../node_modules', filePath));
if (!exists) {
winston.warn('[meta/css] File not found! ' + file);
winston.warn('[meta/css] File not found! ' + filePath);
}
return exists;
});

@ -8,7 +8,7 @@ var winston = require('winston'),
os = require('os'),
nconf = require('nconf'),
fs = require('fs'),
file = require('../file'),
plugins = require('../plugins'),
emitter = require('../emitter'),
utils = require('../../public/src/utils');
@ -208,30 +208,31 @@ module.exports = function(Meta) {
var scriptPath = path.join(__dirname, '../../public/nodebb.min.js'),
mapPath = path.join(__dirname, '../../public/nodebb.min.js.map'),
paths = [scriptPath];
fs.exists(scriptPath, function(exists) {
if (exists) {
if (nconf.get('isPrimary') === 'true') {
fs.exists(mapPath, function(exists) {
if (exists) {
paths.push(mapPath);
}
file.exists(scriptPath, function(exists) {
if (!exists) {
winston.warn('[meta/js] No script file found on disk, re-minifying');
Meta.js.minify(minify, callback);
return;
}
winston.verbose('[meta/js] Reading client-side scripts from file');
async.map(paths, fs.readFile, function(err, files) {
Meta.js.cache = files[0];
Meta.js.map = files[1] || '';
if (nconf.get('isPrimary') !== 'true') {
return callback();
}
emitter.emit('meta:js.compiled');
callback();
});
});
} else {
callback();
file.exists(mapPath, function(exists) {
if (exists) {
paths.push(mapPath);
}
} else {
winston.warn('[meta/js] No script file found on disk, re-minifying');
Meta.js.minify.apply(Meta.js, arguments);
}
winston.verbose('[meta/js] Reading client-side scripts from file');
async.map(paths, fs.readFile, function(err, files) {
Meta.js.cache = files[0];
Meta.js.map = files[1] || '';
emitter.emit('meta:js.compiled');
callback();
});
});
});
};

@ -6,6 +6,8 @@ var nconf = require('nconf'),
fs = require('fs'),
path = require('path'),
async = require('async'),
file = require('../file'),
db = require('../database');
module.exports = function(Meta) {
@ -34,27 +36,24 @@ module.exports = function(Meta) {
async.map(themes, function (theme, next) {
var config = path.join(themePath, theme, 'theme.json');
if (fs.existsSync(config)) {
fs.readFile(config, function (err, file) {
if (err) {
return next();
} else {
var configObj = JSON.parse(file.toString());
// Minor adjustments for API output
configObj.type = 'local';
if (configObj.screenshot) {
configObj.screenshot_url = nconf.get('relative_path') + '/css/previews/' + configObj.id;
} else {
configObj.screenshot_url = nconf.get('relative_path') + '/images/themes/default.png';
}
next(err, configObj);
}
});
} else {
next();
}
fs.readFile(config, function (err, file) {
if (err) {
return next();
}
var configObj = JSON.parse(file.toString());
// Minor adjustments for API output
configObj.type = 'local';
if (configObj.screenshot) {
configObj.screenshot_url = nconf.get('relative_path') + '/css/previews/' + configObj.id;
} else {
configObj.screenshot_url = nconf.get('relative_path') + '/images/themes/default.png';
}
next(null, configObj);
});
}, function (err, themes) {
themes = themes.filter(function (theme) {
return (theme !== undefined);
@ -145,7 +144,7 @@ module.exports = function(Meta) {
if (themeObj.templates) {
themePath = path.join(nconf.get('themes_path'), themeObj.id, themeObj.templates);
} else if (fs.existsSync(fallback)) {
} else if (file.existsSync(fallback)) {
themePath = fallback;
}

@ -2,6 +2,7 @@
var meta = require('../meta'),
db = require('../database'),
file = require('../file'),
auth = require('../routes/authentication'),
path = require('path'),
@ -21,7 +22,7 @@ var middleware = {};
function setupFavicon(app) {
var faviconPath = path.join(__dirname, '../../', 'public', meta.config['brand:favicon'] ? meta.config['brand:favicon'] : 'favicon.ico');
if (fs.existsSync(faviconPath)) {
if (file.existsSync(faviconPath)) {
app.use(nconf.get('relative_path'), favicon(faviconPath));
}
}

@ -14,6 +14,7 @@ var fs = require('fs'),
translator = require('../public/src/modules/translator'),
utils = require('../public/src/utils'),
hotswap = require('./hotswap'),
file = require('./file'),
controllers = require('./controllers'),
app, middleware;
@ -103,7 +104,7 @@ var fs = require('fs'),
return path.join(__dirname, '../node_modules/', plugin);
});
async.filter(plugins, fs.exists, function(plugins){
async.filter(plugins, file.exists, function(plugins) {
async.eachSeries(plugins, Plugins.loadPlugin, next);
});
},

@ -6,6 +6,7 @@ var fs = require('fs'),
async = require('async'),
winston = require('winston'),
nconf = require('nconf'),
file = require('../file'),
utils = require('../../public/src/utils');
@ -107,7 +108,7 @@ module.exports = function(Plugins) {
var realPath = pluginData.staticDirs[mappedPath];
var staticDir = path.join(pluginPath, realPath);
fs.exists(staticDir, function(exists) {
file.exists(staticDir, function(exists) {
if (exists) {
Plugins.staticDirs[pluginData.id + '/' + mappedPath] = staticDir;
} else {

@ -51,6 +51,7 @@ module.exports = function(privileges) {
editable: editable,
deletable: deletable,
view_deleted: isAdminOrMod || results.isOwner,
isAdminOrMod: isAdminOrMod,
disabled: disabled,
tid: tid,
uid: uid

@ -22,31 +22,18 @@ module.exports = function(app, middleware, controllers) {
} else {
return null;
}
}).filter(function(a) { return a; });
}).filter(Boolean);
if (matches) {
async.map(matches, function(mappedPath, next) {
var filePath = path.join(plugins.staticDirs[mappedPath], decodeURIComponent(relPath.slice(mappedPath.length)));
if (!matches) {
return next();
}
fs.exists(filePath, function(exists) {
if (exists) {
next(null, filePath);
} else {
next();
}
});
}, function(err, matches) {
if (err) {
return next(err);
}
matches = matches.filter(Boolean);
matches = matches.map(function(mappedPath) {
return path.join(plugins.staticDirs[mappedPath], decodeURIComponent(relPath.slice(mappedPath.length)));
});
if (matches.length) {
res.sendFile(matches[0]);
} else {
next();
}
});
if (matches.length) {
res.sendFile(matches[0]);
} else {
next();
}

@ -145,21 +145,6 @@ SocketPosts.getRawPost = function(socket, pid, callback) {
], callback);
};
SocketPosts.getPrivileges = function(socket, pids, callback) {
privileges.posts.get(pids, socket.uid, function(err, privileges) {
if (err) {
return callback(err);
}
if (!Array.isArray(privileges) || !privileges.length) {
return callback(new Error('[[error:invalid-data]]'));
}
callback(null, privileges);
});
};
SocketPosts.loadMoreFavourites = function(socket, data, callback) {
loadMorePosts('uid:' + data.uid + ':favourites', socket.uid, data, callback);
};

@ -283,6 +283,9 @@ module.exports = function(Topics) {
topicInfo: function(next) {
Topics.getTopicFields(tid, ['tid', 'title', 'slug', 'cid', 'postcount'], next);
},
parents: function(next) {
Topics.addParentPosts([postData], next);
},
content: function(next) {
posts.parsePost(postData, next);
}

@ -112,6 +112,9 @@ module.exports = function(Topics) {
},
privileges: function(next) {
privileges.posts.get(pids, uid, next);
},
parents: function(next) {
Topics.addParentPosts(postData, next);
}
}, function(err, results) {
if (err) {
@ -129,9 +132,9 @@ module.exports = function(Topics) {
postObj.votes = postObj.votes || 0;
postObj.display_moderator_tools = results.privileges[i].editable;
postObj.display_move_tools = results.privileges[i].move && postObj.index !== 0;
postObj.selfPost = parseInt(uid, 10) === parseInt(postObj.uid, 10);
postObj.selfPost = !!parseInt(uid, 10) && parseInt(uid, 10) === parseInt(postObj.uid, 10);
if(postObj.deleted && !results.privileges[i].view_deleted) {
if (postObj.deleted && !results.privileges[i].view_deleted) {
postObj.content = '[[topic:post_is_deleted]]';
}
@ -146,6 +149,44 @@ module.exports = function(Topics) {
});
};
Topics.addParentPosts = function(postData, callback) {
var parentPids = postData.map(function(postObj) {
return postObj && postObj.hasOwnProperty('toPid') ? parseInt(postObj.toPid, 10) : null;
}).filter(Boolean);
if (!parentPids.length) {
return callback();
}
var parentPosts;
async.waterfall([
async.apply(posts.getPostsFields, parentPids, ['uid']),
function(_parentPosts, next) {
parentPosts = _parentPosts;
var parentUids = parentPosts.map(function(postObj) { return parseInt(postObj.uid, 10); }).filter(function(uid, idx, users) {
return users.indexOf(uid) === idx;
});
user.getUsersFields(parentUids, ['username'], next);
},
function (userData, next) {
var usersMap = {};
userData.forEach(function(user) {
usersMap[user.uid] = user.username;
});
var parents = {};
parentPosts.forEach(function(post, i) {
parents[parentPids[i]] = {username: usersMap[post.uid]};
});
postData.forEach(function(post) {
post.parent = parents[post.toPid];
});
next();
}
], callback);
};
Topics.calculatePostIndices = function(posts, start, stop, postCount, reverse) {
posts.forEach(function(post, index) {
if (reverse) {

@ -1,3 +1,4 @@
<script type="text/tpl" data-template="500">
<div class="alert alert-danger">
<strong>[[global:500.title]]</strong>
<p>[[global:500.message]]</p>
@ -5,3 +6,4 @@
<!-- IF error --><p>{error}</p><!-- ENDIF error -->
</div>
</script>

@ -26,4 +26,7 @@
</div>
</li>
<!-- END categories -->
<li class="children-placeholder"></li>
</ul>

@ -186,9 +186,10 @@ module.exports.testSocket = function(socketPath, callback) {
return callback(new Error('invalid socket path : ' + socketPath));
}
var net = require('net');
var file = require('./file');
async.series([
function(next) {
fs.exists(socketPath, function(exists) {
file.exists(socketPath, function(exists) {
if (exists) {
next();
} else {

Loading…
Cancel
Save