The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
Rocket.Chat/app/discussion/server/methods/createDiscussion.js

186 lines
5.4 KiB

import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import { Match } from 'meteor/check';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import { hasAtLeastOnePermission, canSendMessage } from '../../../authorization/server';
import { Messages, Rooms } from '../../../models/server';
import { createRoom, addUserToRoom, sendMessage, attachMessage } from '../../../lib/server';
import { settings } from '../../../settings/server';
import { callbacks } from '../../../../lib/callbacks';
import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator';
const getParentRoom = (rid) => {
const room = Rooms.findOne(rid);
return room && (room.prid ? Rooms.findOne(room.prid, { fields: { _id: 1 } }) : room);
};
const createDiscussionMessage = (rid, user, drid, msg, message_embedded) => {
const welcomeMessage = {
msg,
rid,
drid,
attachments: [message_embedded].filter((e) => e),
};
return Messages.createWithTypeRoomIdMessageAndUser('discussion-created', rid, '', user, welcomeMessage);
};
const mentionMessage = (rid, { _id, username, name }, message_embedded) => {
const welcomeMessage = {
rid,
u: { _id, username, name },
ts: new Date(),
_updatedAt: new Date(),
attachments: [message_embedded].filter((e) => e),
};
return Messages.insert(welcomeMessage);
};
const create = ({ prid, pmid, t_name, reply, users, user, encrypted }) => {
// if you set both, prid and pmid, and the rooms dont match... should throw an error)
let message = false;
if (pmid) {
message = Messages.findOne({ _id: pmid });
if (!message) {
throw new Meteor.Error('error-invalid-message', 'Invalid message', {
method: 'DiscussionCreation',
});
}
if (prid) {
if (prid !== getParentRoom(message.rid)._id) {
throw new Meteor.Error('error-invalid-arguments', { method: 'DiscussionCreation' });
}
} else {
prid = message.rid;
}
}
if (!prid) {
throw new Meteor.Error('error-invalid-arguments', { method: 'DiscussionCreation' });
}
let p_room;
try {
p_room = canSendMessage(prid, { uid: user._id, username: user.username, type: user.type });
} catch (error) {
throw new Meteor.Error(error.message);
}
if (p_room.prid) {
throw new Meteor.Error('error-nested-discussion', 'Cannot create nested discussions', {
method: 'DiscussionCreation',
});
}
if (!Match.Maybe(encrypted, Boolean)) {
throw new Meteor.Error('error-invalid-arguments', 'Invalid encryption state', {
method: 'DiscussionCreation',
});
}
if (typeof encrypted !== 'boolean') {
encrypted = p_room.encrypted;
}
if (encrypted && reply) {
throw new Meteor.Error('error-invalid-arguments', 'Encrypted discussions must not receive an initial reply.', {
method: 'DiscussionCreation',
});
}
if (pmid) {
const discussionAlreadyExists = Rooms.findOne(
{
prid,
pmid,
},
{
fields: { _id: 1 },
},
);
if (discussionAlreadyExists) {
// do not allow multiple discussions to the same message'\
addUserToRoom(discussionAlreadyExists._id, user);
return discussionAlreadyExists;
}
}
const name = Random.id();
// auto invite the replied message owner
const invitedUsers = message ? [message.u.username, ...users] : users;
const type = roomCoordinator.getRoomDirectives(p_room.t)?.getDiscussionType();
const description = p_room.encrypted ? '' : message.msg;
const topic = p_room.name;
const discussion = createRoom(
type,
name,
user.username,
[...new Set(invitedUsers)],
false,
{
fname: t_name,
description, // TODO discussions remove
topic, // TODO discussions remove
prid,
encrypted,
},
{
// overrides name validation to allow anything, because discussion's name is randomly generated
nameValidationRegex: /.*/,
},
);
let discussionMsg;
if (pmid) {
if (p_room.encrypted) {
message.msg = TAPi18n.__('Encrypted_message');
}
mentionMessage(discussion._id, user, attachMessage(message, p_room));
discussionMsg = createDiscussionMessage(message.rid, user, discussion._id, t_name, attachMessage(message, p_room));
} else {
discussionMsg = createDiscussionMessage(prid, user, discussion._id, t_name);
}
callbacks.runAsync('afterSaveMessage', discussionMsg, p_room);
if (reply) {
sendMessage(user, { msg: reply }, discussion);
}
return discussion;
};
Meteor.methods({
/**
* Create discussion by room or message
* @constructor
* @param {string} prid - Parent Room Id - The room id, optional if you send pmid.
* @param {string} pmid - Parent Message Id - Create the discussion by a message, optional.
* @param {string} reply - The reply, optional
* @param {string} t_name - discussion name
* @param {string[]} users - users to be added
* @param {boolean} encrypted - if the discussion's e2e encryption should be enabled.
*/
createDiscussion({ prid, pmid, t_name, reply, users, encrypted }) {
if (!settings.get('Discussion_enabled')) {
throw new Meteor.Error('error-action-not-allowed', 'You are not allowed to create a discussion', { method: 'createDiscussion' });
}
const uid = Meteor.userId();
if (!uid) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', {
method: 'DiscussionCreation',
});
}
if (!hasAtLeastOnePermission(uid, ['start-discussion', 'start-discussion-other-user'])) {
throw new Meteor.Error('error-action-not-allowed', 'You are not allowed to create a discussion', { method: 'createDiscussion' });
}
return create({ uid, prid, pmid, t_name, reply, users, user: Meteor.user(), encrypted });
},
});