Merge remote-tracking branch 'origin/master' into develop

v1.18.x
Julian Lam 8 years ago
commit 1ebbbdd3f9

@ -223,7 +223,7 @@ fs.open(path.join(__dirname, 'config.json'), 'r', function (err) {
stderr: process.stderr, stderr: process.stderr,
}); });
fs.writeFile(pidFilePath, process.pid); fs.writeFileSync(pidFilePath, process.pid);
} }
async.series([ async.series([

@ -61,7 +61,7 @@
"nodebb-plugin-soundpack-default": "1.0.0", "nodebb-plugin-soundpack-default": "1.0.0",
"nodebb-plugin-spam-be-gone": "0.4.13", "nodebb-plugin-spam-be-gone": "0.4.13",
"nodebb-rewards-essentials": "0.0.9", "nodebb-rewards-essentials": "0.0.9",
"nodebb-theme-lavender": "3.0.15", "nodebb-theme-lavender": "4.0.0",
"nodebb-theme-persona": "4.2.6", "nodebb-theme-persona": "4.2.6",
"nodebb-theme-vanilla": "5.2.0", "nodebb-theme-vanilla": "5.2.0",
"nodebb-widget-essentials": "2.0.13", "nodebb-widget-essentials": "2.0.13",

@ -8,27 +8,27 @@
"mongo.version": "Versione MongoDB", "mongo.version": "Versione MongoDB",
"mongo.storage-engine": "Storage Engine", "mongo.storage-engine": "Storage Engine",
"mongo.collections": "Collections", "mongo.collections": "Collections",
"mongo.objects": "Objects", "mongo.objects": "Oggetti",
"mongo.avg-object-size": "Avg. Object Size", "mongo.avg-object-size": "Dimensione Media dell'Oggetto",
"mongo.data-size": "Data Size", "mongo.data-size": "Dimensione del Data",
"mongo.storage-size": "Storage Size", "mongo.storage-size": "Dimensione dello Spazio di Archiviazione",
"mongo.index-size": "Index Size", "mongo.index-size": "Dimensione dell'Indice",
"mongo.file-size": "File Size", "mongo.file-size": "Dimensione del file",
"mongo.resident-memory": "Resident Memory", "mongo.resident-memory": "Memoria Allocata",
"mongo.virtual-memory": "Virtual Memory", "mongo.virtual-memory": "Memoria Virtuale",
"mongo.mapped-memory": "Mapped Memory", "mongo.mapped-memory": "Memoria Mappata",
"mongo.raw-info": "MongoDB Raw Info", "mongo.raw-info": "MongoDB Raw Info",
"redis": "Redis", "redis": "Redis",
"redis.version": "Redis Version", "redis.version": "Versione Redis",
"redis.connected-clients": "Connected Clients", "redis.connected-clients": "Clients Connessi",
"redis.connected-slaves": "Connected Slaves", "redis.connected-slaves": "Connected Slaves",
"redis.blocked-clients": "Blocked Clients", "redis.blocked-clients": "Clients Bloccati",
"redis.used-memory": "Used Memory", "redis.used-memory": "Memoria Usata",
"redis.memory-frag-ratio": "Memory Fragmentation Ratio", "redis.memory-frag-ratio": "Rateo della Frammentazione della Memoria",
"redis.total-connections-recieved": "Total Connections Received", "redis.total-connections-recieved": "Totale Connessioni Ricevute",
"redis.total-commands-processed": "Total Commands Processed", "redis.total-commands-processed": "Totale Comandi Processati",
"redis.iops": "Instantaneous Ops. Per Second", "redis.iops": "Operazioni Instantanee al Secondo",
"redis.keyspace-hits": "Keyspace Hits", "redis.keyspace-hits": "Keyspace Hits",
"redis.keyspace-misses": "Keyspace Misses", "redis.keyspace-misses": "Keyspace Misses",
"redis.raw-info": "Redis Raw Info" "redis.raw-info": "Redis Raw Info"

@ -1,14 +1,14 @@
{ {
"figure-x": "Figure %1", "figure-x": "Figura %1",
"error-events-per-day": "<code>%1</code> events per day", "error-events-per-day": "<code>%1</code> eventi per giorno",
"error.404": "404 Not Found", "error.404": "404 Non Trovato",
"error.503": "503 Service Unavailable", "error.503": "503 Servizio Non Disponibile",
"manage-error-log": "Manage Error Log", "manage-error-log": "Gestisci il Registro degli Errori",
"export-error-log": "Export Error Log (CSV)", "export-error-log": "Esporta il Registro degli Errori (CSV)",
"clear-error-log": "Clear Error Log", "clear-error-log": "Cancella il Registro degli Errori",
"route": "Route", "route": "Strada",
"count": "Count", "count": "Numero",
"no-routes-not-found": "Hooray! No 404 errors!", "no-routes-not-found": "Hooray! Nessun Errore 404!",
"clear404-confirm": "Are you sure you wish to clear the 404 error logs?", "clear404-confirm": "Sei sicuro di voler cancellare il Registro degli Errori 404?",
"clear404-success": "\"404 Not Found\" errors cleared" "clear404-success": "Error \"404 Non Trovato\" Cancellati"
} }

@ -1,6 +1,6 @@
{ {
"events": "Events", "events": "Eventi",
"no-events": "There are no events", "no-events": "Non ci sono Eventi",
"control-panel": "Events Control Panel", "control-panel": "Pannello di controllo degli Eventi",
"delete-events": "Delete Events" "delete-events": "Cancella gli Eventi"
} }

@ -1,7 +1,7 @@
{ {
"logs": "Logs", "logs": "Registri",
"control-panel": "Logs Control Panel", "control-panel": "Pannello di Controllo dei Registri",
"reload": "Reload Logs", "reload": "Ricarica i Registri",
"clear": "Clear Logs", "clear": "Cancella i Registri",
"clear-success": "Logs Cleared!" "clear-success": "Registri Cancellati!"
} }

@ -1,9 +1,9 @@
{ {
"custom-css": "Custom CSS", "custom-css": "CSS Personalizzato",
"custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", "custom-css.description": "Inserisci le tue dichiarazioni CSS qui, verranno applicate dopo tutti gli altri stili.",
"custom-css.enable": "Enable Custom CSS", "custom-css.enable": "Abilita CSS Personalizzato",
"custom-header": "Custom Header", "custom-header": "Intestazione Personalizzata",
"custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <code>&lt;head&gt;</code> section of your forum's markup.", "custom-header.description": "Inserisci l' HTML personalizzato qui (es. JavaScript, Meta Tags, ecc.), verrà attaccato al codice <code>&lt;head&gt;</code> sezione del markup del tuo forum",
"custom-header.enable": "Enable Custom Header" "custom-header.enable": "Abilita l'Intestazione Personalizzata"
} }

@ -1,9 +1,9 @@
{ {
"loading": "Loading Skins...", "loading": "Caricamento Skins",
"homepage": "Homepage", "homepage": "Pagina Home",
"select-skin": "Select Skin", "select-skin": "Seleziona la Skin",
"current-skin": "Current Skin", "current-skin": "Skin Corrente",
"skin-updated": "Skin Updated", "skin-updated": "Skin Aggiornata",
"applied-success": "%1 skin was succesfully applied", "applied-success": "%1 skin è stata applicata con successo",
"revert-success": "Skin reverted to base colours" "revert-success": "Skin riportata ai colori base"
} }

@ -1,11 +1,11 @@
{ {
"checking-for-installed": "Checking for installed themes...", "checking-for-installed": "Controllando se ci sono temi installati...",
"homepage": "Homepage", "homepage": "Pagina Home",
"select-theme": "Select Theme", "select-theme": "Seleziona il Tema",
"current-theme": "Current Theme", "current-theme": "Tema Corrente",
"no-themes": "No installed themes found", "no-themes": "Nessun tema installato trovato",
"revert-confirm": "Are you sure you wish to restore the default NodeBB theme?", "revert-confirm": "Sei sicuro di voler ripristinare al tema originale di NodeBB?",
"theme-changed": "Theme Changed", "theme-changed": "Tema Cambiato",
"revert-success": "You have successfully reverted your NodeBB back to it's default theme.", "revert-success": "Hai correttamente ripristinato il tuo NodeBB al tema originale.",
"restart-to-activate": "Please restart your NodeBB to fully activate this theme" "restart-to-activate": "Perfavore riavvia il tuo NodeBB per attivare correttamente questo tema"
} }

@ -1,16 +1,16 @@
{ {
"you-are-on": "Info - You are on <strong>%1:%2</strong>", "you-are-on": "Informazione - Tu sei su <strong>%1:%2</strong>",
"host": "host", "host": "host",
"pid": "pid", "pid": "pid",
"nodejs": "nodejs", "nodejs": "nodejs",
"online": "online", "online": "online",
"git": "git", "git": "git",
"load": "load", "load": "carica",
"uptime": "uptime", "uptime": "tempo di caricamento",
"registered": "Registered", "registered": "Registrato",
"sockets": "Sockets", "sockets": "Sockets",
"guests": "Guests", "guests": "Ospiti",
"info": "Info" "info": "Informazioni"
} }

@ -1,6 +1,6 @@
{ {
"logger-settings": "Logger Settings", "logger-settings": "Impostazioni del Registratore",
"description": "By enabling the check boxes, you will receive logs to your terminal. If you specify a path, logs will then be saved to a file instead. HTTP logging is useful for collecting statistics about who, when, and what people access on your forum. In addition to logging HTTP requests, we can also log socket.io events. Socket.io logging, in combination with redis-cli monitor, can be very helpful for learning NodeBB's internals.", "description": "Abilitando le \"check boxes\", riceverai i registri sul tuo terminale. Se vuoi specificare un percorso, i registri verranno invece salvati in un file. Registrare l' HTTP è utile per collezionare statistiche su chi, quando, e a cosa le persone hanno accesso sul tuo forum. In più sul registrare le richieste HTTP, in combinazione con il monitoraggio redis-cli, può essere veramente utile per imparare l'interno di NodeBB",
"explanation": "Simply check/uncheck the logging settings to enable or disable logging on the fly. No restart needed.", "explanation": "Simply check/uncheck the logging settings to enable or disable logging on the fly. No restart needed.",
"enable-http": "Enable HTTP logging", "enable-http": "Enable HTTP logging",
"enable-socket": "Enable socket.io event logging", "enable-socket": "Enable socket.io event logging",

@ -15,7 +15,7 @@
"invalid-username-or-password": "Молимо наведите и корисничко име и лозинку", "invalid-username-or-password": "Молимо наведите и корисничко име и лозинку",
"invalid-search-term": "Неисправан упит за претрагу", "invalid-search-term": "Неисправан упит за претрагу",
"csrf-invalid": "Нисмо успели да вас пријавимо, вероватно због истека сесије. Молимо покушајте поново", "csrf-invalid": "Нисмо успели да вас пријавимо, вероватно због истека сесије. Молимо покушајте поново",
"invalid-pagination-value": "Неважећа вредност при обележавању страна, мора бити најмање %1 а највише %2 ", "invalid-pagination-value": "Неважећа вредност приликом нумерисања страница, мора бити најмање %1 а највише %2 ",
"username-taken": "Корисничко име је заузето", "username-taken": "Корисничко име је заузето",
"email-taken": "Адреса е-поште је заузета", "email-taken": "Адреса е-поште је заузета",
"email-not-confirmed": "Ваша адреса е-поште још увек није оверена, кликните овде да би сте то учинили.", "email-not-confirmed": "Ваша адреса е-поште још увек није оверена, кликните овде да би сте то учинили.",

@ -21,7 +21,7 @@
"save_changes": "Сачувај измене", "save_changes": "Сачувај измене",
"save": "Сачувај", "save": "Сачувај",
"close": "Затвори", "close": "Затвори",
"pagination": "Обележавање страна", "pagination": "Нумерисање страница",
"pagination.out_of": "%1 од %2", "pagination.out_of": "%1 од %2",
"pagination.enter_index": "Унесите индекс", "pagination.enter_index": "Унесите индекс",
"header.admin": "Админ", "header.admin": "Админ",

@ -13,7 +13,7 @@
"notify_me": "Будите обавештени о новим порукама у овој теми", "notify_me": "Будите обавештени о новим порукама у овој теми",
"quote": "Цитирај", "quote": "Цитирај",
"reply": "Одговори", "reply": "Одговори",
"replies_to_this_post": "%1 одговора", "replies_to_this_post": "Одговора: %1",
"last_reply_time": "Последњи одговор", "last_reply_time": "Последњи одговор",
"reply-as-topic": "Постави одговор као тему", "reply-as-topic": "Постави одговор као тему",
"guest-login-reply": "Пријавите се да бисте одговорили", "guest-login-reply": "Пријавите се да бисте одговорили",

@ -90,7 +90,7 @@
"has_no_voted_posts": "Овај корисник нема објаве за које се гласало.", "has_no_voted_posts": "Овај корисник нема објаве за које се гласало.",
"email_hidden": "Скривена е-пошта", "email_hidden": "Скривена е-пошта",
"hidden": "скривена", "hidden": "скривена",
"paginate_description": "Подели теме и поруке по страницама уместо бесконачног скроловања", "paginate_description": "Нумериши теме и странице уместо бесконачног скроловања",
"topics_per_page": "Тема по страници", "topics_per_page": "Тема по страници",
"posts_per_page": "Порука по страници", "posts_per_page": "Порука по страници",
"notification_sounds": "Репродукуј звук приликом примања обавештења", "notification_sounds": "Репродукуј звук приликом примања обавештења",

@ -1,9 +1,9 @@
{ {
"chat-settings": "Sohbet Ayarları", "chat-settings": "Sohbet Ayarları",
"disable": "Sohbeti kapat", "disable": "Sohbeti kapat",
"disable-editing": "Disable chat message editing/deletion", "disable-editing": "Sohbet mesajlarını düzenlemeyi/silmeyi kapat",
"disable-editing-help": "Administrators and global moderators are exempt from this restriction", "disable-editing-help": "Administrators and global moderators are exempt from this restriction",
"max-length": "Maximum length of chat messages", "max-length": "Maksimum sohbet mesajı uzunluğu",
"max-room-size": "Maximum number of users in chat rooms", "max-room-size": "Maximum number of users in chat rooms",
"delay": "Time between chat messages in milliseconds" "delay": "Time between chat messages in milliseconds"
} }

@ -81,7 +81,10 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s
$('[data-toggle="tooltip"]').tooltip(); $('[data-toggle="tooltip"]').tooltip();
setupRealtimeButton(); setupRealtimeButton();
setupGraphs(); setupGraphs(function () {
socket.emit('admin.rooms.getAll', Admin.updateRoomUsage);
initiateDashboard();
});
}; };
Admin.updateRoomUsage = function (err, data) { Admin.updateRoomUsage = function (err, data) {
@ -159,7 +162,8 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s
} }
/* eslint-enable */ /* eslint-enable */
function setupGraphs() { function setupGraphs(callback) {
callback = callback || function () {};
var trafficCanvas = document.getElementById('analytics-traffic'); var trafficCanvas = document.getElementById('analytics-traffic');
var registeredCanvas = document.getElementById('analytics-registered'); var registeredCanvas = document.getElementById('analytics-registered');
var presenceCanvas = document.getElementById('analytics-presence'); var presenceCanvas = document.getElementById('analytics-presence');
@ -303,8 +307,12 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s
$(this).addClass('active'); $(this).addClass('active');
}); });
<<<<<<< HEAD
socket.emit('admin.rooms.getAll', Admin.updateRoomUsage); socket.emit('admin.rooms.getAll', Admin.updateRoomUsage);
initiateDashboard(); initiateDashboard();
=======
callback();
>>>>>>> origin/master
}); });
} }

