diff --git a/.docker/develop/Dockerfile b/.docker/develop/Dockerfile index 7e4d028d5fa..15aa19a7a0d 100644 --- a/.docker/develop/Dockerfile +++ b/.docker/develop/Dockerfile @@ -22,6 +22,7 @@ WORKDIR /app/bundle # needs a mongoinstance - defaults to container linking with alias 'mongo' ENV MONGO_URL=mongodb://mongo:27017/rocketchat \ + HOME=/tmp \ PORT=3000 \ ROOT_URL=http://localhost:3000 \ Accounts_AvatarStorePath=/app/uploads diff --git a/.docker/latest/Dockerfile b/.docker/latest/Dockerfile index 184c04efe52..91e7b43dfd2 100644 --- a/.docker/latest/Dockerfile +++ b/.docker/latest/Dockerfile @@ -22,6 +22,7 @@ WORKDIR /app/bundle # needs a mongoinstance - defaults to container linking with alias 'mongo' ENV MONGO_URL=mongodb://mongo:27017/rocketchat \ + HOME=/tmp \ PORT=3000 \ ROOT_URL=http://localhost:3000 \ Accounts_AvatarStorePath=/app/uploads diff --git a/.meteor/versions b/.meteor/versions index 24c68b72eb2..32c1e547cfc 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -40,7 +40,7 @@ ecmascript-runtime@0.2.6 edgee:slingshot@0.7.1 ejson@1.0.7 email@1.0.8 -emojione:emojione@2.1.1 +emojione:emojione@2.1.2 facebook@1.2.2 fastclick@1.0.7 francocatena:status@1.5.1 @@ -101,7 +101,7 @@ mrt:moment@2.8.1 mrt:moment-timezone@0.2.1 mrt:reactive-store@0.0.1 mystor:device-detection@0.2.0 -nimble:restivus@0.8.7 +nimble:restivus@0.8.9 nooitaf:colors@0.0.3 npm-bcrypt@0.7.8_2 npm-mongo@1.4.39_1 @@ -110,11 +110,11 @@ oauth1@1.1.5 oauth2@1.1.5 observe-sequence@1.0.7 ordered-dict@1.0.4 -ostrio:cookies@2.0.1 +ostrio:cookies@2.0.2 pauli:accounts-linkedin@1.2.0 pauli:linkedin@1.2.0 -peerlibrary:aws-sdk@2.0.17_2 -peerlibrary:blocking@0.4.3 +peerlibrary:aws-sdk@2.2.42_1 +peerlibrary:blocking@0.5.2 perak:codemirror@1.2.9 percolate:synced-cron@1.3.0 pntbr:js-yaml-client@0.0.1 @@ -198,19 +198,19 @@ service-configuration@1.0.5 session@1.1.1 sha@1.0.4 simple:highlight.js@1.2.0 -simple:json-routes@2.0.1 +simple:json-routes@2.1.0 smoral:sweetalert@1.1.1 spacebars@1.0.7 spacebars-compiler@1.0.7 srp@1.0.4 standard-minifiers@1.0.2 steffo:meteor-accounts-saml@0.0.1 -tap:i18n@1.7.0 +tap:i18n@1.8.0 templating@1.1.5 templating-tools@1.0.0 tmeasday:crypto-base@3.1.2 tmeasday:crypto-md5@3.1.2 -todda00:friendly-slugs@0.3.6 +todda00:friendly-slugs@0.4.0 tracker@1.0.9 twitter@1.1.5 ui@1.0.8 diff --git a/HISTORY.md b/HISTORY.md index fb0f6889bd9..05f90e6de9f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,7 @@ - Fixes #2477: Admin settings, plain-text SMTP password. - Closes #625: Filter and sorts direct messages and private groups. +- Closes #2172: Accepts markdown for room topic. - Fixes #2433: Directly linked channel does not load for newly created user ## 0.22.0, 2016-Mar-14 diff --git a/packages/rocketchat-cas/cas_client.js b/packages/rocketchat-cas/cas_client.js index 3537311d1a3..454eb3c6b98 100644 --- a/packages/rocketchat-cas/cas_client.js +++ b/packages/rocketchat-cas/cas_client.js @@ -6,7 +6,7 @@ Meteor.loginWithCas = function(callback) { var popup_width = RocketChat.settings.get("CAS_popup_width"); var popup_height = RocketChat.settings.get("CAS_popup_height"); - if (!login_url) { + if (!login_url) { return; } @@ -45,25 +45,23 @@ Meteor.loginWithCas = function(callback) { }; var openCenteredPopup = function(url, width, height) { - var screenX = typeof window.screenX !== 'undefined' - ? window.screenX : window.screenLeft; - var screenY = typeof window.screenY !== 'undefined' - ? window.screenY : window.screenTop; - var outerWidth = typeof window.outerWidth !== 'undefined' - ? window.outerWidth : document.body.clientWidth; - var outerHeight = typeof window.outerHeight !== 'undefined' - ? window.outerHeight : (document.body.clientHeight - 22); - // XXX what is the 22? - // Use `outerWidth - width` and `outerHeight - height` for help in - // positioning the popup centered relative to the current window - var left = screenX + (outerWidth - width) / 2; - var top = screenY + (outerHeight - height) / 2; - var features = ('width=' + width + ',height=' + height + - ',left=' + left + ',top=' + top + ',scrollbars=yes'); + var screenX = typeof window.screenX !== 'undefined' ? window.screenX : window.screenLeft; + var screenY = typeof window.screenY !== 'undefined' ? window.screenY : window.screenTop; + var outerWidth = typeof window.outerWidth !== 'undefined' ? window.outerWidth : document.body.clientWidth; + var outerHeight = typeof window.outerHeight !== 'undefined' ? window.outerHeight : (document.body.clientHeight - 22); + // XXX what is the 22? - var newwindow = window.open(url, 'Login', features); - if (newwindow.focus) - newwindow.focus(); -return newwindow; + // Use `outerWidth - width` and `outerHeight - height` for help in + // positioning the popup centered relative to the current window + var left = screenX + (outerWidth - width) / 2; + var top = screenY + (outerHeight - height) / 2; + var features = ('width=' + width + ',height=' + height + ',left=' + left + ',top=' + top + ',scrollbars=yes'); + + var newwindow = window.open(url, 'Login', features); + if (newwindow.focus) { + newwindow.focus(); + } + + return newwindow; }; diff --git a/packages/rocketchat-cas/cas_server.js b/packages/rocketchat-cas/cas_server.js index 7041312ae78..858882752fa 100644 --- a/packages/rocketchat-cas/cas_server.js +++ b/packages/rocketchat-cas/cas_server.js @@ -8,77 +8,77 @@ RoutePolicy.declare('/_cas/', 'network'); // Listen to incoming OAuth http requests WebApp.connectHandlers.use(function(req, res, next) { - // Need to create a Fiber since we're using synchronous http calls and nothing - // else is wrapping this in a fiber automatically - Fiber(function () { - middleware(req, res, next); - }).run(); + // Need to create a Fiber since we're using synchronous http calls and nothing + // else is wrapping this in a fiber automatically + Fiber(function () { + middleware(req, res, next); + }).run(); }); var middleware = function (req, res, next) { - // Make sure to catch any exceptions because otherwise we'd crash - // the runner - try { - var barePath = req.url.substring(0, req.url.indexOf('?')); - var splitPath = barePath.split('/'); - - // Any non-cas request will continue down the default - // middlewares. - if (splitPath[1] !== '_cas') { - next(); - return; - } + // Make sure to catch any exceptions because otherwise we'd crash + // the runner + try { + var barePath = req.url.substring(0, req.url.indexOf('?')); + var splitPath = barePath.split('/'); + + // Any non-cas request will continue down the default + // middlewares. + if (splitPath[1] !== '_cas') { + next(); + return; + } - // get auth token - var credentialToken = splitPath[2]; - if (!credentialToken) { - closePopup(res); - return; - } + // get auth token + var credentialToken = splitPath[2]; + if (!credentialToken) { + closePopup(res); + return; + } - // validate ticket - casTicket(req, credentialToken, function() { - closePopup(res); - }); + // validate ticket + casTicket(req, credentialToken, function() { + closePopup(res); + }); - } catch (err) { - logger.error("Unexpected error : " + err.message); - closePopup(res); - } + } catch (err) { + logger.error("Unexpected error : " + err.message); + closePopup(res); + } }; var casTicket = function (req, token, callback) { - // get configuration - if (!RocketChat.settings.get("CAS_enabled")) { - logger.error("Got ticket validation request, but CAS is not enabled"); - callback(); - } - - // get ticket and validate. - var parsedUrl = url.parse(req.url, true); - var ticketId = parsedUrl.query.ticket; - var baseUrl = RocketChat.settings.get("CAS_base_url"); - logger.debug("Using CAS_base_url: " + baseUrl); - - var cas = new CAS({ - base_url: baseUrl, - service: Meteor.absoluteUrl() + "_cas/" + token - }); - - cas.validate(ticketId, function(err, status, username) { - if (err) { - logger.error("error when trying to validate " + err); - } else { - if (status) { - logger.info("Validated user: " + username); - _casCredentialTokens[token] = { id: username }; - } else { - logger.error("Unable to validate ticket: " + ticketId); - } + // get configuration + if (!RocketChat.settings.get("CAS_enabled")) { + logger.error("Got ticket validation request, but CAS is not enabled"); + callback(); } - callback(); + // get ticket and validate. + var parsedUrl = url.parse(req.url, true); + var ticketId = parsedUrl.query.ticket; + var baseUrl = RocketChat.settings.get("CAS_base_url"); + logger.debug("Using CAS_base_url: " + baseUrl); + + var cas = new CAS({ + base_url: baseUrl, + service: Meteor.absoluteUrl() + "_cas/" + token + }); + + cas.validate(ticketId, function(err, status, username) { + if (err) { + logger.error("error when trying to validate " + err); + } else { + if (status) { + logger.info("Validated user: " + username); + _casCredentialTokens[token] = { id: username }; + } else { + logger.error("Unable to validate ticket: " + ticketId); + } + } + + callback(); }); return; @@ -91,58 +91,70 @@ var casTicket = function (req, token, callback) { */ Accounts.registerLoginHandler(function (options) { - if (!options.cas) - return undefined; - - if (!_hasCredential(options.cas.credentialToken)) { - throw new Meteor.Error(Accounts.LoginCancelledError.numericError, - 'no matching login attempt found'); - } - - var result = _retrieveCredential(options.cas.credentialToken); - var options = { profile: { name: result.id } }; - - logger.debug("Looking up user with username: " + result.id ); - var user = Meteor.users.findOne({ 'services.cas.external_id': result.id }); - - if (user) { - logger.debug("Using existing user for '" + result.id + "' with id: " + user._id); - } else { - var newUser = { - username: result.id, - active: true, - globalRoles: ['user'], - services: { - cas: { - external_id: result.id + if (!options.cas) + return undefined; + + if (!_hasCredential(options.cas.credentialToken)) { + throw new Meteor.Error(Accounts.LoginCancelledError.numericError, + 'no matching login attempt found'); + } + + var result = _retrieveCredential(options.cas.credentialToken); + var options = { profile: { name: result.id } }; + + // Search existing user by its external service id + logger.debug("Looking up user with username: " + result.id ); + var user = Meteor.users.findOne({ 'services.cas.external_id': result.id }); + + if (user) { + logger.debug("Using existing user for '" + result.id + "' with id: " + user._id); + } else { + + // Define new user + var newUser = { + username: result.id, + active: true, + globalRoles: ['user'], + services: { + cas: { + external_id: result.id + } } - } - }; + }; + + // Create the user + logger.debug("User '" + result.id + "'does not exist yet, creating it"); + var userId = Accounts.insertUserDoc({}, newUser); - logger.debug("User '" + result.id + "'does not exist yet, creating it"); - var userId = Accounts.insertUserDoc({}, newUser); - user = Meteor.users.findOne(userId); - logger.debug("Created new user for '" + result.id + "' with id: " + user._id); - } + // Fetch and use it + user = Meteor.users.findOne(userId); + logger.debug("Created new user for '" + result.id + "' with id: " + user._id); + + logger.debug('Joining user to default channels'); + Meteor.runAsUser(user._id, function() { + Meteor.call('joinDefaultChannels'); + }); + + } - return { userId: user._id }; + return { userId: user._id }; }); var _hasCredential = function(credentialToken) { - return _.has(_casCredentialTokens, credentialToken); + return _.has(_casCredentialTokens, credentialToken); } /* * Retrieve token and delete it to avoid replaying it. */ var _retrieveCredential = function(credentialToken) { - var result = _casCredentialTokens[credentialToken]; - delete _casCredentialTokens[credentialToken]; - return result; + var result = _casCredentialTokens[credentialToken]; + delete _casCredentialTokens[credentialToken]; + return result; } var closePopup = function(res) { - res.writeHead(200, {'Content-Type': 'text/html'}); - var content = ''; - res.end(content, 'utf-8'); + res.writeHead(200, {'Content-Type': 'text/html'}); + var content = ''; + res.end(content, 'utf-8'); } diff --git a/packages/rocketchat-channel-settings/client/views/channelSettings.html b/packages/rocketchat-channel-settings/client/views/channelSettings.html index cf20528f348..37f64696658 100644 --- a/packages/rocketchat-channel-settings/client/views/channelSettings.html +++ b/packages/rocketchat-channel-settings/client/views/channelSettings.html @@ -24,7 +24,7 @@ {{#if editing 'roomTopic'}} {{else}} - {{roomTopic}}{{#if canEdit}} {{/if}} + {{{RocketChatMarkdown roomTopic}}}{{#if canEdit}} {{/if}} {{/if}} diff --git a/packages/rocketchat-importer-hipchat/server/HipChatImporter.coffee b/packages/rocketchat-importer-hipchat/server/HipChatImporter.coffee index b411d319adb..d3266cc7a9d 100644 --- a/packages/rocketchat-importer-hipchat/server/HipChatImporter.coffee +++ b/packages/rocketchat-importer-hipchat/server/HipChatImporter.coffee @@ -9,95 +9,95 @@ Importer.HipChat = class Importer.HipChat extends Importer.Base prepare: (dataURI, sentContentType, fileName) => super(dataURI, sentContentType, fileName) - try - {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 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 - console.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 - console.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 + # try + {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 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 + console.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 - 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 - @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 + console.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 + @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 - @updateProgress Importer.ProgressStep.USER_SELECTION - return new Importer.Selection @name, selectionUsers, selectionChannels - catch error - @updateRecord { 'failed': true, 'error': error } - console.error Importer.ProgressStep.ERROR - throw new Error 'import-hipchat-error', error + @updateProgress Importer.ProgressStep.USER_SELECTION + return new Importer.Selection @name, selectionUsers, selectionChannels + # catch error + # @updateRecord { 'failed': true, 'error': error } + # console.error Importer.ProgressStep.ERROR + # throw new Error 'import-hipchat-error', error startImport: (importSelection) => super(importSelection) @@ -115,105 +115,105 @@ Importer.HipChat = class Importer.HipChat extends Importer.Base startedByUserId = Meteor.userId() Meteor.defer => - try - @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}" + # try + @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 + Meteor.call 'joinDefaultChannels', true + Meteor.call 'setAvatarFromService', user.photo_url, null, 'url' + Meteor.call 'updateUserUtcOffset', 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 isnt '' Meteor.runAsUser userId, () => - Meteor.call 'setUsername', user.mention_name - Meteor.call 'joinDefaultChannels', true - Meteor.call 'setAvatarFromService', user.photo_url, null, 'url' - Meteor.call 'updateUserUtcOffset', 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 + returned = Meteor.call 'createChannel', channel.name, [] + channel.rocketId = returned.rid + RocketChat.models.Rooms.update { _id: channel.rocketId }, { $set: { 'ts': new Date(channel.created * 1000) }} else - userId = '' - for user in @users.users when user.user_id is channel.owner_user_id - userId = user.rocketId - - if userId isnt '' - 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) }} - else - console.warn "Failed to find the channel creator for #{channel.name}." - @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 - else - if not nousers[message.from.user_id] - nousers[message.from.user_id] = message.from + console.warn "Failed to find the channel creator for #{channel.name}." + @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 else - if not _.isArray message - console.warn 'Please report the following:', message - @addCountCompleted 1 - console.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 - console.log "Import took #{timeTook} milliseconds." - catch error - @updateRecord { 'failed': true, 'error': error } - console.error Importer.ProgressStep.ERROR - throw new Error 'import-hipchat-error', error + 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 + console.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 + console.log "Import took #{timeTook} milliseconds." + # catch error + # @updateRecord { 'failed': true, 'error': error } + # console.error Importer.ProgressStep.ERROR + # throw new Error 'import-hipchat-error', error return @getProgress() diff --git a/packages/rocketchat-importer-slack/server/SlackImporter.coffee b/packages/rocketchat-importer-slack/server/SlackImporter.coffee index fcca408db66..4853cde10ee 100644 --- a/packages/rocketchat-importer-slack/server/SlackImporter.coffee +++ b/packages/rocketchat-importer-slack/server/SlackImporter.coffee @@ -7,88 +7,88 @@ Importer.Slack = class Importer.Slack extends Importer.Base prepare: (dataURI, sentContentType, fileName) => super(dataURI, sentContentType, fileName) - try - {image, contentType} = RocketChatFile.dataURIParse dataURI - zip = new @AdmZip(new Buffer(image, 'base64')) - zipEntries = zip.getEntries() - - tempChannels = [] - tempUsers = [] - tempMessages = {} - for entry in zipEntries - do (entry) => - if entry.entryName == 'channels.json' - @updateProgress Importer.ProgressStep.PREPARING_CHANNELS - tempChannels = JSON.parse entry.getData().toString() - else if entry.entryName == 'users.json' - @updateProgress Importer.ProgressStep.PREPARING_USERS - tempUsers = JSON.parse entry.getData().toString() - - for user in tempUsers when user.is_bot - @bots[user.profile.bot_id] = user - - else if not entry.isDirectory and entry.entryName.indexOf('/') > -1 - item = entry.entryName.split('/') #random/2015-10-04.json - channelName = item[0] #random - msgGroupData = item[1].split('.')[0] #2015-10-04 - if not tempMessages[channelName] - tempMessages[channelName] = {} - # Catch files which aren't valid JSON files, ignore them - try - tempMessages[channelName][msgGroupData] = JSON.parse entry.getData().toString() - catch - console.warn "#{entry.entryName} is not a valid JSON file! Unable to import it." - - # 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 channels records. - channelsId = @collection.insert { 'import': @importRecord._id, 'importer': @name, 'type': 'channels', 'channels': tempChannels } - @channels = @collection.findOne channelsId - @updateRecord { 'count.channels': tempChannels.length } - @addCountToTotal tempChannels.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 tempChannels.length is 0 or messagesCount is 0 - @updateProgress Importer.ProgressStep.ERROR - return @getProgress() - - selectionUsers = tempUsers.map (user) -> - return new Importer.SelectionUser user.id, user.name, user.profile.email, user.deleted, user.is_bot, !user.is_bot - selectionChannels = tempChannels.map (channel) -> - return new Importer.SelectionChannel channel.id, channel.name, channel.is_archived, true + # try + {image, contentType} = RocketChatFile.dataURIParse dataURI + zip = new @AdmZip(new Buffer(image, 'base64')) + zipEntries = zip.getEntries() + + tempChannels = [] + tempUsers = [] + tempMessages = {} + for entry in zipEntries + do (entry) => + if entry.entryName == 'channels.json' + @updateProgress Importer.ProgressStep.PREPARING_CHANNELS + tempChannels = JSON.parse entry.getData().toString() + else if entry.entryName == 'users.json' + @updateProgress Importer.ProgressStep.PREPARING_USERS + tempUsers = JSON.parse entry.getData().toString() + + for user in tempUsers when user.is_bot + @bots[user.profile.bot_id] = user + + else if not entry.isDirectory and entry.entryName.indexOf('/') > -1 + item = entry.entryName.split('/') #random/2015-10-04.json + channelName = item[0] #random + msgGroupData = item[1].split('.')[0] #2015-10-04 + if not tempMessages[channelName] + tempMessages[channelName] = {} + # Catch files which aren't valid JSON files, ignore them + try + tempMessages[channelName][msgGroupData] = JSON.parse entry.getData().toString() + catch + console.warn "#{entry.entryName} is not a valid JSON file! Unable to import it." + + # 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 channels records. + channelsId = @collection.insert { 'import': @importRecord._id, 'importer': @name, 'type': 'channels', 'channels': tempChannels } + @channels = @collection.findOne channelsId + @updateRecord { 'count.channels': tempChannels.length } + @addCountToTotal tempChannels.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 tempChannels.length is 0 or messagesCount is 0 + @updateProgress Importer.ProgressStep.ERROR + return @getProgress() + + selectionUsers = tempUsers.map (user) -> + return new Importer.SelectionUser user.id, user.name, user.profile.email, user.deleted, user.is_bot, !user.is_bot + selectionChannels = tempChannels.map (channel) -> + return new Importer.SelectionChannel channel.id, channel.name, channel.is_archived, true - @updateProgress Importer.ProgressStep.USER_SELECTION - return new Importer.Selection @name, selectionUsers, selectionChannels - catch error - @updateRecord { 'failed': true, 'error': error } - console.error Importer.ProgressStep.ERROR - throw new Error 'import-slack-error', error + @updateProgress Importer.ProgressStep.USER_SELECTION + return new Importer.Selection @name, selectionUsers, selectionChannels + # catch error + # @updateRecord { 'failed': true, 'error': error } + # console.error Importer.ProgressStep.ERROR + # throw new Error 'import-slack-error', error startImport: (importSelection) => super(importSelection) @@ -106,183 +106,183 @@ Importer.Slack = class Importer.Slack extends Importer.Base startedByUserId = Meteor.userId() Meteor.defer => - try - @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.profile.email - if existantUser - user.rocketId = existantUser._id - @userTags.push - slack: "<@#{user.id}>" - slackLong: "<@#{user.id}|#{user.name}>" - rocket: "@#{existantUser.username}" - else - userId = Accounts.createUser { email: user.profile.email, password: Date.now() + user.name + user.profile.email.toUpperCase() } - Meteor.runAsUser userId, () => - Meteor.call 'setUsername', user.name - Meteor.call 'joinDefaultChannels', true - url = null - if user.profile.image_original - url = user.profile.image_original - else if user.profile.image_512 - url = user.profile.image_512 - Meteor.call 'setAvatarFromService', url, null, 'url' - # Slack's is -18000 which translates to Rocket.Chat's after dividing by 3600 - if user.tz_offset - Meteor.call 'updateUserUtcOffset', user.tz_offset / 3600 - - 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 - #TODO: Maybe send emails? - user.rocketId = userId - @userTags.push - slack: "<@#{user.id}>" - slackLong: "<@#{user.id}|#{user.name}>" - rocket: "@#{user.name}" - @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, () => - existantRoom = RocketChat.models.Rooms.findOneByName channel.name - if existantRoom or channel.is_general - if channel.is_general and channel.name isnt existantRoom?.name - Meteor.call 'saveRoomSettings', 'GENERAL', 'roomName', channel.name - channel.rocketId = if channel.is_general then 'GENERAL' else existantRoom._id - else - users = [] - for member in channel.members when member isnt channel.creator - user = @getRocketUser member - if user? - users.push user.username - - userId = '' - for user in @users.users when user.id is channel.creator - userId = user.rocketId - - Meteor.runAsUser userId, () => - returned = Meteor.call 'createChannel', channel.name, users - channel.rocketId = returned.rid - - # @TODO implement model specific function - roomUpdate = - ts: new Date(channel.created * 1000) - - if not _.isEmpty channel.topic?.value - roomUpdate.topic = channel.topic.value - lastSetTopic = channel.topic.last_set - - if not _.isEmpty(channel.purpose?.value) and channel.purpose.last_set > lastSetTopic - roomUpdate.topic = channel.purpose.value - - RocketChat.models.Rooms.update { _id: channel.rocketId }, { $set: roomUpdate } - - @addCountCompleted 1 - @collection.update { _id: @channels._id }, { $set: { 'channels': @channels.channels }} - - missedTypes = {} - ignoreTypes = { 'bot_add': true, 'file_comment': true, 'file_mention': true, 'channel_name': true } - @updateProgress Importer.ProgressStep.IMPORTING_MESSAGES - for channel, messagesObj of @messages - do (channel, messagesObj) => - Meteor.runAsUser startedByUserId, () => - slackChannel = @getSlackChannelFromName channel - if slackChannel?.do_import - room = RocketChat.models.Rooms.findOneById slackChannel.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.type is 'message' - if message.subtype? - if message.subtype is 'channel_join' - if @getRocketUser(message.user)? - RocketChat.models.Messages.createUserJoinWithRoomIdAndUser room._id, @getRocketUser(message.user), { ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) } - else if message.subtype is 'channel_leave' - if @getRocketUser(message.user)? - RocketChat.models.Messages.createUserLeaveWithRoomIdAndUser room._id, @getRocketUser(message.user), { ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) } - else if message.subtype is 'me_message' - RocketChat.sendMessage @getRocketUser(message.user), { msg: '_' + @convertSlackMessageToRocketChat(message.text) + '_', ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) }, room - else if message.subtype is 'bot_message' - botUser = RocketChat.models.Users.findOneById 'rocket.cat', { fields: { username: 1 }} - botUsername = if @bots[message.bot_id] then @bots[message.bot_id]?.name else message.username - msgObj = - msg: if message.text then message.text else '' - ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) + # try + @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.profile.email + if existantUser + user.rocketId = existantUser._id + @userTags.push + slack: "<@#{user.id}>" + slackLong: "<@#{user.id}|#{user.name}>" + rocket: "@#{existantUser.username}" + else + userId = Accounts.createUser { email: user.profile.email, password: Date.now() + user.name + user.profile.email.toUpperCase() } + Meteor.runAsUser userId, () => + Meteor.call 'setUsername', user.name + Meteor.call 'joinDefaultChannels', true + url = null + if user.profile.image_original + url = user.profile.image_original + else if user.profile.image_512 + url = user.profile.image_512 + Meteor.call 'setAvatarFromService', url, null, 'url' + # Slack's is -18000 which translates to Rocket.Chat's after dividing by 3600 + if user.tz_offset + Meteor.call 'updateUserUtcOffset', user.tz_offset / 3600 + + 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 + #TODO: Maybe send emails? + user.rocketId = userId + @userTags.push + slack: "<@#{user.id}>" + slackLong: "<@#{user.id}|#{user.name}>" + rocket: "@#{user.name}" + @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, () => + existantRoom = RocketChat.models.Rooms.findOneByName channel.name + if existantRoom or channel.is_general + if channel.is_general and channel.name isnt existantRoom?.name + Meteor.call 'saveRoomSettings', 'GENERAL', 'roomName', channel.name + channel.rocketId = if channel.is_general then 'GENERAL' else existantRoom._id + else + users = [] + for member in channel.members when member isnt channel.creator + user = @getRocketUser member + if user? + users.push user.username + + userId = '' + for user in @users.users when user.id is channel.creator + userId = user.rocketId + + Meteor.runAsUser userId, () => + returned = Meteor.call 'createChannel', channel.name, users + channel.rocketId = returned.rid + + # @TODO implement model specific function + roomUpdate = + ts: new Date(channel.created * 1000) + + if not _.isEmpty channel.topic?.value + roomUpdate.topic = channel.topic.value + lastSetTopic = channel.topic.last_set + + if not _.isEmpty(channel.purpose?.value) and channel.purpose.last_set > lastSetTopic + roomUpdate.topic = channel.purpose.value + + RocketChat.models.Rooms.update { _id: channel.rocketId }, { $set: roomUpdate } + + @addCountCompleted 1 + @collection.update { _id: @channels._id }, { $set: { 'channels': @channels.channels }} + + missedTypes = {} + ignoreTypes = { 'bot_add': true, 'file_comment': true, 'file_mention': true, 'channel_name': true } + @updateProgress Importer.ProgressStep.IMPORTING_MESSAGES + for channel, messagesObj of @messages + do (channel, messagesObj) => + Meteor.runAsUser startedByUserId, () => + slackChannel = @getSlackChannelFromName channel + if slackChannel?.do_import + room = RocketChat.models.Rooms.findOneById slackChannel.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.type is 'message' + if message.subtype? + if message.subtype is 'channel_join' + if @getRocketUser(message.user)? + RocketChat.models.Messages.createUserJoinWithRoomIdAndUser room._id, @getRocketUser(message.user), { ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) } + else if message.subtype is 'channel_leave' + if @getRocketUser(message.user)? + RocketChat.models.Messages.createUserLeaveWithRoomIdAndUser room._id, @getRocketUser(message.user), { ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) } + else if message.subtype is 'me_message' + RocketChat.sendMessage @getRocketUser(message.user), { msg: '_' + @convertSlackMessageToRocketChat(message.text) + '_', ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) }, room + else if message.subtype is 'bot_message' + botUser = RocketChat.models.Users.findOneById 'rocket.cat', { fields: { username: 1 }} + botUsername = if @bots[message.bot_id] then @bots[message.bot_id]?.name else message.username + msgObj = + msg: if message.text then message.text else '' + ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) + rid: room._id + bot: true + attachments: message.attachments + username: if botUsername then botUsername else undefined + + if message.edited? + msgObj.ets = new Date(parseInt(message.edited.ts.split('.')[0]) * 1000) + + if message.icons? + msgObj.emoji = message.icons.emoji + + msgObj.msg = @convertSlackMessageToRocketChat(msgObj.msg) + + RocketChat.sendMessage botUser, msgObj, room + else if message.subtype is 'channel_purpose' + RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_topic', room._id, message.purpose, @getRocketUser(message.user), { ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) } + else if message.subtype is 'channel_topic' + RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_topic', room._id, message.topic, @getRocketUser(message.user), { ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) } + else if message.subtype is 'pinned_item' + RocketChat.models.Messages.createWithTypeRoomIdMessageAndUser 'message_pinned', room._id, '', @getRocketUser(message.user), + ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) + attachments: [ + "text" : @convertSlackMessageToRocketChat message.attachments[0].text + "author_name" : message.attachments[0].author_subname + "author_icon" : getAvatarUrlFromUsername(message.attachments[0].author_subname) + ] + else if message.subtype is 'file_share' + if message.file?.url_private_download isnt undefined + details = + name: message.file.name + size: message.file.size + type: message.file.mimetype rid: room._id - bot: true - attachments: message.attachments - username: if botUsername then botUsername else undefined - - if message.edited? - msgObj.ets = new Date(parseInt(message.edited.ts.split('.')[0]) * 1000) - - if message.icons? - msgObj.emoji = message.icons.emoji - - msgObj.msg = @convertSlackMessageToRocketChat(msgObj.msg) - - RocketChat.sendMessage botUser, msgObj, room - else if message.subtype is 'channel_purpose' - RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_topic', room._id, message.purpose, @getRocketUser(message.user), { ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) } - else if message.subtype is 'channel_topic' - RocketChat.models.Messages.createRoomSettingsChangedWithTypeRoomIdMessageAndUser 'room_changed_topic', room._id, message.topic, @getRocketUser(message.user), { ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) } - else if message.subtype is 'pinned_item' - RocketChat.models.Messages.createWithTypeRoomIdMessageAndUser 'message_pinned', room._id, '', @getRocketUser(message.user), - ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) - attachments: [ - "text" : @convertSlackMessageToRocketChat message.attachments[0].text - "author_name" : message.attachments[0].author_subname - "author_icon" : getAvatarUrlFromUsername(message.attachments[0].author_subname) - ] - else if message.subtype is 'file_share' - if message.file?.url_private_download isnt undefined - details = - name: message.file.name - size: message.file.size - type: message.file.mimetype - rid: room._id - @uploadFile details, message.file.url_private_download, @getRocketUser(message.user), room, new Date(parseInt(message.ts.split('.')[0]) * 1000) - else - if not missedTypes[message.subtype] and not ignoreTypes[message.subtype] - missedTypes[message.subtype] = message + @uploadFile details, message.file.url_private_download, @getRocketUser(message.user), room, new Date(parseInt(message.ts.split('.')[0]) * 1000) else - user = @getRocketUser(message.user) - if user? - msgObj = - msg: @convertSlackMessageToRocketChat message.text - ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) - rid: room._id - u: - _id: user._id - username: user.username - - if message.edited? - msgObj.ets = new Date(parseInt(message.edited.ts.split('.')[0]) * 1000) - - RocketChat.sendMessage @getRocketUser(message.user), msgObj, room - @addCountCompleted 1 - console.log missedTypes - @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 - console.log "Import took #{timeTook} milliseconds." - catch error - @updateRecord { 'failed': true, 'error': error } - @updateProgress Importer.ProgressStep.ERROR - console.error Importer.ProgressStep.ERROR - throw new Error 'import-slack-error', error + if not missedTypes[message.subtype] and not ignoreTypes[message.subtype] + missedTypes[message.subtype] = message + else + user = @getRocketUser(message.user) + if user? + msgObj = + msg: @convertSlackMessageToRocketChat message.text + ts: new Date(parseInt(message.ts.split('.')[0]) * 1000) + rid: room._id + u: + _id: user._id + username: user.username + + if message.edited? + msgObj.ets = new Date(parseInt(message.edited.ts.split('.')[0]) * 1000) + + RocketChat.sendMessage @getRocketUser(message.user), msgObj, room + @addCountCompleted 1 + console.log missedTypes + @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 + console.log "Import took #{timeTook} milliseconds." + # catch error + # @updateRecord { 'failed': true, 'error': error } + # @updateProgress Importer.ProgressStep.ERROR + # console.error Importer.ProgressStep.ERROR + # throw new Error 'import-slack-error', error return @getProgress() diff --git a/packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.coffee b/packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.coffee index 8764db6ce1e..dffbc0918bb 100644 --- a/packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.coffee +++ b/packages/rocketchat-lib/lib/startup/settingsOnLoadSiteUrl.coffee @@ -13,4 +13,5 @@ RocketChat.settings.get 'Site_Url', (key, value) -> process.env.MOBILE_ROOT_URL = value process.env.MOBILE_DDP_URL = value - # WebAppInternals.generateBoilerplate() + if WebAppInternals?.generateBoilerplate + WebAppInternals.generateBoilerplate() diff --git a/packages/rocketchat-ui-message/message/message.coffee b/packages/rocketchat-ui-message/message/message.coffee index 9cb1406d384..37539a9421b 100644 --- a/packages/rocketchat-ui-message/message/message.coffee +++ b/packages/rocketchat-ui-message/message/message.coffee @@ -80,24 +80,30 @@ Template.message.onCreated -> @wasEdited = msg.editedAt? and not RocketChat.MessageTypes.isSystemMessage(msg) @body = do -> + isSystemMessage = RocketChat.MessageTypes.isSystemMessage(msg) messageType = RocketChat.MessageTypes.getType(msg) if messageType?.render? - return messageType.render(msg) + msg = messageType.render(msg) else if messageType?.template? # render template else if messageType?.message? if messageType.data?(msg)? - return TAPi18n.__(messageType.message, messageType.data(msg)) + msg = TAPi18n.__(messageType.message, messageType.data(msg)) else - return TAPi18n.__(messageType.message) + msg = TAPi18n.__(messageType.message) else if msg.u?.username is RocketChat.settings.get('Chatops_Username') msg.html = msg.msg - message = RocketChat.callbacks.run 'renderMentions', msg + msg = RocketChat.callbacks.run 'renderMentions', msg # console.log JSON.stringify message - return msg.html + msg = msg.html + else + msg = renderMessageBody msg - return renderMessageBody msg + if isSystemMessage + return RocketChat.Markdown msg + else + return msg Template.message.onViewRendered = (context) -> view = this diff --git a/packages/rocketchat-ui/views/app/room.html b/packages/rocketchat-ui/views/app/room.html index e2e048f1483..1278b02c441 100644 --- a/packages/rocketchat-ui/views/app/room.html +++ b/packages/rocketchat-ui/views/app/room.html @@ -14,7 +14,7 @@ {{/if}} {{roomName}} - {{roomTopic}} + {{{RocketChatMarkdown roomTopic}}}
diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee index 5379d49a745..6f7bb0fed41 100644 --- a/server/lib/accounts.coffee +++ b/server/lib/accounts.coffee @@ -4,10 +4,10 @@ Accounts.config accountsConfig RocketChat.settings.get 'Accounts_AllowedDomainsList', (_id, value) -> domainWhiteList = _.map value.split(','), (domain) -> domain.trim() - restrictCreationByEmailDomain = (email) -> + restrictCreationByEmailDomain = if domainWhiteList.length == 1 then domainWhiteList[0] else (email) -> ret = false for domain in domainWhiteList - if email.match(domain + '$') + if email.match('@' + RegExp.escape(domain) + '$') ret = true break;