mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-07-10 14:18:20 +00:00
Added username invite
This commit is contained in:
parent
2a7dfff88a
commit
f049d29d1b
6 changed files with 342 additions and 174 deletions
|
|
@ -23,6 +23,73 @@ describe('Post /groups/:groupId/invite', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('username invites', () => {
|
||||
it('returns an error when invited user is not found', async () => {
|
||||
const fakeID = 'fakeuserid';
|
||||
|
||||
await expect(inviter.post(`/groups/${group._id}/invite`, {
|
||||
usernames: [fakeID],
|
||||
}))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: t('userWithUsernameNotFound', {username: fakeID}),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error when inviting yourself to a group', async () => {
|
||||
await expect(inviter.post(`/groups/${group._id}/invite`, {
|
||||
usernames: [inviter.auth.local.lowerCaseUsername],
|
||||
}))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('cannotInviteSelfToGroup'),
|
||||
});
|
||||
});
|
||||
|
||||
it('invites a user to a group by username', async () => {
|
||||
const userToInvite = await generateUser();
|
||||
|
||||
await expect(inviter.post(`/groups/${group._id}/invite`, {
|
||||
usernames: [userToInvite.auth.local.lowerCaseUsername],
|
||||
})).to.eventually.deep.equal([{
|
||||
id: group._id,
|
||||
name: groupName,
|
||||
inviter: inviter._id,
|
||||
publicGuild: false,
|
||||
}]);
|
||||
|
||||
await expect(userToInvite.get('/user'))
|
||||
.to.eventually.have.nested.property('invitations.guilds[0].id', group._id);
|
||||
});
|
||||
|
||||
it('invites multiple users to a group by uuid', async () => {
|
||||
const userToInvite = await generateUser();
|
||||
const userToInvite2 = await generateUser();
|
||||
|
||||
await expect(inviter.post(`/groups/${group._id}/invite`, {
|
||||
usernames: [userToInvite.auth.local.lowerCaseUsername, userToInvite2.auth.local.lowerCaseUsername],
|
||||
})).to.eventually.deep.equal([
|
||||
{
|
||||
id: group._id,
|
||||
name: groupName,
|
||||
inviter: inviter._id,
|
||||
publicGuild: false,
|
||||
},
|
||||
{
|
||||
id: group._id,
|
||||
name: groupName,
|
||||
inviter: inviter._id,
|
||||
publicGuild: false,
|
||||
},
|
||||
]);
|
||||
|
||||
await expect(userToInvite.get('/user')).to.eventually.have.nested.property('invitations.guilds[0].id', group._id);
|
||||
await expect(userToInvite2.get('/user')).to.eventually.have.nested.property('invitations.guilds[0].id', group._id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('user id invites', () => {
|
||||
it('returns an error when inviter has no chat privileges', async () => {
|
||||
let inviterMuted = await inviter.update({'flags.chatRevoked': true});
|
||||
|
|
|
|||
|
|
@ -240,6 +240,7 @@
|
|||
"userAlreadyPendingInvitation": "UserID: <%= userId %>, User \"<%= username %>\" already pending invitation.",
|
||||
"userAlreadyInAParty": "UserID: <%= userId %>, User \"<%= username %>\" already in a party. ",
|
||||
"userWithIDNotFound": "User with id \"<%= userId %>\" not found.",
|
||||
"userWithUsernameNotFound": "User with username \"<%= username %>\" not found.",
|
||||
"userHasNoLocalRegistration": "User does not have a local registration (username, email, password).",
|
||||
"uuidsMustBeAnArray": "User ID invites must be an array.",
|
||||
"emailsMustBeAnArray": "Email address invites must be an array.",
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import {
|
|||
model as User,
|
||||
nameFields,
|
||||
} from '../../models/user';
|
||||
import { model as EmailUnsubscription } from '../../models/emailUnsubscription';
|
||||
import {
|
||||
NotFound,
|
||||
BadRequest,
|
||||
|
|
@ -17,9 +16,12 @@ import {
|
|||
} from '../../libs/errors';
|
||||
import { removeFromArray } from '../../libs/collectionManipulators';
|
||||
import { sendTxn as sendTxnEmail } from '../../libs/email';
|
||||
import { encrypt } from '../../libs/encryption';
|
||||
import { sendNotification as sendPushNotification } from '../../libs/pushNotifications';
|
||||
import pusher from '../../libs/pusher';
|
||||
import {
|
||||
_inviteByUUID,
|
||||
_inviteByEmail,
|
||||
_inviteByUserName,
|
||||
} from '../../libs/invites';
|
||||
import common from '../../../common';
|
||||
import payments from '../../libs/payments/payments';
|
||||
import stripePayments from '../../libs/payments/stripe';
|
||||
|
|
@ -948,148 +950,6 @@ api.removeGroupMember = {
|
|||
},
|
||||
};
|
||||
|
||||
async function _inviteByUUID (uuid, group, inviter, req, res) {
|
||||
let userToInvite = await User.findById(uuid).exec();
|
||||
const publicGuild = group.type === 'guild' && group.privacy === 'public';
|
||||
|
||||
if (!userToInvite) {
|
||||
throw new NotFound(res.t('userWithIDNotFound', {userId: uuid}));
|
||||
} else if (inviter._id === userToInvite._id) {
|
||||
throw new BadRequest(res.t('cannotInviteSelfToGroup'));
|
||||
}
|
||||
|
||||
const objections = inviter.getObjectionsToInteraction('group-invitation', userToInvite);
|
||||
if (objections.length > 0) {
|
||||
throw new NotAuthorized(res.t(objections[0], { userId: uuid, username: userToInvite.profile.name}));
|
||||
}
|
||||
|
||||
if (group.type === 'guild') {
|
||||
if (_.includes(userToInvite.guilds, group._id)) {
|
||||
throw new NotAuthorized(res.t('userAlreadyInGroup', { userId: uuid, username: userToInvite.profile.name}));
|
||||
}
|
||||
if (_.find(userToInvite.invitations.guilds, {id: group._id})) {
|
||||
throw new NotAuthorized(res.t('userAlreadyInvitedToGroup', { userId: uuid, username: userToInvite.profile.name}));
|
||||
}
|
||||
|
||||
let guildInvite = {
|
||||
id: group._id,
|
||||
name: group.name,
|
||||
inviter: inviter._id,
|
||||
publicGuild,
|
||||
};
|
||||
if (group.isSubscribed() && !group.hasNotCancelled()) guildInvite.cancelledPlan = true;
|
||||
userToInvite.invitations.guilds.push(guildInvite);
|
||||
} else if (group.type === 'party') {
|
||||
// Do not add to invitations.parties array if the user is already invited to that party
|
||||
if (_.find(userToInvite.invitations.parties, {id: group._id})) {
|
||||
throw new NotAuthorized(res.t('userAlreadyPendingInvitation', { userId: uuid, username: userToInvite.profile.name}));
|
||||
}
|
||||
|
||||
if (userToInvite.party._id) {
|
||||
let userParty = await Group.getGroup({user: userToInvite, groupId: 'party', fields: 'memberCount'});
|
||||
|
||||
// Allow user to be invited to a new party when they're partying solo
|
||||
if (userParty && userParty.memberCount !== 1) throw new NotAuthorized(res.t('userAlreadyInAParty', { userId: uuid, username: userToInvite.profile.name}));
|
||||
}
|
||||
|
||||
let partyInvite = {id: group._id, name: group.name, inviter: inviter._id};
|
||||
if (group.isSubscribed() && !group.hasNotCancelled()) partyInvite.cancelledPlan = true;
|
||||
|
||||
userToInvite.invitations.parties.push(partyInvite);
|
||||
userToInvite.invitations.party = partyInvite;
|
||||
}
|
||||
|
||||
let groupLabel = group.type === 'guild' ? 'Guild' : 'Party';
|
||||
let groupTemplate = group.type === 'guild' ? 'guild' : 'party';
|
||||
if (userToInvite.preferences.emailNotifications[`invited${groupLabel}`] !== false) {
|
||||
let emailVars = [
|
||||
{name: 'INVITER', content: inviter.profile.name},
|
||||
];
|
||||
|
||||
if (group.type === 'guild') {
|
||||
emailVars.push(
|
||||
{name: 'GUILD_NAME', content: group.name},
|
||||
{name: 'GUILD_URL', content: '/groups/discovery'}
|
||||
);
|
||||
} else {
|
||||
emailVars.push(
|
||||
{name: 'PARTY_NAME', content: group.name},
|
||||
{name: 'PARTY_URL', content: '/party'}
|
||||
);
|
||||
}
|
||||
|
||||
sendTxnEmail(userToInvite, `invited-${groupTemplate}`, emailVars);
|
||||
}
|
||||
|
||||
if (userToInvite.preferences.pushNotifications[`invited${groupLabel}`] !== false) {
|
||||
let identifier = group.type === 'guild' ? 'invitedGuild' : 'invitedParty';
|
||||
sendPushNotification(
|
||||
userToInvite,
|
||||
{
|
||||
title: group.name,
|
||||
message: res.t(identifier),
|
||||
identifier,
|
||||
payload: {groupID: group._id, publicGuild},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let userInvited = await userToInvite.save();
|
||||
if (group.type === 'guild') {
|
||||
return userInvited.invitations.guilds[userToInvite.invitations.guilds.length - 1];
|
||||
} else if (group.type === 'party') {
|
||||
return userInvited.invitations.parties[userToInvite.invitations.parties.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
async function _inviteByEmail (invite, group, inviter, req, res) {
|
||||
let userReturnInfo;
|
||||
|
||||
if (!invite.email) throw new BadRequest(res.t('inviteMissingEmail'));
|
||||
|
||||
let userToContact = await User.findOne({$or: [
|
||||
{'auth.local.email': invite.email},
|
||||
{'auth.facebook.emails.value': invite.email},
|
||||
{'auth.google.emails.value': invite.email},
|
||||
]})
|
||||
.select({_id: true, 'preferences.emailNotifications': true})
|
||||
.exec();
|
||||
|
||||
if (userToContact) {
|
||||
userReturnInfo = await _inviteByUUID(userToContact._id, group, inviter, req, res);
|
||||
} else {
|
||||
userReturnInfo = invite.email;
|
||||
|
||||
let cancelledPlan = false;
|
||||
if (group.isSubscribed() && !group.hasNotCancelled()) cancelledPlan = true;
|
||||
|
||||
const groupQueryString = JSON.stringify({
|
||||
id: group._id,
|
||||
inviter: inviter._id,
|
||||
publicGuild: group.type === 'guild' && group.privacy === 'public',
|
||||
sentAt: Date.now(), // so we can let it expire
|
||||
cancelledPlan,
|
||||
});
|
||||
let link = `/static/front?groupInvite=${encrypt(groupQueryString)}`;
|
||||
|
||||
let variables = [
|
||||
{name: 'LINK', content: link},
|
||||
{name: 'INVITER', content: req.body.inviter || inviter.profile.name},
|
||||
];
|
||||
|
||||
if (group.type === 'guild') {
|
||||
variables.push({name: 'GUILD_NAME', content: group.name});
|
||||
}
|
||||
|
||||
// Check for the email address not to be unsubscribed
|
||||
let userIsUnsubscribed = await EmailUnsubscription.findOne({email: invite.email}).exec();
|
||||
let groupLabel = group.type === 'guild' ? '-guild' : '';
|
||||
if (!userIsUnsubscribed) sendTxnEmail(invite, `invite-friend${groupLabel}`, variables);
|
||||
}
|
||||
|
||||
return userReturnInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} /api/v3/groups/:groupId/invite Invite users to a group
|
||||
* @apiName InviteToGroup
|
||||
|
|
@ -1176,7 +1036,7 @@ api.inviteToGroup = {
|
|||
url: '/groups/:groupId/invite',
|
||||
middlewares: [authWithHeaders({})],
|
||||
async handler (req, res) {
|
||||
let user = res.locals.user;
|
||||
const user = res.locals.user;
|
||||
|
||||
if (user.flags.chatRevoked) throw new NotAuthorized(res.t('cannotInviteWhenMuted'));
|
||||
|
||||
|
|
@ -1184,35 +1044,48 @@ api.inviteToGroup = {
|
|||
|
||||
if (user.invitesSent >= MAX_EMAIL_INVITES_BY_USER) throw new NotAuthorized(res.t('inviteLimitReached', { techAssistanceEmail: TECH_ASSISTANCE_EMAIL }));
|
||||
|
||||
let validationErrors = req.validationErrors();
|
||||
const validationErrors = req.validationErrors();
|
||||
if (validationErrors) throw validationErrors;
|
||||
|
||||
let group = await Group.getGroup({user, groupId: req.params.groupId, fields: '-chat'});
|
||||
const group = await Group.getGroup({user, groupId: req.params.groupId, fields: '-chat'});
|
||||
if (!group) throw new NotFound(res.t('groupNotFound'));
|
||||
|
||||
if (group.purchased && group.purchased.plan.customerId && user._id !== group.leader) throw new NotAuthorized(res.t('onlyGroupLeaderCanInviteToGroupPlan'));
|
||||
|
||||
let uuids = req.body.uuids;
|
||||
let emails = req.body.emails;
|
||||
const {
|
||||
uuids,
|
||||
emails,
|
||||
usernames,
|
||||
} = req.body;
|
||||
|
||||
await Group.validateInvitations(uuids, emails, res, group);
|
||||
await Group.validateInvitations({
|
||||
uuids,
|
||||
emails,
|
||||
usernames,
|
||||
}, res, group);
|
||||
|
||||
let results = [];
|
||||
const results = [];
|
||||
|
||||
if (uuids) {
|
||||
let uuidInvites = uuids.map((uuid) => _inviteByUUID(uuid, group, user, req, res));
|
||||
let uuidResults = await Promise.all(uuidInvites);
|
||||
const uuidInvites = uuids.map((uuid) => _inviteByUUID(uuid, group, user, req, res));
|
||||
const uuidResults = await Promise.all(uuidInvites);
|
||||
results.push(...uuidResults);
|
||||
}
|
||||
|
||||
if (emails) {
|
||||
let emailInvites = emails.map((invite) => _inviteByEmail(invite, group, user, req, res));
|
||||
const emailInvites = emails.map((invite) => _inviteByEmail(invite, group, user, req, res));
|
||||
user.invitesSent += emails.length;
|
||||
await user.save();
|
||||
let emailResults = await Promise.all(emailInvites);
|
||||
const emailResults = await Promise.all(emailInvites);
|
||||
results.push(...emailResults);
|
||||
}
|
||||
|
||||
if (usernames) {
|
||||
const usernameInvites = usernames.map((username) => _inviteByUserName(username, group, user, req, res));
|
||||
const usernameResults = await Promise.all(usernameInvites);
|
||||
results.push(...usernameResults);
|
||||
}
|
||||
|
||||
res.respond(200, results);
|
||||
},
|
||||
};
|
||||
|
|
|
|||
209
website/server/libs/invites/index.js
Normal file
209
website/server/libs/invites/index.js
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
import _ from 'lodash';
|
||||
|
||||
import { encrypt } from '../encryption';
|
||||
import { sendNotification as sendPushNotification } from '../pushNotifications';
|
||||
import {
|
||||
NotFound,
|
||||
BadRequest,
|
||||
NotAuthorized,
|
||||
} from '../errors';
|
||||
import { sendTxn as sendTxnEmail } from '../email';
|
||||
import { model as EmailUnsubscription } from '../../models/emailUnsubscription';
|
||||
import {
|
||||
model as User,
|
||||
} from '../../models/user';
|
||||
import {
|
||||
model as Group,
|
||||
} from '../../models/group';
|
||||
|
||||
function sendInvitePushNotification (userToInvite, groupLabel, group, publicGuild, res) {
|
||||
if (userToInvite.preferences.pushNotifications[`invited${groupLabel}`] === false) return;
|
||||
|
||||
const identifier = group.type === 'guild' ? 'invitedGuild' : 'invitedParty';
|
||||
|
||||
sendPushNotification(
|
||||
userToInvite,
|
||||
{
|
||||
title: group.name,
|
||||
message: res.t(identifier),
|
||||
identifier,
|
||||
payload: {groupID: group._id, publicGuild},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function sendInviteEmail (userToInvite, groupLabel, group, inviter) {
|
||||
if (userToInvite.preferences.emailNotifications[`invited${groupLabel}`] === false) return;
|
||||
const groupTemplate = group.type === 'guild' ? 'guild' : 'party';
|
||||
|
||||
const emailVars = [
|
||||
{name: 'INVITER', content: inviter.profile.name},
|
||||
];
|
||||
|
||||
if (group.type === 'guild') {
|
||||
emailVars.push(
|
||||
{name: 'GUILD_NAME', content: group.name},
|
||||
{name: 'GUILD_URL', content: '/groups/discovery'}
|
||||
);
|
||||
} else {
|
||||
emailVars.push(
|
||||
{name: 'PARTY_NAME', content: group.name},
|
||||
{name: 'PARTY_URL', content: '/party'}
|
||||
);
|
||||
}
|
||||
|
||||
sendTxnEmail(userToInvite, `invited-${groupTemplate}`, emailVars);
|
||||
}
|
||||
|
||||
function inviteUserToGuild (userToInvite, group, inviter, publicGuild, res) {
|
||||
const uuid = userToInvite._id;
|
||||
|
||||
if (_.includes(userToInvite.guilds, group._id)) {
|
||||
throw new NotAuthorized(res.t('userAlreadyInGroup', { userId: uuid, username: userToInvite.profile.name}));
|
||||
}
|
||||
|
||||
if (_.find(userToInvite.invitations.guilds, {id: group._id})) {
|
||||
throw new NotAuthorized(res.t('userAlreadyInvitedToGroup', { userId: uuid, username: userToInvite.profile.name}));
|
||||
}
|
||||
|
||||
const guildInvite = {
|
||||
id: group._id,
|
||||
name: group.name,
|
||||
inviter: inviter._id,
|
||||
publicGuild,
|
||||
};
|
||||
|
||||
if (group.isSubscribed() && !group.hasNotCancelled()) guildInvite.cancelledPlan = true;
|
||||
|
||||
userToInvite.invitations.guilds.push(guildInvite);
|
||||
}
|
||||
|
||||
async function inviteUserToParty (userToInvite, group, inviter, res) {
|
||||
const uuid = userToInvite._id;
|
||||
|
||||
// Do not add to invitations.parties array if the user is already invited to that party
|
||||
if (_.find(userToInvite.invitations.parties, {id: group._id})) {
|
||||
throw new NotAuthorized(res.t('userAlreadyPendingInvitation', { userId: uuid, username: userToInvite.profile.name}));
|
||||
}
|
||||
|
||||
if (userToInvite.party._id) {
|
||||
let userParty = await Group.getGroup({user: userToInvite, groupId: 'party', fields: 'memberCount'});
|
||||
|
||||
// Allow user to be invited to a new party when they're partying solo
|
||||
if (userParty && userParty.memberCount !== 1) throw new NotAuthorized(res.t('userAlreadyInAParty', { userId: uuid, username: userToInvite.profile.name}));
|
||||
}
|
||||
|
||||
let partyInvite = {id: group._id, name: group.name, inviter: inviter._id};
|
||||
if (group.isSubscribed() && !group.hasNotCancelled()) partyInvite.cancelledPlan = true;
|
||||
|
||||
userToInvite.invitations.parties.push(partyInvite);
|
||||
userToInvite.invitations.party = partyInvite;
|
||||
}
|
||||
|
||||
async function addInvitiationToUser (userToInvite, group, inviter, res) {
|
||||
const publicGuild = group.type === 'guild' && group.privacy === 'public';
|
||||
|
||||
if (group.type === 'guild') {
|
||||
inviteUserToGuild(userToInvite, group, inviter, publicGuild, res);
|
||||
} else if (group.type === 'party') {
|
||||
await inviteUserToParty(userToInvite, group, inviter, res);
|
||||
}
|
||||
|
||||
const groupLabel = group.type === 'guild' ? 'Guild' : 'Party';
|
||||
sendInviteEmail(userToInvite, groupLabel, group, inviter);
|
||||
sendInvitePushNotification(userToInvite, groupLabel, group, publicGuild, res);
|
||||
|
||||
const userInvited = await userToInvite.save();
|
||||
if (group.type === 'guild') {
|
||||
return userInvited.invitations.guilds[userToInvite.invitations.guilds.length - 1];
|
||||
}
|
||||
|
||||
if (group.type === 'party') {
|
||||
return userInvited.invitations.parties[userToInvite.invitations.parties.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
async function _inviteByUUID (uuid, group, inviter, req, res) {
|
||||
const userToInvite = await User.findById(uuid).exec();
|
||||
|
||||
if (!userToInvite) {
|
||||
throw new NotFound(res.t('userWithIDNotFound', {userId: uuid}));
|
||||
} else if (inviter._id === userToInvite._id) {
|
||||
throw new BadRequest(res.t('cannotInviteSelfToGroup'));
|
||||
}
|
||||
|
||||
const objections = inviter.getObjectionsToInteraction('group-invitation', userToInvite);
|
||||
if (objections.length > 0) {
|
||||
throw new NotAuthorized(res.t(objections[0], { userId: uuid, username: userToInvite.profile.name}));
|
||||
}
|
||||
|
||||
return await addInvitiationToUser(userToInvite, group, inviter, res);
|
||||
}
|
||||
|
||||
async function _inviteByEmail (invite, group, inviter, req, res) {
|
||||
let userReturnInfo;
|
||||
|
||||
if (!invite.email) throw new BadRequest(res.t('inviteMissingEmail'));
|
||||
|
||||
let userToContact = await User.findOne({$or: [
|
||||
{'auth.local.email': invite.email},
|
||||
{'auth.facebook.emails.value': invite.email},
|
||||
{'auth.google.emails.value': invite.email},
|
||||
]})
|
||||
.select({_id: true, 'preferences.emailNotifications': true})
|
||||
.exec();
|
||||
|
||||
if (userToContact) {
|
||||
userReturnInfo = await _inviteByUUID(userToContact._id, group, inviter, req, res);
|
||||
} else {
|
||||
userReturnInfo = invite.email;
|
||||
|
||||
let cancelledPlan = false;
|
||||
if (group.isSubscribed() && !group.hasNotCancelled()) cancelledPlan = true;
|
||||
|
||||
const groupQueryString = JSON.stringify({
|
||||
id: group._id,
|
||||
inviter: inviter._id,
|
||||
publicGuild: group.type === 'guild' && group.privacy === 'public',
|
||||
sentAt: Date.now(), // so we can let it expire
|
||||
cancelledPlan,
|
||||
});
|
||||
let link = `/static/front?groupInvite=${encrypt(groupQueryString)}`;
|
||||
|
||||
let variables = [
|
||||
{name: 'LINK', content: link},
|
||||
{name: 'INVITER', content: req.body.inviter || inviter.profile.name},
|
||||
];
|
||||
|
||||
if (group.type === 'guild') {
|
||||
variables.push({name: 'GUILD_NAME', content: group.name});
|
||||
}
|
||||
|
||||
// Check for the email address not to be unsubscribed
|
||||
let userIsUnsubscribed = await EmailUnsubscription.findOne({email: invite.email}).exec();
|
||||
let groupLabel = group.type === 'guild' ? '-guild' : '';
|
||||
if (!userIsUnsubscribed) sendTxnEmail(invite, `invite-friend${groupLabel}`, variables);
|
||||
}
|
||||
|
||||
return userReturnInfo;
|
||||
}
|
||||
|
||||
async function _inviteByUserName (username, group, inviter, req, res) {
|
||||
const userToInvite = await User.findOne({'auth.local.lowerCaseUsername': username}).exec();
|
||||
|
||||
if (!userToInvite) {
|
||||
throw new NotFound(res.t('userWithUsernameNotFound', { username }));
|
||||
}
|
||||
|
||||
if (inviter._id === userToInvite._id) {
|
||||
throw new BadRequest(res.t('cannotInviteSelfToGroup'));
|
||||
}
|
||||
|
||||
return await addInvitiationToUser(userToInvite, group, inviter, res);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
_inviteByUUID,
|
||||
_inviteByEmail,
|
||||
_inviteByUserName,
|
||||
};
|
||||
|
|
@ -16,7 +16,7 @@ module.exports = function errorHandler (err, req, res, next) { // eslint-disable
|
|||
// Otherwise try to identify the type of error (mongoose validation, mongodb unique, ...)
|
||||
// If we can't identify it, respond with a generic 500 error
|
||||
let responseErr = err instanceof CustomError ? err : null;
|
||||
|
||||
console.log(err)
|
||||
// Handle errors created with 'http-errors' or similar that have a status/statusCode property
|
||||
if (err.statusCode && typeof err.statusCode === 'number') {
|
||||
responseErr = new CustomError();
|
||||
|
|
|
|||
|
|
@ -356,23 +356,17 @@ schema.statics.toJSONCleanChat = async function groupToJSONCleanChat (group, use
|
|||
return toJSON;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks invitation uuids and emails for possible errors.
|
||||
*
|
||||
* @param uuids An array of user ids
|
||||
* @param emails An array of emails
|
||||
* @param res Express res object for use with translations
|
||||
* @throws BadRequest An error describing the issue with the invitations
|
||||
*/
|
||||
schema.statics.validateInvitations = async function getInvitationError (uuids, emails, res, group = null) {
|
||||
let uuidsIsArray = Array.isArray(uuids);
|
||||
let emailsIsArray = Array.isArray(emails);
|
||||
let emptyEmails = emailsIsArray && emails.length < 1;
|
||||
let emptyUuids = uuidsIsArray && uuids.length < 1;
|
||||
function getIniviteError (uuids, emails, usernames) {
|
||||
const uuidsIsArray = Array.isArray(uuids);
|
||||
const emailsIsArray = Array.isArray(emails);
|
||||
const usernamesIsArray = Array.isArray(usernames);
|
||||
const emptyEmails = emailsIsArray && emails.length < 1;
|
||||
const emptyUuids = uuidsIsArray && uuids.length < 1;
|
||||
const emptyUsernames = usernamesIsArray && usernames.length < 1;
|
||||
|
||||
let errorString;
|
||||
|
||||
if (!uuids && !emails) {
|
||||
if (!uuids && !emails && !usernames) {
|
||||
errorString = 'canOnlyInviteEmailUuid';
|
||||
} else if (uuids && !uuidsIsArray) {
|
||||
errorString = 'uuidsMustBeAnArray';
|
||||
|
|
@ -386,10 +380,12 @@ schema.statics.validateInvitations = async function getInvitationError (uuids, e
|
|||
errorString = 'inviteMustNotBeEmpty';
|
||||
}
|
||||
|
||||
if (errorString) {
|
||||
throw new BadRequest(res.t(errorString));
|
||||
}
|
||||
if (usernames && emptyUsernames) errorString = 'usernamesMustNotBeEmpty';
|
||||
|
||||
return errorString;
|
||||
}
|
||||
|
||||
function getInviteCount (uuids, emails) {
|
||||
let totalInvites = 0;
|
||||
|
||||
if (uuids) {
|
||||
|
|
@ -400,6 +396,28 @@ schema.statics.validateInvitations = async function getInvitationError (uuids, e
|
|||
totalInvites += emails.length;
|
||||
}
|
||||
|
||||
return totalInvites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks invitation uuids and emails for possible errors.
|
||||
*
|
||||
* @param uuids An array of user ids
|
||||
* @param emails An array of emails
|
||||
* @param res Express res object for use with translations
|
||||
* @throws BadRequest An error describing the issue with the invitations
|
||||
*/
|
||||
schema.statics.validateInvitations = async function getInvitationError (invites, res, group = null) {
|
||||
const {
|
||||
uuids,
|
||||
emails,
|
||||
usernames,
|
||||
} = invites;
|
||||
|
||||
const errorString = getIniviteError(uuids, emails, usernames);
|
||||
if (errorString) throw new BadRequest(res.t(errorString));
|
||||
|
||||
const totalInvites = getInviteCount(uuids, emails);
|
||||
if (totalInvites > INVITES_LIMIT) {
|
||||
throw new BadRequest(res.t('canOnlyInviteMaxInvites', {maxInvites: INVITES_LIMIT}));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue