diff --git a/packages/rocketchat-importer-hipchat-enterprise/server/importer.js b/packages/rocketchat-importer-hipchat-enterprise/server/importer.js index 92b7a69c809..2a87dd8ca17 100644 --- a/packages/rocketchat-importer-hipchat-enterprise/server/importer.js +++ b/packages/rocketchat-importer-hipchat-enterprise/server/importer.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; } diff --git a/packages/rocketchat-importer/client/admin/adminImportPrepare.js b/packages/rocketchat-importer/client/admin/adminImportPrepare.js index 216301adcb5..6ba6e3db5b1 100644 --- a/packages/rocketchat-importer/client/admin/adminImportPrepare.js +++ b/packages/rocketchat-importer/client/admin/adminImportPrepare.js @@ -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) { diff --git a/packages/rocketchat-importer/server/classes/ImporterBase.js b/packages/rocketchat-importer/server/classes/ImporterBase.js index 036161e3ffd..802db96b664 100644 --- a/packages/rocketchat-importer/server/classes/ImporterBase.js +++ b/packages/rocketchat-importer/server/classes/ImporterBase.js @@ -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; } diff --git a/packages/rocketchat-importer/server/methods/downloadPublicImportFile.js b/packages/rocketchat-importer/server/methods/downloadPublicImportFile.js index 1f44d7a99d8..994c61160e3 100644 --- a/packages/rocketchat-importer/server/methods/downloadPublicImportFile.js +++ b/packages/rocketchat-importer/server/methods/downloadPublicImportFile.js @@ -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); } diff --git a/packages/rocketchat-importer/server/methods/getImportFileData.js b/packages/rocketchat-importer/server/methods/getImportFileData.js index 242954bf62d..bd13941ddea 100644 --- a/packages/rocketchat-importer/server/methods/getImportFileData.js +++ b/packages/rocketchat-importer/server/methods/getImportFileData.js @@ -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) {