diff --git a/loader.js b/loader.js index 38009f4691..654d77fb23 100644 --- a/loader.js +++ b/loader.js @@ -223,7 +223,7 @@ fs.open(path.join(__dirname, 'config.json'), 'r', function (err) { stderr: process.stderr, }); - fs.writeFile(pidFilePath, process.pid); + fs.writeFileSync(pidFilePath, process.pid); } async.series([ diff --git a/package.json b/package.json index add7cde955..5b65483516 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "nodebb-plugin-soundpack-default": "1.0.0", "nodebb-plugin-spam-be-gone": "0.4.13", "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-vanilla": "5.2.0", "nodebb-widget-essentials": "2.0.13", diff --git a/public/language/it/admin/advanced/database.json b/public/language/it/admin/advanced/database.json index 33dc5f4934..53404f0915 100644 --- a/public/language/it/admin/advanced/database.json +++ b/public/language/it/admin/advanced/database.json @@ -8,27 +8,27 @@ "mongo.version": "Versione MongoDB", "mongo.storage-engine": "Storage Engine", "mongo.collections": "Collections", - "mongo.objects": "Objects", - "mongo.avg-object-size": "Avg. Object Size", - "mongo.data-size": "Data Size", - "mongo.storage-size": "Storage Size", - "mongo.index-size": "Index Size", - "mongo.file-size": "File Size", - "mongo.resident-memory": "Resident Memory", - "mongo.virtual-memory": "Virtual Memory", - "mongo.mapped-memory": "Mapped Memory", + "mongo.objects": "Oggetti", + "mongo.avg-object-size": "Dimensione Media dell'Oggetto", + "mongo.data-size": "Dimensione del Data", + "mongo.storage-size": "Dimensione dello Spazio di Archiviazione", + "mongo.index-size": "Dimensione dell'Indice", + "mongo.file-size": "Dimensione del file", + "mongo.resident-memory": "Memoria Allocata", + "mongo.virtual-memory": "Memoria Virtuale", + "mongo.mapped-memory": "Memoria Mappata", "mongo.raw-info": "MongoDB Raw Info", "redis": "Redis", - "redis.version": "Redis Version", - "redis.connected-clients": "Connected Clients", + "redis.version": "Versione Redis", + "redis.connected-clients": "Clients Connessi", "redis.connected-slaves": "Connected Slaves", - "redis.blocked-clients": "Blocked Clients", - "redis.used-memory": "Used Memory", - "redis.memory-frag-ratio": "Memory Fragmentation Ratio", - "redis.total-connections-recieved": "Total Connections Received", - "redis.total-commands-processed": "Total Commands Processed", - "redis.iops": "Instantaneous Ops. Per Second", + "redis.blocked-clients": "Clients Bloccati", + "redis.used-memory": "Memoria Usata", + "redis.memory-frag-ratio": "Rateo della Frammentazione della Memoria", + "redis.total-connections-recieved": "Totale Connessioni Ricevute", + "redis.total-commands-processed": "Totale Comandi Processati", + "redis.iops": "Operazioni Instantanee al Secondo", "redis.keyspace-hits": "Keyspace Hits", "redis.keyspace-misses": "Keyspace Misses", "redis.raw-info": "Redis Raw Info" diff --git a/public/language/it/admin/advanced/errors.json b/public/language/it/admin/advanced/errors.json index 546f0f1508..ca148b1236 100644 --- a/public/language/it/admin/advanced/errors.json +++ b/public/language/it/admin/advanced/errors.json @@ -1,14 +1,14 @@ { - "figure-x": "Figure %1", - "error-events-per-day": "%1 events per day", - "error.404": "404 Not Found", - "error.503": "503 Service Unavailable", - "manage-error-log": "Manage Error Log", - "export-error-log": "Export Error Log (CSV)", - "clear-error-log": "Clear Error Log", - "route": "Route", - "count": "Count", - "no-routes-not-found": "Hooray! No 404 errors!", - "clear404-confirm": "Are you sure you wish to clear the 404 error logs?", - "clear404-success": "\"404 Not Found\" errors cleared" + "figure-x": "Figura %1", + "error-events-per-day": "%1 eventi per giorno", + "error.404": "404 Non Trovato", + "error.503": "503 Servizio Non Disponibile", + "manage-error-log": "Gestisci il Registro degli Errori", + "export-error-log": "Esporta il Registro degli Errori (CSV)", + "clear-error-log": "Cancella il Registro degli Errori", + "route": "Strada", + "count": "Numero", + "no-routes-not-found": "Hooray! Nessun Errore 404!", + "clear404-confirm": "Sei sicuro di voler cancellare il Registro degli Errori 404?", + "clear404-success": "Error \"404 Non Trovato\" Cancellati" } \ No newline at end of file diff --git a/public/language/it/admin/advanced/events.json b/public/language/it/admin/advanced/events.json index 766eb5e951..ca64e626db 100644 --- a/public/language/it/admin/advanced/events.json +++ b/public/language/it/admin/advanced/events.json @@ -1,6 +1,6 @@ { - "events": "Events", - "no-events": "There are no events", - "control-panel": "Events Control Panel", - "delete-events": "Delete Events" + "events": "Eventi", + "no-events": "Non ci sono Eventi", + "control-panel": "Pannello di controllo degli Eventi", + "delete-events": "Cancella gli Eventi" } \ No newline at end of file diff --git a/public/language/it/admin/advanced/logs.json b/public/language/it/admin/advanced/logs.json index b9de400e1c..72b330fb5c 100644 --- a/public/language/it/admin/advanced/logs.json +++ b/public/language/it/admin/advanced/logs.json @@ -1,7 +1,7 @@ { - "logs": "Logs", - "control-panel": "Logs Control Panel", - "reload": "Reload Logs", - "clear": "Clear Logs", - "clear-success": "Logs Cleared!" + "logs": "Registri", + "control-panel": "Pannello di Controllo dei Registri", + "reload": "Ricarica i Registri", + "clear": "Cancella i Registri", + "clear-success": "Registri Cancellati!" } \ No newline at end of file diff --git a/public/language/it/admin/appearance/customise.json b/public/language/it/admin/appearance/customise.json index 767d443e29..c97943fd6f 100644 --- a/public/language/it/admin/appearance/customise.json +++ b/public/language/it/admin/appearance/customise.json @@ -1,9 +1,9 @@ { - "custom-css": "Custom CSS", - "custom-css.description": "Enter your own CSS declarations here, which will be applied after all other styles.", - "custom-css.enable": "Enable Custom CSS", + "custom-css": "CSS Personalizzato", + "custom-css.description": "Inserisci le tue dichiarazioni CSS qui, verranno applicate dopo tutti gli altri stili.", + "custom-css.enable": "Abilita CSS Personalizzato", - "custom-header": "Custom Header", - "custom-header.description": "Enter custom HTML here (ex. JavaScript, Meta Tags, etc.), which will be appended to the <head> section of your forum's markup.", - "custom-header.enable": "Enable Custom Header" + "custom-header": "Intestazione Personalizzata", + "custom-header.description": "Inserisci l' HTML personalizzato qui (es. JavaScript, Meta Tags, ecc.), verrà attaccato al codice <head> sezione del markup del tuo forum", + "custom-header.enable": "Abilita l'Intestazione Personalizzata" } \ No newline at end of file diff --git a/public/language/it/admin/appearance/skins.json b/public/language/it/admin/appearance/skins.json index 4db6fbdd8a..e7c26359b5 100644 --- a/public/language/it/admin/appearance/skins.json +++ b/public/language/it/admin/appearance/skins.json @@ -1,9 +1,9 @@ { - "loading": "Loading Skins...", - "homepage": "Homepage", - "select-skin": "Select Skin", - "current-skin": "Current Skin", - "skin-updated": "Skin Updated", - "applied-success": "%1 skin was succesfully applied", - "revert-success": "Skin reverted to base colours" + "loading": "Caricamento Skins", + "homepage": "Pagina Home", + "select-skin": "Seleziona la Skin", + "current-skin": "Skin Corrente", + "skin-updated": "Skin Aggiornata", + "applied-success": "%1 skin è stata applicata con successo", + "revert-success": "Skin riportata ai colori base" } \ No newline at end of file diff --git a/public/language/it/admin/appearance/themes.json b/public/language/it/admin/appearance/themes.json index 3148a01337..1406bb9276 100644 --- a/public/language/it/admin/appearance/themes.json +++ b/public/language/it/admin/appearance/themes.json @@ -1,11 +1,11 @@ { - "checking-for-installed": "Checking for installed themes...", - "homepage": "Homepage", - "select-theme": "Select Theme", - "current-theme": "Current Theme", - "no-themes": "No installed themes found", - "revert-confirm": "Are you sure you wish to restore the default NodeBB theme?", - "theme-changed": "Theme Changed", - "revert-success": "You have successfully reverted your NodeBB back to it's default theme.", - "restart-to-activate": "Please restart your NodeBB to fully activate this theme" + "checking-for-installed": "Controllando se ci sono temi installati...", + "homepage": "Pagina Home", + "select-theme": "Seleziona il Tema", + "current-theme": "Tema Corrente", + "no-themes": "Nessun tema installato trovato", + "revert-confirm": "Sei sicuro di voler ripristinare al tema originale di NodeBB?", + "theme-changed": "Tema Cambiato", + "revert-success": "Hai correttamente ripristinato il tuo NodeBB al tema originale.", + "restart-to-activate": "Perfavore riavvia il tuo NodeBB per attivare correttamente questo tema" } \ No newline at end of file diff --git a/public/language/it/admin/development/info.json b/public/language/it/admin/development/info.json index b2768ca212..38e991ebd6 100644 --- a/public/language/it/admin/development/info.json +++ b/public/language/it/admin/development/info.json @@ -1,16 +1,16 @@ { - "you-are-on": "Info - You are on %1:%2", + "you-are-on": "Informazione - Tu sei su %1:%2", "host": "host", "pid": "pid", "nodejs": "nodejs", "online": "online", "git": "git", - "load": "load", - "uptime": "uptime", + "load": "carica", + "uptime": "tempo di caricamento", - "registered": "Registered", + "registered": "Registrato", "sockets": "Sockets", - "guests": "Guests", + "guests": "Ospiti", - "info": "Info" + "info": "Informazioni" } \ No newline at end of file diff --git a/public/language/it/admin/development/logger.json b/public/language/it/admin/development/logger.json index 6ab9558149..ea6fc6a8c7 100644 --- a/public/language/it/admin/development/logger.json +++ b/public/language/it/admin/development/logger.json @@ -1,6 +1,6 @@ { - "logger-settings": "Logger Settings", - "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.", + "logger-settings": "Impostazioni del Registratore", + "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.", "enable-http": "Enable HTTP logging", "enable-socket": "Enable socket.io event logging", diff --git a/public/language/sr/error.json b/public/language/sr/error.json index 67f18374c3..fb4e7993a4 100644 --- a/public/language/sr/error.json +++ b/public/language/sr/error.json @@ -15,7 +15,7 @@ "invalid-username-or-password": "Молимо наведите и корисничко име и лозинку", "invalid-search-term": "Неисправан упит за претрагу", "csrf-invalid": "Нисмо успели да вас пријавимо, вероватно због истека сесије. Молимо покушајте поново", - "invalid-pagination-value": "Неважећа вредност при обележавању страна, мора бити најмање %1 а највише %2 ", + "invalid-pagination-value": "Неважећа вредност приликом нумерисања страница, мора бити најмање %1 а највише %2 ", "username-taken": "Корисничко име је заузето", "email-taken": "Адреса е-поште је заузета", "email-not-confirmed": "Ваша адреса е-поште још увек није оверена, кликните овде да би сте то учинили.", diff --git a/public/language/sr/global.json b/public/language/sr/global.json index cb938fa889..a66b424eef 100644 --- a/public/language/sr/global.json +++ b/public/language/sr/global.json @@ -21,7 +21,7 @@ "save_changes": "Сачувај измене", "save": "Сачувај", "close": "Затвори", - "pagination": "Обележавање страна", + "pagination": "Нумерисање страница", "pagination.out_of": "%1 од %2", "pagination.enter_index": "Унесите индекс", "header.admin": "Админ", diff --git a/public/language/sr/topic.json b/public/language/sr/topic.json index 3992fad51d..95655a8162 100644 --- a/public/language/sr/topic.json +++ b/public/language/sr/topic.json @@ -13,7 +13,7 @@ "notify_me": "Будите обавештени о новим порукама у овој теми", "quote": "Цитирај", "reply": "Одговори", - "replies_to_this_post": "%1 одговора", + "replies_to_this_post": "Одговора: %1", "last_reply_time": "Последњи одговор", "reply-as-topic": "Постави одговор као тему", "guest-login-reply": "Пријавите се да бисте одговорили", diff --git a/public/language/sr/user.json b/public/language/sr/user.json index 62a64140a7..86b2264429 100644 --- a/public/language/sr/user.json +++ b/public/language/sr/user.json @@ -90,7 +90,7 @@ "has_no_voted_posts": "Овај корисник нема објаве за које се гласало.", "email_hidden": "Скривена е-пошта", "hidden": "скривена", - "paginate_description": "Подели теме и поруке по страницама уместо бесконачног скроловања", + "paginate_description": "Нумериши теме и странице уместо бесконачног скроловања", "topics_per_page": "Тема по страници", "posts_per_page": "Порука по страници", "notification_sounds": "Репродукуј звук приликом примања обавештења", diff --git a/public/language/tr/admin/settings/chat.json b/public/language/tr/admin/settings/chat.json index ea8de84c54..a695d56607 100644 --- a/public/language/tr/admin/settings/chat.json +++ b/public/language/tr/admin/settings/chat.json @@ -1,9 +1,9 @@ { "chat-settings": "Sohbet Ayarları", "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", - "max-length": "Maximum length of chat messages", + "max-length": "Maksimum sohbet mesajı uzunluğu", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds" } \ No newline at end of file diff --git a/public/src/admin/general/dashboard.js b/public/src/admin/general/dashboard.js index 696ad80fae..38d324cbcd 100644 --- a/public/src/admin/general/dashboard.js +++ b/public/src/admin/general/dashboard.js @@ -81,7 +81,10 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s $('[data-toggle="tooltip"]').tooltip(); setupRealtimeButton(); - setupGraphs(); + setupGraphs(function () { + socket.emit('admin.rooms.getAll', Admin.updateRoomUsage); + initiateDashboard(); + }); }; Admin.updateRoomUsage = function (err, data) { @@ -159,7 +162,8 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s } /* eslint-enable */ - function setupGraphs() { + function setupGraphs(callback) { + callback = callback || function () {}; var trafficCanvas = document.getElementById('analytics-traffic'); var registeredCanvas = document.getElementById('analytics-registered'); var presenceCanvas = document.getElementById('analytics-presence'); @@ -303,8 +307,12 @@ define('admin/general/dashboard', ['semver', 'Chart', 'translator'], function (s $(this).addClass('active'); }); +<<<<<<< HEAD socket.emit('admin.rooms.getAll', Admin.updateRoomUsage); initiateDashboard(); +======= + callback(); +>>>>>>> origin/master }); } diff --git a/public/src/admin/modules/search.js b/public/src/admin/modules/search.js index e950ea76c5..c52008fdab 100644 --- a/public/src/admin/modules/search.js +++ b/public/src/admin/modules/search.js @@ -73,7 +73,7 @@ define('admin/modules/search', ['mousetrap'], function (mousetrap) { if (!selected.length) { 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(/^\//, '')); @@ -140,7 +140,7 @@ define('admin/modules/search', ['mousetrap'], function (mousetrap) { menu.find('.search-forum') .not('.divider') .find('a') - .attr('href', config.relative_path + '/search/' + value) + .attr('href', config.relative_path + '/search?in=titlesposts&term=' + value) .find('strong') .html(value); } else { diff --git a/public/src/client/account/edit/password.js b/public/src/client/account/edit/password.js index e6fccf46e5..d2239b36a0 100644 --- a/public/src/client/account/edit/password.js +++ b/public/src/client/account/edit/password.js @@ -79,8 +79,8 @@ define('forum/account/edit/password', ['forum/account/header', 'translator'], fu onPasswordConfirmChanged(); 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 { if (!passwordsmatch) { diff --git a/src/middleware/header.js b/src/middleware/header.js index e5d4de66bb..70c0755def 100644 --- a/src/middleware/header.js +++ b/src/middleware/header.js @@ -82,7 +82,7 @@ module.exports = function (middleware) { picture: meta.config.defaultAvatar, status: 'offline', reputation: 0, - 'email:confirmed': false, + 'email:confirmed': 0, }; if (req.uid) { user.getUserFields(req.uid, Object.keys(userData), next); diff --git a/src/topics/delete.js b/src/topics/delete.js index 3598248d26..67e8bdf230 100644 --- a/src/topics/delete.js +++ b/src/topics/delete.js @@ -11,85 +11,90 @@ var batch = require('../batch'); module.exports = function (Topics) { Topics.delete = function (tid, uid, callback) { - Topics.getTopicFields(tid, ['cid'], function (err, topicData) { - if (err) { - return callback(err); - } - - async.parallel([ - function (next) { - Topics.setTopicFields(tid, { - deleted: 1, - deleterUid: uid, - deletedTimestamp: Date.now(), - }, next); - }, - function (next) { - db.sortedSetsRemove(['topics:recent', 'topics:posts', 'topics:views'], tid, next); - }, - function (next) { - Topics.getPids(tid, function (err, pids) { - if (err) { - return next(err); - } - db.sortedSetRemove('cid:' + topicData.cid + ':pids', pids, next); - }); - }, - ], function (err) { - callback(err); - }); + async.parallel([ + function (next) { + Topics.setTopicFields(tid, { + deleted: 1, + deleterUid: uid, + deletedTimestamp: Date.now(), + }, next); + }, + function (next) { + db.sortedSetsRemove(['topics:recent', 'topics:posts', 'topics:views'], tid, next); + }, + function (next) { + async.waterfall([ + function (next) { + async.parallel({ + cid: function (next) { + Topics.getTopicField(tid, 'cid', next); + }, + pids: function (next) { + Topics.getPids(tid, next); + }, + }, next); + }, + function (results, next) { + db.sortedSetRemove('cid:' + results.cid + ':pids', results.pids, next); + }, + ], next); + }, + ], function (err) { + callback(err); }); }; Topics.restore = function (tid, uid, callback) { - Topics.getTopicFields(tid, ['cid', 'lastposttime', 'postcount', 'viewcount'], function (err, topicData) { - if (err) { - return callback(err); - } - - async.parallel([ - function (next) { - Topics.setTopicField(tid, 'deleted', 0, next); - }, - function (next) { - Topics.deleteTopicFields(tid, ['deleterUid', 'deletedTimestamp'], next); - }, - function (next) { - Topics.updateRecent(tid, topicData.lastposttime, next); - }, - function (next) { - db.sortedSetAdd('topics:posts', topicData.postcount, tid, next); - }, - function (next) { - db.sortedSetAdd('topics:views', topicData.viewcount, tid, next); - }, - function (next) { - Topics.getPids(tid, function (err, pids) { - if (err) { - return callback(err); - } - - posts.getPostsFields(pids, ['pid', 'timestamp', 'deleted'], function (err, postData) { - if (err) { - return next(err); - } - postData = postData.filter(function (post) { - return post && parseInt(post.deleted, 10) !== 1; - }); - var pidsToAdd = []; - var scores = []; - postData.forEach(function (post) { - pidsToAdd.push(post.pid); - scores.push(post.timestamp); - }); - db.sortedSetAdd('cid:' + topicData.cid + ':pids', scores, pidsToAdd, next); - }); - }); - }, - ], function (err) { - callback(err); - }); - }); + var topicData; + async.waterfall([ + function (next) { + Topics.getTopicFields(tid, ['cid', 'lastposttime', 'postcount', 'viewcount'], next); + }, + function (_topicData, next) { + topicData = _topicData; + async.parallel([ + function (next) { + Topics.setTopicField(tid, 'deleted', 0, next); + }, + function (next) { + Topics.deleteTopicFields(tid, ['deleterUid', 'deletedTimestamp'], next); + }, + function (next) { + Topics.updateRecent(tid, topicData.lastposttime, next); + }, + function (next) { + db.sortedSetAdd('topics:posts', topicData.postcount, tid, next); + }, + function (next) { + db.sortedSetAdd('topics:views', topicData.viewcount, tid, next); + }, + function (next) { + async.waterfall([ + function (next) { + Topics.getPids(tid, next); + }, + function (pids, next) { + posts.getPostsFields(pids, ['pid', 'timestamp', 'deleted'], next); + }, + function (postData, next) { + postData = postData.filter(function (post) { + return post && parseInt(post.deleted, 10) !== 1; + }); + var pidsToAdd = []; + var scores = []; + postData.forEach(function (post) { + pidsToAdd.push(post.pid); + scores.push(post.timestamp); + }); + db.sortedSetAdd('cid:' + topicData.cid + ':pids', scores, pidsToAdd, next); + }, + ], next); + }, + ], function (err) { + next(err); + }); + }, + ], callback); }; Topics.purgePostsAndTopic = function (tid, uid, callback) { @@ -179,24 +184,28 @@ module.exports = function (Topics) { } function deleteTopicFromCategoryAndUser(tid, callback) { - Topics.getTopicFields(tid, ['cid', 'uid'], function (err, topicData) { - if (err) { - return callback(err); - } - async.parallel([ - function (next) { - db.sortedSetsRemove([ - 'cid:' + topicData.cid + ':tids', - 'cid:' + topicData.cid + ':tids:pinned', - 'cid:' + topicData.cid + ':tids:posts', - 'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids', - 'uid:' + topicData.uid + ':topics', - ], tid, next); - }, - function (next) { - user.decrementUserFieldBy(topicData.uid, 'topiccount', 1, next); - }, - ], callback); + async.waterfall([ + function (next) { + Topics.getTopicFields(tid, ['cid', 'uid'], next); + }, + function (topicData, next) { + async.parallel([ + function (next) { + db.sortedSetsRemove([ + 'cid:' + topicData.cid + ':tids', + 'cid:' + topicData.cid + ':tids:pinned', + 'cid:' + topicData.cid + ':tids:posts', + 'cid:' + topicData.cid + ':uid:' + topicData.uid + ':tids', + 'uid:' + topicData.uid + ':topics', + ], tid, next); + }, + function (next) { + user.decrementUserFieldBy(topicData.uid, 'topiccount', 1, next); + }, + ], next); + }, + ], function (err) { + callback(err); }); } @@ -207,26 +216,28 @@ module.exports = function (Topics) { db.incrObjectFieldBy('global', 'topicCount', incr, next); }, function (next) { - Topics.getTopicFields(tid, ['cid', 'postcount'], function (err, topicData) { - if (err) { - return next(err); - } - topicData.postcount = parseInt(topicData.postcount, 10); - topicData.postcount = topicData.postcount || 0; - var postCountChange = incr * topicData.postcount; + async.waterfall([ + function (next) { + Topics.getTopicFields(tid, ['cid', 'postcount'], next); + }, + function (topicData, next) { + topicData.postcount = parseInt(topicData.postcount, 10); + topicData.postcount = topicData.postcount || 0; + var postCountChange = incr * topicData.postcount; - async.parallel([ - function (next) { - db.incrObjectFieldBy('global', 'postCount', postCountChange, next); - }, - function (next) { - db.incrObjectFieldBy('category:' + topicData.cid, 'post_count', postCountChange, next); - }, - function (next) { - db.incrObjectFieldBy('category:' + topicData.cid, 'topic_count', incr, next); - }, - ], next); - }); + async.parallel([ + function (next) { + db.incrObjectFieldBy('global', 'postCount', postCountChange, next); + }, + function (next) { + db.incrObjectFieldBy('category:' + topicData.cid, 'post_count', postCountChange, next); + }, + function (next) { + db.incrObjectFieldBy('category:' + topicData.cid, 'topic_count', incr, next); + }, + ], next); + }, + ], next); }, ], callback); } diff --git a/src/user/email.js b/src/user/email.js index f75ff9cf9b..8b8919c73a 100644 --- a/src/user/email.js +++ b/src/user/email.js @@ -83,16 +83,21 @@ var emailer = require('../emailer'); } }); }, + function (next) { + next(null, confirm_code); + }, ], callback); }; UserEmail.confirm = function (code, callback) { - db.getObject('confirm:' + code, function (err, confirmObj) { - if (err) { - return callback(new Error('[[error:parse-error]]')); - } - - if (confirmObj && confirmObj.uid && confirmObj.email) { + async.waterfall([ + function (next) { + db.getObject('confirm:' + code, next); + }, + function (confirmObj, next) { + if (!confirmObj || !confirmObj.uid || !confirmObj.email) { + return next(new Error('[[error:invalid-data]]')); + } async.series([ async.apply(user.setUserField, confirmObj.uid, 'email:confirmed', 1), async.apply(db.delete, 'confirm:' + code), @@ -103,12 +108,10 @@ var emailer = require('../emailer'); function (next) { plugins.fireHook('action:user.email.confirmed', { uid: confirmObj.uid, email: confirmObj.email }, next); }, - ], function (err) { - callback(err ? new Error('[[error:email-confirm-failed]]') : null); - }); - } else { - callback(new Error('[[error:invalid-data]]')); - } + ], next); + }, + ], function (err) { + callback(err); }); }; }(exports)); diff --git a/src/user/profile.js b/src/user/profile.js index 3071977949..e05d3198f3 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -279,6 +279,7 @@ module.exports = function (User) { async.parallel([ async.apply(User.setUserField, data.uid, 'password', hashedPassword), async.apply(User.reset.updateExpiry, data.uid), + async.apply(User.auth.revokeAllSessions, data.uid), ], function (err) { next(err); }); diff --git a/test/user.js b/test/user.js index 468ab9b0b4..ece3881d66 100644 --- a/test/user.js +++ b/test/user.js @@ -399,19 +399,22 @@ describe('User', function () { }); it('should change a user\'s password', function (done) { - this.timeout(20000); - io.emit('user.changePassword', { uid: uid, newPassword: '654321', currentPassword: '123456' }, function (err) { + var socketUser = require('../src/socket.io/user'); + User.create({ username: 'changepassword', password: '123456' }, function (err, uid) { 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(correct); - done(); + User.isPasswordCorrect(uid, '654321', function (err, correct) { + assert.ifError(err); + assert(correct); + 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); db.getObjectField('user:' + uid, 'username', function (err, username) { assert.ifError(err); @@ -422,7 +425,7 @@ describe('User', function () { }); 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); db.getObjectField('user:' + uid, 'email', function (err, email) { 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) { db.emptydb(done);