From 3e993d36c71f66eb13e86e1bbaaff352d9313751 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 4 Apr 2017 15:47:16 -0300 Subject: [PATCH 1/3] conversion part 3 --- .../client/MessageAction.coffee | 247 --------------- .../rocketchat-lib/client/MessageAction.js | 289 ++++++++++++++++++ .../client/Notifications.coffee | 72 ----- .../rocketchat-lib/client/Notifications.js | 86 ++++++ .../rocketchat-lib/client/lib/roomExit.coffee | 20 -- .../rocketchat-lib/client/lib/roomExit.js | 31 ++ .../rocketchat-lib/client/lib/settings.coffee | 65 ---- .../rocketchat-lib/client/lib/settings.js | 87 ++++++ .../client/methods/sendMessage.coffee | 22 -- .../client/methods/sendMessage.js | 18 ++ .../client/models/Uploads.coffee | 3 - .../rocketchat-lib/client/models/Uploads.js | 7 + .../rocketchat-lib/client/models/_Base.coffee | 44 --- .../rocketchat-lib/client/models/_Base.js | 52 ++++ packages/rocketchat-lib/package.js | 14 +- 15 files changed, 577 insertions(+), 480 deletions(-) delete mode 100644 packages/rocketchat-lib/client/MessageAction.coffee create mode 100644 packages/rocketchat-lib/client/MessageAction.js delete mode 100644 packages/rocketchat-lib/client/Notifications.coffee create mode 100644 packages/rocketchat-lib/client/Notifications.js delete mode 100644 packages/rocketchat-lib/client/lib/roomExit.coffee create mode 100644 packages/rocketchat-lib/client/lib/roomExit.js delete mode 100644 packages/rocketchat-lib/client/lib/settings.coffee create mode 100644 packages/rocketchat-lib/client/lib/settings.js delete mode 100644 packages/rocketchat-lib/client/methods/sendMessage.coffee create mode 100644 packages/rocketchat-lib/client/methods/sendMessage.js delete mode 100644 packages/rocketchat-lib/client/models/Uploads.coffee create mode 100644 packages/rocketchat-lib/client/models/Uploads.js delete mode 100644 packages/rocketchat-lib/client/models/_Base.coffee create mode 100644 packages/rocketchat-lib/client/models/_Base.js diff --git a/packages/rocketchat-lib/client/MessageAction.coffee b/packages/rocketchat-lib/client/MessageAction.coffee deleted file mode 100644 index 80837c3a0beb..000000000000 --- a/packages/rocketchat-lib/client/MessageAction.coffee +++ /dev/null @@ -1,247 +0,0 @@ -import moment from 'moment' -import toastr from 'toastr' - -RocketChat.MessageAction = new class - buttons = new ReactiveVar {} - - ### - config expects the following keys (only id is mandatory): - id (mandatory) - icon: string - i18nLabel: string - action: function(event, instance) - validation: function(message) - order: integer - ### - addButton = (config) -> - unless config?.id - return false - - Tracker.nonreactive -> - btns = buttons.get() - btns[config.id] = config - buttons.set btns - - removeButton = (id) -> - Tracker.nonreactive -> - btns = buttons.get() - delete btns[id] - buttons.set btns - - updateButton = (id, config) -> - Tracker.nonreactive -> - btns = buttons.get() - if btns[id] - btns[id] = _.extend btns[id], config - buttons.set btns - - getButtonById = (id) -> - allButtons = buttons.get() - return allButtons[id] - - getButtons = (message, context) -> - allButtons = _.toArray buttons.get() - if message - allowedButtons = _.compact _.map allButtons, (button) -> - if not button.context? or button.context.indexOf(context) > -1 - if not button.validation? or button.validation(message, context) - return button - else - allowedButtons = allButtons - - return _.sortBy allowedButtons, 'order' - - resetButtons = -> - buttons.set {} - - getPermaLink = (msgId) -> - roomData = ChatSubscription.findOne({rid: Session.get('openedRoom')}) - if roomData - routePath = RocketChat.roomTypes.getRouteLink(roomData.t, roomData) - else - routePath = document.location.pathname - return Meteor.absoluteUrl().replace(/\/$/, '') + routePath + '?msg=' + msgId - - hideDropDown = () -> - $('.message-dropdown:visible').hide() - - addButton: addButton - removeButton: removeButton - updateButton: updateButton - getButtons: getButtons - getButtonById: getButtonById - resetButtons: resetButtons - getPermaLink: getPermaLink - hideDropDown: hideDropDown - -Meteor.startup -> - - $(document).click (event) => - target = $(event.target) - if !target.closest('.message-cog-container').length and !target.is('.message-cog-container') - RocketChat.MessageAction.hideDropDown() - - RocketChat.MessageAction.addButton - id: 'reply-message' - icon: 'icon-reply' - i18nLabel: 'Reply' - context: [ - 'message' - 'message-mobile' - ] - action: (event, instance) -> - message = @_arguments[1] - input = instance.find('.input-message') - url = RocketChat.MessageAction.getPermaLink(message._id) - text = '[ ](' + url + ') @' + message.u.username + ' ' - if input.value - input.value += if input.value.endsWith(' ') then '' else ' ' - input.value += text - input.focus() - RocketChat.MessageAction.hideDropDown() - validation: (message) -> - if not RocketChat.models.Subscriptions.findOne({ rid: message.rid })? - return false - return true - order: 1 - - RocketChat.MessageAction.addButton - id: 'edit-message' - icon: 'icon-pencil' - i18nLabel: 'Edit' - context: [ - 'message' - 'message-mobile' - ] - action: (e, instance) -> - message = $(e.currentTarget).closest('.message')[0] - chatMessages[Session.get('openedRoom')].edit(message) - RocketChat.MessageAction.hideDropDown() - input = instance.find('.input-message') - Meteor.setTimeout -> - input.focus() - input.updateAutogrow() - , 200 - validation: (message) -> - if not RocketChat.models.Subscriptions.findOne({ rid: message.rid })? - return false - - hasPermission = RocketChat.authz.hasAtLeastOnePermission('edit-message', message.rid) - isEditAllowed = RocketChat.settings.get 'Message_AllowEditing' - editOwn = message.u?._id is Meteor.userId() - - return unless hasPermission or (isEditAllowed and editOwn) - - blockEditInMinutes = RocketChat.settings.get 'Message_AllowEditing_BlockEditInMinutes' - if blockEditInMinutes? and blockEditInMinutes isnt 0 - msgTs = moment(message.ts) if message.ts? - currentTsDiff = moment().diff(msgTs, 'minutes') if msgTs? - return currentTsDiff < blockEditInMinutes - else - return true - order: 2 - - RocketChat.MessageAction.addButton - id: 'delete-message' - icon: 'icon-trash-alt' - i18nLabel: 'Delete' - context: [ - 'message' - 'message-mobile' - ] - action: (event, instance) -> - message = @_arguments[1] - RocketChat.MessageAction.hideDropDown() - chatMessages[Session.get('openedRoom')].confirmDeleteMsg(message) - validation: (message) -> - if not RocketChat.models.Subscriptions.findOne({ rid: message.rid })? - return false - - hasPermission = RocketChat.authz.hasAtLeastOnePermission('delete-message', message.rid) - isDeleteAllowed = RocketChat.settings.get 'Message_AllowDeleting' - deleteOwn = message.u?._id is Meteor.userId() - - return unless hasPermission or (isDeleteAllowed and deleteOwn) - - blockDeleteInMinutes = RocketChat.settings.get 'Message_AllowDeleting_BlockDeleteInMinutes' - if blockDeleteInMinutes? and blockDeleteInMinutes isnt 0 - msgTs = moment(message.ts) if message.ts? - currentTsDiff = moment().diff(msgTs, 'minutes') if msgTs? - return currentTsDiff < blockDeleteInMinutes - else - return true - order: 3 - - RocketChat.MessageAction.addButton - id: 'permalink' - icon: 'icon-link' - i18nLabel: 'Permalink' - classes: 'clipboard' - context: [ - 'message' - 'message-mobile' - ] - action: (event, instance) -> - message = @_arguments[1] - permalink = RocketChat.MessageAction.getPermaLink(message._id) - RocketChat.MessageAction.hideDropDown() - if Meteor.isCordova - cordova.plugins.clipboard.copy(permalink); - else - $(event.currentTarget).attr('data-clipboard-text', permalink); - toastr.success(TAPi18n.__('Copied')) - validation: (message) -> - if not RocketChat.models.Subscriptions.findOne({ rid: message.rid })? - return false - - return true - order: 4 - - RocketChat.MessageAction.addButton - id: 'copy' - icon: 'icon-paste' - i18nLabel: 'Copy' - classes: 'clipboard' - context: [ - 'message' - 'message-mobile' - ] - action: (event, instance) -> - message = @_arguments[1].msg - RocketChat.MessageAction.hideDropDown() - if Meteor.isCordova - cordova.plugins.clipboard.copy(message); - else - $(event.currentTarget).attr('data-clipboard-text', message) - toastr.success(TAPi18n.__('Copied')) - validation: (message) -> - if not RocketChat.models.Subscriptions.findOne({ rid: message.rid })? - return false - - return true - order: 5 - - RocketChat.MessageAction.addButton - id: 'quote-message' - icon: 'icon-quote-left' - i18nLabel: 'Quote' - context: [ - 'message' - 'message-mobile' - ] - action: (event, instance) -> - message = @_arguments[1] - input = instance.find('.input-message') - url = RocketChat.MessageAction.getPermaLink(message._id) - text = '[ ](' + url + ') ' - if input.value - input.value += if input.value.endsWith(' ') then '' else ' ' - input.value += text - input.focus() - RocketChat.MessageAction.hideDropDown() - validation: (message) -> - if not RocketChat.models.Subscriptions.findOne({ rid: message.rid })? - return false - - return true - order: 6 diff --git a/packages/rocketchat-lib/client/MessageAction.js b/packages/rocketchat-lib/client/MessageAction.js new file mode 100644 index 000000000000..be10a478362b --- /dev/null +++ b/packages/rocketchat-lib/client/MessageAction.js @@ -0,0 +1,289 @@ +import moment from 'moment'; + +import toastr from 'toastr'; + +RocketChat.MessageAction = new class { + /* + config expects the following keys (only id is mandatory): + id (mandatory) + icon: string + i18nLabel: string + action: function(event, instance) + validation: function(message) + order: integer + */ + + constructor() { + this.buttons = new ReactiveVar({}); + } + + addButton(config) { + if (!config || !config.id) { + return false; + } + return Tracker.nonreactive(() => { + const btns = this.buttons.get(); + btns[config.id] = config; + return this.buttons.set(btns); + }); + } + + removeButton(id) { + return Tracker.nonreactive(() => { + const btns = this.buttons.get(); + delete btns[id]; + return this.buttons.set(btns); + }); + } + + updateButton(id, config) { + return Tracker.nonreactive(() => { + const btns = this.buttons.get(); + if (btns[id]) { + btns[id] = _.extend(btns[id], config); + return this.buttons.set(btns); + } + }); + } + + getButtonById(id) { + const allButtons = this.buttons.get(); + return allButtons[id]; + } + + getButtons(message, context) { + const allButtons = _.toArray(this.buttons.get()); + let allowedButtons = allButtons; + if (message) { + allowedButtons = _.compact(_.map(allButtons, function(button) { + if (button.context == null || button.context.includes(context)) { + if (button.validation == null || button.validation(message, context)) { + return button; + } + } + })); + } + return _.sortBy(allowedButtons, 'order'); + } + + resetButtons() { + return this.buttons.set({}); + } + + getPermaLink(msgId) { + const roomData = ChatSubscription.findOne({ + rid: Session.get('openedRoom') + }); + let routePath = document.location.pathname; + if (roomData) { + routePath = RocketChat.roomTypes.getRouteLink(roomData.t, roomData); + } + return `${ Meteor.absoluteUrl().replace(/\/$/, '') + routePath }?msg=${ msgId }`; + } + + hideDropDown() { + return $('.message-dropdown:visible').hide(); + } +}; + +Meteor.startup(function() { + $(document).click((event) => { + const target = $(event.target); + if (!target.closest('.message-cog-container').length && !target.is('.message-cog-container')) { + return RocketChat.MessageAction.hideDropDown(); + } + }); + + RocketChat.MessageAction.addButton({ + id: 'reply-message', + icon: 'icon-reply', + i18nLabel: 'Reply', + context: ['message', 'message-mobile'], + action(event, instance) { + const message = this._arguments[1]; + const input = instance.find('.input-message'); + const url = RocketChat.MessageAction.getPermaLink(message._id); + const text = `[ ](${ url }) @${ message.u.username } `; + if (input.value) { + input.value += input.value.endsWith(' ') ? '' : ' '; + } + input.value += text; + input.focus(); + return RocketChat.MessageAction.hideDropDown(); + }, + validation(message) { + if (RocketChat.models.Subscriptions.findOne({ + rid: message.rid + }) == null) { + return false; + } + return true; + }, + order: 1 + }); + /* globals chatMessages*/ + RocketChat.MessageAction.addButton({ + id: 'edit-message', + icon: 'icon-pencil', + i18nLabel: 'Edit', + context: ['message', 'message-mobile'], + action(e, instance) { + const message = $(e.currentTarget).closest('.message')[0]; + chatMessages[Session.get('openedRoom')].edit(message); + RocketChat.MessageAction.hideDropDown(); + const input = instance.find('.input-message'); + Meteor.setTimeout(() => { + input.focus(); + input.updateAutogrow(); + }, 200); + }, + validation(message) { + if (RocketChat.models.Subscriptions.findOne({ + rid: message.rid + }) == null) { + return false; + } + const hasPermission = RocketChat.authz.hasAtLeastOnePermission('edit-message', message.rid); + const isEditAllowed = RocketChat.settings.get('Message_AllowEditing'); + const editOwn = message.u && message.u._id === Meteor.userId(); + if (!(hasPermission || (isEditAllowed && editOwn))) { + return; + } + const blockEditInMinutes = RocketChat.settings.get('Message_AllowEditing_BlockEditInMinutes'); + if (blockEditInMinutes) { + let msgTs; + if (message.ts != null) { + msgTs = moment(message.ts); + } + let currentTsDiff; + if (msgTs != null) { + currentTsDiff = moment().diff(msgTs, 'minutes'); + } + return currentTsDiff < blockEditInMinutes; + } else { + return true; + } + }, + order: 2 + }); + RocketChat.MessageAction.addButton({ + id: 'delete-message', + icon: 'icon-trash-alt', + i18nLabel: 'Delete', + context: ['message', 'message-mobile'], + action() { + const message = this._arguments[1]; + RocketChat.MessageAction.hideDropDown(); + return chatMessages[Session.get('openedRoom')].confirmDeleteMsg(message); + }, + validation(message) { + if (RocketChat.models.Subscriptions.findOne({ + rid: message.rid + }) == null) { + return false; + } + const hasPermission = RocketChat.authz.hasAtLeastOnePermission('delete-message', message.rid); + const isDeleteAllowed = RocketChat.settings.get('Message_AllowDeleting'); + const deleteOwn = message.u && message.u_id === Meteor.userId(); + if (!(hasPermission || (isDeleteAllowed && deleteOwn))) { + return; + } + const blockDeleteInMinutes = RocketChat.settings.get('Message_AllowDeleting_BlockDeleteInMinutes'); + if ((blockDeleteInMinutes != null) && blockDeleteInMinutes !== 0) { + let msgTs; + if (message.ts != null) { + msgTs = moment(message.ts); + } + let currentTsDiff; + if (msgTs != null) { + currentTsDiff = moment().diff(msgTs, 'minutes'); + } + return currentTsDiff < blockDeleteInMinutes; + } else { + return true; + } + }, + order: 3 + }); + /* globals cordova*/ + RocketChat.MessageAction.addButton({ + id: 'permalink', + icon: 'icon-link', + i18nLabel: 'Permalink', + classes: 'clipboard', + context: ['message', 'message-mobile'], + action() { + const message = this._arguments[1]; + const permalink = RocketChat.MessageAction.getPermaLink(message._id); + RocketChat.MessageAction.hideDropDown(); + if (Meteor.isCordova) { + cordova.plugins.clipboard.copy(permalink); + } else { + $(event.currentTarget).attr('data-clipboard-text', permalink); + } + return toastr.success(TAPi18n.__('Copied')); + }, + validation(message) { + if (RocketChat.models.Subscriptions.findOne({ + rid: message.rid + }) == null) { + return false; + } + return true; + }, + order: 4 + }); + RocketChat.MessageAction.addButton({ + id: 'copy', + icon: 'icon-paste', + i18nLabel: 'Copy', + classes: 'clipboard', + context: ['message', 'message-mobile'], + action() { + const message = this._arguments[1].msg; + RocketChat.MessageAction.hideDropDown(); + if (Meteor.isCordova) { + cordova.plugins.clipboard.copy(message); + } else { + $(event.currentTarget).attr('data-clipboard-text', message); + } + return toastr.success(TAPi18n.__('Copied')); + }, + validation(message) { + if (RocketChat.models.Subscriptions.findOne({ + rid: message.rid + }) == null) { + return false; + } + return true; + }, + order: 5 + }); + return RocketChat.MessageAction.addButton({ + id: 'quote-message', + icon: 'icon-quote-left', + i18nLabel: 'Quote', + context: ['message', 'message-mobile'], + action(event, instance) { + const message = this._arguments[1]; + const input = instance.find('.input-message'); + const url = RocketChat.MessageAction.getPermaLink(message._id); + const text = `[ ](${ url }) `; + if (input.value) { + input.value += input.value.endsWith(' ') ? '' : ' '; + } + input.value += text; + input.focus(); + return RocketChat.MessageAction.hideDropDown(); + }, + validation(message) { + if (RocketChat.models.Subscriptions.findOne({ + rid: message.rid + }) == null) { + return false; + } + return true; + }, + order: 6 + }); +}); diff --git a/packages/rocketchat-lib/client/Notifications.coffee b/packages/rocketchat-lib/client/Notifications.coffee deleted file mode 100644 index 9a51ceca3482..000000000000 --- a/packages/rocketchat-lib/client/Notifications.coffee +++ /dev/null @@ -1,72 +0,0 @@ -RocketChat.Notifications = new class - constructor: -> - @logged = Meteor.userId() isnt null - @loginCb = [] - Tracker.autorun => - if Meteor.userId() isnt null and this.logged is false - cb() for cb in this.loginCb - - @logged = Meteor.userId() isnt null - - @debug = false - @streamAll = new Meteor.Streamer 'notify-all' - @streamLogged = new Meteor.Streamer 'notify-logged' - @streamRoom = new Meteor.Streamer 'notify-room' - @streamRoomUsers = new Meteor.Streamer 'notify-room-users' - @streamUser = new Meteor.Streamer 'notify-user' - - if @debug is true - @onAll -> console.log "RocketChat.Notifications: onAll", arguments - @onUser -> console.log "RocketChat.Notifications: onAll", arguments - - onLogin: (cb) -> - @loginCb.push(cb) - if @logged - cb() - - notifyRoom: (room, eventName, args...) -> - console.log "RocketChat.Notifications: notifyRoom", arguments if @debug is true - - args.unshift "#{room}/#{eventName}" - @streamRoom.emit.apply @streamRoom, args - - notifyUser: (userId, eventName, args...) -> - console.log "RocketChat.Notifications: notifyUser", arguments if @debug is true - - args.unshift "#{userId}/#{eventName}" - @streamUser.emit.apply @streamUser, args - - notifyUsersOfRoom: (room, eventName, args...) -> - console.log "RocketChat.Notifications: notifyUsersOfRoom", arguments if @debug is true - - args.unshift "#{room}/#{eventName}" - @streamRoomUsers.emit.apply @streamRoomUsers, args - - onAll: (eventName, callback) -> - @streamAll.on eventName, callback - - onLogged: (eventName, callback) -> - @onLogin => - @streamLogged.on eventName, callback - - onRoom: (room, eventName, callback) -> - if @debug is true - @streamRoom.on room, -> console.log "RocketChat.Notifications: onRoom #{room}", arguments - - @streamRoom.on "#{room}/#{eventName}", callback - - onUser: (eventName, callback) -> - @streamUser.on "#{Meteor.userId()}/#{eventName}", callback - - - unAll: (callback) -> - @streamAll.removeListener 'notify', callback - - unLogged: (callback) -> - @streamLogged.removeListener 'notify', callback - - unRoom: (room, eventName, callback) -> - @streamRoom.removeListener "#{room}/#{eventName}", callback - - unUser: (callback) -> - @streamUser.removeListener Meteor.userId(), callback diff --git a/packages/rocketchat-lib/client/Notifications.js b/packages/rocketchat-lib/client/Notifications.js new file mode 100644 index 000000000000..4a474c9aec24 --- /dev/null +++ b/packages/rocketchat-lib/client/Notifications.js @@ -0,0 +1,86 @@ +RocketChat.Notifications = new class { + constructor() { + this.logged = Meteor.userId() !== null; + this.loginCb = []; + Tracker.autorun(() => { + if (Meteor.userId() !== null && this.logged === false) { + this.loginCb.forEach(cb => cb()); + } + return this.logged = Meteor.userId() !== null; + }); + this.debug = false; + this.streamAll = new Meteor.Streamer('notify-all'); + this.streamLogged = new Meteor.Streamer('notify-logged'); + this.streamRoom = new Meteor.Streamer('notify-room'); + this.streamRoomUsers = new Meteor.Streamer('notify-room-users'); + this.streamUser = new Meteor.Streamer('notify-user'); + if (this.debug === true) { + this.onAll(function() { + return console.log('RocketChat.Notifications: onAll', arguments); + }); + this.onUser(function() { + return console.log('RocketChat.Notifications: onAll', arguments); + }); + } + } + + onLogin(cb) { + this.loginCb.push(cb); + if (this.logged) { + return cb(); + } + } + notifyRoom(room, eventName, ...args) { + if (this.debug === true) { + console.log('RocketChat.Notifications: notifyRoom', arguments); + } + args.unshift(`${ room }/${ eventName }`); + return this.streamRoom.emit.apply(this.streamRoom, args); + } + notifyUser(userId, eventName, ...args) { + if (this.debug === true) { + console.log('RocketChat.Notifications: notifyUser', arguments); + } + args.unshift(`${ userId }/${ eventName }`); + return this.streamUser.emit.apply(this.streamUser, args); + } + notifyUsersOfRoom(room, eventName, ...args) { + if (this.debug === true) { + console.log('RocketChat.Notifications: notifyUsersOfRoom', arguments); + } + args.unshift(`${ room }/${ eventName }`); + return this.streamRoomUsers.emit.apply(this.streamRoomUsers, args); + } + onAll(eventName, callback) { + return this.streamAll.on(eventName, callback); + } + onLogged(eventName, callback) { + return this.onLogin(() => { + return this.streamLogged.on(eventName, callback); + }); + } + onRoom(room, eventName, callback) { + if (this.debug === true) { + this.streamRoom.on(room, function() { + return console.log(`RocketChat.Notifications: onRoom ${ room }`, arguments); + }); + } + return this.streamRoom.on(`${ room }/${ eventName }`, callback); + } + onUser(eventName, callback) { + return this.streamUser.on(`${ Meteor.userId() }/${ eventName }`, callback); + } + unAll(callback) { + return this.streamAll.removeListener('notify', callback); + } + unLogged(callback) { + return this.streamLogged.removeListener('notify', callback); + } + unRoom(room, eventName, callback) { + return this.streamRoom.removeListener(`${ room }/${ eventName }`, callback); + } + unUser(callback) { + return this.streamUser.removeListener(Meteor.userId(), callback); + } + +}; diff --git a/packages/rocketchat-lib/client/lib/roomExit.coffee b/packages/rocketchat-lib/client/lib/roomExit.coffee deleted file mode 100644 index d7da9ed4a871..000000000000 --- a/packages/rocketchat-lib/client/lib/roomExit.coffee +++ /dev/null @@ -1,20 +0,0 @@ -@roomExit = -> - RocketChat.callbacks.run 'roomExit' - - BlazeLayout.render 'main', {center: 'none'} - - if currentTracker? - currentTracker.stop() - - mainNode = document.querySelector('.main-content') - if mainNode? - for child in mainNode.children - if child? - if child.classList.contains('room-container') - wrapper = child.querySelector('.messages-box > .wrapper') - if wrapper - if wrapper.scrollTop >= wrapper.scrollHeight - wrapper.clientHeight - child.oldScrollTop = 10e10 - else - child.oldScrollTop = wrapper.scrollTop - mainNode.removeChild child diff --git a/packages/rocketchat-lib/client/lib/roomExit.js b/packages/rocketchat-lib/client/lib/roomExit.js new file mode 100644 index 000000000000..1612105dfe28 --- /dev/null +++ b/packages/rocketchat-lib/client/lib/roomExit.js @@ -0,0 +1,31 @@ +/*globals currentTracker */ +this.roomExit = function() { + RocketChat.callbacks.run('roomExit'); + BlazeLayout.render('main', { + center: 'none' + }); + + if (typeof currentTracker !== 'undefined') { + currentTracker.stop(); + } + const mainNode = document.querySelector('.main-content'); + if (mainNode == null) { + return; + } + return mainNode.children.forEach(child => { + if (child == null) { + return; + } + if (child.classList.contains('room-container')) { + const wrapper = child.querySelector('.messages-box > .wrapper'); + if (wrapper) { + if (wrapper.scrollTop >= wrapper.scrollHeight - wrapper.clientHeight) { + child.oldScrollTop = 10e10; + } else { + child.oldScrollTop = wrapper.scrollTop; + } + } + } + mainNode.removeChild(child); + }); +}; diff --git a/packages/rocketchat-lib/client/lib/settings.coffee b/packages/rocketchat-lib/client/lib/settings.coffee deleted file mode 100644 index 38c08e546ba2..000000000000 --- a/packages/rocketchat-lib/client/lib/settings.coffee +++ /dev/null @@ -1,65 +0,0 @@ -### -# RocketChat.settings holds all packages settings -# @namespace RocketChat.settings -### - -RocketChat.settings.cachedCollection = new RocketChat.CachedCollection({ name: 'public-settings', eventType: 'onAll', userRelated: false }) -RocketChat.settings.collection = RocketChat.settings.cachedCollection.collection -RocketChat.settings.cachedCollection.init() - -RocketChat.settings.dict = new ReactiveDict 'settings' - -RocketChat.settings.get = (_id) -> - return RocketChat.settings.dict.get(_id) - -RocketChat.settings.init = -> - initialLoad = true - RocketChat.settings.collection.find().observe - added: (record) -> - Meteor.settings[record._id] = record.value - RocketChat.settings.dict.set record._id, record.value - RocketChat.settings.load record._id, record.value, initialLoad - changed: (record) -> - Meteor.settings[record._id] = record.value - RocketChat.settings.dict.set record._id, record.value - RocketChat.settings.load record._id, record.value, initialLoad - removed: (record) -> - delete Meteor.settings[record._id] - RocketChat.settings.dict.set record._id, undefined - RocketChat.settings.load record._id, undefined, initialLoad - initialLoad = false - -RocketChat.settings.init() - -Meteor.startup -> - if Meteor.isCordova is false - Tracker.autorun (c) -> - siteUrl = RocketChat.settings.get('Site_Url') - if not siteUrl or not Meteor.userId()? - return - - if RocketChat.authz.hasRole(Meteor.userId(), 'admin') is false or Meteor.settings.public.sandstorm - return c.stop() - - Meteor.setTimeout -> - if __meteor_runtime_config__.ROOT_URL isnt location.origin - currentUrl = location.origin + __meteor_runtime_config__.ROOT_URL_PATH_PREFIX - swal - type: 'warning' - title: t('Warning') - text: t("The_setting_s_is_configured_to_s_and_you_are_accessing_from_s", t('Site_Url'), siteUrl, currentUrl) + '

