diff --git a/app.js b/app.js index 2a4fb645ec..896dd82750 100644 --- a/app.js +++ b/app.js @@ -88,30 +88,41 @@ websockets = require('./src/websockets.js'), posts = require('./src/posts.js'), plugins = require('./src/plugins'), // Don't remove this - plugins initializes itself - Notifications = require('./src/notifications'); + Notifications = require('./src/notifications'), + Upgrade = require('./src/upgrade'); - websockets.init(SocketIO); + Upgrade.check(function(schema_ok) { + if (schema_ok || nconf.get('check-schema') === false) { + websockets.init(SocketIO); - global.templates = {}; - global.translator = translator; + global.templates = {}; + global.translator = translator; - translator.loadServer(); - - var customTemplates = meta.config['theme:templates'] ? path.join(__dirname, 'node_modules', meta.config['theme:id'], meta.config['theme:templates']) : false; + translator.loadServer(); - // todo: replace below with read directory code, derp. - templates.init([ - 'header', 'footer', 'logout', 'outgoing', 'admin/header', 'admin/footer', 'admin/index', - 'emails/reset', 'emails/reset_plaintext', 'emails/email_confirm', 'emails/email_confirm_plaintext', - 'emails/header', 'emails/footer', + var customTemplates = meta.config['theme:templates'] ? path.join(__dirname, 'node_modules', meta.config['theme:id'], meta.config['theme:templates']) : false; - 'noscript/header', 'noscript/home', 'noscript/category', 'noscript/topic' - ], customTemplates); - + // todo: replace below with read directory code, derp. + templates.init([ + 'header', 'footer', 'logout', 'outgoing', 'admin/header', 'admin/footer', 'admin/index', + 'emails/reset', 'emails/reset_plaintext', 'emails/email_confirm', 'emails/email_confirm_plaintext', + 'emails/header', 'emails/footer', - templates.ready(webserver.init); + 'noscript/header', 'noscript/home', 'noscript/category', 'noscript/topic' + ], customTemplates); - Notifications.init(); + + templates.ready(webserver.init); + + Notifications.init(); + } else { + winston.warn('Your NodeBB schema is out-of-date. Please run the following command to bring your dataset up to spec:'); + winston.warn(' node app --upgrade'); + winston.warn('To ignore this error (not recommended):'); + winston.warn(' node app --no-check-schema') + process.exit(); + } + }); }); } else if (nconf.get('setup') || !fs.existsSync(__dirname + '/config.json')) { // New install, ask setup questions diff --git a/package.json b/package.json index 1eeaf8e3f7..767d955a12 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPLv3 or later", "description": "NodeBB Forum", - "version": "0.0.7", + "version": "0.1.0", "homepage": "http://www.nodebb.org", "repository": { "type": "git", diff --git a/src/install.js b/src/install.js index 5795a4d605..8ce2a059ed 100644 --- a/src/install.js +++ b/src/install.js @@ -63,13 +63,14 @@ var async = require('async'), } if (setupVal && setupVal instanceof Object) { - if (setupVal['admin:username'] && setupVal['admin:password'] && setupVal['admin:email']) { + if (setupVal['admin:username'] && setupVal['admin:password'] && setupVal['admin:password:confirm'] && setupVal['admin:email']) { install.values = setupVal; next(); } else { winston.error('Required values are missing for automated setup:'); if (!setupVal['admin:username']) winston.error(' admin:username'); if (!setupVal['admin:password']) winston.error(' admin:password'); + if (!setupVal['admin:password:confirm']) winston.error(' admin:password:confirm'); if (!setupVal['admin:email']) winston.error(' admin:email'); process.exit(); } @@ -277,18 +278,32 @@ var async = require('async'), description: 'Administrator email address', pattern: /.+@.+/, required: true - }, { + }], + passwordQuestions = [{ name: 'password', description: 'Password', required: true, hidden: true, type: 'string' + }, { + name: 'password:confirm', + description: 'Confirm Password', + required: true, + hidden: true, + type: 'string' }], success = function(err, results) { if (!results) { return callback(new Error('aborted')); } + // Check if the passwords match + if (results['password:confirm'] !== results.password) { + winston.warn("Passwords did not match, please try again"); + // Re-prompt password questions. + return retryPassword(results); + } + nconf.set('bcrypt_rounds', 12); User.create(results.username, results.password, results.email, function (err, uid) { if (err) { @@ -306,14 +321,33 @@ var async = require('async'), } }); }); + }, + retryPassword = function (originalResults) { + // Ask only the password questions + prompt.get(passwordQuestions, function (err, results) { + if (!results) { + return callback(new Error('aborted')); + } + + // Update the original data with newly collected password + originalResults.password = results.password; + originalResults['password:confirm'] = results['password:confirm']; + + // Send back to success to handle + success(err, originalResults); + }); }; + // Add the password questions + questions = questions.concat(passwordQuestions); + if (!install.values) prompt.get(questions, success); else { var results = { username: install.values['admin:username'], email: install.values['admin:email'], - password: install.values['admin:password'] + password: install.values['admin:password'], + 'password:confirm': install.values['admin:password:confirm'] }; success(null, results); diff --git a/src/routes/user.js b/src/routes/user.js index 8ee9015cd5..27320e25e6 100644 --- a/src/routes/user.js +++ b/src/routes/user.js @@ -191,11 +191,6 @@ var user = require('./../user.js'), is.on('end', function () { fs.unlinkSync(tempPath); - var imageUrl = nconf.get('upload_url') + filename; - - user.setUserField(uid, 'uploadedpicture', imageUrl); - user.setUserField(uid, 'picture', imageUrl); - require('node-imagemagick').crop({ srcPath: uploadPath, dstPath: uploadPath, @@ -204,8 +199,17 @@ var user = require('./../user.js'), }, function (err, stdout, stderr) { if (err) { winston.err(err); + res.send({ + error: 'Invalid image file!' + }); + return; } + var imageUrl = nconf.get('upload_url') + filename; + + user.setUserField(uid, 'uploadedpicture', imageUrl); + user.setUserField(uid, 'picture', imageUrl); + res.json({ path: imageUrl }); diff --git a/src/upgrade.js b/src/upgrade.js index f4040a5886..26ac52cc19 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -1,110 +1,148 @@ +"use strict"; + var RDB = require('./redis.js'), async = require('async'), winston = require('winston'), - notifications = require('./notifications') - Upgrade = {}; + notifications = require('./notifications'), + Upgrade = {}, + + schemaDate, thisSchemaDate; + +Upgrade.check = function(callback) { + var latestSchema = new Date(2013, 10, 11).getTime(); + + RDB.get('schemaDate', function(err, value) { + if (parseInt(value, 10) >= latestSchema) { + callback(true); + } else { + callback(false); + } + }); +}; Upgrade.upgrade = function() { winston.info('Beginning Redis database schema update'); async.series([ function(next) { - RDB.hget('notifications:1', 'score', function(err, score) { - if (score) { - async.series([ - function(next) { - RDB.keys('uid:*:notifications:flag', function(err, keys) { - if (keys.length > 0) { - winston.info('[2013/10/03] Removing deprecated Notification Flags'); - async.each(keys, function(key, next) { - RDB.del(key, next); - }, next); - } else { - winston.info('[2013/10/03] No Notification Flags found. Good.'); - next(); - } - }); - }, - function(next) { - winston.info('[2013/10/03] Updating Notifications'); - RDB.keys('uid:*:notifications:*', function(err, keys) { - async.each(keys, function(key, next) { - RDB.zrange(key, 0, -1, function(err, nids) { - async.each(nids, function(nid, next) { - notifications.get(nid, null, function(notif_data) { - RDB.zadd(key, notif_data.datetime, nid, next); - }); - }, next); - }); - }, next); - }); - }, - function(next) { - RDB.keys('notifications:*', function(err, keys) { - if (keys.length > 0) { - winston.info('[2013/10/03] Removing Notification Scores'); - async.each(keys, function(key, next) { - if (key === 'notifications:next_nid') return next(); - RDB.hdel(key, 'score', next); - }, next); - } else { - winston.info('[2013/10/03] No Notification Scores found. Good.'); - next(); - } - }); - } - ], next); - } else { - winston.info('[2013/10/03] Updates to Notifications skipped.'); - next(); - } + RDB.get('schemaDate', function(err, value) { + schemaDate = value; + next(); }); }, function(next) { - RDB.exists('notifications', function(err, exists) { - if (!exists) { - RDB.keys('notifications:*', function(err, keys) { - var multi = RDB.multi(); + thisSchemaDate = new Date(2013, 9, 3).getTime(); + if (schemaDate < thisSchemaDate) { + async.series([ + function(next) { + RDB.keys('uid:*:notifications:flag', function(err, keys) { + if (keys.length > 0) { + winston.info('[2013/10/03] Removing deprecated Notification Flags'); + async.each(keys, function(key, next) { + RDB.del(key, next); + }, next); + } else { + winston.info('[2013/10/03] No Notification Flags found. Good.'); + next(); + } + }); + }, + function(next) { + winston.info('[2013/10/03] Updating Notifications'); + RDB.keys('uid:*:notifications:*', function(err, keys) { + async.each(keys, function(key, next) { + RDB.zrange(key, 0, -1, function(err, nids) { + async.each(nids, function(nid, next) { + notifications.get(nid, null, function(notif_data) { + if (notif_data) { + RDB.zadd(key, notif_data.datetime, nid, next); + } else { + next(); + } + }); + }, next); + }); + }, next); + }); + }, + function(next) { + RDB.keys('notifications:*', function(err, keys) { + if (keys.length > 0) { + winston.info('[2013/10/03] Removing Notification Scores'); + async.each(keys, function(key, next) { + if (key === 'notifications:next_nid') { + return next(); + } - keys = keys.filter(function(key) { - if (key === 'notifications:next_nid') { - return false; + RDB.hdel(key, 'score', next); + }, next); } else { - return true; + winston.info('[2013/10/03] No Notification Scores found. Good.'); + next(); } - }).map(function(key) { - return key.slice(14); }); + } + ], next); + } else { + winston.info('[2013/10/03] Updates to Notifications skipped.'); + next(); + } + }, + function(next) { + thisSchemaDate = new Date(2013, 9, 23).getTime(); + if (schemaDate < thisSchemaDate) { + RDB.keys('notifications:*', function(err, keys) { - winston.info('[2013/10/23] Adding existing notifications to set'); - RDB.sadd('notifications', keys, next); + keys = keys.filter(function(key) { + if (key === 'notifications:next_nid') { + return false; + } else { + return true; + } + }).map(function(key) { + return key.slice(14); }); - } else { - winston.info('[2013/10/23] Updates to Notifications skipped.'); - next(); - } - }); + + winston.info('[2013/10/23] Adding existing notifications to set'); + + if(keys && Array.isArray(keys)) { + async.each(keys, function(key, cb) { + RDB.sadd('notifications', key, cb); + }, next); + } else next(); + + }); + } else { + winston.info('[2013/10/23] Updates to Notifications skipped.'); + next(); + } }, function(next) { - RDB.hget('config', 'postDelay', function(err, postDelay) { - if(parseInt(postDelay, 10) > 150) { - RDB.hset('config', 'postDelay', 10, function(err, success) { - winston.info('[2013/11/11] Updated postDelay to 10 seconds.'); - next(); - }); - } else { - winston.info('[2013/11/11] Update to postDelay skipped.'); + thisSchemaDate = new Date(2013, 10, 11).getTime(); + if (schemaDate < thisSchemaDate) { + RDB.hset('config', 'postDelay', 10, function(err, success) { + winston.info('[2013/11/11] Updated postDelay to 10 seconds.'); next(); - } - }); + }); + } else { + winston.info('[2013/11/11] Update to postDelay skipped.'); + next(); + } } // Add new schema updates here + // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 12!!! ], function(err) { if (!err) { - winston.info('Redis schema update complete!'); - process.exit(); + RDB.set('schemaDate', thisSchemaDate, function(err) { + if (!err) { + winston.info('[upgrade] Redis schema update complete!'); + process.exit(); + } else { + winston.error('[upgrade] Could not update NodeBB schema date!'); + } + }); } else { - winston.error('Errors were encountered while updating the NodeBB schema: ' + err.message); + winston.error('[upgrade] Errors were encountered while updating the NodeBB schema: ' + err.message); } }); };