mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-05-06 12:06:08 +02:00
feat: invites regardless of registration type, invite privilege, groups to join on acceptance (#8786)
* feat: allow invites in normal registration mode + invite privilege * feat: select groups to join from an invite * test: check if groups from invitations have been joined * fix: remove unused variable * feat: write API versions of socket calls * docs: openapi specs for the new routes * test: iron out mongo redis difference * refactor: move inviteGroups endpoint into write API * refactor: use GET /api/v3/users/:uid/invites/groups Instead of GET /api/v3/users/:uid/inviteGroups * fix: no need for /api/v3 prefix when using api module * fix: tests * refactor: change POST /api/v3/users/invite To POST /api/v3/users/:uid/invites * refactor: make helpers.invite awaitable * fix: restrict invite API to self-use only * fix: move invite groups controller to write api, +tests * fix: tests Co-authored-by: Julian Lam <julian@nodebb.org>
This commit is contained in:
@@ -8,6 +8,7 @@ var validator = require('validator');
|
||||
var db = require('../database');
|
||||
var meta = require('../meta');
|
||||
var emailer = require('../emailer');
|
||||
var groups = require('../groups');
|
||||
var translator = require('../translator');
|
||||
var utils = require('../utils');
|
||||
|
||||
@@ -36,13 +37,7 @@ module.exports = function (User) {
|
||||
});
|
||||
};
|
||||
|
||||
User.sendInvitationEmail = async function (uid, email) {
|
||||
const token = utils.generateUUID();
|
||||
const registerLink = nconf.get('url') + '/register?token=' + token + '&email=' + encodeURIComponent(email);
|
||||
|
||||
const expireDays = meta.config.inviteExpiration;
|
||||
const expireIn = expireDays * 86400000;
|
||||
|
||||
User.sendInvitationEmail = async function (uid, email, groupsToJoin) {
|
||||
const email_exists = await User.getUidByEmail(email);
|
||||
if (email_exists) {
|
||||
throw new Error('[[error:email-taken]]');
|
||||
@@ -53,24 +48,7 @@ module.exports = function (User) {
|
||||
throw new Error('[[error:email-invited]]');
|
||||
}
|
||||
|
||||
await db.setAdd('invitation:uid:' + uid, email);
|
||||
await db.setAdd('invitation:uids', uid);
|
||||
await db.set('invitation:email:' + email, token);
|
||||
await db.pexpireAt('invitation:email:' + email, Date.now() + expireIn);
|
||||
const username = await User.getUserField(uid, 'username');
|
||||
const title = meta.config.title || meta.config.browserTitle || 'NodeBB';
|
||||
const subject = await translator.translate('[[email:invite, ' + title + ']]', meta.config.defaultLang);
|
||||
let data = {
|
||||
site_title: title,
|
||||
registerLink: registerLink,
|
||||
subject: subject,
|
||||
username: username,
|
||||
template: 'invitation',
|
||||
expireDays: expireDays,
|
||||
};
|
||||
|
||||
// Append default data to this email payload
|
||||
data = { ...emailer._defaultPayload, ...data };
|
||||
const data = await prepareInvitation(uid, email, groupsToJoin);
|
||||
|
||||
await emailer.sendToEmail('invitation', email, meta.config.defaultLang, data);
|
||||
};
|
||||
@@ -79,12 +57,28 @@ module.exports = function (User) {
|
||||
if (!query.token || !query.email) {
|
||||
throw new Error('[[error:invalid-data]]');
|
||||
}
|
||||
const token = await db.get('invitation:email:' + query.email);
|
||||
const token = await db.getObjectField('invitation:email:' + query.email, 'token');
|
||||
if (!token || token !== query.token) {
|
||||
throw new Error('[[error:invalid-token]]');
|
||||
}
|
||||
};
|
||||
|
||||
User.joinGroupsFromInvitation = async function (uid, email) {
|
||||
let groupsToJoin = await db.getObjectField('invitation:email:' + email, 'groupsToJoin');
|
||||
|
||||
try {
|
||||
groupsToJoin = JSON.parse(groupsToJoin);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!groupsToJoin || groupsToJoin.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
await groups.join(groupsToJoin, uid);
|
||||
};
|
||||
|
||||
User.deleteInvitation = async function (invitedBy, email) {
|
||||
const invitedByUid = await User.getUidByUsername(invitedBy);
|
||||
if (!invitedByUid) {
|
||||
@@ -109,4 +103,34 @@ module.exports = function (User) {
|
||||
await db.setRemove('invitation:uids', uid);
|
||||
}
|
||||
}
|
||||
|
||||
async function prepareInvitation(uid, email, groupsToJoin) {
|
||||
const token = utils.generateUUID();
|
||||
const registerLink = nconf.get('url') + '/register?token=' + token + '&email=' + encodeURIComponent(email);
|
||||
|
||||
const expireDays = meta.config.inviteExpiration;
|
||||
const expireIn = expireDays * 86400000;
|
||||
|
||||
await db.setAdd('invitation:uid:' + uid, email);
|
||||
await db.setAdd('invitation:uids', uid);
|
||||
await db.setObject('invitation:email:' + email, {
|
||||
token,
|
||||
groupsToJoin: JSON.stringify(groupsToJoin),
|
||||
});
|
||||
await db.pexpireAt('invitation:email:' + email, Date.now() + expireIn);
|
||||
|
||||
const username = await User.getUserField(uid, 'username');
|
||||
const title = meta.config.title || meta.config.browserTitle || 'NodeBB';
|
||||
const subject = await translator.translate('[[email:invite, ' + title + ']]', meta.config.defaultLang);
|
||||
|
||||
return {
|
||||
...emailer._defaultPayload, // Append default data to this email payload
|
||||
site_title: title,
|
||||
registerLink: registerLink,
|
||||
subject: subject,
|
||||
username: username,
|
||||
template: 'invitation',
|
||||
expireDays: expireDays,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user