diff --git a/src/controllers/index.js b/src/controllers/index.js index ceef355cc9..8be1668684 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -205,7 +205,7 @@ Controllers.registerInterstitial = async function (req, res, next) { }; Controllers.confirmEmail = function (req, res) { - user.email.confirm(req.params.code, function (err) { + user.email.confirmByCode(req.params.code, function (err) { res.render('confirm', { error: err ? err.message : '', title: '[[pages:confirm]]', diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index 65201d50d3..a0070d7d37 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -73,11 +73,8 @@ User.validateEmail = async function (socket, uids) { throw new Error('[[error:invalid-data]]'); } - uids = uids.filter(uid => parseInt(uid, 10)); - await db.setObjectField(uids.map(uid => 'user:' + uid), 'email:confirmed', 1); for (const uid of uids) { - await groups.join('verified-users', uid); - await groups.leave('unverified-users', uid); + await user.email.confirmByUid(uid); } }; diff --git a/src/user/email.js b/src/user/email.js index 92e05aa873..08aa37a347 100644 --- a/src/user/email.js +++ b/src/user/email.js @@ -1,17 +1,18 @@ 'use strict'; -var nconf = require('nconf'); - -var user = require('./index'); -var utils = require('../utils'); -var plugins = require('../plugins'); -var db = require('../database'); -var meta = require('../meta'); -var emailer = require('../emailer'); +const nconf = require('nconf'); +const winston = require('winston'); + +const user = require('./index'); +const utils = require('../utils'); +const plugins = require('../plugins'); +const db = require('../database'); +const meta = require('../meta'); +const emailer = require('../emailer'); const groups = require('../groups'); -var UserEmail = module.exports; +const UserEmail = module.exports; UserEmail.exists = async function (email) { const uid = await user.getUidByEmail(email.toLowerCase()); @@ -88,6 +89,13 @@ UserEmail.sendValidationEmail = async function (uid, options) { }; UserEmail.confirm = async function (code) { + // TODO: remove in 1.17.0 + winston.warn('[deprecated] User.email.confirm deprecated use User.email.confirmByCode'); + await UserEmail.confirmByCode(code); +}; + +// confirm email by code sent by confirmation email +UserEmail.confirmByCode = async function (code) { const confirmObj = await db.getObject('confirm:' + code); if (!confirmObj || !confirmObj.uid || !confirmObj.email) { throw new Error('[[error:invalid-data]]'); @@ -96,10 +104,24 @@ UserEmail.confirm = async function (code) { if (!currentEmail || currentEmail.toLowerCase() !== confirmObj.email) { throw new Error('[[error:invalid-email]]'); } - await user.setUserField(confirmObj.uid, 'email:confirmed', 1); - await groups.join('verified-users', confirmObj.uid); - await groups.leave('unverified-users', confirmObj.uid); + await UserEmail.confirmByUid(confirmObj.uid); await db.delete('confirm:' + code); - await db.delete('uid:' + confirmObj.uid + ':confirm:email:sent'); - await plugins.hooks.fire('action:user.email.confirmed', { uid: confirmObj.uid, email: confirmObj.email }); +}; + +// confirm uid's email +UserEmail.confirmByUid = async function (uid) { + if (!(parseInt(uid, 10) > 0)) { + throw new Error('[[error:invalid-uid]]'); + } + const currentEmail = await user.getUserField(uid, 'email'); + if (!currentEmail) { + throw new Error('[[error:invalid-email]]'); + } + await Promise.all([ + user.setUserField(uid, 'email:confirmed', 1), + groups.join('verified-users', uid), + groups.leave('unverified-users', uid), + db.delete('uid:' + uid + ':confirm:email:sent'), + ]); + await plugins.hooks.fire('action:user.email.confirmed', { uid: uid, email: currentEmail }); }; diff --git a/test/user.js b/test/user.js index 2857a1b0f2..253657afa2 100644 --- a/test/user.js +++ b/test/user.js @@ -2335,7 +2335,7 @@ describe('User', function () { describe('email confirm', function () { it('should error with invalid code', function (done) { - User.email.confirm('asdasda', function (err) { + User.email.confirmByCode('asdasda', function (err) { assert.equal(err.message, '[[error:invalid-data]]'); done(); }); @@ -2351,7 +2351,25 @@ describe('User', function () { const code = await User.email.sendValidationEmail(uid, email); const unverified = await groups.isMember(uid, 'unverified-users'); assert.strictEqual(unverified, true); - await User.email.confirm(code); + await User.email.confirmByCode(code); + const [confirmed, isVerified] = await Promise.all([ + db.getObjectField('user:' + uid, 'email:confirmed'), + groups.isMember(uid, 'verified-users', uid), + ]); + assert.strictEqual(parseInt(confirmed, 10), 1); + assert.strictEqual(isVerified, true); + }); + + it('should confirm email of user by uid', async function () { + const email = 'confirm2@me.com'; + const uid = await User.create({ + username: 'confirme2', + email: email, + }); + + const unverified = await groups.isMember(uid, 'unverified-users'); + assert.strictEqual(unverified, true); + await User.email.confirmByUid(uid); const [confirmed, isVerified] = await Promise.all([ db.getObjectField('user:' + uid, 'email:confirmed'), groups.isMember(uid, 'verified-users', uid),