Several fixes for Slack import. Fixes #8134, #8359, #6898

pull/8390/head
Bradley Hilton 8 years ago
parent 76d2061fd9
commit 3ce8e699c0
No known key found for this signature in database
GPG Key ID: 0666B2C24C43C358
  1. 4
      packages/rocketchat-i18n/i18n/en.i18n.json
  2. 530
      packages/rocketchat-importer-slack/server.js
  3. 12
      packages/rocketchat-importer/client/admin/adminImport.html
  4. 12
      packages/rocketchat-importer/client/admin/adminImport.js
  5. 2
      packages/rocketchat-importer/client/admin/adminImportPrepare.html
  6. 15
      packages/rocketchat-importer/client/admin/adminImportPrepare.js
  7. 21
      packages/rocketchat-importer/server/classes/ImporterBase.js
  8. 6
      packages/rocketchat-importer/server/methods/startImport.js
  9. 12
      packages/rocketchat-lib/server/methods/filterATAllTag.js
  10. 10
      packages/rocketchat-lib/server/methods/setUsername.js

@ -807,6 +807,7 @@
"IMAP_intercepter_Not_running": "IMAP intercepter Not running",
"Impersonate_user": "Impersonate User",
"Impersonate_user_description": "When enabled, integration posts as the user that triggered integration",
"Import": "Import",
"Importer_Archived": "Archived",
"Importer_CSV_Information": "The CSV importer requires a specific format, please read the documentation for how to structure your zip file:",
"Importer_done": "Importing complete!",
@ -1663,6 +1664,7 @@
"SSL": "SSL",
"Star_Message": "Star Message",
"Starred_Messages": "Starred Messages",
"Start": "Start",
"Start_audio_call": "Start audio call",
"Start_Chat": "Start Chat",
"Start_of_conversation": "Start of conversation",
@ -2029,4 +2031,4 @@
"your_message_optional": "your message (optional)",
"Your_password_is_wrong": "Your password is wrong!",
"Your_push_was_sent_to_s_devices": "Your push was sent to %s devices"
}
}

