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,
});
fs.writeFile(pidFilePath, process.pid);
fs.writeFileSync(pidFilePath, process.pid);
}
async.series([

@ -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",

@ -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"

@ -1,14 +1,14 @@
{
"figure-x": "Figure %1",
"error-events-per-day": "<code>%1</code> 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": "<code>%1</code> 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"
}

@ -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"
}

@ -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!"
}

@ -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 <code>&lt;head&gt;</code> 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 <code>&lt;head&gt;</code> sezione del markup del tuo forum",
"custom-header.enable": "Abilita l'Intestazione Personalizzata"
}

@ -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"
}

@ -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"
}

@ -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",
"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"
}

@ -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",

@ -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": "Ваша адреса е-поште још увек није оверена, кликните овде да би сте то учинили.",

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

@ -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": "Пријавите се да бисте одговорили",

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

@ -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"
}

@ -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
});
}

@ -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 {

@ -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) {

@ -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);

@ -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);
}

@ -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));

@ -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);
});

@ -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);

Loading…
Cancel
Save