[FIX] Several Problems on HipChat Importer (#13336)

* [IMPROVE] Reduce memory consume of HipChat Enterprise importer

* [IMPROVE] Add users of public channels on HipChat Enterprise importer

* Hipchat importer: add support to import folders

* Fix condition

* [FIX] Deleted users imported as active

* Added more info to log

* Prevent issues with complex user ids

* Improve importer logs

* Improve code quality

* Fixed import of attached files on channels

* Fixed room names imported from hipchat enterprise

* Fixed attachment import
pull/13434/head^2
Pierre H. Lehnen 7 years ago committed by Rodrigo Nascimento
parent a93111873d
commit d5166fdb9c
  1. 427
      packages/rocketchat-importer-hipchat-enterprise/server/importer.js
  2. 4
      packages/rocketchat-importer/client/admin/adminImportPrepare.js
  3. 5
      packages/rocketchat-importer/server/classes/ImporterBase.js
  4. 8
      packages/rocketchat-importer/server/methods/downloadPublicImportFile.js
  5. 3
      packages/rocketchat-importer/server/methods/getImportFileData.js

@ -41,29 +41,23 @@ export class HipChatEnterpriseImporter extends Base {
this.tarStream = require('tar-stream');
this.extract = this.tarStream.extract();
this.path = path;
this.messages = new Map();
this.directMessages = new Map();
this.emailList = [];
}
async parseData(data) {
const dataString = Buffer.concat(data).toString();
let file;
parseData(data) {
const dataString = data.toString();
try {
this.logger.debug('parsing file contents');
file = JSON.parse(dataString);
this.logger.debug('file parsed');
return JSON.parse(dataString);
} catch (e) {
console.error(e);
return false;
}
return file;
}
async storeTempUsers(tempUsers) {
await this.collection.upsert({
await this.collection.model.rawCollection().update({
import: this.importRecord._id,
importer: this.name,
type: 'users',
@ -73,9 +67,11 @@ export class HipChatEnterpriseImporter extends Base {
importer: this.name,
type: 'users',
},
$addToSet: {
$push: {
users: { $each: tempUsers },
},
}, {
upsert: true,
});
this.usersCount += tempUsers.length;
@ -122,7 +118,7 @@ export class HipChatEnterpriseImporter extends Base {
}
async storeTempRooms(tempRooms) {
await this.collection.upsert({
await this.collection.model.rawCollection().update({
import: this.importRecord._id,
importer: this.name,
type: 'channels',
@ -132,9 +128,11 @@ export class HipChatEnterpriseImporter extends Base {
importer: this.name,
type: 'channels',
},
$addToSet: {
$push: {
channels: { $each: tempRooms },
},
}, {
upsert: true,
});
this.channelsCount += tempRooms.length;
@ -150,7 +148,7 @@ export class HipChatEnterpriseImporter extends Base {
id: r.Room.id,
creator: r.Room.owner,
created: new Date(r.Room.created),
name: s.slugify(r.Room.name),
name: r.Room.name,
isPrivate: r.Room.privacy === 'private',
isArchived: r.Room.is_archived,
topic: r.Room.topic,
@ -176,7 +174,7 @@ export class HipChatEnterpriseImporter extends Base {
this.logger.debug('dumping messages to database');
const name = subIndex ? `${ roomIdentifier }/${ index }/${ subIndex }` : `${ roomIdentifier }/${ index }`;
await this.collection.insert({
await this.collection.model.rawCollection().insert({
import: this.importRecord._id,
importer: this.name,
type: 'messages',
@ -204,6 +202,7 @@ export class HipChatEnterpriseImporter extends Base {
}
async prepareUserMessagesFile(file, roomIdentifier, index) {
await this.loadExistingMessagesIfNecessary();
let msgs = [];
this.logger.debug(`preparing room with ${ file.length } messages `);
for (const m of file) {
@ -252,7 +251,18 @@ export class HipChatEnterpriseImporter extends Base {
return false;
}
return Boolean(RocketChat.models.Messages.findOne({ _id: messageId }, { fields: { _id: 1 }, limit: 1 }));
return this._previewsMessagesIds.has(messageId);
}
async loadExistingMessagesIfNecessary() {
if (this._hasAnyImportedMessage === false) {
return false;
}
if (!this._previewsMessagesIds) {
this._previewsMessagesIds = new Set();
await RocketChat.models.Messages.model.rawCollection().find({}, { fields: { _id: 1 } }).forEach((i) => this._previewsMessagesIds.add(i._id));
}
}
async prepareRoomMessagesFile(file, roomIdentifier, id, index) {
@ -260,11 +270,13 @@ export class HipChatEnterpriseImporter extends Base {
this.logger.debug(`preparing room with ${ file.length } messages `);
let subIndex = 0;
await this.loadExistingMessagesIfNecessary();
for (const m of file) {
if (m.UserMessage) {
const newId = `hipchatenterprise-${ id }-user-${ m.UserMessage.id }`;
const skipMessage = this._checkIfMessageExists(newId);
const skipAttachment = (skipMessage && m.UserMessage.attachment_path ? this._checkIfMessageExists(`${ newId }-attachment`) : true);
const skipAttachment = (skipMessage && (m.UserMessage.attachment_path ? this._checkIfMessageExists(`${ newId }-attachment`) : true));
if (!skipMessage || !skipAttachment) {
roomMsgs.push({
@ -312,8 +324,12 @@ export class HipChatEnterpriseImporter extends Base {
skip: skipMessage,
});
}
} else if (m.ArchiveRoomMessage) {
this.logger.warn('Archived Room Notification was ignored.');
} else if (m.GuestAccessMessage) {
this.logger.warn('Guess Access Notification was ignored.');
} else {
this.logger.warn('HipChat Enterprise importer isn\'t configured to handle this message:', m);
this.logger.error('HipChat Enterprise importer isn\'t configured to handle this message:', m);
}
if (roomMsgs.length >= 500) {
@ -348,15 +364,15 @@ export class HipChatEnterpriseImporter extends Base {
messageGroupIndex++;
return this.prepareRoomMessagesFile(file, roomIdentifier, id, messageGroupIndex);
default:
this.logger.warn(`HipChat Enterprise importer isn't configured to handle "${ type }" files.`);
this.logger.error(`HipChat Enterprise importer isn't configured to handle "${ type }" files (${ info.dir }).`);
return 0;
}
}
async prepareFile(info, data, fileName) {
const file = await this.parseData(data);
const file = this.parseData(data);
if (file === false) {
this.logger.warn('failed to parse data');
this.logger.error('failed to parse data');
return false;
}
@ -370,17 +386,202 @@ export class HipChatEnterpriseImporter extends Base {
case 'history.json':
return await this.prepareMessagesFile(file, info);
case 'emoticons.json':
this.logger.warn('HipChat Enterprise importer doesn\'t import emoticons.', info);
this.logger.error('HipChat Enterprise importer doesn\'t import emoticons.', info);
break;
default:
this.logger.warn(`HipChat Enterprise importer doesn't know what to do with the file "${ fileName }" :o`, info);
this.logger.error(`HipChat Enterprise importer doesn't know what to do with the file "${ fileName }" :o`, info);
break;
}
return 0;
}
async _prepareFolderEntry(fullEntryPath, relativeEntryPath) {
const files = fs.readdirSync(fullEntryPath);
for (const fileName of files) {
try {
const fullFilePath = path.join(fullEntryPath, fileName);
const fullRelativePath = path.join(relativeEntryPath, fileName);
this.logger.info(`new entry from import folder: ${ fileName }`);
if (fs.statSync(fullFilePath).isDirectory()) {
await this._prepareFolderEntry(fullFilePath, fullRelativePath);
continue;
}
if (!fileName.endsWith('.json')) {
continue;
}
let fileData;
const promise = new Promise((resolve, reject) => {
fs.readFile(fullFilePath, (error, data) => {
if (error) {
this.logger.error(error);
return reject(error);
}
fileData = data;
return resolve();
});
});
await promise.catch((error) => {
this.logger.error(error);
fileData = null;
});
if (!fileData) {
this.logger.info(`Skipping the file: ${ fileName }`);
continue;
}
this.logger.info(`Processing the file: ${ fileName }`);
const info = this.path.parse(fullRelativePath);
await this.prepareFile(info, fileData, fileName);
this.logger.debug('moving to next import folder entry');
} catch (e) {
this.logger.debug('failed to prepare file');
this.logger.error(e);
}
}
}
prepareUsingLocalFolder(fullFolderPath) {
this.logger.debug('start preparing import operation using local folder');
this.collection.remove({});
this.emailList = [];
this._hasAnyImportedMessage = Boolean(RocketChat.models.Messages.findOne({ _id: /hipchatenterprise\-.*/ }));
this.usersCount = 0;
this.channelsCount = 0;
this.messagesCount = 0;
// HipChat duplicates direct messages (one for each user)
// This object will keep track of messages that have already been prepared so it doesn't try to do it twice
this.preparedMessages = {};
const promise = new Promise(async(resolve, reject) => {
try {
await this._prepareFolderEntry(fullFolderPath, '.');
this._finishPreparationProcess(resolve, reject);
} catch (e) {
this.logger.error(e);
reject(e);
}
});
return promise;
}
async _finishPreparationProcess(resolve, reject) {
await this.fixPublicChannelMembers();
this.logger.info('finished parsing files, checking for errors now');
this._previewsMessagesIds = undefined;
this.emailList = [];
this.preparedMessages = {};
super.updateRecord({ 'count.messages': this.messagesCount, messagesstatus: null });
super.addCountToTotal(this.messagesCount);
// Check if any of the emails used are already taken
if (this.emailList.length > 0) {
const conflictingUsers = RocketChat.models.Users.find({ 'emails.address': { $in: this.emailList } });
const conflictingUserEmails = [];
conflictingUsers.forEach((conflictingUser) => {
if (conflictingUser.emails && conflictingUser.emails.length) {
conflictingUser.emails.forEach((email) => {
conflictingUserEmails.push(email.address);
});
}
});
if (conflictingUserEmails.length > 0) {
this.flagConflictingEmails(conflictingUserEmails);
}
}
// Ensure we have some users, channels, and messages
if (!this.usersCount && !this.channelsCount && !this.messagesCount) {
this.logger.info(`users: ${ this.usersCount }, channels: ${ this.channelsCount }, messages = ${ this.messagesCount }`);
super.updateProgress(ProgressStep.ERROR);
reject(new Meteor.Error('error-import-file-is-empty'));
return;
}
const tempUsers = this.collection.findOne({
import: this.importRecord._id,
importer: this.name,
type: 'users',
});
const tempChannels = this.collection.findOne({
import: this.importRecord._id,
importer: this.name,
type: 'channels',
});
const selectionUsers = tempUsers.users.map((u) => new SelectionUser(u.id, u.username, u.email, u.isDeleted, false, u.do_import !== false, u.is_email_taken === true));
const selectionChannels = tempChannels.channels.map((r) => new SelectionChannel(r.id, r.name, r.isArchived, true, r.isPrivate, r.creator));
const selectionMessages = this.messagesCount;
super.updateProgress(ProgressStep.USER_SELECTION);
resolve(new Selection(this.name, selectionUsers, selectionChannels, selectionMessages));
}
async fixPublicChannelMembers() {
await this.collection.model.rawCollection().aggregate([{
$match: {
import: this.importRecord._id,
type: 'channels',
},
}, {
$unwind: '$channels',
}, {
$match: {
'channels.members.0': { $exists: false },
},
}, {
$group: { _id: '$channels.id' },
}]).forEach(async(channel) => {
const userIds = (await this.collection.model.rawCollection().aggregate([{
$match: {
$or: [
{ roomIdentifier: `rooms/${ channel._id }` },
{ roomIdentifier: `users/${ channel._id }` },
],
},
}, {
$unwind: '$messages',
}, {
$match: { 'messages.userId': { $ne: 'rocket.cat' } },
}, {
$group: { _id: '$messages.userId' },
}]).toArray()).map((i) => i._id);
await this.collection.model.rawCollection().update({
'channels.id': channel._id,
}, {
$set: {
'channels.$.members': userIds,
},
});
});
}
prepareUsingLocalFile(fullFilePath) {
if (fs.statSync(fullFilePath).isDirectory()) {
return this.prepareUsingLocalFolder(fullFilePath);
}
this.logger.debug('start preparing import operation');
this.collection.remove({});
this.emailList = [];
@ -404,15 +605,18 @@ export class HipChatEnterpriseImporter extends Base {
}
const info = this.path.parse(header.name);
const data = [];
let pos = 0;
let data = Buffer.allocUnsafe(header.size);
stream.on('data', Meteor.bindEnvironment((chunk) => {
data.push(chunk);
data.fill(chunk, pos, pos + chunk.length);
pos += chunk.length;
}));
stream.on('end', Meteor.bindEnvironment(async() => {
this.logger.debug(`Processing the file: ${ header.name }`);
this.logger.info(`Processing the file: ${ header.name }`);
await this.prepareFile(info, data, header.name);
data = undefined;
this.logger.debug('next import entry');
next();
@ -423,68 +627,19 @@ export class HipChatEnterpriseImporter extends Base {
}));
this.extract.on('error', (err) => {
this.logger.warn('extract error:', err);
this.logger.error('extract error:', err);
reject(new Meteor.Error('error-import-file-extract-error'));
});
this.extract.on('finish', Meteor.bindEnvironment(() => {
this.logger.debug('finished parsing files, checking for errors now');
super.updateRecord({ 'count.messages': this.messagesCount, messagesstatus: null });
super.addCountToTotal(this.messagesCount);
// Check if any of the emails used are already taken
if (this.emailList.length > 0) {
const conflictingUsers = RocketChat.models.Users.find({ 'emails.address': { $in: this.emailList } });
const conflictingUserEmails = [];
conflictingUsers.forEach((conflictingUser) => {
if (conflictingUser.emails && conflictingUser.emails.length) {
conflictingUser.emails.forEach((email) => {
conflictingUserEmails.push(email.address);
});
}
});
if (conflictingUserEmails.length > 0) {
this.flagConflictingEmails(conflictingUserEmails);
}
}
// Ensure we have some users, channels, and messages
if (!this.usersCount && !this.channelsCount && !this.messagesCount) {
this.logger.debug(`users: ${ this.usersCount }, channels: ${ this.channelsCount }, messages = ${ this.messagesCount }`);
super.updateProgress(ProgressStep.ERROR);
reject(new Meteor.Error('error-import-file-is-empty'));
return;
}
const tempUsers = this.collection.findOne({
import: this.importRecord._id,
importer: this.name,
type: 'users',
});
const tempChannels = this.collection.findOne({
import: this.importRecord._id,
importer: this.name,
type: 'channels',
});
const selectionUsers = tempUsers.users.map((u) => new SelectionUser(u.id, u.username, u.email, u.isDeleted, false, u.do_import !== false, u.is_email_taken === true));
const selectionChannels = tempChannels.channels.map((r) => new SelectionChannel(r.id, r.name, r.isArchived, true, r.isPrivate, r.creator));
const selectionMessages = this.messagesCount;
super.updateProgress(ProgressStep.USER_SELECTION);
resolve(new Selection(this.name, selectionUsers, selectionChannels, selectionMessages));
this._finishPreparationProcess(resolve, reject);
}));
const rs = fs.createReadStream(fullFilePath);
const gunzip = this.zlib.createGunzip();
gunzip.on('error', (err) => {
this.logger.warn('extract error:', err);
this.logger.error('extract error:', err);
reject(new Meteor.Error('error-import-file-extract-error'));
});
this.logger.debug('start extracting import file');
@ -534,20 +689,21 @@ export class HipChatEnterpriseImporter extends Base {
this._saveUserIdReference(userToImport.id, existingUserId);
Meteor.runAsUser(existingUserId, () => {
RocketChat.models.Users.update({ _id: existingUserId }, { $addToSet: { importIds: userToImport.id } });
// TODO: Use moment timezone to calc the time offset - Meteor.call 'userSetUtcOffset', user.tz_offset / 3600
RocketChat.models.Users.setName(existingUserId, userToImport.name);
RocketChat.models.Users.update({ _id: existingUserId }, {
$push: {
importIds: userToImport.id,
},
$set: {
active: userToImport.isDeleted !== true,
name: userToImport.name,
username: userToImport.username,
},
});
// TODO: Think about using a custom field for the users "title" field
if (userToImport.avatar) {
Meteor.call('setAvatarFromService', `data:image/png;base64,${ userToImport.avatar }`);
}
// Deleted users are 'inactive' users in Rocket.Chat
if (userToImport.deleted) {
Meteor.call('setUserActiveStatus', existingUserId, false);
}
});
}
@ -574,16 +730,29 @@ export class HipChatEnterpriseImporter extends Base {
this.addUserError(userToImport.id, e);
}
} else {
const user = { email: userToImport.email, password: Random.id(), username: userToImport.username };
const user = {
email: userToImport.email,
password: Random.id(),
username: userToImport.username,
name: userToImport.name,
active: userToImport.isDeleted !== true,
};
if (!user.email) {
delete user.email;
}
if (!user.username) {
delete user.username;
}
if (!user.name) {
delete user.name;
}
try {
const userId = Accounts.createUser(user);
userToImport.rocketId = userId;
this._saveUserIdReference(userToImport.id, userId);
this._updateImportedUser(userToImport, userId);
} catch (e) {
this.logger.error(e);
@ -731,6 +900,9 @@ export class HipChatEnterpriseImporter extends Base {
const timeTook = Date.now() - started;
this.logger.log(`HipChat Enterprise Import took ${ timeTook } milliseconds.`);
this._userDataCache = {};
this._userIdReference = {};
this._roomIdReference = {};
});
return super.getProgress();
@ -782,23 +954,25 @@ export class HipChatEnterpriseImporter extends Base {
const user = this.getRocketUserFromUserId(hipchatUserId);
if (!user) {
this.logger.warn(`User ${ hipchatUserId } not found on Rocket.Chat database.`);
this.logger.error(`User ${ hipchatUserId } not found on Rocket.Chat database.`);
return;
}
this.logger.info(`Creating user's subscription to room ${ room._id }, rocket.chat user is ${ user._id }, hipchat user is ${ hipchatUserId }`);
RocketChat.models.Subscriptions.createWithRoomAndUser(room, user, extra);
if (RocketChat.models.Subscriptions.find({ rid: room._id, 'u._id': user._id }, { limit: 1 }).count() === 0) {
this.logger.info(`Creating user's subscription to room ${ room._id }, rocket.chat user is ${ user._id }, hipchat user is ${ hipchatUserId }`);
RocketChat.models.Subscriptions.createWithRoomAndUser(room, user, extra);
}
});
}
_importChannel(channelToImport, startedByUserId) {
Meteor.runAsUser(startedByUserId, () => {
const existingRoom = RocketChat.models.Rooms.findOneByName(channelToImport.name);
const existingRoom = RocketChat.models.Rooms.findOneByName(s.slugify(channelToImport.name));
// If the room exists or the name of it is 'general', then we don't need to create it again
if (existingRoom || channelToImport.name.toUpperCase() === 'GENERAL') {
channelToImport.rocketId = channelToImport.name.toUpperCase() === 'GENERAL' ? 'GENERAL' : existingRoom._id;
this._saveRoomIdReference(channelToImport.id, channelToImport.rocketId);
RocketChat.models.Rooms.update({ _id: channelToImport.rocketId }, { $addToSet: { importIds: channelToImport.id } });
RocketChat.models.Rooms.update({ _id: channelToImport.rocketId }, { $push: { importIds: channelToImport.id } });
this._createSubscriptions(channelToImport, existingRoom || 'general');
} else {
@ -817,7 +991,7 @@ export class HipChatEnterpriseImporter extends Base {
});
if (channelToImport.rocketId) {
RocketChat.models.Rooms.update({ _id: channelToImport.rocketId }, { $set: { ts: channelToImport.created, topic: channelToImport.topic }, $addToSet: { importIds: channelToImport.id } });
RocketChat.models.Rooms.update({ _id: channelToImport.rocketId }, { $set: { ts: channelToImport.created, topic: channelToImport.topic }, $push: { importIds: channelToImport.id } });
this._createSubscriptions(channelToImport, channelToImport.rocketId);
}
}
@ -865,38 +1039,43 @@ export class HipChatEnterpriseImporter extends Base {
_importSingleMessage(msg, roomIdentifier, room) {
if (isNaN(msg.ts)) {
this.logger.warn(`Timestamp on a message in ${ roomIdentifier } is invalid`);
this.logger.error(`Timestamp on a message in ${ roomIdentifier } is invalid`);
return;
}
try {
const creator = this.getRocketUserFromUserId(msg.userId);
if (creator) {
this._importAttachment(msg, room, creator);
switch (msg.type) {
case 'user':
if (!msg.skip) {
RocketChat.insertMessage(creator, {
_id: msg.id,
ts: msg.ts,
msg: msg.text,
rid: room._id,
alias: msg.alias,
u: {
_id: creator._id,
username: creator.username,
},
}, room, false);
}
break;
case 'topic':
RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser('room_changed_topic', room._id, msg.text, creator, { _id: msg.id, ts: msg.ts });
break;
}
Meteor.runAsUser(creator._id, () => {
this._importAttachment(msg, room, creator);
switch (msg.type) {
case 'user':
if (!msg.skip) {
RocketChat.insertMessage(creator, {
_id: msg.id,
ts: msg.ts,
msg: msg.text,
rid: room._id,
alias: msg.alias,
u: {
_id: creator._id,
username: creator.username,
},
}, room, false);
}
break;
case 'topic':
RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser('room_changed_topic', room._id, msg.text, creator, { _id: msg.id, ts: msg.ts });
break;
}
});
} else {
this.logger.error(`Hipchat user not found: ${ msg.userId }`);
this.addMessageError(new Meteor.Error('error-message-sender-is-invalid'), `Hipchat user not found: ${ msg.userId }`);
}
} catch (e) {
console.error(e);
this.logger.error(e);
this.addMessageError(e, msg);
}
}
@ -977,18 +1156,18 @@ export class HipChatEnterpriseImporter extends Base {
this.logger.debug(`New list of user messages: ${ item._id }`);
const list = this.collection.findOneById(item._id);
if (!list) {
this.logger.warn('Record of user-messages list not found');
this.logger.error('Record of user-messages list not found');
return;
}
if (!list.messages) {
this.logger.warn('No message list found on record.');
this.logger.error('No message list found on record.');
return;
}
const { roomIdentifier } = list;
if (!this.getRocketUserFromRoomIdentifier(roomIdentifier)) {
this.logger.warn(`Skipping ${ list.messages.length } messages due to missing room.`);
this.logger.error(`Skipping ${ list.messages.length } messages due to missing room ( ${ roomIdentifier } ).`);
return;
}
@ -1005,7 +1184,7 @@ export class HipChatEnterpriseImporter extends Base {
list.messages.forEach((msg) => {
msgCount++;
if (isNaN(msg.ts)) {
this.logger.warn(`Timestamp on a message in ${ list.name } is invalid`);
this.logger.error(`Timestamp on a message in ${ list.name } is invalid`);
return;
}
@ -1015,7 +1194,7 @@ export class HipChatEnterpriseImporter extends Base {
}
if (!roomUsers[msg.senderId]) {
this.logger.warn('Skipping message due to missing sender.');
this.logger.error(`Skipping message due to missing sender ( ${ msg.senderId } ).`);
return;
}
@ -1025,7 +1204,7 @@ export class HipChatEnterpriseImporter extends Base {
}
if (!roomUsers[msg.receiverId]) {
this.logger.warn('Skipping message due to missing receiver.');
this.logger.error(`Skipping message due to missing receiver ( ${ msg.receiverId } ).`);
return;
}

@ -192,11 +192,11 @@ Template.adminImportPrepare.events({
const btn = this;
$(btn).prop('disabled', true);
for (const user of Array.from(template.users.get())) {
user.do_import = $(`[name=${ user.user_id }]`).is(':checked');
user.do_import = $(`[name='${ user.user_id }']`).is(':checked');
}
for (const channel of Array.from(template.channels.get())) {
channel.do_import = $(`[name=${ channel.channel_id }]`).is(':checked');
channel.do_import = $(`[name='${ channel.channel_id }']`).is(':checked');
}
Meteor.call('startImport', FlowRouter.getParam('importer'), { users: template.users.get(), channels: template.channels.get() }, function(error) {

@ -241,13 +241,18 @@ export class Base {
this.oldSettings.FileUpload_MediaTypeWhiteList = RocketChat.models.Settings.findOneById('FileUpload_MediaTypeWhiteList').value;
RocketChat.models.Settings.updateValueById('FileUpload_MediaTypeWhiteList', '*');
this.oldSettings.UI_Allow_room_names_with_special_chars = RocketChat.models.Settings.findOneById('UI_Allow_room_names_with_special_chars').value;
RocketChat.models.Settings.updateValueById('UI_Allow_room_names_with_special_chars', true);
break;
case ProgressStep.DONE:
case ProgressStep.ERROR:
case ProgressStep.CANCELLED:
RocketChat.models.Settings.updateValueById('Accounts_AllowedDomainsList', this.oldSettings.Accounts_AllowedDomainsList);
RocketChat.models.Settings.updateValueById('Accounts_AllowUsernameChange', this.oldSettings.Accounts_AllowUsernameChange);
RocketChat.models.Settings.updateValueById('FileUpload_MaxFileSize', this.oldSettings.FileUpload_MaxFileSize);
RocketChat.models.Settings.updateValueById('FileUpload_MediaTypeWhiteList', this.oldSettings.FileUpload_MediaTypeWhiteList);
RocketChat.models.Settings.updateValueById('UI_Allow_room_names_with_special_chars', this.oldSettings.UI_Allow_room_names_with_special_chars);
break;
}

@ -49,6 +49,14 @@ Meteor.methods({
if (!fs.existsSync(fileUrl)) {
throw new Meteor.Error('error-import-file-missing', fileUrl, { method: 'downloadPublicImportFile' });
}
// If the url is actually a folder path on the current machine, skip moving it to the file store
if (fs.statSync(fileUrl).isDirectory()) {
importer.instance.updateRecord({ file: fileUrl });
importer.instance.updateProgress(ProgressStep.DOWNLOAD_COMPLETE);
return;
}
copyLocalFile(fileUrl, writeStream);
}

@ -3,6 +3,7 @@ import { Meteor } from 'meteor/meteor';
import { Importers } from 'meteor/rocketchat:importer';
import { ProgressStep } from '../../lib/ImporterProgressStep';
import path from 'path';
import fs from 'fs';
Meteor.methods({
getImportFileData(importerKey) {
@ -55,7 +56,7 @@ Meteor.methods({
}
const fileName = importer.instance.importRecord.file;
const fullFilePath = path.join(RocketChatImportFileInstance.absolutePath, fileName);
const fullFilePath = fs.existsSync(fileName) ? fileName : path.join(RocketChatImportFileInstance.absolutePath, fileName);
const results = importer.instance.prepareUsingLocalFile(fullFilePath);
if (results instanceof Promise) {

Loading…
Cancel
Save