@ -73,7 +73,7 @@ define('admin/modules/search', ['mousetrap'], function (mousetrap) {
if (!selected.length) { if (!selected.length) {
selected = menu.find('li.result > a').first().attr('href'); selected = menu.find('li.result > a').first().attr('href');
} }
var href = selected || config.relative_path + '/search/' + input.val(); var href = selected || config.relative_path + '/search?in=titlesposts&term=' + input.val();
ajaxify.go(href.replace(/^\//, '')); ajaxify.go(href.replace(/^\//, ''));
@ -140,7 +140,7 @@ define('admin/modules/search', ['mousetrap'], function (mousetrap) {
menu.find('.search-forum') menu.find('.search-forum')
.not('.divider') .not('.divider')
.find('a') .find('a')
.attr('href', config.relative_path + '/search/' + value) .attr('href', config.relative_path + '/search?in=titlesposts&term=' + value)
.find('strong') .find('strong')
.html(value); .html(value);
} else { } else {

@ -79,8 +79,8 @@ define('forum/account/edit/password', ['forum/account/header', 'translator'], fu
onPasswordConfirmChanged(); onPasswordConfirmChanged();
return app.alertError(err.message); return app.alertError(err.message);
} }
ajaxify.go('user/' + ajaxify.data.userslug);
app.alertSuccess('[[user:change_password_success]]'); window.location.href = config.relative_path + '/login';
}); });
} else { } else {
if (!passwordsmatch) { if (!passwordsmatch) {

@ -82,7 +82,7 @@ module.exports = function (middleware) {
picture: meta.config.defaultAvatar, picture: meta.config.defaultAvatar,
status: 'offline', status: 'offline',
reputation: 0, reputation: 0,
'email:confirmed': false, 'email:confirmed': 0,
}; };
if (req.uid) { if (req.uid) {
user.getUserFields(req.uid, Object.keys(userData), next); user.getUserFields(req.uid, Object.keys(userData), next);

@ -11,85 +11,90 @@ var batch = require('../batch');
module.exports = function (Topics) { module.exports = function (Topics) {
Topics.delete = function (tid, uid, callback) { Topics.delete = function (tid, uid, callback) {
Topics.getTopicFields(tid, ['cid'], function (err, topicData) { async.parallel([
if (err) { function (next) {
return callback(err); Topics.setTopicFields(tid, {
} deleted: 1,
deleterUid: uid,
async.parallel([ deletedTimestamp: Date.now(),
function (next) { }, next);
Topics.setTopicFields(tid, { },
deleted: 1, function (next) {
deleterUid: uid, db.sortedSetsRemove(['topics:recent', 'topics:posts', 'topics:views'], tid, next);
deletedTimestamp: Date.now(), },
}, next); function (next) {
}, async.waterfall([
function (next) { function (next) {
db.sortedSetsRemove(['topics:recent', 'topics:posts', 'topics:views'], tid, next); async.parallel({
}, cid: function (next) {
function (next) { Topics.getTopicField(tid, 'cid', next);
Topics.getPids(tid, function (err, pids) { },
if (err) { pids: function (next) {
return next(err); Topics.getPids(tid, next);
} },
db.sortedSetRemove('cid:' + topicData.cid + ':pids', pids, next); }, next);
}); },
}, function (results, next) {
], function (err) { db.sortedSetRemove('cid:' + results.cid + ':pids', results.pids, next);
callback(err); },
}); ], next);
},
], function (err) {
callback(err);
}); });
}; };
Topics.restore = function (tid, uid, callback) { Topics.restore = function (tid, uid, callback) {
Topics.getTopicFields(tid, ['cid', 'lastposttime', 'postcount', 'viewcount'], function (err, topicData) { var topicData;
if (err) { async.waterfall([
return callback(err); function (next) {
} Topics.getTopicFields(tid, ['cid', 'lastposttime', 'postcount', 'viewcount'], next);
},
async.parallel([ function (_topicData, next) {
function (next) { topicData = _topicData;
Topics.setTopicField(tid, 'deleted', 0, next); async.parallel([
}, function (next) {
function (next) { Topics.setTopicField(tid, 'deleted', 0, next);
Topics.deleteTopicFields(tid, ['deleterUid', 'deletedTimestamp'], next); },
}, function (next) {
function (next) { Topics.deleteTopicFields(tid, ['deleterUid', 'deletedTimestamp'], next);
Topics.updateRecent(tid, topicData.lastposttime, next); },
}, function (next) {
function (next) { Topics.updateRecent(tid, topicData.lastposttime, next);
db.sortedSetAdd('topics:posts', topicData.postcount, tid, next); },
}, function (next) {
function (next) { db.sortedSetAdd('topics:posts', topicData.postcount, tid, next);
db.sortedSetAdd('topics:views', topicData.viewcount, tid, next); },
}, function (next) {
function (next) { db.sortedSetAdd('topics:views', topicData.viewcount, tid, next);
Topics.getPids(tid, function (err, pids) { },
if (err) { function (next) {
return callback(err); async.waterfall([
} function (next) {
Topics.getPids(tid, next);
posts.getPostsFields(pids, ['pid', 'timestamp', 'deleted'], function (err, postData) { },
if (err) { function (pids, next) {
return next(err); posts.getPostsFields(pids, ['pid', 'timestamp', 'deleted'], next);
} },
postData = postData.filter(function (post) { function (postData, next) {
return post && parseInt(post.deleted, 10) !== 1; postData = postData.filter(function (post) {
}); return post && parseInt(post.deleted, 10) !== 1;
var pidsToAdd = []; });
var scores = []; var pidsToAdd = [];
postData.forEach(function (post) { var scores = [];
pidsToAdd.push(post.pid); postData.forEach(function (post) {
scores.push(post.timestamp); pidsToAdd.push(post.pid);
}); scores.push(post.timestamp);
db.sortedSetAdd('cid:' + topicData.cid + ':pids', scores, pidsToAdd, next); });
}); db.sortedSetAdd('cid:' + topicData.cid + ':pids', scores, pidsToAdd, next);
}); },
}, ], next);
], function (err) { },
callback(err); ], function (err) {
}); next(err);
}); });
},
], callback);
}; };
Topics.purgePostsAndTopic = function (tid, uid, callback) { Topics.purgePostsAndTopic = function (tid, uid, callback) {
@ -179,24 +184,28 @@ module.exports = function (Topics) {
} }
function deleteTopicFromCategoryAndUser(tid, callback) { function deleteTopicFromCategoryAndUser(tid, callback) {
Topics.getTopicFields(tid, ['cid', 'uid'], function (err, topicData) { async.waterfall([
if (err) { function (next) {
return callback(err); Topics.getTopicFields(tid, ['cid', 'uid'], next);
} },
async.parallel([ function (topicData, next) {
function (next) { async.parallel([
db.sortedSetsRemove([ function (next) {
'cid:' + topicData.cid + ':tids', db.sortedSetsRemove([
'cid:' + topicData.cid + ':tids:pinned', 'cid:' + topicData.cid + ':tids',
'cid:' + topicData.cid + ':tids:posts', 'cid:' + topicData.cid + ':tids:pinned',
'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids', 'cid:' + topicData.cid + ':tids:posts',
'uid:' + topicData.uid + ':topics', 'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids',
], tid, next); 'uid:' + topicData.uid + ':topics',
}, ], tid, next);
function (next) { },
user.decrementUserFieldBy(topicData.uid, 'topiccount', 1, next); function (next) {
}, user.decrementUserFieldBy(topicData.uid, 'topiccount', 1, next);
], callback); },
], next);
},
], function (err) {
callback(err);
}); });
} }
@ -207,26 +216,28 @@ module.exports = function (Topics) {
db.incrObjectFieldBy('global', 'topicCount', incr, next); db.incrObjectFieldBy('global', 'topicCount', incr, next);
}, },
function (next) { function (next) {
Topics.getTopicFields(tid, ['cid', 'postcount'], function (err, topicData) { async.waterfall([
if (err) { function (next) {
return next(err); Topics.getTopicFields(tid, ['cid', 'postcount'], next);
} },
topicData.postcount = parseInt(topicData.postcount, 10); function (topicData, next) {
topicData.postcount = topicData.postcount || 0; topicData.postcount = parseInt(topicData.postcount, 10);
var postCountChange = incr * topicData.postcount; topicData.postcount = topicData.postcount || 0;
var postCountChange = incr * topicData.postcount;
async.parallel([ async.parallel([
function (next) { function (next) {
db.incrObjectFieldBy('global', 'postCount', postCountChange, next); db.incrObjectFieldBy('global', 'postCount', postCountChange, next);
}, },
function (next) { function (next) {
db.incrObjectFieldBy('category:' + topicData.cid, 'post_count', postCountChange, next); db.incrObjectFieldBy('category:' + topicData.cid, 'post_count', postCountChange, next);
}, },
function (next) { function (next) {
db.incrObjectFieldBy('category:' + topicData.cid, 'topic_count', incr, next); db.incrObjectFieldBy('category:' + topicData.cid, 'topic_count', incr, next);
}, },
], next); ], next);
}); },
], next);
}, },
], callback); ], callback);
} }

