parent
6640cfd9bb
commit
b4f36de2e1
@ -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 |
@ -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; |
@ -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 |
@ -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; |
||||
} |
||||
|
||||
}; |
@ -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 |
@ -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; |
||||
} |
||||
}; |
@ -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 |
@ -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); |
||||
}); |
||||
}); |
||||
}; |
@ -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 |
||||
|
@ -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); |
||||
} |
||||
}; |
@ -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 |
@ -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); |
||||
} |
||||
}); |
||||
} |
||||
}; |
Loading…
Reference in new issue