' + t("Do_you_want_to_change_to_s_question", currentUrl) - showCancelButton: true - confirmButtonText: t('Yes') - cancelButtonText: t('Cancel') - closeOnConfirm: false - html: true - , -> - Meteor.call 'saveSetting', 'Site_Url', currentUrl, -> - swal - title: t('Saved') - type: 'success' - timer: 1000 - showConfirmButton: false - , 100 - - return c.stop() diff --git a/packages/rocketchat-lib/client/lib/settings.js b/packages/rocketchat-lib/client/lib/settings.js new file mode 100644 index 000000000000..0f0c946ecd81 --- /dev/null +++ b/packages/rocketchat-lib/client/lib/settings.js @@ -0,0 +1,87 @@ + +/* +* RocketChat.settings holds all packages settings +* @namespace RocketChat.settings +*/ + +/* globals ReactiveDict*/ + +RocketChat.settings.cachedCollection = new RocketChat.CachedCollection({ + name: 'public-settings', + eventType: 'onAll', + userRelated: false +}); + +RocketChat.settings.collection = RocketChat.settings.cachedCollection.collection; + +RocketChat.settings.cachedCollection.init(); + +RocketChat.settings.dict = new ReactiveDict('settings'); + +RocketChat.settings.get = function(_id) { + return RocketChat.settings.dict.get(_id); +}; + +RocketChat.settings.init = function() { + let initialLoad = true; + RocketChat.settings.collection.find().observe({ + added(record) { + Meteor.settings[record._id] = record.value; + RocketChat.settings.dict.set(record._id, record.value); + return RocketChat.settings.load(record._id, record.value, initialLoad); + }, + changed(record) { + Meteor.settings[record._id] = record.value; + RocketChat.settings.dict.set(record._id, record.value); + return RocketChat.settings.load(record._id, record.value, initialLoad); + }, + removed(record) { + delete Meteor.settings[record._id]; + RocketChat.settings.dict.set(record._id, null); + return RocketChat.settings.load(record._id, null, initialLoad); + } + }); + return initialLoad = false; +}; + +RocketChat.settings.init(); + +Meteor.startup(function() { + if (Meteor.isCordova === true) { + return; + } + Tracker.autorun(function(c) { + const siteUrl = RocketChat.settings.get('Site_Url'); + if (!siteUrl || (Meteor.userId() == null)) { + return; + } + if (RocketChat.authz.hasRole(Meteor.userId(), 'admin') === false || Meteor.settings['public'].sandstorm) { + return c.stop(); + } + Meteor.setTimeout(function() { + if (__meteor_runtime_config__.ROOT_URL !== location.origin) { + const currentUrl = location.origin + __meteor_runtime_config__.ROOT_URL_PATH_PREFIX; + swal({ + type: 'warning', + title: t('Warning'), + text: `${ t('The_setting_s_is_configured_to_s_and_you_are_accessing_from_s', t('Site_Url'), siteUrl, currentUrl) }

