diff --git a/app.js b/app.js index dcdf8e1819..f208072719 100644 --- a/app.js +++ b/app.js @@ -323,7 +323,7 @@ function resetThemes(callback) { function resetPlugin(pluginId) { var db = require('./src/database'); - db.setRemove('plugins:active', pluginId, function(err) { + db.sortedSetRemove('plugins:active', pluginId, function(err) { if (err) { winston.error('[reset] Could not disable plugin: %s encountered error %s', pluginId, err.message); } else { diff --git a/public/language/en_GB/error.json b/public/language/en_GB/error.json index 812ae03a17..b2f9a3b86b 100644 --- a/public/language/en_GB/error.json +++ b/public/language/en_GB/error.json @@ -24,6 +24,7 @@ "email-taken": "Email taken", "email-not-confirmed": "Your email has not been confirmed yet, please click here to confirm your email.", "email-not-confirmed-chat": "You are unable to chat until your email is confirmed", + "no-email-to-confirm": "This forum requires email confirmation, please click here to enter an email", "username-too-short": "Username too short", "username-too-long": "Username too long", diff --git a/public/src/admin/extend/rewards.js b/public/src/admin/extend/rewards.js index 7fc023eda5..45e81cc289 100644 --- a/public/src/admin/extend/rewards.js +++ b/public/src/admin/extend/rewards.js @@ -11,50 +11,48 @@ define('admin/extend/rewards', function() { conditionals; rewards.init = function() { - $(window).on('action:ajaxify.end', function() { - available = JSON.parse(ajaxify.variables.get('rewards')); - active = JSON.parse(ajaxify.variables.get('active')); - conditions = JSON.parse(ajaxify.variables.get('conditions')); - conditionals = JSON.parse(ajaxify.variables.get('conditionals')); - - $('[data-selected]').each(function() { - select($(this)); - }); + available = JSON.parse(ajaxify.variables.get('rewards')); + active = JSON.parse(ajaxify.variables.get('active')); + conditions = JSON.parse(ajaxify.variables.get('conditions')); + conditionals = JSON.parse(ajaxify.variables.get('conditionals')); + + $('[data-selected]').each(function() { + select($(this)); + }); - $('#active') - .on('change', '[data-selected]', function() { - update($(this)); - }) - .on('click', '.delete', function() { - var parent = $(this).parents('[data-id]'), - id = parent.attr('data-id'); - - socket.emit('admin.rewards.delete', {id: id}, function(err) { - if (err) { - app.alertError(err.message); - } else { - app.alertSuccess('Successfully deleted reward'); - } - }); - - parent.remove(); - return false; - }) - .on('click', '.toggle', function() { - var btn = $(this), - disabled = btn.html() === 'Enable', - id = $(this).parents('[data-id]').attr('data-id'); - - btn.toggleClass('btn-warning').toggleClass('btn-success').html(disabled ? 'Enable' : 'Disable'); - // send disable api call - return false; + $('#active') + .on('change', '[data-selected]', function() { + update($(this)); + }) + .on('click', '.delete', function() { + var parent = $(this).parents('[data-id]'), + id = parent.attr('data-id'); + + socket.emit('admin.rewards.delete', {id: id}, function(err) { + if (err) { + app.alertError(err.message); + } else { + app.alertSuccess('Successfully deleted reward'); + } }); - $('#new').on('click', newReward); - $('#save').on('click', saveRewards); + parent.remove(); + return false; + }) + .on('click', '.toggle', function() { + var btn = $(this), + disabled = btn.html() === 'Enable', + id = $(this).parents('[data-id]').attr('data-id'); + + btn.toggleClass('btn-warning').toggleClass('btn-success').html(disabled ? 'Enable' : 'Disable'); + // send disable api call + return false; + }); - populateInputs(); - }); + $('#new').on('click', newReward); + $('#save').on('click', saveRewards); + + populateInputs(); }; function select(el) { diff --git a/public/src/app.js b/public/src/app.js index b4a091f960..d3a47a1bc6 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -570,7 +570,21 @@ app.cacheBuster = null; }; function showEmailConfirmWarning() { - if (config.requireEmailConfirmation && app.user.uid && !app.user['email:confirmed']) { + if (!config.requireEmailConfirmation || !app.user.uid) { + return; + } + if (!app.user.email) { + app.alert({ + alert_id: 'email_confirm', + message: '[[error:no-email-to-confirm]]', + type: 'warning', + timeout: 0, + clickfn: function() { + app.removeAlert('email_confirm'); + ajaxify.go('user/' + app.user.userslug + '/edit'); + } + }); + } else if (!app.user['email:confirmed']) { app.alert({ alert_id: 'email_confirm', message: '[[error:email-not-confirmed]]', diff --git a/src/install.js b/src/install.js index 10c4d25e05..d3df90b267 100644 --- a/src/install.js +++ b/src/install.js @@ -426,7 +426,10 @@ function enableDefaultPlugins(next) { 'nodebb-plugin-soundpack-default' ]; var db = require('./database'); - db.setAdd('plugins:active', defaultEnabled, next); + var order = defaultEnabled.map(function(plugin, index) { + return index; + }); + db.sortedSetAdd('plugins:active', order, defaultEnabled, next); } function setCopyrightWidget(next) { diff --git a/src/middleware/admin.js b/src/middleware/admin.js index a7ed1997fb..a23781fdef 100644 --- a/src/middleware/admin.js +++ b/src/middleware/admin.js @@ -40,13 +40,14 @@ middleware.buildHeader = function(req, res, next) { 'authentication': [] }; - user.getUserFields(uid, ['username', 'userslug', 'picture', 'email:confirmed'], function(err, userData) { + user.getUserFields(uid, ['username', 'userslug', 'email', 'picture', 'email:confirmed'], function(err, userData) { if (err) { return next(err); } userData.uid = uid; - + userData['email:confirmed'] = parseInt(userData['email:confirmed'], 10) === 1; + async.parallel({ scripts: function(next) { plugins.fireHook('filter:admin.scripts.get', [], function(err, scripts) { @@ -72,16 +73,15 @@ middleware.buildHeader = function(req, res, next) { return next(err); } res.locals.config = results.config; + var data = { relative_path: nconf.get('relative_path'), configJSON: JSON.stringify(results.config), + user: userData, userJSON: JSON.stringify(userData), plugins: results.custom_header.plugins, authentication: results.custom_header.authentication, scripts: results.scripts, - userpicture: userData.picture, - username: userData.username, - userslug: userData.userslug, 'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '', env: process.env.NODE_ENV ? true : false }; diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index b5b94263d2..349a227215 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -318,7 +318,7 @@ middleware.renderHeader = function(req, res, callback) { }, user: function(next) { if (uid) { - user.getUserFields(uid, ['username', 'userslug', 'picture', 'status', 'email:confirmed', 'banned'], next); + user.getUserFields(uid, ['username', 'userslug', 'email', 'picture', 'status', 'email:confirmed', 'banned'], next); } else { next(null, { username: '[[global:guest]]', @@ -343,7 +343,7 @@ middleware.renderHeader = function(req, res, callback) { results.user.isAdmin = results.isAdmin || false; results.user.uid = parseInt(results.user.uid, 10); results.user['email:confirmed'] = parseInt(results.user['email:confirmed'], 10) === 1; - + templateValues.browserTitle = results.title; templateValues.isAdmin = results.user.isAdmin; templateValues.user = results.user; diff --git a/src/plugins.js b/src/plugins.js index eed2db94b8..091a54daa6 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -92,13 +92,12 @@ var fs = require('fs'), Plugins.clientScripts.length = 0; Plugins.libraryPaths.length = 0; - // Read the list of activated plugins and require their libraries async.waterfall([ function(next) { - db.getSetMembers('plugins:active', next); + db.getSortedSetRange('plugins:active', 0, -1, next); }, function(plugins, next) { - if (!plugins || !Array.isArray(plugins)) { + if (!Array.isArray(plugins)) { return next(); } diff --git a/src/plugins/install.js b/src/plugins/install.js index a95f16b3b1..06dcbbf659 100644 --- a/src/plugins/install.js +++ b/src/plugins/install.js @@ -38,7 +38,16 @@ module.exports = function(Plugins) { }, function(_isActive, next) { isActive = _isActive; - db[isActive ? 'setRemove' : 'setAdd']('plugins:active', id, next); + if (isActive) { + db.sortedSetRemove('plugins:active', id, next); + } else { + db.sortedSetCard('plugins:active', function(err, count) { + if (err) { + return next(err); + } + db.sortedSetAdd('plugins:active', count, id, next); + }); + } }, function(next) { meta.reloadRequired = true; @@ -119,6 +128,6 @@ module.exports = function(Plugins) { }; Plugins.isActive = function(id, callback) { - db.isSetMember('plugins:active', id, callback); + db.isSortedSetMember('plugins:active', id, callback); }; }; \ No newline at end of file diff --git a/src/upgrade.js b/src/upgrade.js index 117b79848e..2ef1f3efd7 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -21,7 +21,7 @@ var db = require('./database'), schemaDate, thisSchemaDate, // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema - latestSchema = Date.UTC(2015, 1, 17); + latestSchema = Date.UTC(2015, 1, 24); Upgrade.check = function(callback) { db.get('schemaDate', function(err, value) { @@ -859,10 +859,65 @@ Upgrade.upgrade = function(callback) { winston.info('[2015/02/17] renaming home.tpl to categories.tpl skipped'); next(); } + }, + function(next) { + thisSchemaDate = Date.UTC(2015, 1, 23); + if (schemaDate < thisSchemaDate) { + db.setAdd('plugins:active', 'nodebb-rewards-essentials', function(err) { + winston.info('[2015/2/23] Activating NodeBB Essential Rewards'); + Plugins.reload(function() { + if (err) { + next(err); + } else { + Upgrade.update(thisSchemaDate, next); + } + }); + }); + } else { + winston.info('[2015/2/23] Activating NodeBB Essential Rewards - skipped'); + next(); + } + }, + function(next) { + thisSchemaDate = Date.UTC(2015, 1, 24); + if (schemaDate < thisSchemaDate) { + updatesMade = true; + winston.info('[2015/02/24] Upgrading plugins:active to sorted set'); + + db.getSetMembers('plugins:active', function(err, activePlugins) { + if (err) { + return next(err); + } + if (!Array.isArray(activePlugins) || !activePlugins.length) { + winston.info('[2015/02/24] Upgrading plugins:active to sorted set done'); + Upgrade.update(thisSchemaDate, next); + } + + db.delete('plugins:active', function(err) { + if (err) { + return next(err); + } + var order = -1; + async.eachSeries(activePlugins, function(plugin, next) { + ++order; + db.sortedSetAdd('plugins:active', order, plugin, next); + }, function(err) { + if (err) { + return next(err); + } + winston.info('[2015/02/24] Upgrading plugins:active to sorted set done'); + Upgrade.update(thisSchemaDate, next); + }); + }); + }); + } else { + winston.info('[2015/02/24] Upgrading plugins:active to sorted set skipped'); + next(); + } } // Add new schema updates here - // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 22!!! + // IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 24!!! ], function(err) { if (!err) { if(updatesMade) { diff --git a/src/views/admin/header.tpl b/src/views/admin/header.tpl index 7a5d658eb2..89b0dc4ac4 100644 --- a/src/views/admin/header.tpl +++ b/src/views/admin/header.tpl @@ -85,11 +85,11 @@