Skip to content
Snippets Groups Projects
Commit c0a886f5 authored by Guilherme Gazzo's avatar Guilherme Gazzo
Browse files

Merge branch 'hipchat2js' of https://github.com/RocketChat/Rocket.Chat into hipchat2js

parents ea8ce483 b0f4404e
No related branches found
No related tags found
No related merge requests found
Importer.addImporter 'hipchat', Importer.HipChat,
name: 'HipChat'
mimeType: 'application/zip'
/* globals Importer */
Importer.addImporter('hipchat', Importer.HipChat, {
name: 'HipChat',
mimeType: 'application/zip'
});
......@@ -8,11 +8,10 @@ Package.describe({
Package.onUse(function(api) {
api.use([
'ecmascript',
'coffeescript',
'rocketchat:lib',
'rocketchat:importer'
]);
api.use('rocketchat:logger', 'server');
api.addFiles('server.coffee', 'server');
api.addFiles('main.coffee', ['client', 'server']);
api.addFiles('server.js', 'server');
api.addFiles('main.js', ['client', 'server']);
});
import moment from 'moment'
import 'moment-timezone'
Importer.HipChat = class Importer.HipChat extends Importer.Base
@RoomPrefix = 'hipchat_export/rooms/'
@UsersPrefix = 'hipchat_export/users/'
constructor: (name, descriptionI18N, mimeType) ->
super(name, descriptionI18N, mimeType)
@logger.debug('Constructed a new Slack Importer.')
@userTags = []
prepare: (dataURI, sentContentType, fileName) =>
super(dataURI, sentContentType, fileName)
{image, contentType} = RocketChatFile.dataURIParse dataURI
zip = new @AdmZip(new Buffer(image, 'base64'))
zipEntries = zip.getEntries()
tempRooms = []
tempUsers = []
tempMessages = {}
for entry in zipEntries
do (entry) =>
if entry.entryName.indexOf('__MACOSX') > -1
#ignore all of the files inside of __MACOSX
@logger.debug("Ignoring the file: #{entry.entryName}")
if not entry.isDirectory
if entry.entryName.indexOf(Importer.HipChat.RoomPrefix) > -1
roomName = entry.entryName.split(Importer.HipChat.RoomPrefix)[1]
if roomName is 'list.json'
@updateProgress Importer.ProgressStep.PREPARING_CHANNELS
tempRooms = JSON.parse(entry.getData().toString()).rooms
for room in tempRooms
room.name = _.slugify room.name
else if roomName.indexOf('/') > -1
item = roomName.split('/')
roomName = _.slugify item[0] #random
msgGroupData = item[1].split('.')[0] #2015-10-04
if not tempMessages[roomName]
tempMessages[roomName] = {}
# For some reason some of the json files in the HipChat export aren't valid JSON
# files, so we need to catch those and just ignore them (sadly).
try
tempMessages[roomName][msgGroupData] = JSON.parse entry.getData().toString()
catch
@logger.warn "#{entry.entryName} is not a valid JSON file! Unable to import it."
else if entry.entryName.indexOf(Importer.HipChat.UsersPrefix) > -1
usersName = entry.entryName.split(Importer.HipChat.UsersPrefix)[1]
if usersName is 'list.json'
@updateProgress Importer.ProgressStep.PREPARING_USERS
tempUsers = JSON.parse(entry.getData().toString()).users
else
@logger.warn "Unexpected file in the #{@name} import: #{entry.entryName}"
# Insert the users record, eventually this might have to be split into several ones as well
# if someone tries to import a several thousands users instance
usersId = @collection.insert { 'import': @importRecord._id, 'importer': @name, 'type': 'users', 'users': tempUsers }
@users = @collection.findOne usersId
@updateRecord { 'count.users': tempUsers.length }
@addCountToTotal tempUsers.length
# Insert the rooms records.
channelsId = @collection.insert { 'import': @importRecord._id, 'importer': @name, 'type': 'channels', 'channels': tempRooms }
@channels = @collection.findOne channelsId
@updateRecord { 'count.channels': tempRooms.length }
@addCountToTotal tempRooms.length
# Insert the messages records
@updateProgress Importer.ProgressStep.PREPARING_MESSAGES
messagesCount = 0
for channel, messagesObj of tempMessages
do (channel, messagesObj) =>
if not @messages[channel]
@messages[channel] = {}
for date, msgs of messagesObj
messagesCount += msgs.length
@updateRecord { 'messagesstatus': "#{channel}/#{date}" }
if Importer.Base.getBSONSize(msgs) > Importer.Base.MaxBSONSize
for splitMsg, i in Importer.Base.getBSONSafeArraysFromAnArray(msgs)
messagesId = @collection.insert { 'import': @importRecord._id, 'importer': @name, 'type': 'messages', 'name': "#{channel}/#{date}.#{i}", 'messages': splitMsg }
@messages[channel]["#{date}.#{i}"] = @collection.findOne messagesId
else
messagesId = @collection.insert { 'import': @importRecord._id, 'importer': @name, 'type': 'messages', 'name': "#{channel}/#{date}", 'messages': msgs }
@messages[channel][date] = @collection.findOne messagesId
@updateRecord { 'count.messages': messagesCount, 'messagesstatus': null }
@addCountToTotal messagesCount
if tempUsers.length is 0 or tempRooms.length is 0 or messagesCount is 0
@logger.warn "The loaded users count #{tempUsers.length}, the loaded channels #{tempRooms.length}, and the loaded messages #{messagesCount}"
@updateProgress Importer.ProgressStep.ERROR
return @getProgress()
selectionUsers = tempUsers.map (user) ->
#HipChat's export doesn't contain bot users, from the data I've seen
return new Importer.SelectionUser user.user_id, user.name, user.email, user.is_deleted, false, !user.is_bot
selectionChannels = tempRooms.map (room) ->
return new Importer.SelectionChannel room.room_id, room.name, room.is_archived, true, false
@updateProgress Importer.ProgressStep.USER_SELECTION
return new Importer.Selection @name, selectionUsers, selectionChannels
startImport: (importSelection) =>
super(importSelection)
start = Date.now()
for user in importSelection.users
for u in @users.users when u.user_id is user.user_id
u.do_import = user.do_import
@collection.update { _id: @users._id }, { $set: { 'users': @users.users }}
for channel in importSelection.channels
for c in @channels.channels when c.room_id is channel.channel_id
c.do_import = channel.do_import
@collection.update { _id: @channels._id }, { $set: { 'channels': @channels.channels }}
startedByUserId = Meteor.userId()
Meteor.defer =>
@updateProgress Importer.ProgressStep.IMPORTING_USERS
for user in @users.users when user.do_import
do (user) =>
Meteor.runAsUser startedByUserId, () =>
existantUser = RocketChat.models.Users.findOneByEmailAddress user.email
if existantUser
user.rocketId = existantUser._id
@userTags.push
hipchat: "@#{user.mention_name}"
rocket: "@#{existantUser.username}"
else
userId = Accounts.createUser { email: user.email, password: Date.now() + user.name + user.email.toUpperCase() }
user.rocketId = userId
@userTags.push
hipchat: "@#{user.mention_name}"
rocket: "@#{user.mention_name}"
Meteor.runAsUser userId, () =>
Meteor.call 'setUsername', user.mention_name, {joinDefaultChannelsSilenced: true}
Meteor.call 'setAvatarFromService', user.photo_url, undefined, 'url'
Meteor.call 'userSetUtcOffset', parseInt moment().tz(user.timezone).format('Z').toString().split(':')[0]
if user.name?
RocketChat.models.Users.setName userId, user.name
#Deleted users are 'inactive' users in Rocket.Chat
if user.is_deleted
Meteor.call 'setUserActiveStatus', userId, false
@addCountCompleted 1
@collection.update { _id: @users._id }, { $set: { 'users': @users.users }}
@updateProgress Importer.ProgressStep.IMPORTING_CHANNELS
for channel in @channels.channels when channel.do_import
do (channel) =>
Meteor.runAsUser startedByUserId, () =>
channel.name = channel.name.replace(/ /g, '')
existantRoom = RocketChat.models.Rooms.findOneByName channel.name
if existantRoom
channel.rocketId = existantRoom._id
else
userId = ''
for user in @users.users when user.user_id is channel.owner_user_id
userId = user.rocketId
if userId is ''
@logger.warn "Failed to find the channel creator for #{channel.name}, setting it to the current running user."
userId = startedByUserId
Meteor.runAsUser userId, () =>
returned = Meteor.call 'createChannel', channel.name, []
channel.rocketId = returned.rid
RocketChat.models.Rooms.update { _id: channel.rocketId }, { $set: { 'ts': new Date(channel.created * 1000) }}
@addCountCompleted 1
@collection.update { _id: @channels._id }, { $set: { 'channels': @channels.channels }}
@updateProgress Importer.ProgressStep.IMPORTING_MESSAGES
nousers = {};
for channel, messagesObj of @messages
do (channel, messagesObj) =>
Meteor.runAsUser startedByUserId, () =>
hipchatChannel = @getHipChatChannelFromName channel
if hipchatChannel?.do_import
room = RocketChat.models.Rooms.findOneById hipchatChannel.rocketId, { fields: { usernames: 1, t: 1, name: 1 } }
for date, msgs of messagesObj
@updateRecord { 'messagesstatus': "#{channel}/#{date}.#{msgs.messages.length}" }
for message in msgs.messages
if message.from?
user = @getRocketUser(message.from.user_id)
if user?
msgObj =
msg: @convertHipChatMessageToRocketChat(message.message)
ts: new Date(message.date)
u:
_id: user._id
username: user.username
RocketChat.sendMessage user, msgObj, room, true
else
if not nousers[message.from.user_id]
nousers[message.from.user_id] = message.from
else
if not _.isArray message
console.warn 'Please report the following:', message
@addCountCompleted 1
@logger.warn 'The following did not have users:', nousers
@updateProgress Importer.ProgressStep.FINISHING
for channel in @channels.channels when channel.do_import and channel.is_archived
do (channel) =>
Meteor.runAsUser startedByUserId, () =>
Meteor.call 'archiveRoom', channel.rocketId
@updateProgress Importer.ProgressStep.DONE
timeTook = Date.now() - start
@logger.log "Import took #{timeTook} milliseconds."
return @getProgress()
getHipChatChannelFromName: (channelName) =>
for channel in @channels.channels when channel.name is channelName
return channel
getRocketUser: (hipchatId) =>
for user in @users.users when user.user_id is hipchatId
return RocketChat.models.Users.findOneById user.rocketId, { fields: { username: 1, name: 1 }}
convertHipChatMessageToRocketChat: (message) =>
if message?
for userReplace in @userTags
message = message.replace userReplace.hipchat, userReplace.rocket
else
message = ''
return message
getSelection: () =>
selectionUsers = @users.users.map (user) ->
#HipChat's export doesn't contain bot users, from the data I've seen
return new Importer.SelectionUser user.user_id, user.name, user.email, user.is_deleted, false, !user.is_bot
selectionChannels = @channels.channels.map (room) ->
return new Importer.SelectionChannel room.room_id, room.name, room.is_archived, true, false
return new Importer.Selection @name, selectionUsers, selectionChannels
/* globals Importer */
import moment from 'moment';
import 'moment-timezone';
Importer.HipChat = Importer.HipChat = (function() {
class HipChat extends Importer.Base {
constructor(name, descriptionI18N, mimeType) {
super(name, descriptionI18N, mimeType);
this.logger.debug('Constructed a new Slack Importer.');
this.userTags = [];
}
prepare(dataURI, sentContentType, fileName) {
super.prepare(dataURI, sentContentType, fileName);
const image = RocketChatFile.dataURIParse(dataURI).image;
// const contentType = ref.contentType;
const zip = new this.AdmZip(new Buffer(image, 'base64'));
const zipEntries = zip.getEntries();
const tempRooms = [];
let tempUsers = [];
const tempMessages = {};
zipEntries.forEach(entry => {
if (entry.entryName.indexOf('__MACOSX') > -1) {
this.logger.debug(`Ignoring the file: ${ entry.entryName }`);
}
if (entry.isDirectory) {
return;
}
if (entry.entryName.indexOf(Importer.HipChat.RoomPrefix) > -1) {
let roomName = entry.entryName.split(Importer.HipChat.RoomPrefix)[1];
if (roomName === 'list.json') {
this.updateProgress(Importer.ProgressStep.PREPARING_CHANNELS);
const tempRooms = JSON.parse(entry.getData().toString()).rooms;
tempRooms.forEach(room => {
room.name = _.slugify(room.name);
});
} else if (roomName.indexOf('/') > -1) {
const item = roomName.split('/');
roomName = _.slugify(item[0]);
const msgGroupData = item[1].split('.')[0];
if (!tempMessages[roomName]) {
tempMessages[roomName] = {};
}
try {
return tempMessages[roomName][msgGroupData] = JSON.parse(entry.getData().toString());
} catch (error) {
return this.logger.warn(`${ entry.entryName } is not a valid JSON file! Unable to import it.`);
}
}
} else if (entry.entryName.indexOf(Importer.HipChat.UsersPrefix) > -1) {
const usersName = entry.entryName.split(Importer.HipChat.UsersPrefix)[1];
if (usersName === 'list.json') {
this.updateProgress(Importer.ProgressStep.PREPARING_USERS);
return tempUsers = JSON.parse(entry.getData().toString()).users;
} else {
return this.logger.warn(`Unexpected file in the ${ this.name } import: ${ entry.entryName }`);
}
}
});
const usersId = this.collection.insert({
'import': this.importRecord._id,
'importer': this.name,
'type': 'users',
'users': tempUsers
});
this.users = this.collection.findOne(usersId);
this.updateRecord({
'count.users': tempUsers.length
});
this.addCountToTotal(tempUsers.length);
const channelsId = this.collection.insert({
'import': this.importRecord._id,
'importer': this.name,
'type': 'channels',
'channels': tempRooms
});
this.channels = this.collection.findOne(channelsId);
this.updateRecord({
'count.channels': tempRooms.length
});
this.addCountToTotal(tempRooms.length);
this.updateProgress(Importer.ProgressStep.PREPARING_MESSAGES);
let messagesCount = 0;
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 }`
});
if (Importer.Base.getBSONSize(msgs) > Importer.Base.MaxBSONSize) {
Importer.Base.getBSONSafeArraysFromAnArray(msgs).forEach((splitMsg, i) => {
const messagesId = this.collection.insert({
'import': this.importRecord._id,
'importer': this.name,
'type': 'messages',
'name': `${ channel }/${ date }.${ i }`,
'messages': splitMsg
});
this.messages[channel][`${ date }.${ i }`] = this.collection.findOne(messagesId);
});
} else {
const messagesId = this.collection.insert({
'import': this.importRecord._id,
'importer': this.name,
'type': 'messages',
'name': `${ channel }/${ date }`,
'messages': msgs
});
this.messages[channel][date] = this.collection.findOne(messagesId);
}
});
});
this.updateRecord({
'count.messages': messagesCount,
'messagesstatus': null
});
this.addCountToTotal(messagesCount);
if (tempUsers.length === 0 || tempRooms.length === 0 || messagesCount === 0) {
this.logger.warn(`The loaded users count ${ tempUsers.length }, the loaded channels ${ tempRooms.length }, and the loaded messages ${ messagesCount }`);
this.updateProgress(Importer.ProgressStep.ERROR);
return this.getProgress();
}
const selectionUsers = tempUsers.map(function(user) {
return new Importer.SelectionUser(user.user_id, user.name, user.email, user.is_deleted, false, !user.is_bot);
});
const selectionChannels = tempRooms.map(function(room) {
return new Importer.SelectionChannel(room.room_id, room.name, room.is_archived, true, false);
});
this.updateProgress(Importer.ProgressStep.USER_SELECTION);
return new Importer.Selection(this.name, selectionUsers, selectionChannels);
}
startImport(importSelection) {
super.startImport(importSelection);
const start = Date.now();
importSelection.users.forEach(user => {
this.users.users.forEach(u => {
if (u.user_id === user.user_id) {
u.do_import = user.do_import;
}
});
});
this.collection.update({_id: this.users._id}, { $set: { 'users': this.users.users } });
importSelection.channels.forEach(channel =>
this.channels.channels.forEach(c => c.room_id === channel.channel_id && (c.do_import = channel.do_import))
);
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.email);
if (existantUser) {
user.rocketId = existantUser._id;
this.userTags.push({
hipchat: `@${ user.mention_name }`,
rocket: `@${ existantUser.username }`
});
} else {
const userId = Accounts.createUser({
email: user.email,
password: Date.now() + user.name + user.email.toUpperCase()
});
user.rocketId = userId;
this.userTags.push({
hipchat: `@${ user.mention_name }`,
rocket: `@${ user.mention_name }`
});
Meteor.runAsUser(userId, () => {
Meteor.call('setUsername', user.mention_name, {
joinDefaultChannelsSilenced: true
});
Meteor.call('setAvatarFromService', user.photo_url, undefined, 'url');
return Meteor.call('userSetUtcOffset', parseInt(moment().tz(user.timezone).format('Z').toString().split(':')[0]));
});
if (user.name != null) {
RocketChat.models.Users.setName(userId, user.name);
}
if (user.is_deleted) {
Meteor.call('setUserActiveStatus', userId, false);
}
}
return 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, () => {
channel.name = channel.name.replace(/ /g, '');
const existantRoom = RocketChat.models.Rooms.findOneByName(channel.name);
if (existantRoom) {
channel.rocketId = existantRoom._id;
} else {
let userId = '';
this.users.users.forEach(user => {
if (user.user_id === channel.owner_user_id) {
userId = user.rocketId;
}
});
if (userId === '') {
this.logger.warn(`Failed to find the channel creator for ${ channel.name }, setting it to the current running user.`);
userId = startedByUserId;
}
Meteor.runAsUser(userId, () => {
const returned = Meteor.call('createChannel', channel.name, []);
return channel.rocketId = returned.rid;
});
RocketChat.models.Rooms.update({
_id: channel.rocketId
}, {
$set: {
'ts': new Date(channel.created * 1000)
}
});
}
return this.addCountCompleted(1);
});
});
this.collection.update({
_id: this.channels._id
}, {
$set: {
'channels': this.channels.channels
}
});
this.updateProgress(Importer.ProgressStep.IMPORTING_MESSAGES);
const nousers = {};
Object.keys(this.messages).forEach(channel => {
const messagesObj = this.messages[channel];
Meteor.runAsUser(startedByUserId, () => {
const hipchatChannel = this.getHipChatChannelFromName(channel);
if (hipchatChannel != null ? hipchatChannel.do_import : undefined) {
const room = RocketChat.models.Rooms.findOneById(hipchatChannel.rocketId, {
fields: {
usernames: 1,
t: 1,
name: 1
}
});
Object.keys(messagesObj).forEach(date => {
const msgs = messagesObj[date];
this.updateRecord({
'messagesstatus': `${ channel }/${ date }.${ msgs.messages.length }`
});
msgs.messages.forEach(message => {
if (message.from != null) {
const user = this.getRocketUser(message.from.user_id);
if (user != null) {
const msgObj = {
msg: this.convertHipChatMessageToRocketChat(message.message),
ts: new Date(message.date),
u: {
_id: user._id,
username: user.username
}
};
RocketChat.sendMessage(user, msgObj, room, true);
} else if (!nousers[message.from.user_id]) {
nousers[message.from.user_id] = message.from;
}
} else if (!_.isArray(message)) {
console.warn('Please report the following:', message);
}
this.addCountCompleted(1);
});
});
}
});
});
this.logger.warn('The following did not have users:', nousers);
this.updateProgress(Importer.ProgressStep.FINISHING);
this.channels.channels.forEach(channel => {
if (channel.do_import && channel.is_archived) {
Meteor.runAsUser(startedByUserId, () => {
return Meteor.call('archiveRoom', channel.rocketId);
});
}
});
this.updateProgress(Importer.ProgressStep.DONE);
const timeTook = Date.now() - start;
return this.logger.log(`Import took ${ timeTook } milliseconds.`);
});
return this.getProgress();
}
getHipChatChannelFromName(channelName) {
return this.channels.channels.find(channel => channel.name === channelName);
}
getRocketUser(hipchatId) {
const user = this.users.users.find(user => user.user_id === hipchatId);
return user ? RocketChat.models.Users.findOneById(user.rocketId, {
fields: {
username: 1,
name: 1
}
}) : undefined;
}
convertHipChatMessageToRocketChat(message) {
if (message != null) {
this.userTags.forEach(userReplace => {
message = message.replace(userReplace.hipchat, userReplace.rocket);
});
} else {
message = '';
}
return message;
}
getSelection() {
const selectionUsers = this.users.users.map(function(user) {
return new Importer.SelectionUser(user.user_id, user.name, user.email, user.is_deleted, false, !user.is_bot);
});
const selectionChannels = this.channels.channels.map(function(room) {
return new Importer.SelectionChannel(room.room_id, room.name, room.is_archived, true, false);
});
return new Importer.Selection(this.name, selectionUsers, selectionChannels);
}
}
HipChat.RoomPrefix = 'hipchat_export/rooms/';
HipChat.UsersPrefix = 'hipchat_export/users/';
return HipChat;
}());
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment