[FIX] Invite links usage by channel owners/moderators (#16176)

pull/16361/head
pierre-lehnen-rc 5 years ago committed by Diego Sampaio
parent bd334d8172
commit 7559c05997
  1. 9
      app/invites/server/functions/findOrCreateInvite.js
  2. 16
      app/invites/server/functions/useInviteToken.js
  3. 2
      app/invites/server/functions/validateInviteToken.js
  4. 11
      app/lib/server/functions/setUsername.js
  5. 9
      app/models/server/models/Invites.js
  6. 10
      app/models/server/models/Users.js
  7. 2
      app/ui-flextab/client/tabs/membersList.js
  8. 12
      app/utils/lib/getURL.js

@ -15,6 +15,7 @@ function getInviteUrl(invite) {
return getURL(`invite/${ _id }`, {
full: useDirectLink,
cloud: !useDirectLink,
cloud_route: 'invite',
});
}
@ -26,14 +27,14 @@ export const findOrCreateInvite = (userId, invite) => {
return false;
}
if (!hasPermission(userId, 'create-invite-links')) {
throw new Meteor.Error('not_authorized');
}
if (!invite.rid) {
throw new Meteor.Error('error-the-field-is-required', 'The field rid is required', { method: 'findOrCreateInvite', field: 'rid' });
}
if (!hasPermission(userId, 'create-invite-links', invite.rid)) {
throw new Meteor.Error('not_authorized');
}
const subscription = Subscriptions.findOneByRoomIdAndUserId(invite.rid, userId, { fields: { _id: 1 } });
if (!subscription) {
throw new Meteor.Error('error-invalid-room', 'The rid field is invalid', { method: 'findOrCreateInvite', field: 'rid' });

@ -1,6 +1,6 @@
import { Meteor } from 'meteor/meteor';
import { Invites, Users } from '../../../models';
import { Invites, Users } from '../../../models/server';
import { validateInviteToken } from './validateInviteToken';
import { addUserToRoom } from '../../../lib/server/functions/addUserToRoom';
@ -16,18 +16,20 @@ export const useInviteToken = (userId, token) => {
const { inviteData, room } = validateInviteToken(token);
const user = Users.findOneById(userId);
Users.updateInviteToken(user._id, token);
if (addUserToRoom(room._id, user)) {
Invites.update(inviteData._id, {
$inc: {
uses: 1,
},
});
Invites.increaseUsageById(inviteData._id);
// If the user already has an username, then join the invite room,
// If no username is set yet, then the the join will happen on the setUsername method
if (user.username) {
addUserToRoom(room._id, user);
}
return {
room: {
rid: inviteData.rid,
prid: room.prid,
fname: room.fname,
name: room.name,
t: room.t,

@ -12,7 +12,7 @@ export const validateInviteToken = (token) => {
throw new Meteor.Error('error-invalid-token', 'The invite token is invalid.', { method: 'validateInviteToken', field: 'token' });
}
const room = Rooms.findOneById(inviteData.rid, { fields: { _id: 1, name: 1, fname: 1, t: 1 } });
const room = Rooms.findOneById(inviteData.rid, { fields: { _id: 1, name: 1, fname: 1, t: 1, prid: 1 } });
if (!room) {
throw new Meteor.Error('error-invalid-room', 'The invite token is invalid.', { method: 'validateInviteToken', field: 'rid' });
}

@ -4,10 +4,11 @@ import { Accounts } from 'meteor/accounts-base';
import { FileUpload } from '../../../file-upload';
import { settings } from '../../../settings';
import { Users, Messages, Subscriptions, Rooms, LivechatDepartmentAgents } from '../../../models';
import { Users, Messages, Subscriptions, Rooms, LivechatDepartmentAgents, Invites } from '../../../models';
import { hasPermission } from '../../../authorization';
import { RateLimiter } from '../lib';
import { Notifications } from '../../../notifications/server';
import { addUserToRoom } from './addUserToRoom';
import { checkUsernameAvailability, setUserAvatar, getAvatarSuggestionForUser } from '.';
@ -87,6 +88,14 @@ export const _setUsername = function(userId, u) {
}
}
// If it's the first username and the user has an invite Token, then join the invite room
if (!previousUsername && user.inviteToken) {
const inviteData = Invites.findOneById(user.inviteToken);
if (inviteData && inviteData.rid) {
addUserToRoom(inviteData.rid, user);
}
}
Notifications.notifyLogged('Users:NameChanged', {
_id: user._id,
name: user.name,

@ -37,6 +37,15 @@ class Invites extends Base {
removeById(_id) {
return this.remove({ _id });
}
// UPDATE
increaseUsageById(_id, uses = 1) {
return this.update({ _id }, {
$inc: {
uses,
},
});
}
}
export default new Invites();

@ -803,6 +803,16 @@ export class Users extends Base {
return this.update(query, update);
}
updateInviteToken(_id, inviteToken) {
const update = {
$set: {
inviteToken,
},
};
return this.update(_id, update);
}
updateStatusText(_id, statusText) {
const update = {
$set: {

@ -102,7 +102,7 @@ Template.membersList.helpers({
},
canInviteUser() {
return hasPermission('create-invite-links');
return hasPermission('create-invite-links', this._id);
},
showUserInfo() {

@ -3,13 +3,13 @@ import s from 'underscore.string';
import { isURL } from './isURL';
import { settings } from '../../settings';
function getCloudUrl(path, _site_url) {
function getCloudUrl(path, _site_url, cloudRoute) {
const siteUrl = s.rtrim(_site_url, '/');
// Remove the protocol
const host = siteUrl.replace(/https?\:\/\//i, '');
path = s.ltrim(path, '/');
const url = `https://go.rocket.chat/?host=${ encodeURIComponent(host) }&path=${ encodeURIComponent(path) }`;
const url = `https://go.rocket.chat/${ cloudRoute }?host=${ encodeURIComponent(host) }&path=${ encodeURIComponent(path) }`;
if (siteUrl.includes('http://')) {
return `${ url }&secure=no`;
@ -18,7 +18,7 @@ function getCloudUrl(path, _site_url) {
return url;
}
export const _getURL = (path, { cdn, full, cloud, _cdn_prefix, _root_url_path_prefix, _site_url }) => {
export const _getURL = (path, { cdn, full, cloud, cloud_route, _cdn_prefix, _root_url_path_prefix, _site_url }) => {
if (isURL(path)) {
return path;
}
@ -28,6 +28,7 @@ export const _getURL = (path, { cdn, full, cloud, _cdn_prefix, _root_url_path_pr
const query = _query ? `?${ _query }` : '';
const siteUrl = s.rtrim(s.trim(_site_url || ''), '/');
const cloudRoute = s.trim(cloud_route || '');
const cdnPrefix = s.rtrim(s.trim(_cdn_prefix || ''), '/');
const pathPrefix = s.rtrim(s.trim(_root_url_path_prefix || ''), '/');
@ -44,16 +45,17 @@ export const _getURL = (path, { cdn, full, cloud, _cdn_prefix, _root_url_path_pr
}
if (cloud) {
return getCloudUrl(url, siteUrl);
return getCloudUrl(url, siteUrl, cloudRoute);
}
return url;
};
export const getURL = (path, { cdn = true, full = false, cloud = false } = {}) => _getURL(path, {
export const getURL = (path, { cdn = true, full = false, cloud = false, cloud_route = '' } = {}) => _getURL(path, {
cdn,
full,
cloud,
cloud_route,
_cdn_prefix: settings.get('CDN_PREFIX'),
_root_url_path_prefix: __meteor_runtime_config__.ROOT_URL_PATH_PREFIX,
_site_url: settings.get('Site_Url'),

Loading…
Cancel
Save