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

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

@ -38,8 +38,8 @@
"prompt": "~0.2.11", "prompt": "~0.2.11",
"uglify-js": "~2.4.0", "uglify-js": "~2.4.0",
"validator": "~1.5.1", "validator": "~1.5.1",
"nodebb-plugin-mentions": "~0.1.16", "nodebb-plugin-mentions": "~0.1",
"nodebb-plugin-markdown": "~0.2.1", "nodebb-plugin-markdown": "~0.3",
"nodebb-theme-vanilla": "~0.0.12", "nodebb-theme-vanilla": "~0.0.12",
"nodebb-theme-cerulean": "0.0.10", "nodebb-theme-cerulean": "0.0.10",
"cron": "~1.0.1", "cron": "~1.0.1",

@ -94,9 +94,8 @@ define(['taskbar'], function(taskbar) {
var postContainer = $(composerTemplate[0]); var postContainer = $(composerTemplate[0]);
if(config.imgurClientIDSet) { if(config.allowFileUploads || config.imgurClientIDSet)
initializeFileReader(post_uuid); initializeFileReader(post_uuid);
}
var postData = composer.posts[post_uuid], var postData = composer.posts[post_uuid],
titleEl = postContainer.find('.title'), titleEl = postContainer.find('.title'),

@ -123,7 +123,7 @@
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" data-field="disableSocialButtons"> <strong>Disable social buttons on posts</strong> <input type="checkbox" data-field="disableSocialButtons"> <strong>Disable social buttons</strong>
</label> </label>
</div> </div>
<div class="checkbox"> <div class="checkbox">

@ -10,12 +10,13 @@
<div> <div>
<button id="new_post" class="btn btn-primary {show_topic_button}">[[category:new_topic_button]]</button> <button id="new_post" class="btn btn-primary {show_topic_button}">[[category:new_topic_button]]</button>
<!-- IF !disableSocialButtons -->
<div class="inline-block pull-right"> <div class="inline-block pull-right">
<a href="#" id="facebook-share"><i class="fa fa-facebook-square fa-2x"></i></a>&nbsp; <a href="#" id="facebook-share"><i class="fa fa-facebook-square fa-2x"></i></a>&nbsp;
<a href="#" id="twitter-intent"><i class="fa fa-twitter-square fa-2x"></i></a>&nbsp; <a href="#" id="twitter-intent"><i class="fa fa-twitter-square fa-2x"></i></a>&nbsp;
<a href="#" id="google-share"><i class="fa fa-google-plus-square fa-2x"></i></a>&nbsp; <a href="#" id="google-share"><i class="fa fa-google-plus-square fa-2x"></i></a>&nbsp;
</div> </div>
<!-- ENDIF !disableSocialButtons -->
</div> </div>
<hr/> <hr/>

@ -80,6 +80,7 @@ var db = require('./database.js'),
'category_id': category_id, 'category_id': category_id,
'active_users': [], 'active_users': [],
'topics': [], 'topics': [],
'disableSocialButtons': meta.config.disableSocialButtons !== undefined ? parseInt(meta.config.disableSocialButtons, 10) !== 0 : false,
'twitter-intent-url': 'https://twitter.com/intent/tweet?url=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug) + '&text=' + encodeURIComponent(category_name), 'twitter-intent-url': 'https://twitter.com/intent/tweet?url=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug) + '&text=' + encodeURIComponent(category_name),
'facebook-share-url': 'https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug), 'facebook-share-url': 'https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug),
'google-share-url': 'https://plus.google.com/share?url=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug), 'google-share-url': 'https://plus.google.com/share?url=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug),

@ -50,13 +50,20 @@
function createCollections() { function createCollections() {
db.createCollection('objects', function(err, collection) { db.createCollection('objects', function(err, collection) {
if(err) { if(err) {
winston.error("Error creating collection " + err.message); winston.error('Error creating collection ' + err.message);
return; return;
} }
if(collection) { if(collection) {
collection.ensureIndex({_key :1}, {background:true}, function(err, name){ collection.ensureIndex({_key :1}, {background:true}, function(err, name) {
if(err) { if(err) {
winston.error("Error creating index " + err.message); winston.error('Error creating index ' + err.message);
}
});
collection.ensureIndex({'expireAt':1}, {expireAfterSeconds:0, background:true}, function(err, name) {
if(err) {
winston.error('Error creating index ' + err.message);
} }
}); });
} }
@ -64,13 +71,13 @@
db.createCollection('search', function(err, collection) { db.createCollection('search', function(err, collection) {
if(err) { if(err) {
winston.error("Error creating collection " + err.message); winston.error('Error creating collection ' + err.message);
return; return;
} }
if(collection) { if(collection) {
collection.ensureIndex({content:'text'}, {background:true}, function(err, name){ collection.ensureIndex({content:'text'}, {background:true}, function(err, name){
if(err) { if(err) {
winston.error("Error creating index " + err.message); winston.error('Error creating index ' + err.message);
} }
}); });
} }
@ -241,6 +248,14 @@
}); });
} }
module.expire = function(key, seconds, callback) {
module.expireAt(key, Math.round(Date.now() / 1000) + seconds, callback);
}
module.expireAt = function(key, timestamp, callback) {
module.setObjectField(key, 'expireAt', new Date(timestamp * 1000), callback);
}
//hashes //hashes
module.setObject = function(key, data, callback) { module.setObject = function(key, data, callback) {
data['_key'] = key; data['_key'] = key;
@ -254,6 +269,9 @@
module.setObjectField = function(key, field, value, callback) { module.setObjectField = function(key, field, value, callback) {
var data = {}; var data = {};
// if there is a '.' in the field name it inserts subdocument in mongo, replace '.'s with \uff0E // if there is a '.' in the field name it inserts subdocument in mongo, replace '.'s with \uff0E
if(typeof field !== 'string') {
field = field.toString();
}
field = field.replace(/\./g, '\uff0E'); field = field.replace(/\./g, '\uff0E');
data[field] = value; data[field] = value;
db.collection('objects').update({_key:key}, {$set:data}, {upsert:true, w: 1}, function(err, result) { db.collection('objects').update({_key:key}, {$set:data}, {upsert:true, w: 1}, function(err, result) {
@ -303,7 +321,7 @@
var _fields = {}; var _fields = {};
for(var i=0; i<fields.length; ++i) { for(var i=0; i<fields.length; ++i) {
if(typeof fields[i] !== string) { if(typeof fields[i] !== 'string') {
_fields[fields[i].toString().replace(/\./g, '\uff0E')] = 1; _fields[fields[i].toString().replace(/\./g, '\uff0E')] = 1;
} else { } else {
_fields[fields[i].replace(/\./g, '\uff0E')] = 1; _fields[fields[i].replace(/\./g, '\uff0E')] = 1;
@ -348,6 +366,9 @@
module.isObjectField = function(key, field, callback) { module.isObjectField = function(key, field, callback) {
var data = {}; var data = {};
if(typeof field !== 'string') {
field = field.toString();
}
field = field.replace(/\./g, '\uff0E'); field = field.replace(/\./g, '\uff0E');
data[field] = ''; data[field] = '';
db.collection('objects').findOne({_key:key}, {fields:data}, function(err, item) { db.collection('objects').findOne({_key:key}, {fields:data}, function(err, item) {
@ -360,6 +381,9 @@
module.deleteObjectField = function(key, field, callback) { module.deleteObjectField = function(key, field, callback) {
var data = {}; var data = {};
if(typeof field !== 'string') {
field = field.toString();
}
field = field.replace(/\./g, '\uff0E'); field = field.replace(/\./g, '\uff0E');
data[field] = ""; data[field] = "";
db.collection('objects').update({_key:key}, {$unset : data}, function(err, result) { db.collection('objects').update({_key:key}, {$unset : data}, function(err, result) {
@ -379,6 +403,9 @@
module.incrObjectFieldBy = function(key, field, value, callback) { module.incrObjectFieldBy = function(key, field, value, callback) {
var data = {}; var data = {};
if(typeof field !== 'string') {
field = field.toString();
}
field = field.replace(/\./g, '\uff0E'); field = field.replace(/\./g, '\uff0E');
data[field] = value; data[field] = value;
db.collection('objects').update({_key:key}, {$inc : data}, {upsert:true}, function(err, result) { db.collection('objects').update({_key:key}, {$inc : data}, {upsert:true}, function(err, result) {

@ -211,6 +211,14 @@
redisClient.keys(key, callback); redisClient.keys(key, callback);
} }
module.expire = function(key, seconds, callback) {
redisClient.expire(key, seconds, callback);
}
module.expireAt = function(key, timestamp, callback) {
redisClient.expireat(key, timestamp, callback);
}
//hashes //hashes
module.setObject = function(key, data, callback) { module.setObject = function(key, data, callback) {

@ -3,11 +3,12 @@
*/ */
var fs = require('fs'), var fs = require('fs'),
path = require('path'),
express = require('express'), express = require('express'),
winston = require('winston'), winston = require('winston'),
util = require('util'), util = require('util'),
socketio = require('socket.io'), socketio = require('socket.io'),
meta = require('./meta.js'); meta = require('./meta');
var opts = { var opts = {
/* /*
@ -72,10 +73,20 @@ var opts = {
/* Open the streams to log to: either a path or stdout */ /* Open the streams to log to: either a path or stdout */
var stream; var stream;
if(value && fs.existsSync(value)) { if(value && fs.existsSync(value)) {
fs.stat(value, function(err, stats) {
if(stats.isDirectory()) {
stream = fs.createWriteStream(path.join(value, 'nodebb.log'), {flags: 'a'});
} else {
stream = fs.createWriteStream(value, {flags: 'a'}); stream = fs.createWriteStream(value, {flags: 'a'});
} }
else stream.on('error', function(err) {
winston.error(err.message);
});
});
} else {
stream = process.stdout; stream = process.stdout;
}
return stream; return stream;
} }
@ -112,8 +123,7 @@ var opts = {
*/ */
if(meta.config.loggerStatus > 0) { if(meta.config.loggerStatus > 0) {
return opts.express.ofn(req,res,next); return opts.express.ofn(req,res,next);
} } else {
else {
return next(); return next();
} }
} }
@ -140,13 +150,15 @@ var opts = {
for(var v in clients) { for(var v in clients) {
var client = clients[v]; var client = clients[v];
if(client.oEmit != undefined && client.oEmit != client.emit) if(client.oEmit != undefined && client.oEmit != client.emit) {
client.emit = client.oEmit; client.emit = client.oEmit;
}
if(client.$oEmit != undefined && client.$oEmit != client.$emit) if(client.$oEmit != undefined && client.$oEmit != client.$emit) {
client.$emit = client.$oEmit; client.$emit = client.$oEmit;
} }
} }
}
Logger.io = function(socket) { Logger.io = function(socket) {
/* /*

@ -152,7 +152,7 @@ var winston = require('winston'),
// Delete the thread if it is the last undeleted post // Delete the thread if it is the last undeleted post
threadTools.getLatestUndeletedPid(postData.tid, function(err, pid) { threadTools.getLatestUndeletedPid(postData.tid, function(err, pid) {
if (err && err.message === 'no-undeleted-pids-found') { if (err && err.message === 'no-undeleted-pids-found') {
threadTools.delete(postData.tid, function(err) { threadTools.delete(postData.tid, uid, function(err) {
if (err) { if (err) {
winston.error('Could not delete topic (tid: ' + postData.tid + ')', err.stack); winston.error('Could not delete topic (tid: ' + postData.tid + ')', err.stack);
} }

@ -360,10 +360,7 @@ var db = require('./database'),
Posts.uploadPostImage = function(image, callback) { Posts.uploadPostImage = function(image, callback) {
if(!meta.config.imgurClientID) { if(meta.config.imgurClientID) {
return callback('imgurClientID not set', null);
}
if(!image) { if(!image) {
return callback('invalid image', null); return callback('invalid image', null);
} }
@ -378,6 +375,11 @@ var db = require('./database'),
}); });
} }
}); });
} else if (meta.config.allowFileUploads) {
Posts.uploadPostFile(image, callback);
} else {
callback('Uploads are disabled!');
}
} }
Posts.uploadPostFile = function(file, callback) { Posts.uploadPostFile = function(file, callback) {

@ -66,7 +66,7 @@ var path = require('path'),
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;@NodeBB</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/NodeBB\" 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);
}); });
}); });

@ -539,7 +539,7 @@ var fs = require('fs'),
if (!data.birthday) { if (!data.birthday) {
data.age = ''; data.age = '';
} else { } else {
data.age = new Date().getFullYear() - new Date(data.birthday).getFullYear(); data.age = Math.floor((new Date().getTime() - new Date(data.birthday).getTime()) / 31536000000);
} }
function canSeeEmail() { function canSeeEmail() {

@ -91,7 +91,7 @@ var winston = require('winston'),
} }
} }
ThreadTools.delete = function(tid, callback) { ThreadTools.delete = function(tid, uid, callback) {
topics.delete(tid); topics.delete(tid);
db.decrObjectField('global', 'topicCount'); db.decrObjectField('global', 'topicCount');
@ -112,7 +112,7 @@ var winston = require('winston'),
} }
} }
ThreadTools.restore = function(tid, socket, callback) { ThreadTools.restore = function(tid, uid, callback) {
topics.restore(tid); topics.restore(tid);
db.incrObjectField('global', 'topicCount'); db.incrObjectField('global', 'topicCount');
ThreadTools.unlock(tid); ThreadTools.unlock(tid);

@ -55,7 +55,7 @@ var path = require('path'),
/** /**
* `options` object requires: req, res * `options` object requires: req, res
* accepts: metaTags * accepts: metaTags, linkTags
*/ */
app.build_header = function (options, callback) { app.build_header = function (options, callback) {
var custom_header = { var custom_header = {
@ -83,8 +83,6 @@ var path = require('path'),
rel: 'apple-touch-icon', rel: 'apple-touch-icon',
href: meta.config['brand:logo'] || nconf.get('relative_path') + '/logo.png' href: meta.config['brand:logo'] || nconf.get('relative_path') + '/logo.png'
}], }],
metaString = utils.buildMetaTags(defaultMetaTags.concat(options.metaTags || [])),
linkTags = utils.buildLinkTags(defaultLinkTags.concat(options.linkTags || [])),
templateValues = { templateValues = {
cssSrc: meta.config['theme:src'] || nconf.get('relative_path') + '/vendor/bootstrap/css/bootstrap.min.css', cssSrc: meta.config['theme:src'] || nconf.get('relative_path') + '/vendor/bootstrap/css/bootstrap.min.css',
pluginCSS: plugins.cssFiles.map(function(file) { return { path: file + (meta.config['cache-buster'] ? '?v=' + meta.config['cache-buster'] : '') }; }), pluginCSS: plugins.cssFiles.map(function(file) { return { path: file + (meta.config['cache-buster'] ? '?v=' + meta.config['cache-buster'] : '') }; }),
@ -96,16 +94,30 @@ var path = require('path'),
browserTitle: meta.config.title || 'NodeBB', browserTitle: meta.config.title || 'NodeBB',
csrf: options.res.locals.csrf_token, csrf: options.res.locals.csrf_token,
relative_path: nconf.get('relative_path'), relative_path: nconf.get('relative_path'),
meta_tags: metaString,
link_tags: linkTags,
clientScripts: clientScripts, clientScripts: clientScripts,
navigation: custom_header.navigation, navigation: custom_header.navigation,
'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '', 'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '',
allowRegistration: meta.config.allowRegistration === undefined || parseInt(meta.config.allowRegistration, 10) === 1 allowRegistration: meta.config.allowRegistration === undefined || parseInt(meta.config.allowRegistration, 10) === 1
},
escapeList = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
"'": '&apos;',
'"': '&quot;'
}; };
var uid = '0'; var uid = '0';
// Meta Tags
templateValues.meta_tags = utils.buildMetaTags(defaultMetaTags.concat(options.metaTags || []).map(function(tag) {
tag.content = tag.content.replace(/[&<>'"]/g, function(tag) {
return escapeList[tag] || tag;
});
return tag;
}));
templateValues.link_tags = utils.buildLinkTags(defaultLinkTags.concat(options.linkTags || []));
if(options.req.user && options.req.user.uid) { if(options.req.user && options.req.user.uid) {
uid = options.req.user.uid; uid = options.req.user.uid;
} }

@ -562,7 +562,7 @@ websockets.init = function(io) {
socket.on('api:topic.delete', function(data) { socket.on('api:topic.delete', function(data) {
threadTools.privileges(data.tid, uid, function(err, privileges) { threadTools.privileges(data.tid, uid, function(err, privileges) {
if (!err && privileges.editable) { if (!err && privileges.editable) {
threadTools.delete(data.tid, function(err) { threadTools.delete(data.tid, uid, function(err) {
if (!err) { if (!err) {
emitTopicPostStats(); emitTopicPostStats();
socket.emit('api:topic.delete', { socket.emit('api:topic.delete', {
@ -578,7 +578,7 @@ websockets.init = function(io) {
socket.on('api:topic.restore', function(data) { socket.on('api:topic.restore', function(data) {
threadTools.privileges(data.tid, uid, function(err, privileges) { threadTools.privileges(data.tid, uid, function(err, privileges) {
if (!err && privileges.editable) { if (!err && privileges.editable) {
threadTools.restore(data.tid, socket, function(err) { threadTools.restore(data.tid, uid, function(err) {
emitTopicPostStats(); emitTopicPostStats();
socket.emit('api:topic.restore', { socket.emit('api:topic.restore', {

Loading…
Cancel
Save