@ -83,16 +83,21 @@ var emailer = require('../emailer');
} }
}); });
}, },
function (next) {
next(null, confirm_code);
},
], callback); ], callback);
}; };
UserEmail.confirm = function (code, callback) { UserEmail.confirm = function (code, callback) {
db.getObject('confirm:' + code, function (err, confirmObj) { async.waterfall([
if (err) { function (next) {
return callback(new Error('[[error:parse-error]]')); db.getObject('confirm:' + code, next);
} },
function (confirmObj, next) {
if (confirmObj && confirmObj.uid && confirmObj.email) { if (!confirmObj || !confirmObj.uid || !confirmObj.email) {
return next(new Error('[[error:invalid-data]]'));
}
async.series([ async.series([
async.apply(user.setUserField, confirmObj.uid, 'email:confirmed', 1), async.apply(user.setUserField, confirmObj.uid, 'email:confirmed', 1),
async.apply(db.delete, 'confirm:' + code), async.apply(db.delete, 'confirm:' + code),
@ -103,12 +108,10 @@ var emailer = require('../emailer');
function (next) { function (next) {
plugins.fireHook('action:user.email.confirmed', { uid: confirmObj.uid, email: confirmObj.email }, next); plugins.fireHook('action:user.email.confirmed', { uid: confirmObj.uid, email: confirmObj.email }, next);
}, },
], function (err) { ], next);
callback(err ? new Error('[[error:email-confirm-failed]]') : null); },
}); ], function (err) {
} else { callback(err);
callback(new Error('[[error:invalid-data]]'));
}
}); });
}; };
}(exports)); }(exports));