@ -6,37 +6,48 @@ Importer.Slack = class extends Importer.Base {
this.bots = {};
this.logger.debug('Constructed a new Slack Importer.');
}
prepare(dataURI, sentContentType, fileName) {
super.prepare(dataURI, sentContentType, fileName);
const {image/*, contentType*/} = RocketChatFile.dataURIParse(dataURI);
const { image } = RocketChatFile.dataURIParse(dataURI);
const zip = new this.AdmZip(new Buffer(image, 'base64'));
const zipEntries = zip.getEntries();
let tempChannels = [];
let tempUsers = [];
const tempMessages = {};
zipEntries.forEach(entry => {
if (entry.entryName.indexOf('__MACOSX') > -1) {
return this.logger.debug(`Ignoring the file: ${ entry.entryName }`);
}
if (entry.entryName === 'channels.json') {
this.updateProgress(Importer.ProgressStep.PREPARING_CHANNELS);
tempChannels = JSON.parse(entry.getData().toString()).filter(channel => channel.creator != null);
return;
}
if (entry.entryName === 'users.json') {
this.updateProgress(Importer.ProgressStep.PREPARING_USERS);
tempUsers = JSON.parse(entry.getData().toString());
return tempUsers.forEach(user => {
tempUsers.forEach(user => {
if (user.is_bot) {
this.bots[user.profile.bot_id] = user;
}
});
return;
}
if (!entry.isDirectory && entry.entryName.indexOf('/') > -1) {
const item = entry.entryName.split('/');
const channelName = item[0];
const msgGroupData = item[1].split('.')[0];
tempMessages[channelName] = tempMessages[channelName] || {};
try {
tempMessages[channelName][msgGroupData] = JSON.parse(entry.getData().toString());
} catch (error) {
@ -65,10 +76,11 @@ Importer.Slack = class extends Importer.Base {
Object.keys(tempMessages).forEach(channel => {
const messagesObj = tempMessages[channel];
this.messages[channel] = this.messages[channel] || {};
Object.keys(messagesObj).forEach(date => {
const msgs = messagesObj[date];
messagesCount += msgs.length;
this.updateRecord({ 'messagesstatus': '#{channel}/#{date}' });
this.updateRecord({ 'messagesstatus': `${ channel }/${ date }` });
if (Importer.Base.getBSONSize(msgs) > Importer.Base.MaxBSONSize) {
const tmp = Importer.Base.getBSONSafeArraysFromAnArray(msgs);
Object.keys(tmp).forEach(i => {
@ -82,6 +94,7 @@ Importer.Slack = class extends Importer.Base {
}
});
});
this.updateRecord({ 'count.messages': messagesCount, 'messagesstatus': null });
this.addCountToTotal(messagesCount);
if ([tempUsers.length, tempChannels.length, messagesCount].some(e => e === 0)) {
@ -99,6 +112,7 @@ Importer.Slack = class extends Importer.Base {
startImport(importSelection) {
super.startImport(importSelection);
const start = Date.now();
Object.keys(importSelection.users).forEach(key => {
const user = importSelection.users[key];
Object.keys(this.users.users).forEach(k => {
@ -109,6 +123,7 @@ Importer.Slack = class extends Importer.Base {
});
});
this.collection.update({ _id: this.users._id }, { $set: { 'users': this.users.users }});
Object.keys(importSelection.channels).forEach(key => {
const channel = importSelection.channels[key];
Object.keys(this.channels.channels).forEach(k => {
@ -119,283 +134,310 @@ Importer.Slack = class extends Importer.Base {
});
});
this.collection.update({ _id: this.channels._id }, { $set: { 'channels': this.channels.channels }});
const startedByUserId = Meteor.userId();
Meteor.defer(() => {
this.updateProgress(Importer.ProgressStep.IMPORTING_USERS);
this.users.users.forEach(user => {
if (!user.do_import) {
return;
}
Meteor.runAsUser(startedByUserId, () => {
const existantUser = RocketChat.models.Users.findOneByEmailAddress(user.profile.email) || RocketChat.models.Users.findOneByUsername(user.name);
if (existantUser) {
user.rocketId = existantUser._id;
RocketChat.models.Users.update({ _id: user.rocketId }, { $addToSet: { importIds: user.id } });
this.userTags.push({
slack: `<@${ user.id }>`,
slackLong: `<@${ user.id }|${ user.name }>`,
rocket: `@${ existantUser.username }`
});
} else {
const userId = user.profile.email ? Accounts.createUser({ email: user.profile.email, password: Date.now() + user.name + user.profile.email.toUpperCase() }) : Accounts.createUser({ username: user.name, password: Date.now() + user.name, joinDefaultChannelsSilenced: true });
Meteor.runAsUser(userId, () => {
Meteor.call('setUsername', user.name, {joinDefaultChannelsSilenced: true});
const url = user.profile.image_original || user.profile.image_512;
try {
Meteor.call('setAvatarFromService', url, undefined, 'url');
} catch (error) {
this.logger.warn(`Failed to set ${ user.name }'s avatar from url ${ url }`);
console.log(`Failed to set ${ user.name }'s avatar from url ${ url }`);
}
// Slack's is -18000 which translates to Rocket.Chat's after dividing by 3600
if (user.tz_offset) {
Meteor.call('userSetUtcOffset', user.tz_offset / 3600);
try {
this.updateProgress(Importer.ProgressStep.IMPORTING_USERS);
this.users.users.forEach(user => {
if (!user.do_import) {
return;
}
Meteor.runAsUser(startedByUserId, () => {
const existantUser = RocketChat.models.Users.findOneByEmailAddress(user.profile.email) || RocketChat.models.Users.findOneByUsername(user.name);
if (existantUser) {
user.rocketId = existantUser._id;
RocketChat.models.Users.update({ _id: user.rocketId }, { $addToSet: { importIds: user.id } });
this.userTags.push({
slack: `<@${ user.id }>`,
slackLong: `<@${ user.id }|${ user.name }>`,
rocket: `@${ existantUser.username }`
});
} else {
const userId = user.profile.email ? Accounts.createUser({ email: user.profile.email, password: Date.now() + user.name + user.profile.email.toUpperCase() }) : Accounts.createUser({ username: user.name, password: Date.now() + user.name, joinDefaultChannelsSilenced: true });
Meteor.runAsUser(userId, () => {
Meteor.call('setUsername', user.name, { joinDefaultChannelsSilenced: true });
const url = user.profile.image_original || user.profile.image_512;
try {
Meteor.call('setAvatarFromService', url, undefined, 'url');
} catch (error) {
this.logger.warn(`Failed to set ${ user.name }'s avatar from url ${ url }`);
console.log(`Failed to set ${ user.name }'s avatar from url ${ url }`);
}
// Slack's is -18000 which translates to Rocket.Chat's after dividing by 3600
if (user.tz_offset) {
Meteor.call('userSetUtcOffset', user.tz_offset / 3600);
}
});
RocketChat.models.Users.update({ _id: userId }, { $addToSet: { importIds: user.id } });
if (user.profile.real_name) {
RocketChat.models.Users.setName(userId, user.profile.real_name);
}
});
RocketChat.models.Users.update({ _id: userId }, { $addToSet: { importIds: user.id } });
//Deleted users are 'inactive' users in Rocket.Chat
if (user.deleted) {
Meteor.call('setUserActiveStatus', userId, false);
}
if (user.profile.real_name) {
RocketChat.models.Users.setName(userId, user.profile.real_name);
}
//Deleted users are 'inactive' users in Rocket.Chat
if (user.deleted) {
Meteor.call('setUserActiveStatus', userId, false);
user.rocketId = userId;
this.userTags.push({
slack: `<@${ user.id }>`,
slackLong: `<@${ user.id }|${ user.name }>`,
rocket: `@${ user.name }`
});
}
//TODO: Maybe send emails?
user.rocketId = userId;
this.userTags.push({
slack: `<@${ user.id }>`,
slackLong: `<@${ user.id }|${ user.name }>`,
rocket: `@${ user.name }`
});
}
this.addCountCompleted(1);
this.addCountCompleted(1);
});
});
});
this.collection.update({ _id: this.users._id }, { $set: { 'users': this.users.users }});
this.updateProgress(Importer.ProgressStep.IMPORTING_CHANNELS);
this.channels.channels.forEach(channel => {
if (!channel.do_import) {
return;
}
Meteor.runAsUser (startedByUserId, () => {
const existantRoom = RocketChat.models.Rooms.findOneByName(channel.name);
if (existantRoom || channel.is_general) {
if (channel.is_general && existantRoom && channel.name !== existantRoom.name) {
Meteor.call('saveRoomSettings', 'GENERAL', 'roomName', channel.name);
}
channel.rocketId = channel.is_general ? 'GENERAL' : existantRoom._id;
RocketChat.models.Rooms.update({ _id: channel.rocketId }, { $addToSet: { importIds: channel.id } });
} else {
const users = channel.members
.reduce((ret, member) => {
if (member !== channel.creator) {
const user = this.getRocketUser(member);
if (user && user.username) {
ret.push(user.username);
this.collection.update({ _id: this.users._id }, { $set: { 'users': this.users.users }});
this.updateProgress(Importer.ProgressStep.IMPORTING_CHANNELS);
this.channels.channels.forEach(channel => {
if (!channel.do_import) {
return;
}
Meteor.runAsUser (startedByUserId, () => {
const existantRoom = RocketChat.models.Rooms.findOneByName(channel.name);
if (existantRoom || channel.is_general) {
if (channel.is_general && existantRoom && channel.name !== existantRoom.name) {
Meteor.call('saveRoomSettings', 'GENERAL', 'roomName', channel.name);
}
channel.rocketId = channel.is_general ? 'GENERAL' : existantRoom._id;
RocketChat.models.Rooms.update({ _id: channel.rocketId }, { $addToSet: { importIds: channel.id } });
} else {
const users = channel.members
.reduce((ret, member) => {
if (member !== channel.creator) {
const user = this.getRocketUser(member);
if (user && user.username) {
ret.push(user.username);
}
}
return ret;
}, []);
let userId = startedByUserId;
this.users.users.forEach(user => {
if (user.id === channel.creator && user.do_import) {
userId = user.rocketId;
}
return ret;
}, []);
let userId = startedByUserId;
this.users.users.forEach(user => {
if (user.id === channel.creator && user.do_import) {
userId = user.rocketId;
}
});
Meteor.runAsUser(userId, () => {
const returned = Meteor.call('createChannel', channel.name, users);
channel.rocketId = returned.rid;
});
});
Meteor.runAsUser(userId, () => {
const returned = Meteor.call('createChannel', channel.name, users);
channel.rocketId = returned.rid;
});
// @TODO implement model specific function
const roomUpdate = {
ts: new Date(channel.created * 1000)
};
if (!_.isEmpty(channel.topic && channel.topic.value)) {
roomUpdate.topic = channel.topic.value;
}
if (!_.isEmpty(channel.purpose && channel.purpose.value)) {
roomUpdate.description = channel.purpose.value;
// @TODO implement model specific function
const roomUpdate = {
ts: new Date(channel.created * 1000)
};
if (!_.isEmpty(channel.topic && channel.topic.value)) {
roomUpdate.topic = channel.topic.value;
}
if (!_.isEmpty(channel.purpose && channel.purpose.value)) {
roomUpdate.description = channel.purpose.value;
}
RocketChat.models.Rooms.update({ _id: channel.rocketId }, { $set: roomUpdate, $addToSet: { importIds: channel.id } });
}
RocketChat.models.Rooms.update({ _id: channel.rocketId }, { $set: roomUpdate, $addToSet: { importIds: channel.id } });
}
this.addCountCompleted(1);
this.addCountCompleted(1);
});
});
});
this.collection.update({ _id: this.channels._id }, { $set: { 'channels': this.channels.channels }});
const missedTypes = {};
const ignoreTypes = { 'bot_add': true, 'file_comment': true, 'file_mention': true };
this.updateProgress(Importer.ProgressStep.IMPORTING_MESSAGES);
Object.keys(this.messages).forEach(channel => {
const messagesObj = this.messages[channel];
Meteor.runAsUser(startedByUserId, () =>{
const slackChannel = this.getSlackChannelFromName(channel);
if (!slackChannel || !slackChannel.do_import) { return; }
const room = RocketChat.models.Rooms.findOneById(slackChannel.rocketId, { fields: { usernames: 1, t: 1, name: 1 } });
Object.keys(messagesObj).forEach(date => {
const msgs = messagesObj[date];
msgs.messages.forEach(message => {
this.updateRecord({ 'messagesstatus': '#{channel}/#{date}.#{msgs.messages.length}' });
const msgDataDefaults ={
_id: `slack-${ slackChannel.id }-${ message.ts.replace(/\./g, '-') }`,
ts: new Date(parseInt(message.ts.split('.')[0]) * 1000)
};
if (message.type === 'message') {
if (message.subtype) {
if (message.subtype === 'channel_join') {
if (this.getRocketUser(message.user)) {
RocketChat.models.Messages.createUserJoinWithRoomIdAndUser(room._id, this.getRocketUser(message.user), msgDataDefaults);
}
} else if (message.subtype === 'channel_leave') {
if (this.getRocketUser(message.user)) {
RocketChat.models.Messages.createUserLeaveWithRoomIdAndUser(room._id, this.getRocketUser(message.user), msgDataDefaults);
}
} else if (message.subtype === 'me_message') {
const msgObj = {
...msgDataDefaults,
msg: `_${ this.convertSlackMessageToRocketChat(message.text) }_`
};
RocketChat.sendMessage(this.getRocketUser(message.user), msgObj, room, true);
} else if (message.subtype === 'bot_message' || message.subtype === 'slackbot_response') {
const botUser = RocketChat.models.Users.findOneById('rocket.cat', { fields: { username: 1 }});
const botUsername = this.bots[message.bot_id] ? this.bots[message.bot_id].name : message.username;
const msgObj = {
...msgDataDefaults,
msg: this.convertSlackMessageToRocketChat(message.text),
rid: room._id,
bot: true,
attachments: message.attachments,
username: botUsername || undefined
};
if (message.edited) {
msgObj.editedAt = new Date(parseInt(message.edited.ts.split('.')[0]) * 1000);
const editedBy = this.getRocketUser(message.edited.user);
if (editedBy) {
msgObj.editedBy = {
_id: editedBy._id,
username: editedBy.username
};
}
}
this.collection.update({ _id: this.channels._id }, { $set: { 'channels': this.channels.channels }});
if (message.icons) {
msgObj.emoji = message.icons.emoji;
}
RocketChat.sendMessage(botUser, msgObj, room, true);
} else if (message.subtype === 'channel_purpose') {
if (this.getRocketUser(message.user)) {
RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser('room_changed_description', room._id, message.purpose, this.getRocketUser(message.user), msgDataDefaults);
}
} else if (message.subtype === 'channel_topic') {
if (this.getRocketUser(message.user)) {
RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser('room_changed_topic', room._id, message.topic, this.getRocketUser(message.user), msgDataDefaults);
}
} else if (message.subtype === 'channel_name') {
if (this.getRocketUser(message.user)) {
RocketChat.models.Messages.createRoomRenamedWithRoomIdRoomNameAndUser(room._id, message.name, this.getRocketUser(message.user), msgDataDefaults);
const missedTypes = {};
const ignoreTypes = { 'bot_add': true, 'file_comment': true, 'file_mention': true };
this.updateProgress(Importer.ProgressStep.IMPORTING_MESSAGES);
Object.keys(this.messages).forEach(channel => {
const messagesObj = this.messages[channel];
Meteor.runAsUser(startedByUserId, () =>{
const slackChannel = this.getSlackChannelFromName(channel);
if (!slackChannel || !slackChannel.do_import) { return; }
const room = RocketChat.models.Rooms.findOneById(slackChannel.rocketId, { fields: { usernames: 1, t: 1, name: 1 } });
Object.keys(messagesObj).forEach(date => {
const msgs = messagesObj[date];
msgs.messages.forEach(message => {
this.updateRecord({ 'messagesstatus': `${ channel }/${ date }.${ msgs.messages.length }` });
const msgDataDefaults ={
_id: `slack-${ slackChannel.id }-${ message.ts.replace(/\./g, '-') }`,
ts: new Date(parseInt(message.ts.split('.')[0]) * 1000)
};
// Process the reactions
if (message.reactions && message.reactions.length > 0) {
msgDataDefaults.reactions = {};
message.reactions.forEach(reaction => {
msgDataDefaults.reactions[reaction.name] = { usernames: [] };
reaction.users.forEach(u => {
const rcUser = this.getRocketUser(u);
if (!rcUser) { return; }
msgDataDefaults.reactions[reaction.name].usernames.push(rcUser.username);
});
if (msgDataDefaults.reactions[reaction.name].usernames.length === 0) {
delete msgDataDefaults.reactions[reaction.name];
}
} else if (message.subtype === 'pinned_item') {
if (message.attachments) {
});
}
if (message.type === 'message') {
if (message.subtype) {
if (message.subtype === 'channel_join') {
if (this.getRocketUser(message.user)) {
RocketChat.models.Messages.createUserJoinWithRoomIdAndUser(room._id, this.getRocketUser(message.user), msgDataDefaults);
}
} else if (message.subtype === 'channel_leave') {
if (this.getRocketUser(message.user)) {
RocketChat.models.Messages.createUserLeaveWithRoomIdAndUser(room._id, this.getRocketUser(message.user), msgDataDefaults);
}
} else if (message.subtype === 'me_message') {
const msgObj = {
...msgDataDefaults,
attachments: [{
'text': this.convertSlackMessageToRocketChat(message.attachments[0].text),
'author_name' : message.attachments[0].author_subname,
'author_icon' : getAvatarUrlFromUsername(message.attachments[0].author_subname)
}]
msg: `_${ this.convertSlackMessageToRocketChat(message.text) }_`
};
RocketChat.models.Messages.createWithTypeRoomIdMessageAndUser('message_pinned', room._id, '', this.getRocketUser(message.user), msgObj);
} else {
//TODO: make this better
this.logger.debug('Pinned item with no attachment, needs work.');
//RocketChat.models.Messages.createWithTypeRoomIdMessageAndUser 'message_pinned', room._id, '', @getRocketUser(message.user), msgDataDefaults
}
} else if (message.subtype === 'file_share') {
if (message.file && message.file.url_private_download !== undefined) {
const details = {
message_id: `slack-${ message.ts.replace(/\./g, '-') }`,
name: message.file.name,
size: message.file.size,
type: message.file.mimetype,
rid: room._id
RocketChat.sendMessage(this.getRocketUser(message.user), msgObj, room, true);
} else if (message.subtype === 'bot_message' || message.subtype === 'slackbot_response') {
const botUser = RocketChat.models.Users.findOneById('rocket.cat', { fields: { username: 1 }});
const botUsername = this.bots[message.bot_id] ? this.bots[message.bot_id].name : message.username;
const msgObj = {
...msgDataDefaults,
msg: this.convertSlackMessageToRocketChat(message.text),
rid: room._id,
bot: true,
attachments: message.attachments,
username: botUsername || undefined
};
this.uploadFile(details, message.file.url_private_download, this.getRocketUser(message.user), room, new Date(parseInt(message.ts.split('.')[0]) * 1000));
}
} else if (!missedTypes[message.subtype] && !ignoreTypes[message.subtype]) {
missedTypes[message.subtype] = message;
}
} else {
const user = this.getRocketUser(message.user);
if (user) {
const msgObj = {
...msgDataDefaults,
msg: this.convertSlackMessageToRocketChat(message.text),
rid: room._id,
u: {
_id: user._id,
username: user.username
if (message.edited) {
msgObj.editedAt = new Date(parseInt(message.edited.ts.split('.')[0]) * 1000);
const editedBy = this.getRocketUser(message.edited.user);
if (editedBy) {
msgObj.editedBy = {
_id: editedBy._id,
username: editedBy.username
};
}
}
if (message.icons) {
msgObj.emoji = message.icons.emoji;
}
RocketChat.sendMessage(botUser, msgObj, room, true);
} else if (message.subtype === 'channel_purpose') {
if (this.getRocketUser(message.user)) {
RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser('room_changed_description', room._id, message.purpose, this.getRocketUser(message.user), msgDataDefaults);
}
} else if (message.subtype === 'channel_topic') {
if (this.getRocketUser(message.user)) {
RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser('room_changed_topic', room._id, message.topic, this.getRocketUser(message.user), msgDataDefaults);
}
};
if (message.edited) {
msgObj.editedAt = new Date(parseInt(message.edited.ts.split('.')[0]) * 1000);
const editedBy = this.getRocketUser(message.edited.user);
if (editedBy) {
msgObj.editedBy = {
_id: editedBy._id,
username: editedBy.username
} else if (message.subtype === 'channel_name') {
if (this.getRocketUser(message.user)) {
RocketChat.models.Messages.createRoomRenamedWithRoomIdRoomNameAndUser(room._id, message.name, this.getRocketUser(message.user), msgDataDefaults);
}
} else if (message.subtype === 'pinned_item') {
if (message.attachments) {
const msgObj = {
...msgDataDefaults,
attachments: [{
'text': this.convertSlackMessageToRocketChat(message.attachments[0].text),
'author_name' : message.attachments[0].author_subname,
'author_icon' : getAvatarUrlFromUsername(message.attachments[0].author_subname)
}]
};
RocketChat.models.Messages.createWithTypeRoomIdMessageAndUser('message_pinned', room._id, '', this.getRocketUser(message.user), msgObj);
} else {
//TODO: make this better
this.logger.debug('Pinned item with no attachment, needs work.');
//RocketChat.models.Messages.createWithTypeRoomIdMessageAndUser 'message_pinned', room._id, '', @getRocketUser(message.user), msgDataDefaults
}
} else if (message.subtype === 'file_share') {
if (message.file && message.file.url_private_download !== undefined) {
const details = {
message_id: `slack-${ message.ts.replace(/\./g, '-') }`,
name: message.file.name,
size: message.file.size,
type: message.file.mimetype,
rid: room._id
};
this.uploadFile(details, message.file.url_private_download, this.getRocketUser(message.user), room, new Date(parseInt(message.ts.split('.')[0]) * 1000));
}
} else if (!missedTypes[message.subtype] && !ignoreTypes[message.subtype]) {
missedTypes[message.subtype] = message;
}
} else {
const user = this.getRocketUser(message.user);
if (user) {
const msgObj = {
...msgDataDefaults,
msg: this.convertSlackMessageToRocketChat(message.text),
rid: room._id,
u: {
_id: user._id,
username: user.username
}
};
if (message.edited) {
msgObj.editedAt = new Date(parseInt(message.edited.ts.split('.')[0]) * 1000);
const editedBy = this.getRocketUser(message.edited.user);
if (editedBy) {
msgObj.editedBy = {
_id: editedBy._id,
username: editedBy.username
};
}
}
RocketChat.sendMessage(this.getRocketUser(message.user), msgObj, room, true);
try {
RocketChat.sendMessage(this.getRocketUser(message.user), msgObj, room, true);
} catch (e) {
this.logger.warn(`Failed to import the message: ${ msgDataDefaults._id }`);
}
}
}
}
}
// Process the reactions
if (RocketChat.models.Messages.findOneById(msgDataDefaults._id) && message.reactions && message.reactions.length > 0) {
message.reactions.forEach(reaction => {
reaction.users.forEach(u => {
const rcUser = this.getRocketUser(u);
if (!rcUser) { return; }
Meteor.runAsUser(rcUser._id, () => Meteor.call('setReaction', `:${ reaction.name }:`, msgDataDefaults._id));
});
});
}
this.addCountCompleted(1);
this.addCountCompleted(1);
});
});
});
});
});
if (!_.isEmpty(missedTypes)) {
console.log('Missed import types:', missedTypes);
}
this.updateProgress(Importer.ProgressStep.FINISHING);
this.channels.channels.forEach(channel => {
if (channel.do_import && channel.is_archived) {
Meteor.runAsUser(startedByUserId, function() {
Meteor.call('archiveRoom', channel.rocketId);
});
if (!_.isEmpty(missedTypes)) {
console.log('Missed import types:', missedTypes);
}
});
this.updateProgress(Importer.ProgressStep.DONE);
const timeTook = Date.now() - start;
this.updateProgress(Importer.ProgressStep.FINISHING);
this.logger.log(`Import took ${ timeTook } milliseconds.`);
this.channels.channels.forEach(channel => {
if (channel.do_import && channel.is_archived) {
Meteor.runAsUser(startedByUserId, function() {
Meteor.call('archiveRoom', channel.rocketId);
});
}
});
this.updateProgress(Importer.ProgressStep.DONE);
const timeTook = Date.now() - start;
this.logger.log(`Import took ${ timeTook } milliseconds.`);
} catch (e) {
this.logger.error(e);
this.updateProgress(Importer.ProgressStep.ERROR);
}
});
return this.getProgress();
}
getSlackChannelFromName(channelName) {

@ -3,30 +3,26 @@
<header class="fixed-title border-component-color">
{{> burger}}
<h2>
<span class="room-title">Import</span>
<span class="room-title">{{_ "Import"}}</span>
</h2>
</header>
<div class="content">
{{#unless isAdmin}}
<p>You are not authorized to view this page.</p>
<p>{{_ "You_are_not_authorized_to_view_this_page"}}</p>
{{else}}
{{#if isImporters}}
<div class="rocket-form">
<fieldset>
{{#each importers}}
<div class="section">
<h1>{{name}}</h1>
<h1>{{ name }}</h1>
<div class="section-content">
<div>{{getDescription .}}</div>
<button class="button primary start-import">Start</button>
<button class="button primary start-import">{{_ "Start"}}</button>
</div>
</div>
{{/each}}
</fieldset>
</div>
{{else}}
No Importers Available
{{/if}}
{{/unless}}
</div>
</section>

@ -3,9 +3,6 @@ Template.adminImport.helpers({
isAdmin() {
return RocketChat.authz.hasRole(Meteor.userId(), 'admin');
},
isImporters() {
return Object.keys(Importer.Importers).length > 0;
},
getDescription(importer) {
return TAPi18n.__('Importer_From_Description', { from: importer.name });
},
@ -22,12 +19,15 @@ Template.adminImport.helpers({
Template.adminImport.events({
'click .start-import'() {
const importer = this;
return Meteor.call('setupImporter', importer.key, function(error) {
Meteor.call('setupImporter', importer.key, function(error) {
if (error) {
console.log(t('importer_setup_error'), importer.key, error);
return handleError(error);
handleError(error);
return;
}
return FlowRouter.go(`/admin/import/prepare/${ importer.key }`);
FlowRouter.go(`/admin/import/prepare/${ importer.key }`);
});
}
});

@ -9,7 +9,7 @@
</header>
<div class="content">
{{#unless isAdmin}}
<p>You are not authorized to view this page.</p>
<p>{{_ "You_are_not_authorized_to_view_this_page"}}</p>
{{else}}
<div class="rocket-form">
<fieldset>

@ -36,7 +36,7 @@ Template.adminImportPrepare.helpers({
Template.adminImportPrepare.events({
'change .import-file-input'(event, template) {
const importer = this;
if (!importer.key) { return; }
if (!importer || !importer.key) { return; }
const e = event.originalEvent || event;
let { files } = e.target;
@ -44,13 +44,13 @@ Template.adminImportPrepare.events({
files = (e.dataTransfer != null ? e.dataTransfer.files : undefined) || [];
}
return Array.from(files).map((blob) => {
return Array.from(files).map((file) => {
template.preparing.set(true);
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.readAsDataURL(file);
reader.onloadend = () => {
Meteor.call('prepareImport', importer.key, reader.result, blob.type, blob.name, function(error, data) {
Meteor.call('prepareImport', importer.key, reader.result, file.type, file.name, function(error, data) {
if (error) {
toastr.error(t('Invalid_Import_File_Type'));
template.preparing.set(false);
@ -84,7 +84,6 @@ Template.adminImportPrepare.events({
'click .button.start'(event, template) {
const btn = this;
$(btn).prop('disabled', true);
// const importer = this;
for (const user of Array.from(template.users.get())) {
user.do_import = $(`[name=${ user.user_id }]`).is(':checked');
}
@ -93,12 +92,12 @@ Template.adminImportPrepare.events({
channel.do_import = $(`[name=${ channel.channel_id }]`).is(':checked');
}
return Meteor.call('startImport', FlowRouter.getParam('importer'), { users: template.users.get(), channels: template.channels.get() }, function(error) {
Meteor.call('startImport', FlowRouter.getParam('importer'), { users: template.users.get(), channels: template.channels.get() }, function(error) {
if (error) {
console.warn('Error on starting the import:', error);
return handleError(error);
handleError(error);
} else {
return FlowRouter.go(`/admin/import/progress/${ FlowRouter.getParam('importer') }`);
FlowRouter.go(`/admin/import/progress/${ FlowRouter.getParam('importer') }`);
}
});
},

@ -61,17 +61,22 @@ Importer.Base = class Base {
this.addCountCompleted = this.addCountCompleted.bind(this);
this.updateRecord = this.updateRecord.bind(this);
this.uploadFile = this.uploadFile.bind(this);
this.name = name;
this.description = description;
this.mimeType = mimeType;
this.logger = new Logger(`${ this.name } Importer`, {});
this.progress = new Importer.Progress(this.name);
this.collection = Importer.RawImports;
const importId = Importer.Imports.insert({ 'type': this.name, 'ts': Date.now(), 'status': this.progress.step, 'valid': true, 'user': Meteor.user()._id });
this.importRecord = Importer.Imports.findOne(importId);
this.users = {};
this.channels = {};
this.messages = {};
this.oldSettings = {};
}
// Takes the uploaded file and extracts the users, channels, and messages from it.
@ -89,6 +94,7 @@ Importer.Base = class Base {
if (!fileType || (fileType.mime !== this.mimeType)) {
this.logger.warn(`Invalid file uploaded for the ${ this.name } importer.`);
this.updateProgress(Importer.ProgressStep.ERROR);
throw new Meteor.Error('error-invalid-file-uploaded', `Invalid file uploaded to import ${ this.name } data from.`, { step: 'prepare' });
}
@ -137,6 +143,21 @@ Importer.Base = class Base {
updateProgress(step) {
this.progress.step = step;
switch (step) {
case Importer.ProgressStep.IMPORTING_STARTED:
this.oldSettings.Accounts_AllowedDomainsList = RocketChat.models.Settings.findOneById('Accounts_AllowedDomainsList').value;
RocketChat.models.Settings.updateValueById('Accounts_AllowedDomainsList', '');
this.oldSettings.Accounts_AllowUsernameChange = RocketChat.models.Settings.findOneById('Accounts_AllowUsernameChange').value;
RocketChat.models.Settings.updateValueById('Accounts_AllowUsernameChange', true);
break;
case Importer.ProgressStep.DONE:
case Importer.ProgressStep.ERROR:
RocketChat.models.Settings.updateValueById('Accounts_AllowedDomainsList', this.oldSettings.Accounts_AllowedDomainsList);
RocketChat.models.Settings.updateValueById('Accounts_AllowUsernameChange', this.oldSettings.Accounts_AllowUsernameChange);
break;
}
this.logger.debug(`${ this.name } is now at ${ step }.`);
this.updateRecord({ 'status': this.progress.step });

@ -7,7 +7,11 @@ Meteor.methods({
}
if (!RocketChat.authz.hasPermission(Meteor.userId(), 'run-import')) {
throw new Meteor.Error('error-action-not-allowed', 'Importing is not allowed', { method: 'setupImporter'});
throw new Meteor.Error('error-action-not-allowed', 'Importing is not allowed', { method: 'startImport'});
}
if (!name) {
throw new Meteor.Error('error-invalid-importer', `No defined importer by: "${ name }"`, { method: 'startImport' });
}
if (Importer.Importers[name] && Importer.Importers[name].importerInstance) {

@ -20,14 +20,10 @@ RocketChat.callbacks.add('beforeSaveMessage', function(message) {
});
// Also throw to stop propagation of 'sendMessage'.
throw new Meteor.Error(
'error-action-not-allowed',
'Notify all in this room not allowed',
{
method: 'filterATAllTag',
action: 'Notify_all_in_this_room'
}
);
throw new Meteor.Error('error-action-not-allowed', 'Notify all in this room not allowed', {
method: 'filterATAllTag',
action: 'Notify_all_in_this_room'
});
}
}

@ -13,7 +13,7 @@ Meteor.methods({
throw new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'setUsername' });
}
if (user.username === username) {
if (user.username === username || (user.username && user.username.toLowerCase() === username.toLowerCase())) {
return username;
}
@ -28,13 +28,7 @@ Meteor.methods({
throw new Meteor.Error('username-invalid', `${ _.escape(username) } is not a valid username, use only letters, numbers, dots, hyphens and underscores`);
}
if (user.username !== undefined) {
if (!username.toLowerCase() === user.username.toLowerCase()) {
if (!RocketChat.checkUsernameAvailability(username)) {
throw new Meteor.Error('error-field-unavailable', `<strong>${ _.escape(username) }</strong> is already in use :(`, { method: 'setUsername', field: username });
}
}
} else if (!RocketChat.checkUsernameAvailability(username)) {
if (!RocketChat.checkUsernameAvailability(username)) {
throw new Meteor.Error('error-field-unavailable', `<strong>${ _.escape(username) }</strong> is already in use :(`, { method: 'setUsername', field: username });
}

Loading…
Cancel
Save