diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 43190850da..5ab08eb0fa 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -158,7 +158,7 @@ $(document).ready(function() { $(window).trigger('action:ajaxify.end', {url: url}); }); - $(window).trigger('action:ajaxify.contentLoaded', {url: url}); + $(window).trigger('action:ajaxify.contentLoaded', {url: url, tpl: tpl_url}); app.processPage(); }; diff --git a/public/src/client/account/settings.js b/public/src/client/account/settings.js index 20b33a613b..848bf8c1ef 100644 --- a/public/src/client/account/settings.js +++ b/public/src/client/account/settings.js @@ -41,8 +41,8 @@ define('forum/account/settings', ['forum/account/header'], function(header) { if (newSettings.hasOwnProperty(key)) { if (key === 'userLang' && config.userLang !== newSettings.userLang) { requireReload = true; - } - config[key] = newSettings[key]; + } + config[key] = newSettings[key]; } } app.exposeConfigToTemplates(); @@ -61,31 +61,6 @@ define('forum/account/settings', ['forum/account/header'], function(header) { return false; }); - - socket.emit('user.getSettings', {uid: ajaxify.variables.get('theirid')}, function(err, settings) { - var inputs = $('.account').find('input, textarea, select'); - - inputs.each(function(index, input) { - input = $(input); - var setting = input.attr('data-property'); - if (setting) { - if (input.is('select')) { - input.val(settings[setting]); - return; - } - - switch (input.attr('type')) { - case 'text' : - case 'textarea' : - input.val(settings[setting]); - break; - case 'checkbox' : - input.prop('checked', !!settings[setting]); - break; - } - } - }); - }); }; return AccountSettings; diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index a0283f0401..e8071ec8ad 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -298,7 +298,7 @@ function getFromUserSet(tpl, set, method, type, req, res, next) { }, data: function(next) { var start = (page - 1) * itemsPerPage; - var stop = start + itemsPerPage; + var stop = start + itemsPerPage - 1; method(setName, req.uid, start, stop, next); } }, function(err, results) { @@ -375,38 +375,59 @@ accountsController.accountEdit = function(req, res, next) { }; accountsController.accountSettings = function(req, res, next) { - accountsController.getBaseUser(req.params.userslug, req.uid, function(err, userData) { + var userData; + async.waterfall([ + function(next) { + accountsController.getBaseUser(req.params.userslug, req.uid, next); + }, + function(_userData, next) { + userData = _userData; + if (!userData) { + return helpers.notFound(req, res); + } + async.parallel({ + settings: function(next) { + user.getSettings(userData.uid, next); + }, + userGroups: function(next) { + groups.getUserGroups([userData.uid], next); + }, + languages: function(next) { + languages.list(next); + } + }, next); + }, + function(results, next) { + userData.languages = results.languages; + userData.userGroups = results.userGroups[0]; + plugins.fireHook('filter:user.settings', {settings: results.settings, uid: req.uid}, next); + }, + function(data, next) { + userData.settings = data.settings; + userData.disableEmailSubscriptions = parseInt(meta.config.disableEmailSubscriptions, 10) === 1; + next(); + } + ], function(err) { if (err) { return next(err); } - if (!userData) { - return helpers.notFound(req, res); - } + userData.dailyDigestFreqOptions = [ + {value: 'off', name: '[[user:digest_off]]', selected: 'off' === userData.settings.dailyDigestFreq}, + {value: 'day', name: '[[user:digest_daily]]', selected: 'day' === userData.settings.dailyDigestFreq}, + {value: 'week', name: '[[user:digest_weekly]]', selected: 'week' === userData.settings.dailyDigestFreq}, + {value: 'month', name: '[[user:digest_monthly]]', selected: 'month' === userData.settings.dailyDigestFreq} + ]; - async.parallel({ - settings: function(next) { - plugins.fireHook('filter:user.settings', [], next); - }, - userGroups: function(next) { - groups.getUserGroups([userData.uid], next); - }, - languages: function(next) { - languages.list(next); - } - }, function(err, results) { - if (err) { - return next(err); - } - - userData.settings = results.settings; - userData.languages = results.languages; - userData.userGroups = results.userGroups[0]; - - userData.disableEmailSubscriptions = parseInt(meta.config.disableEmailSubscriptions, 10) === 1; + userData.userGroups.forEach(function(group) { + group.selected = group.name === userData.settings.groupTitle; + }); - res.render('account/settings', userData); + userData.languages.forEach(function(language) { + language.selected = language.code === userData.settings.userLang; }); + + res.render('account/settings', userData); }); }; diff --git a/src/controllers/admin.js b/src/controllers/admin.js index 52cf194353..4487167873 100644 --- a/src/controllers/admin.js +++ b/src/controllers/admin.js @@ -211,8 +211,29 @@ adminController.flags.get = function(req, res, next) { }; adminController.database.get = function(req, res, next) { - db.info(function (err, data) { - res.render('admin/advanced/database', data); + async.parallel({ + redis: function(next) { + if (nconf.get('redis')) { + var rdb = require('../database/redis'); + var cxn = rdb.connect(); + rdb.info(cxn, next); + } else { + next(); + } + }, + mongo: function(next) { + if (nconf.get('mongo')) { + var mdb = require('../database/mongo'); + mdb.info(mdb.client, next); + } else { + next(); + } + } + }, function(err, results) { + if (err) { + return next(err); + } + res.render('admin/advanced/database', results); }); }; diff --git a/src/database/mongo.js b/src/database/mongo.js index e031132b99..63fdc8b9c2 100644 --- a/src/database/mongo.js +++ b/src/database/mongo.js @@ -158,6 +158,24 @@ }); }; + module.info = function(db, callback) { + db.stats({scale:1024}, function(err, stats) { + if(err) { + return callback(err); + } + + stats.avgObjSize = (stats.avgObjSize / 1024).toFixed(2); + stats.dataSize = (stats.dataSize / 1024).toFixed(2); + stats.storageSize = (stats.storageSize / 1024).toFixed(2); + stats.fileSize = (stats.fileSize / 1024).toFixed(2); + stats.indexSize = (stats.indexSize / 1024).toFixed(2); + stats.raw = JSON.stringify(stats, null, 4); + stats.mongo = true; + + callback(null, stats); + }); + }; + module.close = function() { db.close(); }; diff --git a/src/database/mongo/main.js b/src/database/mongo/main.js index eba0b3b14b..7ba58499d3 100644 --- a/src/database/mongo/main.js +++ b/src/database/mongo/main.js @@ -79,24 +79,6 @@ module.exports = function(db, module) { db.dropDatabase(callback); }; - module.info = function(callback) { - db.stats({scale:1024}, function(err, stats) { - if(err) { - return callback(err); - } - - stats.avgObjSize = (stats.avgObjSize / 1024).toFixed(2); - stats.dataSize = (stats.dataSize / 1024).toFixed(2); - stats.storageSize = (stats.storageSize / 1024).toFixed(2); - stats.fileSize = (stats.fileSize / 1024).toFixed(2); - stats.indexSize = (stats.indexSize / 1024).toFixed(2); - stats.raw = JSON.stringify(stats, null, 4); - stats.mongo = true; - - callback(null, stats); - }); - }; - module.exists = function(key, callback) { if (!key) { return callback(); diff --git a/src/database/redis.js b/src/database/redis.js index 8e06ce837a..1c224276cc 100644 --- a/src/database/redis.js +++ b/src/database/redis.js @@ -115,6 +115,28 @@ redisClient.quit(); }; + module.info = function(cxn, callback) { + cxn.info(function (err, data) { + if (err) { + return callback(err); + } + + var lines = data.toString().split("\r\n").sort(); + var redisData = {}; + lines.forEach(function (line) { + var parts = line.split(':'); + if (parts[1]) { + redisData[parts[0]] = parts[1]; + } + }); + + redisData.raw = JSON.stringify(redisData, null, 4); + redisData.redis = true; + + callback(null, redisData); + }); + }; + module.helpers = module.helpers || {}; module.helpers.redis = require('./redis/helpers'); }(exports)); diff --git a/src/database/redis/main.js b/src/database/redis/main.js index 84e31eaae4..503d515569 100644 --- a/src/database/redis/main.js +++ b/src/database/redis/main.js @@ -35,27 +35,7 @@ module.exports = function(redisClient, module) { }); }; - module.info = function(callback) { - redisClient.info(function (err, data) { - if(err) { - return callback(err); - } - - var lines = data.toString().split("\r\n").sort(); - var redisData = {}; - lines.forEach(function (line) { - var parts = line.split(':'); - if (parts[1]) { - redisData[parts[0]] = parts[1]; - } - }); - - redisData.raw = JSON.stringify(redisData, null, 4); - redisData.redis = true; - callback(null, redisData); - }); - }; module.exists = function(key, callback) { redisClient.exists(key, function(err, exists) { diff --git a/src/groups.js b/src/groups.js index 632a51f805..4f52d2bc9f 100644 --- a/src/groups.js +++ b/src/groups.js @@ -760,17 +760,18 @@ var async = require('async'), tasks.push(async.apply(db.setAdd, 'group:' + groupName + ':owners', uid)); } async.parallel(tasks, next); + }, + function(results, next) { + user.setGroupTitle(groupName, uid, next); + }, + function(next) { + plugins.fireHook('action:group.join', { + groupName: groupName, + uid: uid + }); + next(); } - ], function(err, results) { - if (err) { - return callback(err); - } - plugins.fireHook('action:group.join', { - groupName: groupName, - uid: uid - }); - callback(); - }); + ], callback); } callback = callback || function() {}; diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 0df36121e8..65af901b08 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -340,26 +340,6 @@ function toggleFollow(method, uid, theiruid, callback) { }); } -SocketUser.getSettings = function(socket, data, callback) { - if (socket.uid) { - if (socket.uid === parseInt(data.uid, 10)) { - return user.getSettings(socket.uid, callback); - } - - user.isAdministrator(socket.uid, function(err, isAdmin) { - if (err) { - return callback(err); - } - - if (!isAdmin) { - return callback(new Error('[[error:no-privileges]]')); - } - - user.getSettings(data.uid, callback); - }); - } -}; - SocketUser.saveSettings = function(socket, data, callback) { if (!socket.uid || !data) { return callback(new Error('[[error:invalid-data]]')); diff --git a/src/upgrade.js b/src/upgrade.js index da5edb4a36..1044cde651 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, 4, 7); + latestSchema = Date.UTC(2015, 4, 8); Upgrade.check = function(callback) { db.get('schemaDate', function(err, value) { @@ -233,18 +233,17 @@ Upgrade.upgrade = function(callback) { var privs = ['find', 'read', 'topics:reply', 'topics:create']; async.each(privs, function(priv, next) { - categoryHasPrivilegesSet(cid, priv, function(err, privilegesSet) { if (err || privilegesSet) { return next(err); } async.eachLimit(groups, 50, function(group, next) { - if (group && !group.hidden) { - if (group.name === 'guests' && (priv === 'topics:reply' || priv === 'topics:create')) { + if (group) { + if (group === 'guests' && (priv === 'topics:reply' || priv === 'topics:create')) { return next(); } - Groups.join('cid:' + cid + ':privileges:groups:' + priv, group.name, next); + Groups.join('cid:' + cid + ':privileges:groups:' + priv, group, next); } else { next(); } @@ -989,7 +988,7 @@ Upgrade.upgrade = function(callback) { thisSchemaDate = Date.UTC(2015, 4, 7); if (schemaDate < thisSchemaDate) { updatesMade = true; - winston.info('[2015/02/25] Upgrading uid mappings to sorted set'); + winston.info('[2015/05/07] Upgrading uid mappings to sorted set'); async.series([ async.apply(upgradeHashToSortedSet, 'email:uid'), @@ -1009,6 +1008,41 @@ Upgrade.upgrade = function(callback) { winston.info('[2015/05/07] Upgrading uid mappings to sorted set skipped'); next(); } + }, + function(next) { + thisSchemaDate = Date.UTC(2015, 4, 8); + if (schemaDate < thisSchemaDate) { + updatesMade = true; + winston.info('[2015/05/08] Fixing emails'); + + db.getSortedSetRangeWithScores('email:uid', 0, -1, function(err, users) { + if (err) { + return next(err); + } + + async.eachLimit(users, 100, function(user, next) { + var newEmail = user.value.replace(/\uff0E/g, '.'); + if (newEmail === user.value) { + return next(); + } + async.series([ + async.apply(db.sortedSetRemove, 'email:uid', user.value), + async.apply(db.sortedSetAdd, 'email:uid', user.score, newEmail) + ], next); + + }, function(err) { + if (err) { + return next(err); + } + winston.info('[2015/05/08] Fixing emails done'); + Upgrade.update(thisSchemaDate, next); + }); + }); + + } else { + winston.info('[2015/05/08] Fixing emails skipped'); + next(); + } } // Add new schema updates here diff --git a/src/user/settings.js b/src/user/settings.js index 7c12cbfd00..ec493457aa 100644 --- a/src/user/settings.js +++ b/src/user/settings.js @@ -143,4 +143,17 @@ module.exports = function(User) { User.setSetting = function(uid, key, value, callback) { db.setObjectField('user:' + uid + ':settings', key, value, callback); }; + + User.setGroupTitle = function(groupName, uid, callback) { + if (groupName === 'registered-users') { + return callback(); + } + db.getObjectField('user:' + uid + ':settings', 'groupTitle', function(err, currentTitle) { + if (err || (currentTitle || currentTitle === '')) { + return callback(err); + } + + User.setSetting(uid, 'groupTitle', groupName, callback); + }); + }; }; diff --git a/src/views/admin/advanced/database.tpl b/src/views/admin/advanced/database.tpl index e08daac3f7..740418fc35 100644 --- a/src/views/admin/advanced/database.tpl +++ b/src/views/admin/advanced/database.tpl @@ -1,5 +1,23 @@ <div class="database"> <div class="col-sm-9"> + <!-- IF mongo --> + <div class="panel panel-default"> + <div class="panel-heading"><i class="fa fa-hdd-o"></i> Mongo</div> + <div class="panel-body"> + <div class="database-info"> + <span>Collections</span> <span class="text-right formatted-number">{collections}</span><br/> + <span>Objects</span> <span class="text-right formatted-number">{objects}</span><br/> + <span>Avg. Object Size</span> <span class="text-right">{avgObjSize} kb</span><br/> + <hr/> + <span>Data Size</span> <span class="text-right">{dataSize} mb</span><br/> + <span>Storage Size</span> <span class="text-right">{storageSize} mb</span><br/> + <span>Index Size</span> <span class="text-right">{indexSize} mb</span><br/> + <span>File Size</span> <span class="text-right">{fileSize} mb</span><br/> + </div> + </div> + </div> + <!-- ENDIF mongo --> + <!-- IF redis --> <div class="panel panel-default"> <div class="panel-heading"><i class="fa fa-hdd-o"></i> Redis</div> @@ -31,29 +49,30 @@ <!-- IF mongo --> <div class="panel panel-default"> - <div class="panel-heading"><i class="fa fa-hdd-o"></i> Mongo</div> - <div class="panel-body"> - <div class="database-info"> - <span>Collections</span> <span class="text-right formatted-number">{collections}</span><br/> - <span>Objects</span> <span class="text-right formatted-number">{objects}</span><br/> - <span>Avg. Object Size</span> <span class="text-right">{avgObjSize} kb</span><br/> - <hr/> - <span>Data Size</span> <span class="text-right">{dataSize} mb</span><br/> - <span>Storage Size</span> <span class="text-right">{storageSize} mb</span><br/> - <span>Index Size</span> <span class="text-right">{indexSize} mb</span><br/> - <span>File Size</span> <span class="text-right">{fileSize} mb</span><br/> + <div class="panel-heading" data-toggle="collapse" data-target=".mongodb-raw"> + <h3 class="panel-title"><i class="fa fa-caret-down"></i> MongoDB Raw Info</h3> + </div> + + <div class="panel-body mongodb-raw collapse"> + <div class="highlight"> + <pre>{mongo.raw}</pre> </div> </div> </div> <!-- ENDIF mongo --> + <!-- IF redis --> <div class="panel panel-default"> - <div class="panel-heading"><i class="fa fa-hdd-o"></i> Raw Info</div> - <div class="panel-body"> + <div class="panel-heading" data-toggle="collapse" data-target=".redis-raw"> + <h3 class="panel-title"><i class="fa fa-caret-down"></i> Redis Raw Info</h3> + </div> + + <div class="panel-body redis-raw collapse"> <div class="highlight"> - <pre>{raw}</pre> + <pre>{redis.raw}</pre> </div> </div> </div> + <!-- ENDIF redis --> </div> </div> diff --git a/src/views/admin/extend/plugins.tpl b/src/views/admin/extend/plugins.tpl index 72c7228d0e..90611e6d47 100644 --- a/src/views/admin/extend/plugins.tpl +++ b/src/views/admin/extend/plugins.tpl @@ -73,7 +73,7 @@ <small>Latest <strong class="latestVersion">{plugins.latest}</strong></small> <!-- IF plugins.url --> - <p>For more information: <a href="{plugins.url}">{plugins.url}</a></p> + <p>For more information: <a target="_blank" href="{plugins.url}">{plugins.url}</a></p> <!-- ENDIF plugins.url --> </li> <!-- ENDIF !plugins.installed -->