@ -279,6 +279,7 @@ module.exports = function (User) {
async.parallel([ async.parallel([
async.apply(User.setUserField, data.uid, 'password', hashedPassword), async.apply(User.setUserField, data.uid, 'password', hashedPassword),
async.apply(User.reset.updateExpiry, data.uid), async.apply(User.reset.updateExpiry, data.uid),
async.apply(User.auth.revokeAllSessions, data.uid),
], function (err) { ], function (err) {
next(err); next(err);
}); });

@ -399,19 +399,22 @@ describe('User', function () {
}); });
it('should change a user\'s password', function (done) { it('should change a user\'s password', function (done) {
this.timeout(20000); var socketUser = require('../src/socket.io/user');
io.emit('user.changePassword', { uid: uid, newPassword: '654321', currentPassword: '123456' }, function (err) { User.create({ username: 'changepassword', password: '123456' }, function (err, uid) {
assert.ifError(err); assert.ifError(err);
User.isPasswordCorrect(uid, '654321', function (err, correct) { socketUser.changePassword({ uid: uid }, { uid: uid, newPassword: '654321', currentPassword: '123456' }, function (err) {
assert.ifError(err); assert.ifError(err);
assert(correct); User.isPasswordCorrect(uid, '654321', function (err, correct) {
done(); assert.ifError(err);
assert(correct);
done();
});
}); });
}); });
}); });
it('should change username', function (done) { it('should change username', function (done) {
io.emit('user.changeUsernameEmail', { uid: uid, username: 'updatedAgain', password: '654321' }, function (err) { io.emit('user.changeUsernameEmail', { uid: uid, username: 'updatedAgain', password: '123456' }, function (err) {
assert.ifError(err); assert.ifError(err);
db.getObjectField('user:' + uid, 'username', function (err, username) { db.getObjectField('user:' + uid, 'username', function (err, username) {
assert.ifError(err); assert.ifError(err);
@ -422,7 +425,7 @@ describe('User', function () {
}); });
it('should change email', function (done) { it('should change email', function (done) {
io.emit('user.changeUsernameEmail', { uid: uid, email: 'updatedAgain@me.com', password: '654321' }, function (err) { io.emit('user.changeUsernameEmail', { uid: uid, email: 'updatedAgain@me.com', password: '123456' }, function (err) {
assert.ifError(err); assert.ifError(err);
db.getObjectField('user:' + uid, 'email', function (err, email) { db.getObjectField('user:' + uid, 'email', function (err, email) {
assert.ifError(err); assert.ifError(err);
@ -1152,6 +1155,45 @@ describe('User', function () {
}); });
}); });
describe('email confirm', function () {
it('should error with invalid code', function (done) {
User.email.confirm('asdasda', function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should confirm email of user', function (done) {
var email = 'confirm@me.com';
User.create({
username: 'confirme',
email: email,
}, function (err, uid) {
assert.ifError(err);
User.email.sendValidationEmail(uid, email, function (err, code) {
assert.ifError(err);
User.email.confirm(code, function (err) {
assert.ifError(err);
async.parallel({
confirmed: function (next) {
db.getObjectField('user:' + uid, 'email:confirmed', next);
},
isMember: function (next) {
db.isSortedSetMember('users:notvalidated', uid, next);
},
}, function (err, results) {
assert.ifError(err);
assert.equal(results.confirmed, 1);
assert.equal(results.isMember, false);
done();
});
});
});
});
});
});
after(function (done) { after(function (done) {
db.emptydb(done); db.emptydb(done);

Loading…
Cancel
Save