${ t('Do_you_want_to_change_to_s_question', currentUrl) }`, + showCancelButton: true, + confirmButtonText: t('Yes'), + cancelButtonText: t('Cancel'), + closeOnConfirm: false, + html: true + }, function() { + Meteor.call('saveSetting', 'Site_Url', currentUrl, function() { + swal({ + title: t('Saved'), + type: 'success', + timer: 1000, + showConfirmButton: false + }); + }); + }); + } + }, 100); + return c.stop(); + }); +}); diff --git a/packages/rocketchat-lib/client/methods/sendMessage.coffee b/packages/rocketchat-lib/client/methods/sendMessage.coffee deleted file mode 100644 index c8ae9426c32a..000000000000 --- a/packages/rocketchat-lib/client/methods/sendMessage.coffee +++ /dev/null @@ -1,22 +0,0 @@ -Meteor.methods - sendMessage: (message) -> - if not Meteor.userId() - return false - - if _.trim(message.msg) isnt '' - if isNaN(TimeSync.serverOffset()) - message.ts = new Date() - else - message.ts = new Date(Date.now() + TimeSync.serverOffset()) - - message.u = - _id: Meteor.userId() - username: Meteor.user().username - - message.temp = true - - message = RocketChat.callbacks.run 'beforeSaveMessage', message - - RocketChat.promises.run('onClientMessageReceived', message).then (message) -> - ChatMessage.insert message - RocketChat.callbacks.run 'afterSaveMessage', message diff --git a/packages/rocketchat-lib/client/methods/sendMessage.js b/packages/rocketchat-lib/client/methods/sendMessage.js new file mode 100644 index 000000000000..cc37a2611f53 --- /dev/null +++ b/packages/rocketchat-lib/client/methods/sendMessage.js @@ -0,0 +1,18 @@ +Meteor.methods({ + sendMessage(message) { + if (!Meteor.userId() || _.trim(message.msg) === '') { + return false; + } + message.ts = isNaN(TimeSync.serverOffset()) ? new Date() : new Date(Date.now() + TimeSync.serverOffset()); + message.u = { + _id: Meteor.userId(), + username: Meteor.user().username + }; + message.temp = true; + message = RocketChat.callbacks.run('beforeSaveMessage', message); + RocketChat.promises.run('onClientMessageReceived', message).then(function(message) { + ChatMessage.insert(message); + return RocketChat.callbacks.run('afterSaveMessage', message); + }); + } +}); diff --git a/packages/rocketchat-lib/client/models/Uploads.coffee b/packages/rocketchat-lib/client/models/Uploads.coffee deleted file mode 100644 index 4572e735b99b..000000000000 --- a/packages/rocketchat-lib/client/models/Uploads.coffee +++ /dev/null @@ -1,3 +0,0 @@ -RocketChat.models.Uploads = new class extends RocketChat.models._Base - constructor: -> - @_initModel 'uploads' diff --git a/packages/rocketchat-lib/client/models/Uploads.js b/packages/rocketchat-lib/client/models/Uploads.js new file mode 100644 index 000000000000..eefe630c708c --- /dev/null +++ b/packages/rocketchat-lib/client/models/Uploads.js @@ -0,0 +1,7 @@ + +RocketChat.models.Uploads = new class extends RocketChat.models._Base { + constructor() { + super(); + this._initModel('uploads'); + } +}; diff --git a/packages/rocketchat-lib/client/models/_Base.coffee b/packages/rocketchat-lib/client/models/_Base.coffee deleted file mode 100644 index fb485723241a..000000000000 --- a/packages/rocketchat-lib/client/models/_Base.coffee +++ /dev/null @@ -1,44 +0,0 @@ -RocketChat.models._Base = class - _baseName: -> - return 'rocketchat_' - - _initModel: (name) -> - check name, String - - @model = new Mongo.Collection @_baseName() + name - - find: -> - return @model.find.apply @model, arguments - - findOne: -> - return @model.findOne.apply @model, arguments - - insert: -> - return @model.insert.apply @model, arguments - - update: -> - return @model.update.apply @model, arguments - - upsert: -> - return @model.upsert.apply @model, arguments - - remove: -> - return @model.remove.apply @model, arguments - - allow: -> - return @model.allow.apply @model, arguments - - deny: -> - return @model.deny.apply @model, arguments - - ensureIndex: -> - return - - dropIndex: -> - return - - tryEnsureIndex: -> - return - - tryDropIndex: -> - return diff --git a/packages/rocketchat-lib/client/models/_Base.js b/packages/rocketchat-lib/client/models/_Base.js new file mode 100644 index 000000000000..55623317be66 --- /dev/null +++ b/packages/rocketchat-lib/client/models/_Base.js @@ -0,0 +1,52 @@ +RocketChat.models._Base = class { + + _baseName() { + return 'rocketchat_'; + } + + _initModel(name) { + check(name, String); + return this.model = new Mongo.Collection(this._baseName() + name); + } + + find() { + return this.model.find.apply(this.model, arguments); + } + + findOne() { + return this.model.findOne.apply(this.model, arguments); + } + + insert() { + return this.model.insert.apply(this.model, arguments); + } + + update() { + return this.model.update.apply(this.model, arguments); + } + + upsert() { + return this.model.upsert.apply(this.model, arguments); + } + + remove() { + return this.model.remove.apply(this.model, arguments); + } + + allow() { + return this.model.allow.apply(this.model, arguments); + } + + deny() { + return this.model.deny.apply(this.model, arguments); + } + + ensureIndex() {} + + dropIndex() {} + + tryEnsureIndex() {} + + tryDropIndex() {} + +}; diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 6e7e7c4022e4..8aea1663f7bb 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -173,29 +173,29 @@ Package.onUse(function(api) { api.addFiles('lib/startup/settingsOnLoadSiteUrl.js'); // CLIENT LIB - api.addFiles('client/Notifications.coffee', 'client'); + api.addFiles('client/Notifications.js', 'client'); api.addFiles('client/OAuthProxy.js', 'client'); api.addFiles('client/lib/TabBar.js', 'client'); api.addFiles('client/lib/RocketChatTabBar.js', 'client'); api.addFiles('client/lib/cachedCollection.js', 'client'); api.addFiles('client/lib/openRoom.coffee', 'client'); - api.addFiles('client/lib/roomExit.coffee', 'client'); - api.addFiles('client/lib/settings.coffee', 'client'); + api.addFiles('client/lib/roomExit.js', 'client'); + api.addFiles('client/lib/settings.js', 'client'); api.addFiles('client/lib/roomTypes.coffee', 'client'); api.addFiles('client/lib/userRoles.js', 'client'); api.addFiles('client/lib/Layout.js', 'client'); // CLIENT METHODS - api.addFiles('client/methods/sendMessage.coffee', 'client'); + api.addFiles('client/methods/sendMessage.js', 'client'); api.addFiles('client/AdminBox.js', 'client'); - api.addFiles('client/MessageAction.coffee', 'client'); + api.addFiles('client/MessageAction.js', 'client'); api.addFiles('client/defaultTabBars.js', 'client'); api.addFiles('client/CustomTranslations.js', 'client'); // CLIENT MODELS - api.addFiles('client/models/_Base.coffee', 'client'); - api.addFiles('client/models/Uploads.coffee', 'client'); + api.addFiles('client/models/_Base.js', 'client'); + api.addFiles('client/models/Uploads.js', 'client'); // CLIENT VIEWS api.addFiles('client/views/customFieldsForm.html', 'client'); From b4f36de2e167a1158cb1eac302f0a1b3d69d252e Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 12 Apr 2017 15:23:24 -0300 Subject: [PATCH 2/3] lib3 --- .../rocketchat-lib/client/lib/openRoom.coffee | 79 ----------- .../rocketchat-lib/client/lib/openRoom.js | 102 ++++++++++++++ .../client/lib/roomTypes.coffee | 87 ------------ .../rocketchat-lib/client/lib/roomTypes.js | 124 +++++++++++++++++ packages/rocketchat-lib/lib/callbacks.coffee | 129 ----------------- packages/rocketchat-lib/lib/callbacks.js | 131 ++++++++++++++++++ packages/rocketchat-lib/lib/promises.coffee | 93 ------------- packages/rocketchat-lib/lib/promises.js | 89 ++++++++++++ .../rocketchat-lib/lib/roomTypesCommon.coffee | 75 ---------- .../rocketchat-lib/lib/roomTypesCommon.js | 83 +++++++++++ packages/rocketchat-lib/lib/settings.coffee | 83 ----------- packages/rocketchat-lib/lib/settings.js | 102 ++++++++++++++ packages/rocketchat-lib/package.js | 12 +- 13 files changed, 637 insertions(+), 552 deletions(-) delete mode 100644 packages/rocketchat-lib/client/lib/openRoom.coffee create mode 100644 packages/rocketchat-lib/client/lib/openRoom.js delete mode 100644 packages/rocketchat-lib/client/lib/roomTypes.coffee create mode 100644 packages/rocketchat-lib/client/lib/roomTypes.js delete mode 100644 packages/rocketchat-lib/lib/callbacks.coffee create mode 100644 packages/rocketchat-lib/lib/callbacks.js delete mode 100644 packages/rocketchat-lib/lib/promises.coffee create mode 100644 packages/rocketchat-lib/lib/promises.js delete mode 100644 packages/rocketchat-lib/lib/roomTypesCommon.coffee create mode 100644 packages/rocketchat-lib/lib/roomTypesCommon.js delete mode 100644 packages/rocketchat-lib/lib/settings.coffee create mode 100644 packages/rocketchat-lib/lib/settings.js diff --git a/packages/rocketchat-lib/client/lib/openRoom.coffee b/packages/rocketchat-lib/client/lib/openRoom.coffee deleted file mode 100644 index af932dfc5aa3..000000000000 --- a/packages/rocketchat-lib/client/lib/openRoom.coffee +++ /dev/null @@ -1,79 +0,0 @@ -currentTracker = undefined - -@openRoom = (type, name) -> - Session.set 'openedRoom', null - - Meteor.defer -> - currentTracker = Tracker.autorun (c) -> - if RoomManager.open(type + name).ready() isnt true - BlazeLayout.render 'main', { modal: RocketChat.Layout.isEmbedded(), center: 'loading' } - return - - user = Meteor.user() - unless user?.username - return - - currentTracker = undefined - c.stop() - - room = RocketChat.roomTypes.findRoom(type, name, user) - if not room? - if type is 'd' - Meteor.call 'createDirectMessage', name, (err) -> - if !err - RoomManager.close(type + name) - openRoom('d', name) - else - Session.set 'roomNotFound', {type: type, name: name} - BlazeLayout.render 'main', {center: 'roomNotFound'} - return - else - Meteor.call 'getRoomByTypeAndName', type, name, (err, record) -> - if err? - Session.set 'roomNotFound', {type: type, name: name} - BlazeLayout.render 'main', {center: 'roomNotFound'} - else - delete record.$loki - RocketChat.models.Rooms.upsert({ _id: record._id }, _.omit(record, '_id')) - RoomManager.close(type + name) - openRoom(type, name) - - return - - mainNode = document.querySelector('.main-content') - if mainNode? - for child in mainNode.children - mainNode.removeChild child if child? - roomDom = RoomManager.getDomOfRoom(type + name, room._id) - mainNode.appendChild roomDom - if roomDom.classList.contains('room-container') - roomDom.querySelector('.messages-box > .wrapper').scrollTop = roomDom.oldScrollTop - - Session.set 'openedRoom', room._id - - fireGlobalEvent 'room-opened', _.omit room, 'usernames' - - Session.set 'editRoomTitle', false - RoomManager.updateMentionsMarksOfRoom type + name - Meteor.setTimeout -> - readMessage.readNow() - , 2000 - # KonchatNotification.removeRoomNotification(params._id) - - if Meteor.Device.isDesktop() and window.chatMessages?[room._id]? - setTimeout -> - $('.message-form .input-message').focus() - , 100 - - # update user's room subscription - sub = ChatSubscription.findOne({rid: room._id}) - if sub?.open is false - Meteor.call 'openRoom', room._id, (err) -> - if err - return handleError(err) - - if FlowRouter.getQueryParam('msg') - msg = { _id: FlowRouter.getQueryParam('msg'), rid: room._id } - RoomHistoryManager.getSurroundingMessages(msg); - - RocketChat.callbacks.run 'enter-room', sub diff --git a/packages/rocketchat-lib/client/lib/openRoom.js b/packages/rocketchat-lib/client/lib/openRoom.js new file mode 100644 index 000000000000..7224887c27da --- /dev/null +++ b/packages/rocketchat-lib/client/lib/openRoom.js @@ -0,0 +1,102 @@ +/* globals fireGlobalEvent readMessage*/ +const openRoom = function(type, name) { + Session.set('openedRoom', null); + Meteor.defer(function() { + Tracker.autorun(function(c) { + if (RoomManager.open(type + name).ready() !== true) { + return BlazeLayout.render('main', { + modal: RocketChat.Layout.isEmbedded(), + center: 'loading' + }); + } + const user = Meteor.user(); + if (!(user != null && user.username)) { + return; + } + c.stop(); + const room = RocketChat.roomTypes.findRoom(type, name, user); + if (room == null) { + if (type === 'd') { + Meteor.call('createDirectMessage', name, function(err) { + if (!err) { + RoomManager.close(type + name); + return openRoom('d', name); + } else { + Session.set('roomNotFound', { + type, + name + }); + BlazeLayout.render('main', { + center: 'roomNotFound' + }); + } + }); + } else { + Meteor.call('getRoomByTypeAndName', type, name, function(err, record) { + if (err != null) { + Session.set('roomNotFound', { + type, + name + }); + return BlazeLayout.render('main', { + center: 'roomNotFound' + }); + } else { + delete record.$loki; + RocketChat.models.Rooms.upsert({ + _id: record._id + }, _.omit(record, '_id')); + RoomManager.close(type + name); + return openRoom(type, name); + } + }); + } + return; + } + const mainNode = document.querySelector('.main-content'); + if (mainNode != null) { + [...((mainNode && mainNode.children) || [])].forEach(child => { + mainNode.removeChild(child); + }); + const roomDom = RoomManager.getDomOfRoom(type + name, room._id); + mainNode.appendChild(roomDom); + if (roomDom.classList.contains('room-container')) { + roomDom.querySelector('.messages-box > .wrapper').scrollTop = roomDom.oldScrollTop; + } + } + Session.set('openedRoom', room._id); + fireGlobalEvent('room-opened', _.omit(room, 'usernames')); + Session.set('editRoomTitle', false); + RoomManager.updateMentionsMarksOfRoom(type + name); + + Meteor.setTimeout(() => { + readMessage.readNow(); + }, 2000); + + if (Meteor.Device.isDesktop() && window.chatMessages && window.chatMessages[room._id] != null) { + setTimeout(() => { + return $('.message-form .input-message').focus(); + }, 100); + } + const sub = ChatSubscription.findOne({ + rid: room._id + }); + if (sub && sub.open === false) { + Meteor.call('openRoom', room._id, function(err) { + if (err) { + return handleError(err); + } + }); + } + if (FlowRouter.getQueryParam('msg')) { + const msg = { + _id: FlowRouter.getQueryParam('msg'), + rid: room._id + }; + RoomHistoryManager.getSurroundingMessages(msg); + } + return RocketChat.callbacks.run('enter-room', sub); + }); + }); +}; +this.openRoom = openRoom; diff --git a/packages/rocketchat-lib/client/lib/roomTypes.coffee b/packages/rocketchat-lib/client/lib/roomTypes.coffee deleted file mode 100644 index 424636cd38a2..000000000000 --- a/packages/rocketchat-lib/client/lib/roomTypes.coffee +++ /dev/null @@ -1,87 +0,0 @@ -RocketChat.roomTypes = new class roomTypesClient extends roomTypesCommon - checkCondition: (roomType) -> - return not roomType.condition? or roomType.condition() - - getTypes: -> - orderedTypes = [] - - _.sortBy(@roomTypesOrder, 'order').forEach (type) => - orderedTypes.push @roomTypes[type.identifier] - - return orderedTypes - - getIcon: (roomType) -> - return @roomTypes[roomType]?.icon - - getRoomName: (roomType, roomData) -> - return @roomTypes[roomType]?.roomName roomData - - getIdentifiers: (except) -> - except = [].concat except - list = _.reject @roomTypesOrder, (t) -> return except.indexOf(t.identifier) isnt -1 - return _.map list, (t) -> return t.identifier - - getUserStatus: (roomType, roomId) -> - return @roomTypes[roomType]?.getUserStatus?(roomId) - - findRoom: (roomType, identifier, user) -> - return @roomTypes[roomType]?.findRoom identifier, user - - canSendMessage: (roomId) -> - return ChatSubscription.find({ rid: roomId }).count() > 0 - - readOnly: (roomId, user) -> - - fields = { ro: 1 } - - # if a user has been specified then we want to see if that user has been muted in the room - if user - fields.muted = 1 - - room = ChatRoom.findOne({ _id: roomId }, fields : fields) - - unless user - return room?.ro; - - userOwner = RoomRoles.findOne({ rid: roomId, "u._id": user._id, roles: 'owner' }, { fields: { _id: 1 } }) - - return room?.ro is true and Array.isArray(room?.muted) and room?.muted.indexOf(user.username) != -1 and !userOwner - - archived: (roomId) -> - fields = { archived: 1 } - - room = ChatRoom.findOne({ _id: roomId }, fields : fields) - - return room?.archived is true - - verifyCanSendMessage: (roomId) -> - room = ChatRoom.findOne({ _id: roomId }, { fields: { t: 1 } }) - return if not room?.t? - - roomType = room.t - - return @roomTypes[roomType]?.canSendMessage roomId if @roomTypes[roomType]?.canSendMessage? - - return @canSendMessage roomId - - verifyShowJoinLink: (roomId) -> - room = ChatRoom.findOne({ _id: roomId }, { fields: { t: 1 } }) - return if not room?.t? - - roomType = room.t - - if not @roomTypes[roomType]?.showJoinLink? - return false - - return @roomTypes[roomType].showJoinLink roomId - - getNotSubscribedTpl: (roomId) -> - room = ChatRoom.findOne({ _id: roomId }, { fields: { t: 1 } }) - return if not room?.t? - - roomType = room.t - - if not @roomTypes[roomType]?.notSubscribedTpl? - return false - - return @roomTypes[roomType].notSubscribedTpl diff --git a/packages/rocketchat-lib/client/lib/roomTypes.js b/packages/rocketchat-lib/client/lib/roomTypes.js new file mode 100644 index 000000000000..dec8c462888a --- /dev/null +++ b/packages/rocketchat-lib/client/lib/roomTypes.js @@ -0,0 +1,124 @@ +import roomTypesCommon from '../../lib/roomTypesCommon'; + +RocketChat.roomTypes = new class extends roomTypesCommon { + checkCondition(roomType) { + return (roomType.condition == null) || roomType.condition(); + } + getTypes() { + return _.sortBy(this.roomTypesOrder, 'order').map((type) => this.roomTypes[type.identifier]); + } + getIcon(roomType) { + return this.roomTypes[roomType] && this.roomTypes[roomType].icon; + } + getRoomName(roomType, roomData) { + return this.roomTypes[roomType] && this.roomTypes[roomType].roomName && this.roomTypes[roomType].roomName(roomData); + } + getIdentifiers(e) { + const except = [].concat(e); + const list = _.reject(this.roomTypesOrder, (t) => except.indexOf(t.identifier) !== -1); + return _.map(list, (t) => t.identifier); + } + getUserStatus(roomType, roomId) { + this.roomTypes[roomType] && typeof this.roomTypes[roomType].getUserStatus === 'function' && this.roomTypes[roomType].getUserStatus(roomId); + } + findRoom(roomType, identifier, user) { + return this.roomTypes[roomType] && this.roomTypes[roomType].findRoom(identifier, user); + } + canSendMessage(roomId) { + return ChatSubscription.find({ + rid: roomId + }).count() > 0; + } + readOnly(roomId, user) { + const fields = { + ro: 1 + }; + if (user) { + fields.muted = 1; + } + const room = ChatRoom.findOne({ + _id: roomId + }, { + fields + }); + if (!user) { + return room && room.ro; + } + /* globals RoomRoles */ + const userOwner = RoomRoles.findOne({ + rid: roomId, + 'u._id': user._id, + roles: 'owner' + }, { + fields: { + _id: 1 + } + }); + return room && (room.ro === true && Array.isArray(room.muted) && room.muted.indexOf(user.username) !== -1 && !userOwner); + } + archived(roomId) { + const fields = { + archived: 1 + }; + const room = ChatRoom.findOne({ + _id: roomId + }, { + fields + }); + return room && room.archived === true; + } + verifyCanSendMessage(roomId) { + const room = ChatRoom.findOne({ + _id: roomId + }, { + fields: { + t: 1 + } + }); + + if (room && !room.t) { + return; + } + + const roomType = room.t; + if (this.roomTypes[roomType] && this.roomTypes[roomType].canSendMessage) { + return this.roomTypes[roomType].canSendMessage(roomId); + } + return this.canSendMessage(roomId); + } + verifyShowJoinLink(roomId) { + const room = ChatRoom.findOne({ + _id: roomId + }, { + fields: { + t: 1 + } + }); + if (room && !room.t) { + return; + } + const roomType = room.t; + if (this.roomTypes[roomType] && !this.roomTypes[roomType].showJoinLink) { + return false; + } + return this.roomTypes[roomType].showJoinLink(roomId); + } + getNotSubscribedTpl(roomId) { + const room = ChatRoom.findOne({ + _id: roomId + }, { + fields: { + t: 1 + } + }); + if (room && !room.t) { + return; + } + const roomType = room.t; + if (this.roomTypes[roomType] && !this.roomTypes[roomType].notSubscribedTpl) { + return false; + } + return this.roomTypes[roomType].notSubscribedTpl; + } + +}; diff --git a/packages/rocketchat-lib/lib/callbacks.coffee b/packages/rocketchat-lib/lib/callbacks.coffee deleted file mode 100644 index d0e3feb8ff32..000000000000 --- a/packages/rocketchat-lib/lib/callbacks.coffee +++ /dev/null @@ -1,129 +0,0 @@ -# https://github.com/TelescopeJS/Telescope/blob/master/packages/telescope-lib/lib/callbacks.js - -### -# Callback hooks provide an easy way to add extra steps to common operations. -# @namespace RocketChat.callbacks -### -RocketChat.callbacks = {} - -if Meteor.isServer - RocketChat.callbacks.showTime = true - RocketChat.callbacks.showTotalTime = true -else - RocketChat.callbacks.showTime = false - RocketChat.callbacks.showTotalTime = false - -### -# Callback priorities -### -RocketChat.callbacks.priority = - HIGH: -1000 - MEDIUM: 0 - LOW: 1000 - -### -# Add a callback function to a hook -# @param {String} hook - The name of the hook -# @param {Function} callback - The callback function -### -RocketChat.callbacks.add = (hook, callback, priority, id) -> - # if callback array doesn't exist yet, initialize it - priority ?= RocketChat.callbacks.priority.MEDIUM - unless _.isNumber priority - priority = RocketChat.callbacks.priority.MEDIUM - callback.priority = priority - callback.id = id or Random.id() - RocketChat.callbacks[hook] ?= [] - - if RocketChat.callbacks.showTime is true - err = new Error - callback.stack = err.stack - - # if not id? - # console.log('Callback without id', callback.stack) - - # Avoid adding the same callback twice - for cb in RocketChat.callbacks[hook] - if cb.id is callback.id - return - - RocketChat.callbacks[hook].push callback - return - -### -# Remove a callback from a hook -# @param {string} hook - The name of the hook -# @param {string} id - The callback's id -### - -RocketChat.callbacks.remove = (hookName, id) -> - RocketChat.callbacks[hookName] = _.reject RocketChat.callbacks[hookName], (callback) -> - callback.id is id - return - -### -# Successively run all of a hook's callbacks on an item -# @param {String} hook - The name of the hook -# @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks -# @param {Object} [constant] - An optional constant that will be passed along to each callback -# @returns {Object} Returns the item after it's been through all the callbacks for this hook -### - -RocketChat.callbacks.run = (hook, item, constant) -> - callbacks = RocketChat.callbacks[hook] - if !!callbacks?.length - if RocketChat.callbacks.showTotalTime is true - totalTime = 0 - - # if the hook exists, and contains callbacks to run - result = _.sortBy(callbacks, (callback) -> return callback.priority or RocketChat.callbacks.priority.MEDIUM).reduce (result, callback) -> - # console.log(callback.name); - if RocketChat.callbacks.showTime is true or RocketChat.callbacks.showTotalTime is true - time = Date.now() - - callbackResult = callback result, constant - - if RocketChat.callbacks.showTime is true or RocketChat.callbacks.showTotalTime is true - currentTime = Date.now() - time - totalTime += currentTime - if RocketChat.callbacks.showTime is true - if Meteor.isServer - RocketChat.statsTracker.timing('callbacks.time', currentTime, ["hook:#{hook}", "callback:#{callback.id}"]); - else - console.log String(currentTime), hook, callback.id, callback.stack?.split?('\n')[2]?.match(/\(.+\)/)?[0] - - return if typeof callbackResult == 'undefined' then result else callbackResult - , item - - if RocketChat.callbacks.showTotalTime is true - if Meteor.isServer - RocketChat.statsTracker.timing('callbacks.totalTime', totalTime, ["hook:#{hook}"]); - else - console.log hook+':', totalTime - - return result - else - # else, just return the item unchanged - return item - -### -# Successively run all of a hook's callbacks on an item, in async mode (only works on server) -# @param {String} hook - The name of the hook -# @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks -# @param {Object} [constant] - An optional constant that will be passed along to each callback -### - -RocketChat.callbacks.runAsync = (hook, item, constant) -> - callbacks = RocketChat.callbacks[hook] - if Meteor.isServer and !!callbacks?.length - # use defer to avoid holding up client - Meteor.defer -> - # run all post submit server callbacks on post object successively - _.sortBy(callbacks, (callback) -> return callback.priority or RocketChat.callbacks.priority.MEDIUM).forEach (callback) -> - # console.log(callback.name); - callback item, constant - return - return - else - return item - return diff --git a/packages/rocketchat-lib/lib/callbacks.js b/packages/rocketchat-lib/lib/callbacks.js new file mode 100644 index 000000000000..511523f1e40b --- /dev/null +++ b/packages/rocketchat-lib/lib/callbacks.js @@ -0,0 +1,131 @@ +/* +* Callback hooks provide an easy way to add extra steps to common operations. +* @namespace RocketChat.callbacks +*/ + +RocketChat.callbacks = {}; + +if (Meteor.isServer) { + RocketChat.callbacks.showTime = true; + RocketChat.callbacks.showTotalTime = true; +} else { + RocketChat.callbacks.showTime = false; + RocketChat.callbacks.showTotalTime = false; +} + + +/* +* Callback priorities +*/ + +RocketChat.callbacks.priority = { + HIGH: -1000, + MEDIUM: 0, + LOW: 1000 +}; + + +/* +* Add a callback function to a hook +* @param {String} hook - The name of the hook +* @param {Function} callback - The callback function +*/ + +RocketChat.callbacks.add = function(hook, callback, priority, id) { + if (priority == null) { + priority = RocketChat.callbacks.priority.MEDIUM; + } + if (!_.isNumber(priority)) { + priority = RocketChat.callbacks.priority.MEDIUM; + } + callback.priority = priority; + callback.id = id || Random.id(); + RocketChat.callbacks[hook] = RocketChat.callbacks[hook] || []; + if (RocketChat.callbacks.showTime === true) { + const err = new Error; + callback.stack = err.stack; + } + if (RocketChat.callbacks[hook].find((cb) => cb.id === callback.id)) { + return; + } + RocketChat.callbacks[hook].push(callback); +}; + + +/* +* Remove a callback from a hook +* @param {string} hook - The name of the hook +* @param {string} id - The callback's id +*/ + +RocketChat.callbacks.remove = function(hookName, id) { + RocketChat.callbacks[hookName] = _.reject(RocketChat.callbacks[hookName], (callback) => callback.id === id); +}; + + +/* +* Successively run all of a hook's callbacks on an item +* @param {String} hook - The name of the hook +* @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks +* @param {Object} [constant] - An optional constant that will be passed along to each callback +* @returns {Object} Returns the item after it's been through all the callbacks for this hook +*/ + +RocketChat.callbacks.run = function(hook, item, constant) { + const callbacks = RocketChat.callbacks[hook]; + if (!callbacks && callbacks.length) { + let totalTime = 0; + const result = _.sortBy(callbacks, function(callback) { + return callback.priority || RocketChat.callbacks.priority.MEDIUM; + }).reduce(function(result, callback) { + let time = 0; + if (RocketChat.callbacks.showTime === true || RocketChat.callbacks.showTotalTime === true) { + time = Date.now(); + } + const callbackResult = callback(result, constant); + if (RocketChat.callbacks.showTime === true || RocketChat.callbacks.showTotalTime === true) { + const currentTime = Date.now() - time; + totalTime += currentTime; + if (RocketChat.callbacks.showTime === true) { + if (Meteor.isServer) { + RocketChat.statsTracker.timing('callbacks.time', currentTime, [`hook:${ hook }`, `callback:${ callback.id }`]); + } else { + let stack = callback.stack && typeof callback.stack.split === 'function' && callback.stack.split('\n'); + stack = stack && stack[2] && (stack[2].match(/\(.+\)/)||[])[0]; + console.log(String(currentTime), hook, callback.id, stack); + } + } + } + return (typeof callbackResult === 'undefined') ? result : callbackResult; + }, item); + if (RocketChat.callbacks.showTotalTime === true) { + if (Meteor.isServer) { + RocketChat.statsTracker.timing('callbacks.totalTime', totalTime, [`hook:${ hook }`]); + } else { + console.log(`${ hook }:`, totalTime); + } + } + return result; + } else { + return item; + } +}; + + +/* +* Successively run all of a hook's callbacks on an item, in async mode (only works on server) +* @param {String} hook - The name of the hook +* @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks +* @param {Object} [constant] - An optional constant that will be passed along to each callback +*/ + +RocketChat.callbacks.runAsync = function(hook, item, constant) { + const callbacks = RocketChat.callbacks[hook]; + if (Meteor.isServer && callbacks && callbacks.length) { + Meteor.defer(function() { + _.sortBy(callbacks, (callback) => callback.priority || RocketChat.callbacks.priority.MEDIUM).forEach((callback) => callback(item, constant)); + }); + } else { + return item; + } +}; diff --git a/packages/rocketchat-lib/lib/promises.coffee b/packages/rocketchat-lib/lib/promises.coffee deleted file mode 100644 index a23ab907b738..000000000000 --- a/packages/rocketchat-lib/lib/promises.coffee +++ /dev/null @@ -1,93 +0,0 @@ -# https://github.com/TelescopeJS/Telescope/blob/master/packages/telescope-lib/lib/callbacks.js - -### -# Callback hooks provide an easy way to add extra steps to common operations. -# @namespace RocketChat.promises -### -RocketChat.promises = {} - -### -# Callback priorities -### -RocketChat.promises.priority = - HIGH: -1000 - MEDIUM: 0 - LOW: 1000 - -### -# Add a callback function to a hook -# @param {String} hook - The name of the hook -# @param {Function} callback - The callback function -### - -RocketChat.promises.add = (hook, callback, priority, id) -> - # if callback array doesn't exist yet, initialize it - priority ?= RocketChat.promises.priority.MEDIUM - unless _.isNumber priority - priority = RocketChat.promises.priority.MEDIUM - callback.priority = priority - callback.id = id or Random.id() - RocketChat.promises[hook] ?= [] - - # Avoid adding the same callback twice - for cb in RocketChat.promises[hook] - if cb.id is callback.id - return - - RocketChat.promises[hook].push callback - return - -### -# Remove a callback from a hook -# @param {string} hook - The name of the hook -# @param {string} id - The callback's id -### - -RocketChat.promises.remove = (hookName, id) -> - RocketChat.promises[hookName] = _.reject RocketChat.promises[hookName], (callback) -> - callback.id is id - return - -### -# Successively run all of a hook's callbacks on an item -# @param {String} hook - The name of the hook -# @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks -# @param {Object} [constant] - An optional constant that will be passed along to each callback -# @returns {Object} Returns the item after it's been through all the callbacks for this hook -### - -RocketChat.promises.run = (hook, item, constant) -> - callbacks = RocketChat.promises[hook] - if !!callbacks?.length - # if the hook exists, and contains callbacks to run - callbacks = _.sortBy(callbacks, (callback) -> return callback.priority or RocketChat.promises.priority.MEDIUM) - return callbacks.reduce (previousPromise, callback) -> - return new Promise (resolve, reject) -> - previousPromise.then (result) -> - callback(result, constant).then(resolve, reject) - , Promise.resolve(item) - else - # else, just return the item unchanged - return Promise.resolve(item) - -### -# Successively run all of a hook's callbacks on an item, in async mode (only works on server) -# @param {String} hook - The name of the hook -# @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks -# @param {Object} [constant] - An optional constant that will be passed along to each callback -### - -RocketChat.promises.runAsync = (hook, item, constant) -> - callbacks = RocketChat.promises[hook] - if Meteor.isServer and !!callbacks?.length - # use defer to avoid holding up client - Meteor.defer -> - # run all post submit server callbacks on post object successively - _.sortBy(callbacks, (callback) -> return callback.priority or RocketChat.promises.priority.MEDIUM).forEach (callback) -> - # console.log(callback.name); - callback item, constant - return - return - else - return item - return diff --git a/packages/rocketchat-lib/lib/promises.js b/packages/rocketchat-lib/lib/promises.js new file mode 100644 index 000000000000..1e040f172bc5 --- /dev/null +++ b/packages/rocketchat-lib/lib/promises.js @@ -0,0 +1,89 @@ + +/* +* Callback hooks provide an easy way to add extra steps to common operations. +* @namespace RocketChat.promises +*/ + +RocketChat.promises = {}; + + +/* +* Callback priorities +*/ + +RocketChat.promises.priority = { + HIGH: -1000, + MEDIUM: 0, + LOW: 1000 +}; + + +/* +* Add a callback function to a hook +* @param {String} hook - The name of the hook +* @param {Function} callback - The callback function +*/ + +RocketChat.promises.add = function(hook, callback, p = RocketChat.promises.priority.MEDIUM, id) { + const priority = !_.isNumber(p) ? RocketChat.promises.priority.MEDIUM : p; + callback.priority = priority; + callback.id = id || Random.id(); + RocketChat.promises[hook] = RocketChat.promises[hook] || []; + if (RocketChat.promises[hook].find(cb => cb.id === callback.id)) { + return; + } + RocketChat.promises[hook].push(callback); +}; + + +/* +* Remove a callback from a hook +* @param {string} hook - The name of the hook +* @param {string} id - The callback's id +*/ + +RocketChat.promises.remove = function(hookName, id) { + RocketChat.promises[hookName] = _.reject(RocketChat.promises[hookName], (callback) => callback.id === id); +}; + + +/* +* Successively run all of a hook's callbacks on an item +* @param {String} hook - The name of the hook +* @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks +* @param {Object} [constant] - An optional constant that will be passed along to each callback +* @returns {Object} Returns the item after it's been through all the callbacks for this hook +*/ + +RocketChat.promises.run = function(hook, item, constant) { + let callbacks = RocketChat.promises[hook]; + if (callbacks == null || callbacks.length === 0) { + return Promise.resolve(item); + } + callbacks = _.sortBy(callbacks, (callback) => callback.priority || RocketChat.promises.priority.MEDIUM); + return callbacks.reduce(function(previousPromise, callback) { + return new Promise(function(resolve, reject) { + return previousPromise.then((result) => callback(result, constant).then(resolve, reject)); + }); + }, Promise.resolve(item)); +}; + + +/* +* Successively run all of a hook's callbacks on an item, in async mode (only works on server) +* @param {String} hook - The name of the hook +* @param {Object} item - The post, comment, modifier, etc. on which to run the callbacks +* @param {Object} [constant] - An optional constant that will be passed along to each callback +*/ + +RocketChat.promises.runAsync = function(hook, item, constant) { + const callbacks = RocketChat.promises[hook]; + if (!Meteor.isServer || callbacks == null || callbacks.length === 0) { + return item; + } + Meteor.defer(() => { + _.sortBy(callbacks, (callback) => callback.priority || RocketChat.promises.priority.MEDIUM).forEach(function(callback) { + callback(item, constant); + }); + }); +}; diff --git a/packages/rocketchat-lib/lib/roomTypesCommon.coffee b/packages/rocketchat-lib/lib/roomTypesCommon.coffee deleted file mode 100644 index a351dc258922..000000000000 --- a/packages/rocketchat-lib/lib/roomTypesCommon.coffee +++ /dev/null @@ -1,75 +0,0 @@ -class @roomTypesCommon - roomTypes: {} - roomTypesOrder: [] - mainOrder: 1 - - ### Adds a room type to app - @param identifier An identifier to the room type. If a real room, MUST BE the same of `db.rocketchat_room.t` field, if not, can be null - @param order Order number of the type - @param config - template: template name to render on sideNav - icon: icon class - route: - name: route name - action: route action function - ### - add: (identifier, order, config) -> - unless identifier? - identifier = Random.id() - - if @roomTypes[identifier]? - return false - - if not order? - order = @mainOrder + 10 - @mainOrder += 10 - - # @TODO validate config options - @roomTypesOrder.push - identifier: identifier - order: order - @roomTypes[identifier] = config - - if config.route?.path? and config.route?.name? and config.route?.action? - routeConfig = - name: config.route.name - action: config.route.action - - if Meteor.isClient - routeConfig.triggersExit = [ roomExit ] - - FlowRouter.route config.route.path, routeConfig - - hasCustomLink: (roomType) -> - return @roomTypes[roomType]?.route?.link? - - ### - @param roomType: room type (e.g.: c (for channels), d (for direct channels)) - @param subData: the user's subscription data - ### - getRouteLink: (roomType, subData) -> - unless @roomTypes[roomType]? - return false - - routeData = {} - - if @roomTypes[roomType]?.route?.link? - routeData = @roomTypes[roomType].route.link(subData) - else if subData?.name? - routeData = { name: subData.name } - - return FlowRouter.path @roomTypes[roomType].route.name, routeData - - openRouteLink: (roomType, subData, queryParams) -> - unless @roomTypes[roomType]? - return false - - routeData = {} - - if @roomTypes[roomType]?.route?.link? - routeData = @roomTypes[roomType].route.link(subData) - else if subData?.name? - routeData = { name: subData.name } - - return FlowRouter.go @roomTypes[roomType].route.name, routeData, queryParams - diff --git a/packages/rocketchat-lib/lib/roomTypesCommon.js b/packages/rocketchat-lib/lib/roomTypesCommon.js new file mode 100644 index 000000000000..d7275875d8eb --- /dev/null +++ b/packages/rocketchat-lib/lib/roomTypesCommon.js @@ -0,0 +1,83 @@ +/* globals roomExit*/ +this.roomTypesCommon = class { + constructor() { + this.roomTypes = {}; + this.roomTypesOrder = []; + this.mainOrder = 1; + } + + /* Adds a room type to app + @param identifier An identifier to the room type. If a real room, MUST BE the same of `db.rocketchat_room.t` field, if not, can be null + @param order Order number of the type + @param config + template: template name to render on sideNav + icon: icon class + route: + name: route name + action: route action function + */ + + add(identifier = Random.id(), order, config) { + if (this.roomTypes[identifier] != null) { + return false; + } + if (order == null) { + order = this.mainOrder + 10; + this.mainOrder += 10; + } + this.roomTypesOrder.push({ + identifier, + order + }); + this.roomTypes[identifier] = config; + if (config.route && config.route.path && config.route.name && config.route.action) { + const routeConfig = { + name: config.route.name, + action: config.route.action + }; + if (Meteor.isClient) { + routeConfig.triggersExit = [roomExit]; + } + return FlowRouter.route(config.route.path, routeConfig); + } + } + + hasCustomLink(roomType) { + return this.roomTypes[roomType] && this.roomTypes[roomType].route && this.roomTypes[roomType].route.link != null; + } + + /* + @param roomType: room type (e.g.: c (for channels), d (for direct channels)) + @param subData: the user's subscription data + */ + + getRouteLink(roomType, subData) { + if (this.roomTypes[roomType] == null) { + return false; + } + let routeData = {}; + if (this.roomTypes[roomType] && this.roomTypes[roomType].route && this.roomTypes[roomType].route.link) { + routeData = this.roomTypes[roomType].route.link(subData); + } else if (subData && subData.name) { + routeData = { + name: subData.name + }; + } + return FlowRouter.path(this.roomTypes[roomType].route.name, routeData); + } + + openRouteLink(roomType, subData, queryParams) { + if (this.roomTypes[roomType] == null) { + return false; + } + let routeData = {}; + if (this.roomTypes[roomType] && this.roomTypes[roomType].route && this.roomTypes[roomType].route.link) { + routeData = this.roomTypes[roomType].route.link(subData); + } else if (subData && subData.name) { + routeData = { + name: subData.name + }; + } + return FlowRouter.go(this.roomTypes[roomType].route.name, routeData, queryParams); + } +}; diff --git a/packages/rocketchat-lib/lib/settings.coffee b/packages/rocketchat-lib/lib/settings.coffee deleted file mode 100644 index cdc221064b39..000000000000 --- a/packages/rocketchat-lib/lib/settings.coffee +++ /dev/null @@ -1,83 +0,0 @@ -### -# RocketChat.settings holds all packages settings -# @namespace RocketChat.settings -### -RocketChat.settings = - callbacks: {} - regexCallbacks: {} - ts: new Date - - get: (_id, callback) -> - if callback? - RocketChat.settings.onload _id, callback - if _id is '*' and Meteor.settings? - for key, value of Meteor.settings - callback key, value - return - - if _.isRegExp(_id) - for key, value of Meteor.settings when _id.test(key) - callback key, value - return - - if Meteor.settings?[_id]? - callback _id, Meteor.settings?[_id] - else - if _.isRegExp(_id) - items = [] - for key, value of Meteor.settings when _id.test(key) - items.push - key: key - value: value - return items - - return Meteor.settings?[_id] - - set: (_id, value, callback) -> - Meteor.call 'saveSetting', _id, value, callback - - batchSet: (settings, callback) -> - - # async -> sync - # http://daemon.co.za/2012/04/simple-async-with-only-underscore/ - - save = (setting) -> - return (callback) -> - Meteor.call 'saveSetting', setting._id, setting.value, setting.editor, callback - - actions = _.map settings, (setting) -> save(setting) - _(actions).reduceRight(_.wrap, (err, success) -> return callback err, success)() - - load: (key, value, initialLoad) -> - if RocketChat.settings.callbacks[key]? - for callback in RocketChat.settings.callbacks[key] - callback key, value, initialLoad - - if RocketChat.settings.callbacks['*']? - for callback in RocketChat.settings.callbacks['*'] - callback key, value, initialLoad - - for cbKey, cbValue of RocketChat.settings.regexCallbacks - if cbValue.regex.test(key) - callback(key, value, initialLoad) for callback in cbValue.callbacks - - - onload: (key, callback) -> - # if key is '*' - # for key, value in Meteor.settings - # callback key, value, false - # else if Meteor.settings?[_id]? - # callback key, Meteor.settings[_id], false - - keys = [].concat key - - for k in keys - if _.isRegExp k - RocketChat.settings.regexCallbacks[k.source] ?= { - regex: k - callbacks: [] - } - RocketChat.settings.regexCallbacks[k.source].callbacks.push callback - else - RocketChat.settings.callbacks[k] ?= [] - RocketChat.settings.callbacks[k].push callback diff --git a/packages/rocketchat-lib/lib/settings.js b/packages/rocketchat-lib/lib/settings.js new file mode 100644 index 000000000000..2e5bb09eba08 --- /dev/null +++ b/packages/rocketchat-lib/lib/settings.js @@ -0,0 +1,102 @@ + +/* +* RocketChat.settings holds all packages settings +* @namespace RocketChat.settings +*/ +RocketChat.settings = { + callbacks: {}, + regexCallbacks: {}, + ts: new Date, + get(_id, callback) { + if (callback != null) { + RocketChat.settings.onload(_id, callback); + if (!Meteor.settings) { + return; + } + if (_id === '*') { + return Object.keys(Meteor.settings).forEach(key => { + const value = Meteor.settings[key]; + callback(key, value); + }); + } + if (_.isRegExp(_id) && Meteor.settings) { + return Object.keys(Meteor.settings).forEach(key => { + if (!_id.test(key)) { + return; + } + const value = Meteor.settings[key]; + callback(key, value); + }); + } + return Meteor.settings[_id] && callback(_id, Meteor.settings[_id]); + } else { + if (!Meteor.settings) { + return; + } + if (_.isRegExp(_id)) { + return Object.keys(Meteor.settings).reduce((items, key) => { + const value = Meteor.settings[key]; + if (_id.test(key)) { + items.push({ + key, + value + }); + } + return items; + }, []); + } + return Meteor.settings && Meteor.settings[_id]; + } + }, + set(_id, value, callback) { + return Meteor.call('saveSetting', _id, value, callback); + }, + batchSet(settings, callback) { + // async -> sync + // http://daemon.co.za/2012/04/simple-async-with-only-underscore/ + const save = function(setting) { + return function(callback) { + return Meteor.call('saveSetting', setting._id, setting.value, setting.editor, callback); + }; + }; + const actions = _.map(settings, (setting) => save(setting)); + return _(actions).reduceRight(_.wrap, (err, success) => callback(err, success))(); + }, + load(key, value, initialLoad) { + Object.keys({ + '*': 1, + [key]: 1 + }).forEach(key => { + if (RocketChat.settings.callbacks[key]) { + RocketChat.settings.callbacks[key].forEach(callback => callback(key, value, initialLoad)); + } + }); + Object.keys(RocketChat.settings.regexCallbacks).forEach(cbKey => { + const cbValue = RocketChat.settings.regexCallbacks[cbKey]; + if (!cbValue.regex.test(key)) { + return; + } + cbValue.callbacks.forEach(callback => callback(key, value, initialLoad)); + }); + }, + onload(key, callback) { + // if key is '*' + // for key, value in Meteor.settings + // callback key, value, false + // else if Meteor.settings?[_id]? + // callback key, Meteor.settings[_id], false + const keys = [].concat(key); + keys.forEach(k => { + if (_.isRegExp(k)) { + RocketChat.settings.regexCallbacks[name = k.source] = RocketChat.settings.regexCallbacks[name = k.source] || { + regex: k, + callbacks: [] + }; + RocketChat.settings.regexCallbacks[k.source].callbacks.push(callback); + } else { + RocketChat.settings.callbacks[k] = RocketChat.settings.callbacks[k] || []; + RocketChat.settings.callbacks[k].push(callback); + } + }); + } +}; diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 8aea1663f7bb..c7b8e96eab93 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -52,13 +52,13 @@ Package.onUse(function(api) { // COMMON LIB api.addFiles('lib/getURL.js'); - api.addFiles('lib/settings.coffee'); + api.addFiles('lib/settings.js'); api.addFiles('lib/configLogger.js'); - api.addFiles('lib/callbacks.coffee'); + api.addFiles('lib/callbacks.js'); api.addFiles('lib/fileUploadRestrictions.js'); api.addFiles('lib/placeholders.js'); - api.addFiles('lib/promises.coffee'); - api.addFiles('lib/roomTypesCommon.coffee'); + api.addFiles('lib/promises.js'); + api.addFiles('lib/roomTypesCommon.js'); api.addFiles('lib/slashCommand.js'); api.addFiles('lib/Message.js'); api.addFiles('lib/MessageTypes.js'); @@ -178,10 +178,10 @@ Package.onUse(function(api) { api.addFiles('client/lib/TabBar.js', 'client'); api.addFiles('client/lib/RocketChatTabBar.js', 'client'); api.addFiles('client/lib/cachedCollection.js', 'client'); - api.addFiles('client/lib/openRoom.coffee', 'client'); + api.addFiles('client/lib/openRoom.js', 'client'); api.addFiles('client/lib/roomExit.js', 'client'); api.addFiles('client/lib/settings.js', 'client'); - api.addFiles('client/lib/roomTypes.coffee', 'client'); + api.addFiles('client/lib/roomTypes.js', 'client'); api.addFiles('client/lib/userRoles.js', 'client'); api.addFiles('client/lib/Layout.js', 'client'); From 888a08da9c01d6e633e093cc2cb97bf41b25202a Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 27 Apr 2017 18:00:55 -0300 Subject: [PATCH 3/3] fix review --- .../rocketchat-lib/client/lib/roomTypes.js | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/rocketchat-lib/client/lib/roomTypes.js b/packages/rocketchat-lib/client/lib/roomTypes.js index bb634e222ca2..9cfc41585961 100644 --- a/packages/rocketchat-lib/client/lib/roomTypes.js +++ b/packages/rocketchat-lib/client/lib/roomTypes.js @@ -2,7 +2,7 @@ import roomTypesCommon from '../../lib/roomTypesCommon'; RocketChat.roomTypes = new class extends roomTypesCommon { checkCondition(roomType) { - return (roomType.condition == null) || roomType.condition(); + return roomType.condition == null || roomType.condition(); } getTypes() { return _.sortBy(this.roomTypesOrder, 'order').map((type) => this.roomTypes[type.identifier]); @@ -71,15 +71,9 @@ RocketChat.roomTypes = new class extends roomTypesCommon { return room && room.archived === true; } verifyCanSendMessage(roomId) { - const room = ChatRoom.findOne({ - _id: roomId - }, { - fields: { - t: 1 - } - }); + const room = ChatRoom.findOne({ _id: roomId }, { fields: { t: 1 }}); - if (room && !room.t) { + if (!room || !room.t) { return; } @@ -97,7 +91,7 @@ RocketChat.roomTypes = new class extends roomTypesCommon { t: 1 } }); - if (room && !room.t) { + if (!room || !room.t) { return; } const roomType = room.t; @@ -107,14 +101,8 @@ RocketChat.roomTypes = new class extends roomTypesCommon { return this.roomTypes[roomType].showJoinLink(roomId); } getNotSubscribedTpl(roomId) { - const room = ChatRoom.findOne({ - _id: roomId - }, { - fields: { - t: 1 - } - }); - if (room && !room.t) { + const room = ChatRoom.findOne({ _id: roomId }, { fields: { t: 1 }}); + if (!room || !room.t) { return; } const roomType = room.t;