From 2678365dfeab99f8bde4dbc1a2cb7d12e7a20aa0 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Tue, 15 Aug 2017 19:10:33 -0500 Subject: [PATCH 01/42] Rocketlets: Initial structure for the rocketlets package inside of Rocket.Chat. --- .eslintrc | 1 + .meteor/packages | 1 + .meteor/versions | 1 + packages/rocketchat-api/package.js | 1 + packages/rocketchat-api/server/api.js | 6 +- packages/rocketchat-api/server/v1/commands.js | 85 +++++++++++++++++++ packages/rocketchat-lib/lib/slashCommand.js | 1 + packages/rocketchat-rocketlets/.gitignore | 1 + .../client/communication/websockets.js | 12 +++ .../rocketchat-rocketlets/lib/Rocketlets.js | 2 + packages/rocketchat-rocketlets/package.js | 41 +++++++++ .../server/bridges/commands.js | 84 ++++++++++++++++++ .../server/bridges/index.js | 3 + .../server/communication/index.js | 5 ++ .../server/communication/rest.js | 8 ++ .../server/communication/websockets.js | 16 ++++ .../server/converters/index.js | 9 ++ .../server/converters/messages.js | 21 +++++ .../server/converters/rooms.js | 13 +++ .../server/converters/users.js | 13 +++ .../server/models/Rocketlets.js | 5 ++ .../server/orchestrator.js | 42 +++++++++ .../server.js | 5 +- .../rocketchat-slashcommands-create/server.js | 5 +- .../rocketchat-slashcommands-help/server.js | 2 + .../rocketchat-slashcommands-invite/server.js | 7 +- .../server.js | 10 ++- .../rocketchat-slashcommands-join/server.js | 3 + .../rocketchat-slashcommands-kick/server.js | 5 +- .../rocketchat-slashcommands-leave/leave.js | 15 +--- 30 files changed, 403 insertions(+), 20 deletions(-) create mode 100644 packages/rocketchat-api/server/v1/commands.js create mode 100644 packages/rocketchat-rocketlets/.gitignore create mode 100644 packages/rocketchat-rocketlets/client/communication/websockets.js create mode 100644 packages/rocketchat-rocketlets/lib/Rocketlets.js create mode 100644 packages/rocketchat-rocketlets/package.js create mode 100644 packages/rocketchat-rocketlets/server/bridges/commands.js create mode 100644 packages/rocketchat-rocketlets/server/bridges/index.js create mode 100644 packages/rocketchat-rocketlets/server/communication/index.js create mode 100644 packages/rocketchat-rocketlets/server/communication/rest.js create mode 100644 packages/rocketchat-rocketlets/server/communication/websockets.js create mode 100644 packages/rocketchat-rocketlets/server/converters/index.js create mode 100644 packages/rocketchat-rocketlets/server/converters/messages.js create mode 100644 packages/rocketchat-rocketlets/server/converters/rooms.js create mode 100644 packages/rocketchat-rocketlets/server/converters/users.js create mode 100644 packages/rocketchat-rocketlets/server/models/Rocketlets.js create mode 100644 packages/rocketchat-rocketlets/server/orchestrator.js diff --git a/.eslintrc b/.eslintrc index 6e652c53b845..df4bec84696c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -133,6 +133,7 @@ "ReactiveVar" : false, "RocketChat" : true, "RocketChatFile" : false, + "Rocketlets" : false, "RoomHistoryManager" : false, "RoomManager" : false, "s" : false, diff --git a/.meteor/packages b/.meteor/packages index 16aacf8c6ca3..cc549ff64a58 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -93,6 +93,7 @@ rocketchat:oembed rocketchat:otr rocketchat:push-notifications rocketchat:reactions +rocketchat:rocketlets rocketchat:sandstorm rocketchat:slackbridge rocketchat:slashcommands-archive diff --git a/.meteor/versions b/.meteor/versions index 08ec0c6b51f0..76740ca513da 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -185,6 +185,7 @@ rocketchat:otr@0.0.1 rocketchat:postcss@1.0.0 rocketchat:push-notifications@0.0.1 rocketchat:reactions@0.0.1 +rocketchat:rocketlets@1.0.0 rocketchat:sandstorm@0.0.1 rocketchat:slackbridge@0.0.1 rocketchat:slashcommands-archive@0.0.1 diff --git a/packages/rocketchat-api/package.js b/packages/rocketchat-api/package.js index 16d34b948044..9068cdeac457 100644 --- a/packages/rocketchat-api/package.js +++ b/packages/rocketchat-api/package.js @@ -34,6 +34,7 @@ Package.onUse(function(api) { //Add v1 routes api.addFiles('server/v1/channels.js', 'server'); api.addFiles('server/v1/chat.js', 'server'); + api.addFiles('server/v1/commands.js', 'server'); api.addFiles('server/v1/groups.js', 'server'); api.addFiles('server/v1/im.js', 'server'); api.addFiles('server/v1/integrations.js', 'server'); diff --git a/packages/rocketchat-api/server/api.js b/packages/rocketchat-api/server/api.js index a8ee3da879d6..033e3d679861 100644 --- a/packages/rocketchat-api/server/api.js +++ b/packages/rocketchat-api/server/api.js @@ -125,7 +125,6 @@ class API extends Restivus { } } -RocketChat.API = {}; const getUserAuth = function _getUserAuth() { const invalidResults = [undefined, null, false]; @@ -160,6 +159,11 @@ const getUserAuth = function _getUserAuth() { }; }; +RocketChat.API = { + getUserAuth, + ApiClass: API +}; + RocketChat.API.v1 = new API({ version: 'v1', useDefaultAuth: true, diff --git a/packages/rocketchat-api/server/v1/commands.js b/packages/rocketchat-api/server/v1/commands.js new file mode 100644 index 000000000000..eeda89444260 --- /dev/null +++ b/packages/rocketchat-api/server/v1/commands.js @@ -0,0 +1,85 @@ +RocketChat.API.v1.addRoute('commands.getOne', { authRequired: true }, { + get() { + const params = this.queryParams; + + if (typeof params.command !== 'string') { + return RocketChat.API.v1.failure('The query param "command" must be provided.'); + } + + const cmd = RocketChat.slashCommands.commands[params.command.toLowerCase()]; + + if (!cmd) { + return RocketChat.API.v1.failure(`There is no command in the system by the name of: ${ params.command }`); + } + + return RocketChat.API.v1.success({ command: cmd }); + } +}); + +RocketChat.API.v1.addRoute('commands.list', { authRequired: true }, { + get() { + const { offset, count } = this.getPaginationItems(); + const { sort, fields, query } = this.parseJsonQuery(); + + let commands = Object.values(RocketChat.slashCommands.commands); + + if (query.command) { + commands = commands.filter((command) => command.command === query.command); + } + + const totalCount = commands.length; + commands = RocketChat.models.Rooms.processQueryOptionsOnResult(commands, { + sort: sort ? sort : { name: 1 }, + skip: offset, + limit: count, + fields: Object.assign({}, fields, RocketChat.API.v1.defaultFieldsToExclude) + }); + + return RocketChat.API.v1.success({ + commands, + offset, + count: commands.length, + total: totalCount + }); + } +}); + +// Expects a body of: { command: 'gimme', params: 'any string value', roomId: 'value' } +RocketChat.API.v1.addRoute('commands.run', { authRequired: true }, { + post() { + const body = this.bodyParams; + const user = this.getLoggedInUser(); + + if (typeof body.command !== 'string') { + return RocketChat.API.v1.failure('You must provide a command to run.'); + } + + if (body.params && typeof body.params !== 'string') { + return RocketChat.API.v1.failure('The parameters for the command must be a single string.'); + } + const params = body.params ? body.params : ''; + + if (typeof body.roomId !== 'string') { + return RocketChat.API.v1.failure('The room\'s id where to execute this command must provided and be a string.'); + } + + const cmd = body.command.toLowerCase(); + if (!RocketChat.slashCommands.commands[body.command.toLowerCase()]) { + return RocketChat.API.v1.failure('The command provided does not exist (or is disabled).'); + } + + // This will throw an error if they can't or the room is invalid + Meteor.call('canAccessRoom', body.roomId, user._id); + + let result; + Meteor.runAsUser(user._id, () => { + result = RocketChat.slashCommands.run(cmd, params, { + _id: Random.id(), + rid: body.roomId, + msg: `/${ cmd } ${ params }` + }); + }); + + return RocketChat.API.v1.success({ result }); + } +}); diff --git a/packages/rocketchat-lib/lib/slashCommand.js b/packages/rocketchat-lib/lib/slashCommand.js index 0a07065a15dc..7f37a7933adc 100644 --- a/packages/rocketchat-lib/lib/slashCommand.js +++ b/packages/rocketchat-lib/lib/slashCommand.js @@ -26,6 +26,7 @@ Meteor.methods({ method: 'slashCommand' }); } + return RocketChat.slashCommands.run(command.cmd, command.params, command.msg); } }); diff --git a/packages/rocketchat-rocketlets/.gitignore b/packages/rocketchat-rocketlets/.gitignore new file mode 100644 index 000000000000..918ef5d781a1 --- /dev/null +++ b/packages/rocketchat-rocketlets/.gitignore @@ -0,0 +1 @@ +.npm diff --git a/packages/rocketchat-rocketlets/client/communication/websockets.js b/packages/rocketchat-rocketlets/client/communication/websockets.js new file mode 100644 index 000000000000..2a783649a3b6 --- /dev/null +++ b/packages/rocketchat-rocketlets/client/communication/websockets.js @@ -0,0 +1,12 @@ +export class RocketletWebsocketReceiver { + constructor(restApi) { + this.rest = restApi; + this.streamer = new Meteor.Streamer('rocketlets'); + + this.streamer.on('command/added', this.onCommandAdded); + } + + onCommandAdded(command) { + console.log('Added:', command); + } +} diff --git a/packages/rocketchat-rocketlets/lib/Rocketlets.js b/packages/rocketchat-rocketlets/lib/Rocketlets.js new file mode 100644 index 000000000000..44fa4fc44330 --- /dev/null +++ b/packages/rocketchat-rocketlets/lib/Rocketlets.js @@ -0,0 +1,2 @@ +// Please see both server and client's repsective "orchestrator" file for the contents +Rocketlets = {}; diff --git a/packages/rocketchat-rocketlets/package.js b/packages/rocketchat-rocketlets/package.js new file mode 100644 index 000000000000..127b469b9e53 --- /dev/null +++ b/packages/rocketchat-rocketlets/package.js @@ -0,0 +1,41 @@ +Package.describe({ + name: 'rocketchat:rocketlets', + version: '1.0.0' +}); + +Package.onUse(function(api) { + api.use([ + 'ecmascript', + 'rocketchat:lib', + 'rocketchat:api' + ]); + + api.addFiles('lib/Rocketlets.js', ['client', 'server']); + + api.addFiles('server/orchestrator.js', 'server'); + + api.addFiles('server/models/Rocketlets.js', 'server'); + + // Bridges + api.addFiles([ + 'server/bridges/commands.js' + ], 'server'); + + // Communication pieces + api.addFiles([ + 'server/communication/rest.js', + 'server/communication/websockets.js' + ], 'server'); + + // Client communication pieces + api.addFiles([ + 'client/communication/websockets.js' + ], 'client'); + + api.export('Rocketlets'); +}); + +Npm.depends({ + 'temporary-rocketlets-server': '0.1.11', + 'temporary-rocketlets-ts-definition': '0.6.2' +}); diff --git a/packages/rocketchat-rocketlets/server/bridges/commands.js b/packages/rocketchat-rocketlets/server/bridges/commands.js new file mode 100644 index 000000000000..99169f96c5f2 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/bridges/commands.js @@ -0,0 +1,84 @@ +export class RocketletCommandsBridge { + constructor(converters) { + console.log('CommandsBridge constructor'); + this.converters = converters; + this.disabledCommands = new Map(); + } + + doesCommandExist(command, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is check if "${ command }" command exists.`); + + if (typeof command !== 'string') { + return false; + } + + return typeof RocketChat.slashCommands.commands[command.toLowerCase()] === 'object'; + } + + disableCommand(command, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is attempting to disable the command: "${ command }"`); + + if (typeof command !== 'string' || command.trim().length === 0) { + throw new Error('Invalid command parameter provided, must be a string.'); + } + + const cmd = command.toLowerCase(); + if (typeof RocketChat.slashCommands.commands[cmd] === 'undefined') { + throw new Error(`Command does not exist in the system currently (or it is disabled): ${ cmd }`); + } + + this.disabledCommands.set(cmd, RocketChat.slashCommands.commands[cmd]); + delete RocketChat.slashCommands.commands[cmd]; + + Rocketlets.getNotifier().commandDisabled(cmd); + } + + // command: { command, paramsExample, i18nDescription, executor: function } + modifyCommand(command, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is attempting to modify the command: "${ command }"`); + + this._verifyCommand(command); + + const cmd = command.toLowerCase(); + if (typeof RocketChat.slashCommands.commands[cmd] === 'undefined') { + throw new Error(`Command does not exist in the system currently (or it is disabled): ${ cmd }`); + } + + const item = RocketChat.slashCommands.commands[cmd]; + item.params = command.paramsExample ? command.paramsExample : item.params; + item.description = command.i18nDescription ? command.i18nDescription : item.params; + item.callback = this._executorWrapper(command.executor); + + } + + _verifyCommand(command) { + if (typeof command !== 'object') { + throw new Error('Invalid Slash Command parameter provided, it must be a valid ISlashCommand object.'); + } + + if (typeof command.command !== 'string') { + throw new Error('Invalid Slash Command parameter provided, it must be a valid ISlashCommand object.'); + } + + if (command.paramsExample && typeof command.paramsExample !== 'string') { + throw new Error('Invalid Slash Command parameter provided, it must be a valid ISlashCommand object.'); + } + + if (command.i18nDescription && typeof command.i18nDescription !== 'string') { + throw new Error('Invalid Slash Command parameter provided, it must be a valid ISlashCommand object.'); + } + + if (typeof command.executor !== 'function') { + throw new Error('Invalid Slash Command parameter provided, it must be a valid ISlashCommand object.'); + } + } + + _executorWrapper(executor) { + return function _wrappedExecutor(command, params, message) { + // TODO: Converters + this.converters.get('messages').translate(message); + + executor(command); + }; + } +} diff --git a/packages/rocketchat-rocketlets/server/bridges/index.js b/packages/rocketchat-rocketlets/server/bridges/index.js new file mode 100644 index 000000000000..82cad72f3770 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/bridges/index.js @@ -0,0 +1,3 @@ +import { RocketletCommandsBridge } from './commands'; + +export { RocketletCommandsBridge }; diff --git a/packages/rocketchat-rocketlets/server/communication/index.js b/packages/rocketchat-rocketlets/server/communication/index.js new file mode 100644 index 000000000000..8781d1737c41 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/communication/index.js @@ -0,0 +1,5 @@ +import { RocketletWebsocketNotifier } from './websockets'; + +export { + RocketletWebsocketNotifier +}; diff --git a/packages/rocketchat-rocketlets/server/communication/rest.js b/packages/rocketchat-rocketlets/server/communication/rest.js new file mode 100644 index 000000000000..c463e1e60c7a --- /dev/null +++ b/packages/rocketchat-rocketlets/server/communication/rest.js @@ -0,0 +1,8 @@ +/* Rocketlets.API = new RocketChat.API.ApiClass({ + version: 'rocketlets', + useDefaultAuth: true, + prettyJson: true, + enableCors: false, + auth: RocketChat.API.getUserAuth() +}); +*/ diff --git a/packages/rocketchat-rocketlets/server/communication/websockets.js b/packages/rocketchat-rocketlets/server/communication/websockets.js new file mode 100644 index 000000000000..8fda659d65c8 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/communication/websockets.js @@ -0,0 +1,16 @@ +export class RocketletWebsocketNotifier { + constructor() { + this.streamer = new Meteor.Streamer('rocketlets', { retransmit: false }); + this.streamer.allowRead('all'); + this.streamer.allowEmit('all'); + this.streamer.allowWrite('none'); + } + + commandAdded(command) { + this.streamer.emit('command/added', command); + } + + commandDisabled(command) { + this.streamer.emit('command/disabled', command); + } +} diff --git a/packages/rocketchat-rocketlets/server/converters/index.js b/packages/rocketchat-rocketlets/server/converters/index.js new file mode 100644 index 000000000000..2a402be1b351 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/converters/index.js @@ -0,0 +1,9 @@ +import { RocketletMessagesConverter } from './messages'; +import { RocketletRoomsConverter } from './rooms'; +import { RocketletUsersConverter } from './users'; + +export { + RocketletMessagesConverter, + RocketletRoomsConverter, + RocketletUsersConverter +}; diff --git a/packages/rocketchat-rocketlets/server/converters/messages.js b/packages/rocketchat-rocketlets/server/converters/messages.js new file mode 100644 index 000000000000..80a745a0ea74 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/converters/messages.js @@ -0,0 +1,21 @@ +export class RocketletMessagesConverter { + constructor(converters) { + this.converters = converters; + } + + convertById(msgId) { + const msg = RocketChat.models.Messages.getOneById(msgId); + + return { + id: msg._id, + text: msg.msg + }; + } + + convertMessage(msgObj) { + return { + id: msgObj._id, + text: msgObj.msg + }; + } +} diff --git a/packages/rocketchat-rocketlets/server/converters/rooms.js b/packages/rocketchat-rocketlets/server/converters/rooms.js new file mode 100644 index 000000000000..23481dda5ef1 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/converters/rooms.js @@ -0,0 +1,13 @@ +export class RocketletRoomsConverter { + constructor(converters) { + this.converters = converters; + } + + convertById(roomId) { + const room = RocketChat.models.Rooms.findOneById(roomId); + + return { + id: room._id + }; + } +} diff --git a/packages/rocketchat-rocketlets/server/converters/users.js b/packages/rocketchat-rocketlets/server/converters/users.js new file mode 100644 index 000000000000..0eea353ffb95 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/converters/users.js @@ -0,0 +1,13 @@ +export class RocketletUsersConverter { + constructor(converters) { + this.converters = converters; + } + + convertById(userId) { + const user = RocketChat.models.Users.findOneById(userId); + + return { + id: user._id + }; + } +} diff --git a/packages/rocketchat-rocketlets/server/models/Rocketlets.js b/packages/rocketchat-rocketlets/server/models/Rocketlets.js new file mode 100644 index 000000000000..a4e4a89eb4e1 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/models/Rocketlets.js @@ -0,0 +1,5 @@ +export class RocketletsModel extends RocketChat.models._Base { + constructor() { + super('rocketlets'); + } +} diff --git a/packages/rocketchat-rocketlets/server/orchestrator.js b/packages/rocketchat-rocketlets/server/orchestrator.js new file mode 100644 index 000000000000..2f030bbfd347 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/orchestrator.js @@ -0,0 +1,42 @@ +import { RocketletCommandsBridge } from './bridges'; +import { RocketletWebsocketNotifier } from './communication'; +import { RocketletMessagesConverter, RocketletRoomsConverter } from './converters'; +import { RocketletsModel } from './models/Rocketlets'; + +class RocketletServerOrchestrator { + constructor() { + this._model = new RocketletsModel(); + + this._converters = new Map(); + this._converters.set('messages', new RocketletMessagesConverter(this._converters)); + this._converters.set('rooms', new RocketletRoomsConverter(this._converters)); + + this._bridges = new Map(); + this._bridges.set('commands', new RocketletCommandsBridge(this._converters)); + + this._communicators = new Map(); + this._communicators.set('notifier', new RocketletWebsocketNotifier()); + } + + getModel() { + return this._model; + } + + getConverters() { + return this._converters; + } + + getBridges() { + return this._bridges; + } + + getNotifier() { + return this._communicators.get('notifier'); + } +} + +Meteor.startup(function _rocketletServerOrchestrator() { + console.log('Orchestrating the rocketlet piece...'); + Rocketlets = new RocketletServerOrchestrator(); + console.log('...done! :)'); +}); diff --git a/packages/rocketchat-slashcommands-archiveroom/server.js b/packages/rocketchat-slashcommands-archiveroom/server.js index 3d382cc25cb7..b8d54600bb2a 100644 --- a/packages/rocketchat-slashcommands-archiveroom/server.js +++ b/packages/rocketchat-slashcommands-archiveroom/server.js @@ -49,4 +49,7 @@ function Archive(command, params, item) { return Archive; } -RocketChat.slashCommands.add('archive', Archive); +RocketChat.slashCommands.add('archive', Archive, { + description: 'Archive', + params: '#channel' +}); diff --git a/packages/rocketchat-slashcommands-create/server.js b/packages/rocketchat-slashcommands-create/server.js index a64262065c95..3a33fa5c5443 100644 --- a/packages/rocketchat-slashcommands-create/server.js +++ b/packages/rocketchat-slashcommands-create/server.js @@ -45,4 +45,7 @@ function Create(command, params, item) { Meteor.call('createChannel', channel, []); } -RocketChat.slashCommands.add('create', Create); +RocketChat.slashCommands.add('create', Create, { + description: 'Create_A_New_Channel', + params: '#channel' +}); diff --git a/packages/rocketchat-slashcommands-help/server.js b/packages/rocketchat-slashcommands-help/server.js index ff7e61af5d00..f8aefcd869cb 100644 --- a/packages/rocketchat-slashcommands-help/server.js +++ b/packages/rocketchat-slashcommands-help/server.js @@ -45,4 +45,6 @@ RocketChat.slashCommands.add('help', function Help(command, params, item) { }); }); +}, { + description: 'Show_the_keyboard_shortcut_list' }); diff --git a/packages/rocketchat-slashcommands-invite/server.js b/packages/rocketchat-slashcommands-invite/server.js index a379762496fd..2dcd6923c5d2 100644 --- a/packages/rocketchat-slashcommands-invite/server.js +++ b/packages/rocketchat-slashcommands-invite/server.js @@ -77,6 +77,7 @@ function Invite(command, params, item) { }); } -RocketChat.slashCommands.add('invite', Invite); - -export {Invite}; +RocketChat.slashCommands.add('invite', Invite, { + description: 'Invite_user_to_join_channel', + params: '@username' +}); diff --git a/packages/rocketchat-slashcommands-inviteall/server.js b/packages/rocketchat-slashcommands-inviteall/server.js index 4d32c55697ad..a80cc3b04d08 100644 --- a/packages/rocketchat-slashcommands-inviteall/server.js +++ b/packages/rocketchat-slashcommands-inviteall/server.js @@ -76,6 +76,12 @@ function inviteAll(type) { } }; } -RocketChat.slashCommands.add('invite-all-to', inviteAll('to')); -RocketChat.slashCommands.add('invite-all-from', inviteAll('from')); +RocketChat.slashCommands.add('invite-all-to', inviteAll('to'), { + description: 'Invite_user_to_join_channel_all_to', + params: '#room' +}); +RocketChat.slashCommands.add('invite-all-from', inviteAll('from'), { + description: 'Invite_user_to_join_channel_all_from', + params: '#room' +}); module.exports = inviteAll; diff --git a/packages/rocketchat-slashcommands-join/server.js b/packages/rocketchat-slashcommands-join/server.js index 65f2294ec6fe..1cabe1e1a307 100644 --- a/packages/rocketchat-slashcommands-join/server.js +++ b/packages/rocketchat-slashcommands-join/server.js @@ -34,4 +34,7 @@ RocketChat.slashCommands.add('join', function Join(command, params, item) { }); } Meteor.call('joinRoom', room._id); +}, { + description: 'Join_the_given_channel', + params: '#channel' }); diff --git a/packages/rocketchat-slashcommands-kick/server.js b/packages/rocketchat-slashcommands-kick/server.js index aec3a5118733..ff484022fe54 100644 --- a/packages/rocketchat-slashcommands-kick/server.js +++ b/packages/rocketchat-slashcommands-kick/server.js @@ -37,4 +37,7 @@ const Kick = function(command, params, {rid}) { Meteor.call('removeUserFromRoom', {rid, username}); }; -RocketChat.slashCommands.add('kick', Kick); +RocketChat.slashCommands.add('kick', Kick, { + description: 'Remove_someone_from_room', + params: '@username' +}); diff --git a/packages/rocketchat-slashcommands-leave/leave.js b/packages/rocketchat-slashcommands-leave/leave.js index c58dfdf4f3b8..a6dd74fa82e1 100644 --- a/packages/rocketchat-slashcommands-leave/leave.js +++ b/packages/rocketchat-slashcommands-leave/leave.js @@ -7,6 +7,7 @@ function Leave(command, params, item) { if (command !== 'leave' && command !== 'part') { return; } + try { Meteor.call('leaveRoom', item.rid); } catch ({error}) { @@ -18,14 +19,6 @@ function Leave(command, params, item) { }); } } -if (Meteor.isClient) { - RocketChat.slashCommands.add('leave', undefined, { - description: 'Leave_the_current_channel' - }); - RocketChat.slashCommands.add('part', undefined, { - description: 'Leave_the_current_channel' - }); -} else { - RocketChat.slashCommands.add('leave', Leave); - RocketChat.slashCommands.add('part', Leave); -} + +RocketChat.slashCommands.add('leave', Meteor.isClient ? undefined : Leave, { description: 'Leave_the_current_channel' }); +RocketChat.slashCommands.add('part', Meteor.isClient ? undefined : Leave, { description: 'Leave_the_current_channel' }); From a16d5eaf017a58f7a81b7a70e17339350a97da2a Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Tue, 22 Aug 2017 15:18:41 -0500 Subject: [PATCH 02/42] RocketletManager is now loaded. --- packages/rocketchat-rocketlets/package.js | 26 ++++- .../server/bridges/bridges.js | 26 +++++ .../server/bridges/commands.js | 3 +- .../server/bridges/environmental.js | 20 ++++ .../server/bridges/index.js | 5 +- .../server/bridges/settings.js | 35 +++++++ .../server/converters/index.js | 2 + .../server/converters/settings.js | 13 +++ .../server/orchestrator.js | 31 ++++-- .../server/storage/index.js | 4 + .../Rocketlets.js => storage/rl-model.js} | 0 .../server/storage/storage.js | 96 +++++++++++++++++++ 12 files changed, 247 insertions(+), 14 deletions(-) create mode 100644 packages/rocketchat-rocketlets/server/bridges/bridges.js create mode 100644 packages/rocketchat-rocketlets/server/bridges/environmental.js create mode 100644 packages/rocketchat-rocketlets/server/bridges/settings.js create mode 100644 packages/rocketchat-rocketlets/server/converters/settings.js create mode 100644 packages/rocketchat-rocketlets/server/storage/index.js rename packages/rocketchat-rocketlets/server/{models/Rocketlets.js => storage/rl-model.js} (100%) create mode 100644 packages/rocketchat-rocketlets/server/storage/storage.js diff --git a/packages/rocketchat-rocketlets/package.js b/packages/rocketchat-rocketlets/package.js index 127b469b9e53..c654c4775ac0 100644 --- a/packages/rocketchat-rocketlets/package.js +++ b/packages/rocketchat-rocketlets/package.js @@ -14,17 +14,35 @@ Package.onUse(function(api) { api.addFiles('server/orchestrator.js', 'server'); - api.addFiles('server/models/Rocketlets.js', 'server'); + // Storage + api.addFiles([ + 'server/storage/rl-model.js', + 'server/storage/storage.js', + 'server/storage/index.js' + ], 'server'); // Bridges api.addFiles([ - 'server/bridges/commands.js' + 'server/bridges/bridges.js', + 'server/bridges/commands.js', + 'server/bridges/environmental.js', + 'server/bridges/settings.js', + 'server/bridges/index.js' ], 'server'); // Communication pieces api.addFiles([ 'server/communication/rest.js', - 'server/communication/websockets.js' + 'server/communication/websockets.js', + 'server/communication/index.js' + ], 'server'); + + api.addFiles([ + 'server/converters/messages.js', + 'server/converters/rooms.js', + 'server/converters/settings.js', + 'server/converters/users.js', + 'server/converters/index.js' ], 'server'); // Client communication pieces @@ -36,6 +54,6 @@ Package.onUse(function(api) { }); Npm.depends({ - 'temporary-rocketlets-server': '0.1.11', + 'temporary-rocketlets-server': '0.1.12', 'temporary-rocketlets-ts-definition': '0.6.2' }); diff --git a/packages/rocketchat-rocketlets/server/bridges/bridges.js b/packages/rocketchat-rocketlets/server/bridges/bridges.js new file mode 100644 index 000000000000..85acb7d0143f --- /dev/null +++ b/packages/rocketchat-rocketlets/server/bridges/bridges.js @@ -0,0 +1,26 @@ +import { RocketletBridges } from 'temporary-rocketlets-server/server/bridges'; +import { RocketletCommandsBridge } from './commands'; +import { RocketletEnvironmentalVariableBridge } from './environmental'; +import { RocketletSettingBridge } from './settings'; + +export class RealRocketletBridges extends RocketletBridges { + constructor(converters) { + super(); + + this._cmdBridge = new RocketletCommandsBridge(converters); + this._envBridge = new RocketletEnvironmentalVariableBridge(converters); + this._setsBridge = new RocketletSettingBridge(converters); + } + + getCommandBridge() { + return this._cmdBridge; + } + + getEnvironmentalVariableBridge() { + return this._envBridge; + } + + getServerSettingBridge() { + return this._setsBridge; + } +} diff --git a/packages/rocketchat-rocketlets/server/bridges/commands.js b/packages/rocketchat-rocketlets/server/bridges/commands.js index 99169f96c5f2..cefc56a7836f 100644 --- a/packages/rocketchat-rocketlets/server/bridges/commands.js +++ b/packages/rocketchat-rocketlets/server/bridges/commands.js @@ -1,12 +1,11 @@ export class RocketletCommandsBridge { constructor(converters) { - console.log('CommandsBridge constructor'); this.converters = converters; this.disabledCommands = new Map(); } doesCommandExist(command, rocketletId) { - console.log(`The Rocketlet ${ rocketletId } is check if "${ command }" command exists.`); + console.log(`The Rocketlet ${ rocketletId } is checking if "${ command }" command exists.`); if (typeof command !== 'string') { return false; diff --git a/packages/rocketchat-rocketlets/server/bridges/environmental.js b/packages/rocketchat-rocketlets/server/bridges/environmental.js new file mode 100644 index 000000000000..731fb3e798e0 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/bridges/environmental.js @@ -0,0 +1,20 @@ +export class RocketletEnvironmentalVariableBridge { + constructor(converters) { + this.converters = converters; + } + + getValueByName(envVarName, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is getting the environmental variable value ${ envVarName }.`); + throw new Error('Method not implemented.'); + } + + isReadable(envVarName, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is checking if the environmental variable is readable ${ envVarName }.`); + throw new Error('Method not implemented.'); + } + + isSet(envVarName, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is checking if the environmental variable is set ${ envVarName }.`); + throw new Error('Method not implemented.'); + } +} diff --git a/packages/rocketchat-rocketlets/server/bridges/index.js b/packages/rocketchat-rocketlets/server/bridges/index.js index 82cad72f3770..bab289eac933 100644 --- a/packages/rocketchat-rocketlets/server/bridges/index.js +++ b/packages/rocketchat-rocketlets/server/bridges/index.js @@ -1,3 +1,6 @@ +import { RealRocketletBridges } from './bridges'; import { RocketletCommandsBridge } from './commands'; +import { RocketletEnvironmentalVariableBridge } from './environmental'; +import { RocketletSettingBridge } from './settings'; -export { RocketletCommandsBridge }; +export { RealRocketletBridges, RocketletCommandsBridge, RocketletEnvironmentalVariableBridge, RocketletSettingBridge }; diff --git a/packages/rocketchat-rocketlets/server/bridges/settings.js b/packages/rocketchat-rocketlets/server/bridges/settings.js new file mode 100644 index 000000000000..b27d2be634f4 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/bridges/settings.js @@ -0,0 +1,35 @@ +export class RocketletSettingBridge { + constructor(converters) { + this.converters = converters; + } + + getAll(rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is getting all the settings.`); + throw new Error('Method not implemented.'); + } + + getOneById(id, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is getting the setting by id ${ id }.`); + throw new Error('Method not implemented.'); + } + + hideGroup(name, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is hidding the group ${ name }.`); + throw new Error('Method not implemented.'); + } + + hideSetting(id, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is hidding the setting ${ id }.`); + throw new Error('Method not implemented.'); + } + + isReadableById(id, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is checking if they can read the setting ${ id }.`); + throw new Error('Method not implemented.'); + } + + updateOne(setting, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is updating the setting ${ setting.id } .`); + throw new Error('Method not implemented.'); + } +} diff --git a/packages/rocketchat-rocketlets/server/converters/index.js b/packages/rocketchat-rocketlets/server/converters/index.js index 2a402be1b351..0713f78dd5fb 100644 --- a/packages/rocketchat-rocketlets/server/converters/index.js +++ b/packages/rocketchat-rocketlets/server/converters/index.js @@ -1,9 +1,11 @@ import { RocketletMessagesConverter } from './messages'; import { RocketletRoomsConverter } from './rooms'; +import { RocketletSettingsConverter } from './settings'; import { RocketletUsersConverter } from './users'; export { RocketletMessagesConverter, RocketletRoomsConverter, + RocketletSettingsConverter, RocketletUsersConverter }; diff --git a/packages/rocketchat-rocketlets/server/converters/settings.js b/packages/rocketchat-rocketlets/server/converters/settings.js new file mode 100644 index 000000000000..6421e7989217 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/converters/settings.js @@ -0,0 +1,13 @@ +export class RocketletSettingsConverter { + constructor(converters) { + this.converters = converters; + } + + convertById(settingId) { + const setting = RocketChat.models.Settings.findOneById(settingId); + + return { + id: setting._id + }; + } +} diff --git a/packages/rocketchat-rocketlets/server/orchestrator.js b/packages/rocketchat-rocketlets/server/orchestrator.js index 2f030bbfd347..dbb6cf068a17 100644 --- a/packages/rocketchat-rocketlets/server/orchestrator.js +++ b/packages/rocketchat-rocketlets/server/orchestrator.js @@ -1,27 +1,37 @@ -import { RocketletCommandsBridge } from './bridges'; +import { RealRocketletBridges } from './bridges'; import { RocketletWebsocketNotifier } from './communication'; -import { RocketletMessagesConverter, RocketletRoomsConverter } from './converters'; -import { RocketletsModel } from './models/Rocketlets'; +import { RocketletMessagesConverter, RocketletRoomsConverter, RocketletSettingsConverter, RocketletUsersConverter } from './converters'; +import { RocketletsModel, RocketletRealStorage } from './storage'; + +import { RocketletManager } from 'temporary-rocketlets-server/server/RocketletManager'; class RocketletServerOrchestrator { constructor() { this._model = new RocketletsModel(); + this._storage = new RocketletRealStorage(this._model); this._converters = new Map(); this._converters.set('messages', new RocketletMessagesConverter(this._converters)); this._converters.set('rooms', new RocketletRoomsConverter(this._converters)); + this._converters.set('settings', new RocketletSettingsConverter(this._converters)); + this._converters.set('users', new RocketletUsersConverter(this._converters)); - this._bridges = new Map(); - this._bridges.set('commands', new RocketletCommandsBridge(this._converters)); + this._bridges = new RealRocketletBridges(this._converters); this._communicators = new Map(); this._communicators.set('notifier', new RocketletWebsocketNotifier()); + + this._manager = new RocketletManager(this._storage, this._bridges); } getModel() { return this._model; } + getStorage() { + return this._storage; + } + getConverters() { return this._converters; } @@ -33,10 +43,17 @@ class RocketletServerOrchestrator { getNotifier() { return this._communicators.get('notifier'); } + + getManager() { + return this._manager; + } } Meteor.startup(function _rocketletServerOrchestrator() { console.log('Orchestrating the rocketlet piece...'); - Rocketlets = new RocketletServerOrchestrator(); - console.log('...done! :)'); + global.Rocketlets = new RocketletServerOrchestrator(); + + global.Rocketlets.getManager().load() + .then(() => console.log('...done! ;)')) + .catch((err) => console.warn('...failed!', err)); }); diff --git a/packages/rocketchat-rocketlets/server/storage/index.js b/packages/rocketchat-rocketlets/server/storage/index.js new file mode 100644 index 000000000000..45a5e19e9c46 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/storage/index.js @@ -0,0 +1,4 @@ +import { RocketletsModel } from './rl-model'; +import { RocketletRealStorage } from './storage'; + +export { RocketletsModel, RocketletRealStorage }; diff --git a/packages/rocketchat-rocketlets/server/models/Rocketlets.js b/packages/rocketchat-rocketlets/server/storage/rl-model.js similarity index 100% rename from packages/rocketchat-rocketlets/server/models/Rocketlets.js rename to packages/rocketchat-rocketlets/server/storage/rl-model.js diff --git a/packages/rocketchat-rocketlets/server/storage/storage.js b/packages/rocketchat-rocketlets/server/storage/storage.js new file mode 100644 index 000000000000..0ac51c5e0a48 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/storage/storage.js @@ -0,0 +1,96 @@ +import { RocketletStorage } from 'temporary-rocketlets-server/server/storage'; + +export class RocketletRealStorage extends RocketletStorage { + constructor(data) { + super('mongodb'); + this.db = data; + } + + create(item) { + return new Promise((resolve, reject) => { + item.createdAt = new Date(); + item.updatedAt = new Date(); + + let doc; + + try { + doc = this.db.findOne({ $or: [{ id: item.id }, { 'info.nameSlug': item.info.nameSlug }] }); + } catch (e) { + return reject(e); + } + + if (doc) { + return reject(new Error('Rocketlet already exists.')); + } + + try { + const id = this.db.insert(item); + item._id = id; + + resolve(item); + } catch (e) { + reject(e); + } + }); + } + + retrieveOne(id) { + return new Promise((resolve, reject) => { + let doc; + + try { + doc = this.db.findOneById(id); + } catch (e) { + return reject(e); + } + + if (doc) { + resolve(doc); + } else { + reject(new Error(`Nothing found by the id: ${ id }`)); + } + }); + } + + retrieveAll() { + return new Promise((resolve, reject) => { + let docs; + + try { + docs = this.db.find({}).fetch(); + } catch (e) { + return reject(e); + } + + const items = new Map(); + + docs.forEach((i) => items.set(i.id, i)); + + resolve(items); + }); + } + + update(item) { + return new Promise((resolve, reject) => { + try { + this.db.update({ id: item.id }, item); + } catch (e) { + return reject(e); + } + + this.retrieveOne(item.id).then((updated) => resolve(updated)).catch((err) => reject(err)); + }); + } + + remove(id) { + return new Promise((resolve, reject) => { + try { + this.db.remove({ id }); + } catch (e) { + return reject(e); + } + + resolve({ success: true }); + }); + } +} From f65ca7a63a9de74a5f81b4c52a64e12917babdaa Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Wed, 23 Aug 2017 17:22:28 -0500 Subject: [PATCH 03/42] Rocketlet commands are now loaded onto the client and server --- .meteor/packages | 1 - .meteor/versions | 1 - packages/rocketchat-api/server/v1/commands.js | 2 +- .../client/lib/RestApiClient.js | 41 +++++++++ .../client/lib/startup/commands.js | 11 +++ packages/rocketchat-lib/package.js | 4 + .../client/communication/index.js | 4 + .../client/communication/restclient.js | 30 +++++++ .../client/communication/websockets.js | 22 ++++- .../client/orchestrator.js | 20 +++++ packages/rocketchat-rocketlets/package.js | 14 ++- .../server/bridges/bridges.js | 8 +- .../server/bridges/commands.js | 39 +++++--- .../server/communication/index.js | 2 + .../server/communication/rest.js | 88 +++++++++++++++++-- .../server/communication/websockets.js | 16 ++++ .../server/converters/messages.js | 4 +- .../server/converters/rooms.js | 4 +- .../server/converters/settings.js | 4 +- .../server/converters/users.js | 4 +- .../server/orchestrator.js | 17 ++-- .../gimme.js | 18 ---- .../lenny.js | 18 ---- .../package.js | 20 ----- .../shrug.js | 18 ---- .../tableflip.js | 18 ---- .../unflip.js | 18 ---- 27 files changed, 287 insertions(+), 159 deletions(-) create mode 100644 packages/rocketchat-lib/client/lib/RestApiClient.js create mode 100644 packages/rocketchat-lib/client/lib/startup/commands.js create mode 100644 packages/rocketchat-rocketlets/client/communication/index.js create mode 100644 packages/rocketchat-rocketlets/client/communication/restclient.js create mode 100644 packages/rocketchat-rocketlets/client/orchestrator.js delete mode 100644 packages/rocketchat-slashcommand-asciiarts/gimme.js delete mode 100644 packages/rocketchat-slashcommand-asciiarts/lenny.js delete mode 100644 packages/rocketchat-slashcommand-asciiarts/package.js delete mode 100644 packages/rocketchat-slashcommand-asciiarts/shrug.js delete mode 100644 packages/rocketchat-slashcommand-asciiarts/tableflip.js delete mode 100644 packages/rocketchat-slashcommand-asciiarts/unflip.js diff --git a/.meteor/packages b/.meteor/packages index cc549ff64a58..c3655aff0d37 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -97,7 +97,6 @@ rocketchat:rocketlets rocketchat:sandstorm rocketchat:slackbridge rocketchat:slashcommands-archive -rocketchat:slashcommands-asciiarts rocketchat:slashcommands-create rocketchat:slashcommands-help rocketchat:slashcommands-invite diff --git a/.meteor/versions b/.meteor/versions index 76740ca513da..cc64980c9840 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -189,7 +189,6 @@ rocketchat:rocketlets@1.0.0 rocketchat:sandstorm@0.0.1 rocketchat:slackbridge@0.0.1 rocketchat:slashcommands-archive@0.0.1 -rocketchat:slashcommands-asciiarts@0.0.1 rocketchat:slashcommands-create@0.0.1 rocketchat:slashcommands-help@0.0.1 rocketchat:slashcommands-invite@0.0.1 diff --git a/packages/rocketchat-api/server/v1/commands.js b/packages/rocketchat-api/server/v1/commands.js index eeda89444260..e903e0f8dc13 100644 --- a/packages/rocketchat-api/server/v1/commands.js +++ b/packages/rocketchat-api/server/v1/commands.js @@ -23,7 +23,7 @@ RocketChat.API.v1.addRoute('commands.list', { authRequired: true }, { let commands = Object.values(RocketChat.slashCommands.commands); - if (query.command) { + if (query && query.command) { commands = commands.filter((command) => command.command === query.command); } diff --git a/packages/rocketchat-lib/client/lib/RestApiClient.js b/packages/rocketchat-lib/client/lib/RestApiClient.js new file mode 100644 index 000000000000..ab353e69cb12 --- /dev/null +++ b/packages/rocketchat-lib/client/lib/RestApiClient.js @@ -0,0 +1,41 @@ +RocketChat.API = { + get(endpoint, params) { + return RocketChat.API._jqueryCall('GET', endpoint, params); + }, + + _jqueryCall(method, endpoint, params, body) { + let query = ''; + if (params) { + Object.keys(params).forEach((key) => { + query += query === '' ? '?' : '&'; + + query += `${ key }=${ params[key] }`; + }); + } + + return new Promise(function _rlRestApiGet(resolve, reject) { + jQuery.ajax({ + method, + url: `${ Meteor.absoluteUrl() }api/${ endpoint }${ query }`, + headers: { + 'Content-Type': 'application/json', + 'X-User-Id': localStorage['Meteor.userId'], + 'X-Auth-Token': localStorage['Meteor.loginToken'] + }, + data: body, + success: function _rlGetSuccess(result) { + resolve(result); + }, + error: function _rlGetFailure(xhr, status, errorThrown) { + reject(new Error(errorThrown)); + } + }); + }); + }, + + v1: { + get(endpoint, params) { + return RocketChat.API.get(`v1/${ endpoint }`, params); + } + } +}; diff --git a/packages/rocketchat-lib/client/lib/startup/commands.js b/packages/rocketchat-lib/client/lib/startup/commands.js new file mode 100644 index 000000000000..01d97477c1fa --- /dev/null +++ b/packages/rocketchat-lib/client/lib/startup/commands.js @@ -0,0 +1,11 @@ +Meteor.startup(function _loadDynamicallyDefinedCommands() { + // The reason there is a 500 millisecond delay is so that we are + // a little "easier" on the server during start up + setTimeout(() => { + RocketChat.API.v1.get('commands.list').then(function _loadedCommands(result) { + result.commands.forEach((command) => { + RocketChat.slashCommands.commands[command.command] = command; + }); + }); + }, 500); +}); diff --git a/packages/rocketchat-lib/package.js b/packages/rocketchat-lib/package.js index 88eab2cb0557..47e7c8bb7b5d 100644 --- a/packages/rocketchat-lib/package.js +++ b/packages/rocketchat-lib/package.js @@ -182,6 +182,7 @@ Package.onUse(function(api) { // CLIENT LIB api.addFiles('client/Notifications.js', 'client'); api.addFiles('client/OAuthProxy.js', 'client'); + api.addFiles('client/lib/RestApiClient.js', 'client'); api.addFiles('client/lib/TabBar.js', 'client'); api.addFiles('client/lib/RocketChatTabBar.js', 'client'); api.addFiles('client/lib/cachedCollection.js', 'client'); @@ -192,6 +193,9 @@ Package.onUse(function(api) { api.addFiles('client/lib/userRoles.js', 'client'); api.addFiles('client/lib/Layout.js', 'client'); + // CLIENT LIB STARTUP + api.addFiles('client/lib/startup/commands.js', 'client'); + // CLIENT METHODS api.addFiles('client/methods/sendMessage.js', 'client'); api.addFiles('client/AdminBox.js', 'client'); diff --git a/packages/rocketchat-rocketlets/client/communication/index.js b/packages/rocketchat-rocketlets/client/communication/index.js new file mode 100644 index 000000000000..8f92c01d21b7 --- /dev/null +++ b/packages/rocketchat-rocketlets/client/communication/index.js @@ -0,0 +1,4 @@ +import { RocketletRestApiClient } from './restclient'; +import { RocketletWebsocketReceiver } from './websockets'; + +export { RocketletRestApiClient, RocketletWebsocketReceiver }; diff --git a/packages/rocketchat-rocketlets/client/communication/restclient.js b/packages/rocketchat-rocketlets/client/communication/restclient.js new file mode 100644 index 000000000000..0a09c49074fc --- /dev/null +++ b/packages/rocketchat-rocketlets/client/communication/restclient.js @@ -0,0 +1,30 @@ +export class RocketletRestApiClient { + constructor(orch) { + this.orch = orch; + } + + get(endpoint, params) { + return this._jqueryCall('GET', endpoint, params); + } + + _jqueryCall(method, endpoint, params) { + return new Promise(function _rlRestApiGet(resolve, reject) { + jQuery.ajax({ + method, + url: `${ Meteor.absoluteUrl() }api/${ endpoint }`, + headers: { + 'Content-Type': 'application/json', + 'X-User-Id': localStorage['Meteor.userId'], + 'X-Auth-Token': localStorage['Meteor.loginToken'] + }, + data: params, + success: function _rlGetSuccess(result) { + resolve(result); + }, + error: function _rlGetFailure(xhr, status, errorThrown) { + reject(new Error(errorThrown)); + } + }); + }); + } +} diff --git a/packages/rocketchat-rocketlets/client/communication/websockets.js b/packages/rocketchat-rocketlets/client/communication/websockets.js index 2a783649a3b6..d661600d5acf 100644 --- a/packages/rocketchat-rocketlets/client/communication/websockets.js +++ b/packages/rocketchat-rocketlets/client/communication/websockets.js @@ -1,12 +1,26 @@ export class RocketletWebsocketReceiver { - constructor(restApi) { - this.rest = restApi; + constructor(orch) { + this.orch = orch; this.streamer = new Meteor.Streamer('rocketlets'); - this.streamer.on('command/added', this.onCommandAdded); + this.streamer.on('command/added', this.onCommandAdded.bind(this)); + this.streamer.on('command/disabled', this.onCommandDisabled.bind(this)); + this.streamer.on('command/updated', this.onCommandUpdated.bind(this)); } onCommandAdded(command) { - console.log('Added:', command); + RocketChat.API.v1.get('commands.getOne', { command }).then((result) => { + RocketChat.slashCommands.commands[command] = result.command; + }); + } + + onCommandDisabled(command) { + delete RocketChat.slashCommands.commands[command]; + } + + onCommandUpdated(command) { + RocketChat.API.v1.get('commands.getOne', { command }).then((result) => { + RocketChat.slashCommands.commands[command] = result.command; + }); } } diff --git a/packages/rocketchat-rocketlets/client/orchestrator.js b/packages/rocketchat-rocketlets/client/orchestrator.js new file mode 100644 index 000000000000..7fc1f4bf3e78 --- /dev/null +++ b/packages/rocketchat-rocketlets/client/orchestrator.js @@ -0,0 +1,20 @@ +import { RocketletRestApiClient, RocketletWebsocketReceiver } from './communication'; + +class RocketletClientOrchestrator { + constructor() { + this.ws = new RocketletWebsocketReceiver(this); + this.rest = new RocketletRestApiClient(this); + } + + getWsListener() { + return this.ws; + } + + getRestApiClient() { + return this.rest; + } +} + +Meteor.startup(function _rlClientOrch() { + window.Rocketlets = new RocketletClientOrchestrator(); +}); diff --git a/packages/rocketchat-rocketlets/package.js b/packages/rocketchat-rocketlets/package.js index c654c4775ac0..bc7473b8e7af 100644 --- a/packages/rocketchat-rocketlets/package.js +++ b/packages/rocketchat-rocketlets/package.js @@ -12,8 +12,6 @@ Package.onUse(function(api) { api.addFiles('lib/Rocketlets.js', ['client', 'server']); - api.addFiles('server/orchestrator.js', 'server'); - // Storage api.addFiles([ 'server/storage/rl-model.js', @@ -45,15 +43,23 @@ Package.onUse(function(api) { 'server/converters/index.js' ], 'server'); + // Server Orchestrator + api.addFiles('server/orchestrator.js', 'server'); + // Client communication pieces api.addFiles([ - 'client/communication/websockets.js' + 'client/communication/websockets.js', + 'client/communication/index.js' ], 'client'); + // Client orchestrator + api.addFiles('client/orchestrator.js', 'client'); + api.export('Rocketlets'); }); Npm.depends({ - 'temporary-rocketlets-server': '0.1.12', + 'busboy': '0.2.13', + 'temporary-rocketlets-server': '0.1.16', 'temporary-rocketlets-ts-definition': '0.6.2' }); diff --git a/packages/rocketchat-rocketlets/server/bridges/bridges.js b/packages/rocketchat-rocketlets/server/bridges/bridges.js index 85acb7d0143f..713987341246 100644 --- a/packages/rocketchat-rocketlets/server/bridges/bridges.js +++ b/packages/rocketchat-rocketlets/server/bridges/bridges.js @@ -4,12 +4,12 @@ import { RocketletEnvironmentalVariableBridge } from './environmental'; import { RocketletSettingBridge } from './settings'; export class RealRocketletBridges extends RocketletBridges { - constructor(converters) { + constructor(orch) { super(); - this._cmdBridge = new RocketletCommandsBridge(converters); - this._envBridge = new RocketletEnvironmentalVariableBridge(converters); - this._setsBridge = new RocketletSettingBridge(converters); + this._cmdBridge = new RocketletCommandsBridge(orch); + this._envBridge = new RocketletEnvironmentalVariableBridge(orch); + this._setsBridge = new RocketletSettingBridge(orch); } getCommandBridge() { diff --git a/packages/rocketchat-rocketlets/server/bridges/commands.js b/packages/rocketchat-rocketlets/server/bridges/commands.js index cefc56a7836f..3bf584ecbd59 100644 --- a/packages/rocketchat-rocketlets/server/bridges/commands.js +++ b/packages/rocketchat-rocketlets/server/bridges/commands.js @@ -1,6 +1,8 @@ +import { SlashCommandContext } from 'temporary-rocketlets-ts-definition/slashcommands'; + export class RocketletCommandsBridge { - constructor(converters) { - this.converters = converters; + constructor(orch) { + this.orch = orch; this.disabledCommands = new Map(); } @@ -29,7 +31,7 @@ export class RocketletCommandsBridge { this.disabledCommands.set(cmd, RocketChat.slashCommands.commands[cmd]); delete RocketChat.slashCommands.commands[cmd]; - Rocketlets.getNotifier().commandDisabled(cmd); + this.orch.getNotifier().commandDisabled(cmd); } // command: { command, paramsExample, i18nDescription, executor: function } @@ -46,8 +48,26 @@ export class RocketletCommandsBridge { const item = RocketChat.slashCommands.commands[cmd]; item.params = command.paramsExample ? command.paramsExample : item.params; item.description = command.i18nDescription ? command.i18nDescription : item.params; - item.callback = this._executorWrapper(command.executor); + item.callback = this._rocketletCommandExecutor.bind(this); + RocketChat.slashCommands.commands[cmd] = item; + this.orch.getNotifier().commandUpdated(cmd); + } + + registerCommand(command, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is registering the command: "${ command.command }"`); + + this._verifyCommand(command); + + const item = { + command: command.command.toLowerCase(), + params: command.paramsExample, + description: command.i18nDescription, + callback: this._rocketletCommandExecutor.bind(this) + }; + + RocketChat.slashCommands.commands[command.command.toLowerCase()] = item; + this.orch.getNotifier().commandAdded(command.command.toLowerCase()); } _verifyCommand(command) { @@ -72,12 +92,11 @@ export class RocketletCommandsBridge { } } - _executorWrapper(executor) { - return function _wrappedExecutor(command, params, message) { - // TODO: Converters - this.converters.get('messages').translate(message); + _rocketletCommandExecutor(command, parameters, message) { + const user = this.orch.getConverters().get('users').convertById(Meteor.userId()); + const room = this.orch.getConverters().get('rooms').convertById(message.rid); + const params = parameters.length === 0 || parameters === ' ' ? [] : parameters.split(' '); - executor(command); - }; + this.orch.getManager().getCommandManager().executeCommand(command, new SlashCommandContext(user, room, params)); } } diff --git a/packages/rocketchat-rocketlets/server/communication/index.js b/packages/rocketchat-rocketlets/server/communication/index.js index 8781d1737c41..870a5316c06e 100644 --- a/packages/rocketchat-rocketlets/server/communication/index.js +++ b/packages/rocketchat-rocketlets/server/communication/index.js @@ -1,5 +1,7 @@ +import { RocketletsRestApi } from './rest'; import { RocketletWebsocketNotifier } from './websockets'; export { + RocketletsRestApi, RocketletWebsocketNotifier }; diff --git a/packages/rocketchat-rocketlets/server/communication/rest.js b/packages/rocketchat-rocketlets/server/communication/rest.js index c463e1e60c7a..d8b58d47f9c4 100644 --- a/packages/rocketchat-rocketlets/server/communication/rest.js +++ b/packages/rocketchat-rocketlets/server/communication/rest.js @@ -1,8 +1,80 @@ -/* Rocketlets.API = new RocketChat.API.ApiClass({ - version: 'rocketlets', - useDefaultAuth: true, - prettyJson: true, - enableCors: false, - auth: RocketChat.API.getUserAuth() -}); -*/ +export class RocketletsRestApi { + constructor(manager) { + this._manager = manager; + this.api = new RocketChat.API.ApiClass({ + version: 'rocketlets', + useDefaultAuth: true, + prettyJson: true, + enableCors: false, + auth: RocketChat.API.getUserAuth() + }); + + this.addManagementRoutes(); + } + + _handleFile(request, fileField) { + const Busboy = Npm.require('busboy'); + const busboy = new Busboy({ headers: request.headers }); + + return Meteor.wrapAsync((callback) => { + busboy.on('file', Meteor.bindEnvironment((fieldname, file) => { + if (fieldname !== fileField) { + return callback(new Meteor.Error('invalid-field', `Expected the field "${ fileField }" but got "${ fieldname }" instead.`)); + } + + const fileData = []; + file.on('data', Meteor.bindEnvironment((data) => { + fileData.push(data); + })); + + file.on('end', Meteor.bindEnvironment(() => callback(undefined, Buffer.concat(fileData)))); + })); + + request.pipe(busboy); + })(); + } + + addManagementRoutes() { + const manager = this._manager; + const fileHandler = this._handleFile; + + this.api.addRoute('', { authRequired: true }, { + post() { + console.log('Creating a new Rocketlet via the rest api'); + + const buff = fileHandler(this.request, 'rocketlet'); + const item = Meteor.wrapAsync((callback) => { + manager.add(buff.toString('base64')).then((rl) => { + console.log('Success?'); + callback(undefined, rl); + }).catch((e) => { + console.warn('Error!', e); + callback(e); + }); + })(); + + console.log('result:', item.rocketlet.info); + + return { success: true, rocketlet: item.rocketlet.info }; + } + }); + + this.api.addRoute(':id', { authRequired: true }, { + get() { + console.log('Getting:', this.urlParams.id); + return { success: false }; + }, + post() { + console.log('Updating:', this.urlParams.id); + // TODO: Verify permissions + + const buff = fileHandler(this.request, 'rocketlet'); + const item = Meteor.wrapAsync((callback) => { + manager.update(buff.toString('base64')).then((rl) => callback(rl)).catch((e) => callback(e)); + }); + + return { success: false, item }; + } + }); + } +} diff --git a/packages/rocketchat-rocketlets/server/communication/websockets.js b/packages/rocketchat-rocketlets/server/communication/websockets.js index 8fda659d65c8..d92da25cae44 100644 --- a/packages/rocketchat-rocketlets/server/communication/websockets.js +++ b/packages/rocketchat-rocketlets/server/communication/websockets.js @@ -6,6 +6,18 @@ export class RocketletWebsocketNotifier { this.streamer.allowWrite('none'); } + rocketletAdded(rocketletId) { + this.streamer.emit('rocketlet/added', rocketletId); + } + + rockletRemoved(rocketletId) { + this.streamer.emit('rocketlet/removed', rocketletId); + } + + rockletUpdated(rocketletId) { + this.streamer.emit('rocketlet/updated', rocketletId); + } + commandAdded(command) { this.streamer.emit('command/added', command); } @@ -13,4 +25,8 @@ export class RocketletWebsocketNotifier { commandDisabled(command) { this.streamer.emit('command/disabled', command); } + + commandUpdated(command) { + this.streamer.emit('command/updated', command); + } } diff --git a/packages/rocketchat-rocketlets/server/converters/messages.js b/packages/rocketchat-rocketlets/server/converters/messages.js index 80a745a0ea74..3b6892da346f 100644 --- a/packages/rocketchat-rocketlets/server/converters/messages.js +++ b/packages/rocketchat-rocketlets/server/converters/messages.js @@ -1,6 +1,6 @@ export class RocketletMessagesConverter { - constructor(converters) { - this.converters = converters; + constructor(orch) { + this.orch = orch; } convertById(msgId) { diff --git a/packages/rocketchat-rocketlets/server/converters/rooms.js b/packages/rocketchat-rocketlets/server/converters/rooms.js index 23481dda5ef1..d198482bb595 100644 --- a/packages/rocketchat-rocketlets/server/converters/rooms.js +++ b/packages/rocketchat-rocketlets/server/converters/rooms.js @@ -1,6 +1,6 @@ export class RocketletRoomsConverter { - constructor(converters) { - this.converters = converters; + constructor(orch) { + this.orch = orch; } convertById(roomId) { diff --git a/packages/rocketchat-rocketlets/server/converters/settings.js b/packages/rocketchat-rocketlets/server/converters/settings.js index 6421e7989217..eec1f01984f2 100644 --- a/packages/rocketchat-rocketlets/server/converters/settings.js +++ b/packages/rocketchat-rocketlets/server/converters/settings.js @@ -1,6 +1,6 @@ export class RocketletSettingsConverter { - constructor(converters) { - this.converters = converters; + constructor(orch) { + this.orch = orch; } convertById(settingId) { diff --git a/packages/rocketchat-rocketlets/server/converters/users.js b/packages/rocketchat-rocketlets/server/converters/users.js index 0eea353ffb95..6f52033f096b 100644 --- a/packages/rocketchat-rocketlets/server/converters/users.js +++ b/packages/rocketchat-rocketlets/server/converters/users.js @@ -1,6 +1,6 @@ export class RocketletUsersConverter { - constructor(converters) { - this.converters = converters; + constructor(orch) { + this.orch = orch; } convertById(userId) { diff --git a/packages/rocketchat-rocketlets/server/orchestrator.js b/packages/rocketchat-rocketlets/server/orchestrator.js index dbb6cf068a17..f35d9cfbb5dd 100644 --- a/packages/rocketchat-rocketlets/server/orchestrator.js +++ b/packages/rocketchat-rocketlets/server/orchestrator.js @@ -1,5 +1,5 @@ import { RealRocketletBridges } from './bridges'; -import { RocketletWebsocketNotifier } from './communication'; +import { RocketletsRestApi, RocketletWebsocketNotifier } from './communication'; import { RocketletMessagesConverter, RocketletRoomsConverter, RocketletSettingsConverter, RocketletUsersConverter } from './converters'; import { RocketletsModel, RocketletRealStorage } from './storage'; @@ -11,17 +11,18 @@ class RocketletServerOrchestrator { this._storage = new RocketletRealStorage(this._model); this._converters = new Map(); - this._converters.set('messages', new RocketletMessagesConverter(this._converters)); - this._converters.set('rooms', new RocketletRoomsConverter(this._converters)); - this._converters.set('settings', new RocketletSettingsConverter(this._converters)); - this._converters.set('users', new RocketletUsersConverter(this._converters)); + this._converters.set('messages', new RocketletMessagesConverter(this)); + this._converters.set('rooms', new RocketletRoomsConverter(this)); + this._converters.set('settings', new RocketletSettingsConverter(this)); + this._converters.set('users', new RocketletUsersConverter(this)); - this._bridges = new RealRocketletBridges(this._converters); + this._bridges = new RealRocketletBridges(this); + + this._manager = new RocketletManager(this._storage, this._bridges); this._communicators = new Map(); + this._communicators.set('restapi', new RocketletsRestApi(this._manager)); this._communicators.set('notifier', new RocketletWebsocketNotifier()); - - this._manager = new RocketletManager(this._storage, this._bridges); } getModel() { diff --git a/packages/rocketchat-slashcommand-asciiarts/gimme.js b/packages/rocketchat-slashcommand-asciiarts/gimme.js deleted file mode 100644 index f8997115d321..000000000000 --- a/packages/rocketchat-slashcommand-asciiarts/gimme.js +++ /dev/null @@ -1,18 +0,0 @@ -/* -* Gimme is a named function that will replace /gimme commands -* @param {Object} message - The message object -*/ - - -function Gimme(command, params, item) { - if (command === 'gimme') { - const msg = item; - msg.msg = `༼ つ ◕_◕ ༽つ ${ params }`; - Meteor.call('sendMessage', msg); - } -} - -RocketChat.slashCommands.add('gimme', Gimme, { - description: 'Slash_Gimme_Description', - params: 'your_message_optional' -}); diff --git a/packages/rocketchat-slashcommand-asciiarts/lenny.js b/packages/rocketchat-slashcommand-asciiarts/lenny.js deleted file mode 100644 index 5272a7b67867..000000000000 --- a/packages/rocketchat-slashcommand-asciiarts/lenny.js +++ /dev/null @@ -1,18 +0,0 @@ -/* -* Lenny is a named function that will replace /lenny commands -* @param {Object} message - The message object -*/ - - -function LennyFace(command, params, item) { - if (command === 'lennyface') { - const msg = item; - msg.msg = `${ params } ( ͡° ͜ʖ ͡°)`; - Meteor.call('sendMessage', msg); - } -} - -RocketChat.slashCommands.add('lennyface', LennyFace, { - description: 'Slash_LennyFace_Description', - params: 'your_message_optional' -}); diff --git a/packages/rocketchat-slashcommand-asciiarts/package.js b/packages/rocketchat-slashcommand-asciiarts/package.js deleted file mode 100644 index 703d6cca492f..000000000000 --- a/packages/rocketchat-slashcommand-asciiarts/package.js +++ /dev/null @@ -1,20 +0,0 @@ -Package.describe({ - name: 'rocketchat:slashcommands-asciiarts', - version: '0.0.1', - summary: 'Message pre-processor that will add ascii arts to messages', - git: '' -}); - -Package.onUse(function(api) { - api.use([ - 'rocketchat:lib' - ]); - - api.use('ecmascript'); - - api.addFiles('gimme.js', ['server', 'client']); - api.addFiles('lenny.js', ['server', 'client']); - api.addFiles('shrug.js', ['server', 'client']); - api.addFiles('tableflip.js', ['server', 'client']); - api.addFiles('unflip.js', ['server', 'client']); -}); diff --git a/packages/rocketchat-slashcommand-asciiarts/shrug.js b/packages/rocketchat-slashcommand-asciiarts/shrug.js deleted file mode 100644 index 656c739e354a..000000000000 --- a/packages/rocketchat-slashcommand-asciiarts/shrug.js +++ /dev/null @@ -1,18 +0,0 @@ -/* -* Shrug is a named function that will replace /shrug commands -* @param {Object} message - The message object -*/ - - -function Shrug(command, params, item) { - if (command === 'shrug') { - const msg = item; - msg.msg = `${ params } ¯\\_(ツ)_/¯`; - Meteor.call('sendMessage', msg); - } -} - -RocketChat.slashCommands.add('shrug', Shrug, { - description: 'Slash_Shrug_Description', - params: 'your_message_optional' -}); diff --git a/packages/rocketchat-slashcommand-asciiarts/tableflip.js b/packages/rocketchat-slashcommand-asciiarts/tableflip.js deleted file mode 100644 index 1d7d172c6286..000000000000 --- a/packages/rocketchat-slashcommand-asciiarts/tableflip.js +++ /dev/null @@ -1,18 +0,0 @@ -/* -* Tableflip is a named function that will replace /Tableflip commands -* @param {Object} message - The message object -*/ - - -function Tableflip(command, params, item) { - if (command === 'tableflip') { - const msg = item; - msg.msg = `${ params } (╯°□°)╯︵ ┻━┻`; - Meteor.call('sendMessage', msg); - } -} - -RocketChat.slashCommands.add('tableflip', Tableflip, { - description: 'Slash_Tableflip_Description', - params: 'your_message_optional' -}); diff --git a/packages/rocketchat-slashcommand-asciiarts/unflip.js b/packages/rocketchat-slashcommand-asciiarts/unflip.js deleted file mode 100644 index 3df04e43d6c5..000000000000 --- a/packages/rocketchat-slashcommand-asciiarts/unflip.js +++ /dev/null @@ -1,18 +0,0 @@ -/* -* Unflip is a named function that will replace /unflip commands -* @param {Object} message - The message object -*/ - - -function Unflip(command, params, item) { - if (command === 'unflip') { - const msg = item; - msg.msg = `${ params } ┬─┬ ノ( ゜-゜ノ)`; - Meteor.call('sendMessage', msg); - } -} - -RocketChat.slashCommands.add('unflip', Unflip, { - description: 'Slash_TableUnflip_Description', - params: 'your_message_optional' -}); From 9a609bf6d6e6ec16896ff96e3b8ff489f5dde9db Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Thu, 24 Aug 2017 13:21:48 -0500 Subject: [PATCH 04/42] Improve the commands and add permission nodes to the commands --- packages/rocketchat-lib/lib/slashCommand.js | 1 + .../client/communication/index.js | 3 +- .../client/communication/restclient.js | 30 ------------------- .../client/orchestrator.js | 7 +---- .../server/orchestrator.js | 3 +- .../client.js | 4 --- .../package.js | 5 +--- .../rocketchat-slashcommands-create/client.js | 4 --- .../package.js | 2 -- .../rocketchat-slashcommands-help/client.js | 3 -- .../rocketchat-slashcommands-help/package.js | 1 - .../rocketchat-slashcommands-help/server.js | 4 --- .../rocketchat-slashcommands-invite/client.js | 4 --- .../package.js | 2 -- .../client.js | 8 ----- .../package.js | 1 - .../server.js | 2 +- .../rocketchat-slashcommands-kick/client.js | 10 ------- .../rocketchat-slashcommands-kick/package.js | 2 -- .../rocketchat-slashcommands-kick/server.js | 3 +- .../rocketchat-slashcommands-leave/leave.js | 4 +-- .../rocketchat-slashcommands-leave/package.js | 3 +- packages/rocketchat-slashcommands-me/me.js | 1 + .../rocketchat-slashcommands-me/package.js | 2 +- .../rocketchat-slashcommands-msg/client.js | 4 --- .../rocketchat-slashcommands-msg/package.js | 2 -- .../rocketchat-slashcommands-msg/server.js | 5 +++- .../client/mute.js | 4 --- .../client/unmute.js | 4 --- .../rocketchat-slashcommands-mute/package.js | 8 +---- .../server/mute.js | 3 ++ .../server/unmute.js | 3 ++ .../client.js | 4 --- .../package.js | 6 +--- .../server.js | 5 +++- .../client/popup/messagePopupConfig.js | 22 +++++++++----- .../rocketchat-ui/client/lib/chatMessages.js | 15 ++++++---- 37 files changed, 55 insertions(+), 139 deletions(-) delete mode 100644 packages/rocketchat-rocketlets/client/communication/restclient.js delete mode 100644 packages/rocketchat-slashcommands-archiveroom/client.js delete mode 100644 packages/rocketchat-slashcommands-create/client.js delete mode 100644 packages/rocketchat-slashcommands-help/client.js delete mode 100644 packages/rocketchat-slashcommands-invite/client.js delete mode 100644 packages/rocketchat-slashcommands-inviteall/client.js delete mode 100644 packages/rocketchat-slashcommands-kick/client.js delete mode 100644 packages/rocketchat-slashcommands-msg/client.js delete mode 100644 packages/rocketchat-slashcommands-mute/client/mute.js delete mode 100644 packages/rocketchat-slashcommands-mute/client/unmute.js delete mode 100644 packages/rocketchat-slashcommands-unarchiveroom/client.js diff --git a/packages/rocketchat-lib/lib/slashCommand.js b/packages/rocketchat-lib/lib/slashCommand.js index 7f37a7933adc..69bb56b56b48 100644 --- a/packages/rocketchat-lib/lib/slashCommand.js +++ b/packages/rocketchat-lib/lib/slashCommand.js @@ -8,6 +8,7 @@ RocketChat.slashCommands.add = function(command, callback, options = {}, result) callback, params: options.params, description: options.description, + permission: options.permission, clientOnly: options.clientOnly || false, result }; diff --git a/packages/rocketchat-rocketlets/client/communication/index.js b/packages/rocketchat-rocketlets/client/communication/index.js index 8f92c01d21b7..7ee19cdf2081 100644 --- a/packages/rocketchat-rocketlets/client/communication/index.js +++ b/packages/rocketchat-rocketlets/client/communication/index.js @@ -1,4 +1,3 @@ -import { RocketletRestApiClient } from './restclient'; import { RocketletWebsocketReceiver } from './websockets'; -export { RocketletRestApiClient, RocketletWebsocketReceiver }; +export { RocketletWebsocketReceiver }; diff --git a/packages/rocketchat-rocketlets/client/communication/restclient.js b/packages/rocketchat-rocketlets/client/communication/restclient.js deleted file mode 100644 index 0a09c49074fc..000000000000 --- a/packages/rocketchat-rocketlets/client/communication/restclient.js +++ /dev/null @@ -1,30 +0,0 @@ -export class RocketletRestApiClient { - constructor(orch) { - this.orch = orch; - } - - get(endpoint, params) { - return this._jqueryCall('GET', endpoint, params); - } - - _jqueryCall(method, endpoint, params) { - return new Promise(function _rlRestApiGet(resolve, reject) { - jQuery.ajax({ - method, - url: `${ Meteor.absoluteUrl() }api/${ endpoint }`, - headers: { - 'Content-Type': 'application/json', - 'X-User-Id': localStorage['Meteor.userId'], - 'X-Auth-Token': localStorage['Meteor.loginToken'] - }, - data: params, - success: function _rlGetSuccess(result) { - resolve(result); - }, - error: function _rlGetFailure(xhr, status, errorThrown) { - reject(new Error(errorThrown)); - } - }); - }); - } -} diff --git a/packages/rocketchat-rocketlets/client/orchestrator.js b/packages/rocketchat-rocketlets/client/orchestrator.js index 7fc1f4bf3e78..d65a626290fb 100644 --- a/packages/rocketchat-rocketlets/client/orchestrator.js +++ b/packages/rocketchat-rocketlets/client/orchestrator.js @@ -1,18 +1,13 @@ -import { RocketletRestApiClient, RocketletWebsocketReceiver } from './communication'; +import { RocketletWebsocketReceiver } from './communication'; class RocketletClientOrchestrator { constructor() { this.ws = new RocketletWebsocketReceiver(this); - this.rest = new RocketletRestApiClient(this); } getWsListener() { return this.ws; } - - getRestApiClient() { - return this.rest; - } } Meteor.startup(function _rlClientOrch() { diff --git a/packages/rocketchat-rocketlets/server/orchestrator.js b/packages/rocketchat-rocketlets/server/orchestrator.js index f35d9cfbb5dd..7d6c7d73f12b 100644 --- a/packages/rocketchat-rocketlets/server/orchestrator.js +++ b/packages/rocketchat-rocketlets/server/orchestrator.js @@ -1,5 +1,5 @@ import { RealRocketletBridges } from './bridges'; -import { RocketletsRestApi, RocketletWebsocketNotifier } from './communication'; +import { RocketletWebsocketNotifier } from './communication'; import { RocketletMessagesConverter, RocketletRoomsConverter, RocketletSettingsConverter, RocketletUsersConverter } from './converters'; import { RocketletsModel, RocketletRealStorage } from './storage'; @@ -21,7 +21,6 @@ class RocketletServerOrchestrator { this._manager = new RocketletManager(this._storage, this._bridges); this._communicators = new Map(); - this._communicators.set('restapi', new RocketletsRestApi(this._manager)); this._communicators.set('notifier', new RocketletWebsocketNotifier()); } diff --git a/packages/rocketchat-slashcommands-archiveroom/client.js b/packages/rocketchat-slashcommands-archiveroom/client.js deleted file mode 100644 index 200e172e43fc..000000000000 --- a/packages/rocketchat-slashcommands-archiveroom/client.js +++ /dev/null @@ -1,4 +0,0 @@ -RocketChat.slashCommands.add('archive', null, { - description: 'Archive', - params: '#channel' -}); diff --git a/packages/rocketchat-slashcommands-archiveroom/package.js b/packages/rocketchat-slashcommands-archiveroom/package.js index 1d14abd954e7..4c287ba87cdf 100644 --- a/packages/rocketchat-slashcommands-archiveroom/package.js +++ b/packages/rocketchat-slashcommands-archiveroom/package.js @@ -6,7 +6,6 @@ Package.describe({ }); Package.onUse(function(api) { - api.use([ 'ecmascript', 'check', @@ -15,7 +14,5 @@ Package.onUse(function(api) { api.use('templating', 'client'); - api.addFiles('client.js', 'client'); - api.addFiles('messages.js', 'server'); - api.addFiles('server.js', 'server'); + api.addFiles(['messages.js', 'server.js'], 'server'); }); diff --git a/packages/rocketchat-slashcommands-create/client.js b/packages/rocketchat-slashcommands-create/client.js deleted file mode 100644 index 54d6aa95d601..000000000000 --- a/packages/rocketchat-slashcommands-create/client.js +++ /dev/null @@ -1,4 +0,0 @@ -RocketChat.slashCommands.add('create', null, { - description: 'Create_A_New_Channel', - params: '#channel' -}); diff --git a/packages/rocketchat-slashcommands-create/package.js b/packages/rocketchat-slashcommands-create/package.js index 3f47398d6216..112be0d49e1e 100644 --- a/packages/rocketchat-slashcommands-create/package.js +++ b/packages/rocketchat-slashcommands-create/package.js @@ -6,7 +6,6 @@ Package.describe({ }); Package.onUse(function(api) { - api.use([ 'ecmascript', 'check', @@ -15,6 +14,5 @@ Package.onUse(function(api) { api.use('templating', 'client'); - api.addFiles('client.js', 'client'); api.addFiles('server.js', 'server'); }); diff --git a/packages/rocketchat-slashcommands-help/client.js b/packages/rocketchat-slashcommands-help/client.js deleted file mode 100644 index 5f26f43b21b1..000000000000 --- a/packages/rocketchat-slashcommands-help/client.js +++ /dev/null @@ -1,3 +0,0 @@ -RocketChat.slashCommands.add('help', undefined, { - description: 'Show_the_keyboard_shortcut_list' -}); diff --git a/packages/rocketchat-slashcommands-help/package.js b/packages/rocketchat-slashcommands-help/package.js index f8cdabea9deb..f9a6529b5ff7 100644 --- a/packages/rocketchat-slashcommands-help/package.js +++ b/packages/rocketchat-slashcommands-help/package.js @@ -15,6 +15,5 @@ Package.onUse(function(api) { api.use('templating', 'client'); - api.addFiles('client.js', 'client'); api.addFiles('server.js', 'server'); }); diff --git a/packages/rocketchat-slashcommands-help/server.js b/packages/rocketchat-slashcommands-help/server.js index f8aefcd869cb..490c7020692d 100644 --- a/packages/rocketchat-slashcommands-help/server.js +++ b/packages/rocketchat-slashcommands-help/server.js @@ -6,10 +6,6 @@ RocketChat.slashCommands.add('help', function Help(command, params, item) { - - if (command !== 'help') { - return; - } const user = Meteor.users.findOne(Meteor.userId()); const keys = [{ 'Open_channel_user_search': 'Command (or Ctrl) + p OR Command (or Ctrl) + k' diff --git a/packages/rocketchat-slashcommands-invite/client.js b/packages/rocketchat-slashcommands-invite/client.js deleted file mode 100644 index c5440a78d065..000000000000 --- a/packages/rocketchat-slashcommands-invite/client.js +++ /dev/null @@ -1,4 +0,0 @@ -RocketChat.slashCommands.add('invite', undefined, { - description: 'Invite_user_to_join_channel', - params: '@username' -}); diff --git a/packages/rocketchat-slashcommands-invite/package.js b/packages/rocketchat-slashcommands-invite/package.js index 1a410fa17800..bd92d1165df0 100644 --- a/packages/rocketchat-slashcommands-invite/package.js +++ b/packages/rocketchat-slashcommands-invite/package.js @@ -6,7 +6,6 @@ Package.describe({ }); Package.onUse(function(api) { - api.use([ 'ecmascript', 'check', @@ -15,6 +14,5 @@ Package.onUse(function(api) { api.use('templating', 'client'); - api.addFiles('client.js', 'client'); api.addFiles('server.js', 'server'); }); diff --git a/packages/rocketchat-slashcommands-inviteall/client.js b/packages/rocketchat-slashcommands-inviteall/client.js deleted file mode 100644 index 1e6bd4917e88..000000000000 --- a/packages/rocketchat-slashcommands-inviteall/client.js +++ /dev/null @@ -1,8 +0,0 @@ -RocketChat.slashCommands.add('invite-all-to', undefined, { - description: 'Invite_user_to_join_channel_all_to', - params: '#room' -}); -RocketChat.slashCommands.add('invite-all-from', undefined, { - description: 'Invite_user_to_join_channel_all_from', - params: '#room' -}); diff --git a/packages/rocketchat-slashcommands-inviteall/package.js b/packages/rocketchat-slashcommands-inviteall/package.js index e44deba52141..92b40866f3bd 100644 --- a/packages/rocketchat-slashcommands-inviteall/package.js +++ b/packages/rocketchat-slashcommands-inviteall/package.js @@ -15,6 +15,5 @@ Package.onUse(function(api) { api.use('templating', 'client'); - api.addFiles('client.js', 'client'); api.addFiles('server.js', 'server'); }); diff --git a/packages/rocketchat-slashcommands-inviteall/server.js b/packages/rocketchat-slashcommands-inviteall/server.js index a80cc3b04d08..133c8200ef18 100644 --- a/packages/rocketchat-slashcommands-inviteall/server.js +++ b/packages/rocketchat-slashcommands-inviteall/server.js @@ -4,7 +4,6 @@ */ function inviteAll(type) { - return function inviteAll(command, params, item) { if (!/invite\-all-(to|from)/.test(command) || !Match.test(params, String)) { @@ -76,6 +75,7 @@ function inviteAll(type) { } }; } + RocketChat.slashCommands.add('invite-all-to', inviteAll('to'), { description: 'Invite_user_to_join_channel_all_to', params: '#room' diff --git a/packages/rocketchat-slashcommands-kick/client.js b/packages/rocketchat-slashcommands-kick/client.js deleted file mode 100644 index 7b1d001c6f6e..000000000000 --- a/packages/rocketchat-slashcommands-kick/client.js +++ /dev/null @@ -1,10 +0,0 @@ -RocketChat.slashCommands.add('kick', function(command, params) { - const username = params.trim(); - if (username === '') { - return; - } - return username.replace('@', ''); -}, { - description: 'Remove_someone_from_room', - params: '@username' -}); diff --git a/packages/rocketchat-slashcommands-kick/package.js b/packages/rocketchat-slashcommands-kick/package.js index d73a92fca71e..32d102a112be 100644 --- a/packages/rocketchat-slashcommands-kick/package.js +++ b/packages/rocketchat-slashcommands-kick/package.js @@ -6,7 +6,6 @@ Package.describe({ }); Package.onUse(function(api) { - api.use([ 'ecmascript', 'check', @@ -15,6 +14,5 @@ Package.onUse(function(api) { api.use('templating', 'client'); - api.addFiles('client.js', 'client'); api.addFiles('server.js', 'server'); }); diff --git a/packages/rocketchat-slashcommands-kick/server.js b/packages/rocketchat-slashcommands-kick/server.js index ff484022fe54..8b6a298838cf 100644 --- a/packages/rocketchat-slashcommands-kick/server.js +++ b/packages/rocketchat-slashcommands-kick/server.js @@ -39,5 +39,6 @@ const Kick = function(command, params, {rid}) { RocketChat.slashCommands.add('kick', Kick, { description: 'Remove_someone_from_room', - params: '@username' + params: '@username', + permission: 'remove-user' }); diff --git a/packages/rocketchat-slashcommands-leave/leave.js b/packages/rocketchat-slashcommands-leave/leave.js index a6dd74fa82e1..6b748eb9eb01 100644 --- a/packages/rocketchat-slashcommands-leave/leave.js +++ b/packages/rocketchat-slashcommands-leave/leave.js @@ -20,5 +20,5 @@ function Leave(command, params, item) { } } -RocketChat.slashCommands.add('leave', Meteor.isClient ? undefined : Leave, { description: 'Leave_the_current_channel' }); -RocketChat.slashCommands.add('part', Meteor.isClient ? undefined : Leave, { description: 'Leave_the_current_channel' }); +RocketChat.slashCommands.add('leave', Leave, { description: 'Leave_the_current_channel' }); +RocketChat.slashCommands.add('part', Leave, { description: 'Leave_the_current_channel' }); diff --git a/packages/rocketchat-slashcommands-leave/package.js b/packages/rocketchat-slashcommands-leave/package.js index c5260f9dee8d..1bbd3a6e037a 100644 --- a/packages/rocketchat-slashcommands-leave/package.js +++ b/packages/rocketchat-slashcommands-leave/package.js @@ -10,5 +10,6 @@ Package.onUse(function(api) { 'ecmascript', 'rocketchat:lib' ]); - api.addFiles('leave.js'); + + api.addFiles('leave.js', 'server'); }); diff --git a/packages/rocketchat-slashcommands-me/me.js b/packages/rocketchat-slashcommands-me/me.js index 97d0e9e6b0cd..c2e51a03c6d2 100644 --- a/packages/rocketchat-slashcommands-me/me.js +++ b/packages/rocketchat-slashcommands-me/me.js @@ -7,6 +7,7 @@ RocketChat.slashCommands.add('me', function Me(command, params, item) { if (command !== 'me') { return; } + if (_.trim(params)) { const msg = item; msg.msg = `_${ params }_`; diff --git a/packages/rocketchat-slashcommands-me/package.js b/packages/rocketchat-slashcommands-me/package.js index eb2f4a5e6c08..0a164dc9544e 100644 --- a/packages/rocketchat-slashcommands-me/package.js +++ b/packages/rocketchat-slashcommands-me/package.js @@ -11,5 +11,5 @@ Package.onUse(function(api) { 'rocketchat:lib' ]); - api.addFiles('me.js', ['server', 'client']); + api.addFiles('me.js', 'server'); }); diff --git a/packages/rocketchat-slashcommands-msg/client.js b/packages/rocketchat-slashcommands-msg/client.js deleted file mode 100644 index 81b75c2c9d87..000000000000 --- a/packages/rocketchat-slashcommands-msg/client.js +++ /dev/null @@ -1,4 +0,0 @@ -RocketChat.slashCommands.add('msg', undefined, { - description: 'Direct_message_someone', - params: '@username ' -}); diff --git a/packages/rocketchat-slashcommands-msg/package.js b/packages/rocketchat-slashcommands-msg/package.js index bafb90f1c42d..366686a6cc3c 100644 --- a/packages/rocketchat-slashcommands-msg/package.js +++ b/packages/rocketchat-slashcommands-msg/package.js @@ -6,7 +6,6 @@ Package.describe({ }); Package.onUse(function(api) { - api.use([ 'ecmascript', 'check', @@ -15,6 +14,5 @@ Package.onUse(function(api) { api.use('templating', 'client'); - api.addFiles('client.js', 'client'); api.addFiles('server.js', 'server'); }); diff --git a/packages/rocketchat-slashcommands-msg/server.js b/packages/rocketchat-slashcommands-msg/server.js index 3e546c8526fc..2fbc8d512748 100644 --- a/packages/rocketchat-slashcommands-msg/server.js +++ b/packages/rocketchat-slashcommands-msg/server.js @@ -43,4 +43,7 @@ function Msg(command, params, item) { Meteor.call('sendMessage', msgObject); } -RocketChat.slashCommands.add('msg', Msg); +RocketChat.slashCommands.add('msg', Msg, { + description: 'Direct_message_someone', + params: '@username ' +}); diff --git a/packages/rocketchat-slashcommands-mute/client/mute.js b/packages/rocketchat-slashcommands-mute/client/mute.js deleted file mode 100644 index 14735ce70ae9..000000000000 --- a/packages/rocketchat-slashcommands-mute/client/mute.js +++ /dev/null @@ -1,4 +0,0 @@ -RocketChat.slashCommands.add('mute', undefined, { - description: 'Mute_someone_in_room', - params: '@username' -}); diff --git a/packages/rocketchat-slashcommands-mute/client/unmute.js b/packages/rocketchat-slashcommands-mute/client/unmute.js deleted file mode 100644 index 447e02cec79b..000000000000 --- a/packages/rocketchat-slashcommands-mute/client/unmute.js +++ /dev/null @@ -1,4 +0,0 @@ -RocketChat.slashCommands.add('unmute', undefined, { - description: 'Unmute_someone_in_room', - params: '@username' -}); diff --git a/packages/rocketchat-slashcommands-mute/package.js b/packages/rocketchat-slashcommands-mute/package.js index aee8058a6f7b..4c0c8a5c9d07 100644 --- a/packages/rocketchat-slashcommands-mute/package.js +++ b/packages/rocketchat-slashcommands-mute/package.js @@ -6,17 +6,11 @@ Package.describe({ }); Package.onUse(function(api) { - api.use([ 'ecmascript', 'check', 'rocketchat:lib' ]); - api.use('templating', 'client'); - - api.addFiles('client/mute.js', 'client'); - api.addFiles('client/unmute.js', 'client'); - api.addFiles('server/mute.js', 'server'); - api.addFiles('server/unmute.js', 'server'); + api.addFiles(['server/mute.js', 'server/unmute.js'], 'server'); }); diff --git a/packages/rocketchat-slashcommands-mute/server/mute.js b/packages/rocketchat-slashcommands-mute/server/mute.js index 21601cebe080..2c477609d797 100644 --- a/packages/rocketchat-slashcommands-mute/server/mute.js +++ b/packages/rocketchat-slashcommands-mute/server/mute.js @@ -42,4 +42,7 @@ RocketChat.slashCommands.add('mute', function Mute(command, params, item) { rid: item.rid, username }); +}, { + description: 'Mute_someone_in_room', + params: '@username' }); diff --git a/packages/rocketchat-slashcommands-mute/server/unmute.js b/packages/rocketchat-slashcommands-mute/server/unmute.js index 0d5d6a93e12e..1a864ab63f89 100644 --- a/packages/rocketchat-slashcommands-mute/server/unmute.js +++ b/packages/rocketchat-slashcommands-mute/server/unmute.js @@ -41,4 +41,7 @@ RocketChat.slashCommands.add('unmute', function Unmute(command, params, item) { rid: item.rid, username }); +}, { + description: 'Unmute_someone_in_room', + params: '@username' }); diff --git a/packages/rocketchat-slashcommands-unarchiveroom/client.js b/packages/rocketchat-slashcommands-unarchiveroom/client.js deleted file mode 100644 index 25be36519e8a..000000000000 --- a/packages/rocketchat-slashcommands-unarchiveroom/client.js +++ /dev/null @@ -1,4 +0,0 @@ -RocketChat.slashCommands.add('unarchive', null, { - description: 'Unarchive', - params: '#channel' -}); diff --git a/packages/rocketchat-slashcommands-unarchiveroom/package.js b/packages/rocketchat-slashcommands-unarchiveroom/package.js index 0b3120438385..7667a15c0b9a 100644 --- a/packages/rocketchat-slashcommands-unarchiveroom/package.js +++ b/packages/rocketchat-slashcommands-unarchiveroom/package.js @@ -13,9 +13,5 @@ Package.onUse(function(api) { 'rocketchat:lib' ]); - api.use('templating', 'client'); - - api.addFiles('client.js', 'client'); - api.addFiles('messages.js', 'server'); - api.addFiles('server.js', 'server'); + api.addFiles(['messages.js', 'server.js'], 'server'); }); diff --git a/packages/rocketchat-slashcommands-unarchiveroom/server.js b/packages/rocketchat-slashcommands-unarchiveroom/server.js index a9884b870755..968dde2444d4 100644 --- a/packages/rocketchat-slashcommands-unarchiveroom/server.js +++ b/packages/rocketchat-slashcommands-unarchiveroom/server.js @@ -50,4 +50,7 @@ function Unarchive(command, params, item) { return Unarchive; } -RocketChat.slashCommands.add('unarchive', Unarchive); +RocketChat.slashCommands.add('unarchive', Unarchive, { + description: 'Unarchive', + params: '#channel' +}); diff --git a/packages/rocketchat-ui-message/client/popup/messagePopupConfig.js b/packages/rocketchat-ui-message/client/popup/messagePopupConfig.js index 4293d3e1c90c..e8fadcee5dd3 100644 --- a/packages/rocketchat-ui-message/client/popup/messagePopupConfig.js +++ b/packages/rocketchat-ui-message/client/popup/messagePopupConfig.js @@ -236,14 +236,22 @@ Template.messagePopupConfig.helpers({ return { _id: command, params: item.params ? TAPi18n.__(item.params) : '', - description: TAPi18n.__(item.description) + description: TAPi18n.__(item.description), + permission: item.permission }; - }) - .filter(command => command._id.indexOf(filter) > -1) - .sort(function(a, b) { - return a._id > b._id; - }) - .slice(0, 11); + }).filter(command => { + const isMatch = command._id.indexOf(filter) > -1; + + if (!isMatch) { + return false; + } + + if (!command.permission) { + return true; + } + + return RocketChat.authz.hasAtLeastOnePermission(command.permission, Session.get('openedRoom')); + }).sort((a, b) => a._id > b._id).slice(0, 11); } }; return config; diff --git a/packages/rocketchat-ui/client/lib/chatMessages.js b/packages/rocketchat-ui/client/lib/chatMessages.js index f0046e918df9..a3f006ddda20 100644 --- a/packages/rocketchat-ui/client/lib/chatMessages.js +++ b/packages/rocketchat-ui/client/lib/chatMessages.js @@ -217,12 +217,16 @@ this.ChatMessages = class ChatMessages { const commandOptions = RocketChat.slashCommands.commands[match[1]]; command = match[1]; const param = match[2] || ''; - if (commandOptions.clientOnly) { - commandOptions.callback(command, param, msgObject); - } else { - Meteor.call('slashCommand', {cmd: command, params: param, msg: msgObject }, (err, result) => typeof commandOptions.result === 'function' && commandOptions.result(err, result, {cmd: command, params: param, msg: msgObject })); + + if (!commandOptions.permission || RocketChat.authz.hasAtLeastOnePermission(commandOptions.permission, Session.get('openedRoom'))) { + if (commandOptions.clientOnly) { + commandOptions.callback(command, param, msgObject); + } else { + Meteor.call('slashCommand', {cmd: command, params: param, msg: msgObject }, (err, result) => typeof commandOptions.result === 'function' && commandOptions.result(err, result, {cmd: command, params: param, msg: msgObject })); + } + + return; } - return; } if (!RocketChat.settings.get('Message_AllowUnrecognizedSlashCommand')) { @@ -236,6 +240,7 @@ this.ChatMessages = class ChatMessages { }, private: true }; + ChatMessage.upsert({ _id: invalidCommandMsg._id }, invalidCommandMsg); return; } From f7e34cf69c1a3e5dd3b2225c38aae1a320be43d2 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Wed, 30 Aug 2017 12:41:59 -0500 Subject: [PATCH 05/42] Work on bridges and saving of data, basic messages are now sent :tada: --- packages/rocketchat-rocketlets/package.js | 10 ++- .../server/bridges/bridges.js | 24 +++++++ .../server/bridges/commands.js | 3 +- .../server/bridges/environmental.js | 4 +- .../server/bridges/index.js | 15 +++- .../server/bridges/messages.js | 23 ++++++ .../server/bridges/persistence.js | 19 +++++ .../server/bridges/rooms.js | 45 ++++++++++++ .../server/bridges/settings.js | 4 +- .../server/bridges/users.js | 17 +++++ .../server/communication/rest.js | 18 ++--- .../server/converters/messages.js | 27 +++++++ .../server/converters/rooms.js | 71 ++++++++++++++++++- .../server/converters/users.js | 60 +++++++++++++++- .../server/orchestrator.js | 10 ++- .../server/storage/index.js | 3 +- .../server/storage/rl-persistence-model.js | 5 ++ 17 files changed, 336 insertions(+), 22 deletions(-) create mode 100644 packages/rocketchat-rocketlets/server/bridges/messages.js create mode 100644 packages/rocketchat-rocketlets/server/bridges/persistence.js create mode 100644 packages/rocketchat-rocketlets/server/bridges/rooms.js create mode 100644 packages/rocketchat-rocketlets/server/bridges/users.js create mode 100644 packages/rocketchat-rocketlets/server/storage/rl-persistence-model.js diff --git a/packages/rocketchat-rocketlets/package.js b/packages/rocketchat-rocketlets/package.js index bc7473b8e7af..cebcc6ef2f5f 100644 --- a/packages/rocketchat-rocketlets/package.js +++ b/packages/rocketchat-rocketlets/package.js @@ -15,6 +15,7 @@ Package.onUse(function(api) { // Storage api.addFiles([ 'server/storage/rl-model.js', + 'server/storage/rl-persistence-model.js', 'server/storage/storage.js', 'server/storage/index.js' ], 'server'); @@ -24,7 +25,11 @@ Package.onUse(function(api) { 'server/bridges/bridges.js', 'server/bridges/commands.js', 'server/bridges/environmental.js', + 'server/bridges/messages.js', + 'server/bridges/persistence.js', + 'server/bridges/rooms.js', 'server/bridges/settings.js', + 'server/bridges/users.js', 'server/bridges/index.js' ], 'server'); @@ -35,6 +40,7 @@ Package.onUse(function(api) { 'server/communication/index.js' ], 'server'); + // RocketChat <-> Rocketlet Data Converters api.addFiles([ 'server/converters/messages.js', 'server/converters/rooms.js', @@ -60,6 +66,6 @@ Package.onUse(function(api) { Npm.depends({ 'busboy': '0.2.13', - 'temporary-rocketlets-server': '0.1.16', - 'temporary-rocketlets-ts-definition': '0.6.2' + 'temporary-rocketlets-server': '0.1.20', + 'temporary-rocketlets-ts-definition': '0.6.11' }); diff --git a/packages/rocketchat-rocketlets/server/bridges/bridges.js b/packages/rocketchat-rocketlets/server/bridges/bridges.js index 713987341246..37d83623f62a 100644 --- a/packages/rocketchat-rocketlets/server/bridges/bridges.js +++ b/packages/rocketchat-rocketlets/server/bridges/bridges.js @@ -1,7 +1,11 @@ import { RocketletBridges } from 'temporary-rocketlets-server/server/bridges'; import { RocketletCommandsBridge } from './commands'; import { RocketletEnvironmentalVariableBridge } from './environmental'; +import { RocketletMessageBridge } from './messages'; +import { RocketletPersistenceBridge } from './persistence'; +import { RocketletRoomBridge } from './rooms'; import { RocketletSettingBridge } from './settings'; +import { RocketletUserBridge } from './users'; export class RealRocketletBridges extends RocketletBridges { constructor(orch) { @@ -9,7 +13,11 @@ export class RealRocketletBridges extends RocketletBridges { this._cmdBridge = new RocketletCommandsBridge(orch); this._envBridge = new RocketletEnvironmentalVariableBridge(orch); + this._msgBridge = new RocketletMessageBridge(orch); + this._persistBridge = new RocketletPersistenceBridge(orch); + this._roomBridge = new RocketletRoomBridge(orch); this._setsBridge = new RocketletSettingBridge(orch); + this._userBridge = new RocketletUserBridge(orch); } getCommandBridge() { @@ -20,7 +28,23 @@ export class RealRocketletBridges extends RocketletBridges { return this._envBridge; } + getMessageBridge() { + return this._msgBridge; + } + + getPersistenceBridge() { + return this._persistBridge; + } + + getRoomBridge() { + return this._roomBridge; + } + getServerSettingBridge() { return this._setsBridge; } + + getUserBridge() { + return this._userBridge; + } } diff --git a/packages/rocketchat-rocketlets/server/bridges/commands.js b/packages/rocketchat-rocketlets/server/bridges/commands.js index 3bf584ecbd59..5a15730ed1d3 100644 --- a/packages/rocketchat-rocketlets/server/bridges/commands.js +++ b/packages/rocketchat-rocketlets/server/bridges/commands.js @@ -97,6 +97,7 @@ export class RocketletCommandsBridge { const room = this.orch.getConverters().get('rooms').convertById(message.rid); const params = parameters.length === 0 || parameters === ' ' ? [] : parameters.split(' '); - this.orch.getManager().getCommandManager().executeCommand(command, new SlashCommandContext(user, room, params)); + const context = new SlashCommandContext(Object.freeze(user), Object.freeze(room), Object.freeze(params)); + this.orch.getManager().getCommandManager().executeCommand(command, context); } } diff --git a/packages/rocketchat-rocketlets/server/bridges/environmental.js b/packages/rocketchat-rocketlets/server/bridges/environmental.js index 731fb3e798e0..9b4188e75a85 100644 --- a/packages/rocketchat-rocketlets/server/bridges/environmental.js +++ b/packages/rocketchat-rocketlets/server/bridges/environmental.js @@ -1,6 +1,6 @@ export class RocketletEnvironmentalVariableBridge { - constructor(converters) { - this.converters = converters; + constructor(orch) { + this.orch = orch; } getValueByName(envVarName, rocketletId) { diff --git a/packages/rocketchat-rocketlets/server/bridges/index.js b/packages/rocketchat-rocketlets/server/bridges/index.js index bab289eac933..0e3881bb49e1 100644 --- a/packages/rocketchat-rocketlets/server/bridges/index.js +++ b/packages/rocketchat-rocketlets/server/bridges/index.js @@ -1,6 +1,19 @@ import { RealRocketletBridges } from './bridges'; import { RocketletCommandsBridge } from './commands'; import { RocketletEnvironmentalVariableBridge } from './environmental'; +import { RocketletMessageBridge } from './messages'; +import { RocketletPersistenceBridge } from './persistence'; +import { RocketletRoomBridge } from './rooms'; import { RocketletSettingBridge } from './settings'; +import { RocketletUserBridge } from './users'; -export { RealRocketletBridges, RocketletCommandsBridge, RocketletEnvironmentalVariableBridge, RocketletSettingBridge }; +export { + RealRocketletBridges, + RocketletCommandsBridge, + RocketletEnvironmentalVariableBridge, + RocketletMessageBridge, + RocketletPersistenceBridge, + RocketletRoomBridge, + RocketletSettingBridge, + RocketletUserBridge +}; diff --git a/packages/rocketchat-rocketlets/server/bridges/messages.js b/packages/rocketchat-rocketlets/server/bridges/messages.js new file mode 100644 index 000000000000..812e930dc429 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/bridges/messages.js @@ -0,0 +1,23 @@ +export class RocketletMessageBridge { + constructor(orch) { + this.orch = orch; + } + + create(message, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is creating a new message.`, message); + + let msg = this.orch.getConverters().get('messages').convertRocketletMessage(message); + + Meteor.runAsUser(msg.u._id, () => { + msg = Meteor.call('sendMessage', msg); + }); + + return msg._id; + } + + getById(messageId, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is getting the message: "${ messageId }"`); + + return this.orch.getConverters().get('messages').convertById(messageId); + } +} diff --git a/packages/rocketchat-rocketlets/server/bridges/persistence.js b/packages/rocketchat-rocketlets/server/bridges/persistence.js new file mode 100644 index 000000000000..01661d342645 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/bridges/persistence.js @@ -0,0 +1,19 @@ +export class RocketletPersistenceBridge { + constructor(orch) { + this.orch = orch; + } + + create(data, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is storing a new object in their persistence.`, data); + + return this.orch.getPersistenceModel().insert({ rocketletId, data }); + } + + readById(id, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is reading their data in their persistence with the id: "${ id }"`); + + const record = this.orch.getPersistenceModel().findOneById(id); + + return record.data; + } +} diff --git a/packages/rocketchat-rocketlets/server/bridges/rooms.js b/packages/rocketchat-rocketlets/server/bridges/rooms.js new file mode 100644 index 000000000000..c6e8db60ae0f --- /dev/null +++ b/packages/rocketchat-rocketlets/server/bridges/rooms.js @@ -0,0 +1,45 @@ +import { RoomType } from 'temporary-rocketlets-ts-definition/rooms'; + +export class RocketletRoomBridge { + constructor(orch) { + this.orch = orch; + } + + create(room, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is creating a new room.`, room); + + const rcRoom = this.orch.getConverters().get('rooms').convertRocketletRoom(room); + let method; + + switch (room.type) { + case RoomType.CHANNEL: + method = 'createChannel'; + break; + case RoomType.PRIVATE_GROUP: + method = 'createPrivateGroup'; + break; + default: + throw new Error('Only channels and private groups can be created.'); + } + + let rid; + Meteor.runAsUser(room.creator.id, () => { + const info = Meteor.call(method, rcRoom.usernames); + rid = info.rid; + }); + + return rid; + } + + getById(roomId, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is getting the roomById: "${ roomId }"`); + + return this.orch.getConverters().get('rooms').convertById(roomId); + } + + getByName(roomName, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is getting the roomByName: "${ roomName }"`); + + return this.orch.getConverters().get('rooms').convertByName(roomName); + } +} diff --git a/packages/rocketchat-rocketlets/server/bridges/settings.js b/packages/rocketchat-rocketlets/server/bridges/settings.js index b27d2be634f4..c997bc7f5746 100644 --- a/packages/rocketchat-rocketlets/server/bridges/settings.js +++ b/packages/rocketchat-rocketlets/server/bridges/settings.js @@ -1,6 +1,6 @@ export class RocketletSettingBridge { - constructor(converters) { - this.converters = converters; + constructor(orch) { + this.orch = orch; } getAll(rocketletId) { diff --git a/packages/rocketchat-rocketlets/server/bridges/users.js b/packages/rocketchat-rocketlets/server/bridges/users.js new file mode 100644 index 000000000000..6652b1ee285b --- /dev/null +++ b/packages/rocketchat-rocketlets/server/bridges/users.js @@ -0,0 +1,17 @@ +export class RocketletUserBridge { + constructor(orch) { + this.orch = orch; + } + + getById(userId, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is getting the userId: "${ userId }"`); + + return this.orch.getConverters().get('users').convertById(userId); + } + + getByUsername(username, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is getting the username: "${ username }"`); + + return this.orch.getConverters().get('users').convertByUsername(username); + } +} diff --git a/packages/rocketchat-rocketlets/server/communication/rest.js b/packages/rocketchat-rocketlets/server/communication/rest.js index d8b58d47f9c4..0b6bc5153796 100644 --- a/packages/rocketchat-rocketlets/server/communication/rest.js +++ b/packages/rocketchat-rocketlets/server/communication/rest.js @@ -39,22 +39,20 @@ export class RocketletsRestApi { const fileHandler = this._handleFile; this.api.addRoute('', { authRequired: true }, { - post() { - console.log('Creating a new Rocketlet via the rest api'); + get() { + const rocketlets = manager.get().map(prl => prl.getInfo()); + return { success: true, rocketlets }; + }, + post() { const buff = fileHandler(this.request, 'rocketlet'); const item = Meteor.wrapAsync((callback) => { - manager.add(buff.toString('base64')).then((rl) => { - console.log('Success?'); - callback(undefined, rl); - }).catch((e) => { + manager.add(buff.toString('base64')).then((rl) => callback(undefined, rl)).catch((e) => { console.warn('Error!', e); callback(e); }); })(); - console.log('result:', item.rocketlet.info); - return { success: true, rocketlet: item.rocketlet.info }; } }); @@ -62,7 +60,9 @@ export class RocketletsRestApi { this.api.addRoute(':id', { authRequired: true }, { get() { console.log('Getting:', this.urlParams.id); - return { success: false }; + const rocketlet = manager.getOneById(this.urlParams.id).getInfo(); + + return { success: true, rocketlet }; }, post() { console.log('Updating:', this.urlParams.id); diff --git a/packages/rocketchat-rocketlets/server/converters/messages.js b/packages/rocketchat-rocketlets/server/converters/messages.js index 3b6892da346f..12c8d80234ae 100644 --- a/packages/rocketchat-rocketlets/server/converters/messages.js +++ b/packages/rocketchat-rocketlets/server/converters/messages.js @@ -6,6 +6,10 @@ export class RocketletMessagesConverter { convertById(msgId) { const msg = RocketChat.models.Messages.getOneById(msgId); + if (!msg) { + return undefined; + } + return { id: msg._id, text: msg.msg @@ -18,4 +22,27 @@ export class RocketletMessagesConverter { text: msgObj.msg }; } + + convertRocketletMessage(message) { + if (!message) { + return undefined; + } + + const room = RocketChat.models.Rooms.findOneById(message.room.id); + const user = RocketChat.models.Users.findOneById(message.sender.id); + + if (!room || !user) { + throw new Error('Invalid user or room provided on the message.'); + } + + return { + _id: message.id || Random.id(), + msg: message.text, + rid: room._id, + u: { + _id: user._id, + username: user.username + } + }; + } } diff --git a/packages/rocketchat-rocketlets/server/converters/rooms.js b/packages/rocketchat-rocketlets/server/converters/rooms.js index d198482bb595..d9b98f2a718e 100644 --- a/packages/rocketchat-rocketlets/server/converters/rooms.js +++ b/packages/rocketchat-rocketlets/server/converters/rooms.js @@ -1,3 +1,5 @@ +import { RoomType } from 'temporary-rocketlets-ts-definition/rooms'; + export class RocketletRoomsConverter { constructor(orch) { this.orch = orch; @@ -6,8 +8,75 @@ export class RocketletRoomsConverter { convertById(roomId) { const room = RocketChat.models.Rooms.findOneById(roomId); + return this._convertToRocketlet(room); + } + + convertByName(roomName) { + const room = RocketChat.models.Rooms.findOneByName(roomName); + + return this._convertToRocketlet(room); + } + + convertRocketletRoom(room) { + if (!room) { + return undefined; + } + + const creator = RocketChat.models.Users.findOneById(room.creator.id); + return { - id: room._id + _id: room.id, + u: { + _id: creator._id, + username: creator.username + }, + ts: room.createdAt, + t: room.type, + name: room.name, + msgs: room.messageCount || 0, + default: typeof room.isDefault === 'undefined' ? false : room.isDefault, + _updatedAt: room.updatedAt, + lm: room.lastModifiedAt, + usernames: room.usernames }; } + + _convertToRocketlet(room) { + if (!room) { + return undefined; + } + + let creator; + if (room.u) { + creator = this.orch.getConverters().get('users').convertById(room.u._id); + } + + return { + id: room._id, + name: room.name, + type: this._convertTypeToRocketlet(room.t), + creator, + usernames: room.usernames, + isDefault: typeof room.default === 'undefined' ? false : room.default, + messageCount: room.msgs, + createdAt: room.ts, + updatedAt: room._updatedAt, + lastModifiedAt: room.lm + }; + } + + _convertTypeToRocketlet(typeChar) { + switch (typeChar) { + case 'c': + return RoomType.CHANNEL; + case 'p': + return RoomType.PRIVATE_GROUP; + case 'd': + return RoomType.DIRECT_MESSAGE; + case 'lc': + return RoomType.LIVE_CHAT; + default: + throw new Error(`Unknown room type of: "${ typeChar }"`); + } + } } diff --git a/packages/rocketchat-rocketlets/server/converters/users.js b/packages/rocketchat-rocketlets/server/converters/users.js index 6f52033f096b..4cd1a1d65deb 100644 --- a/packages/rocketchat-rocketlets/server/converters/users.js +++ b/packages/rocketchat-rocketlets/server/converters/users.js @@ -1,3 +1,5 @@ +import { UserStatusConnection, UserType } from 'temporary-rocketlets-ts-definition/users'; + export class RocketletUsersConverter { constructor(orch) { this.orch = orch; @@ -6,8 +8,64 @@ export class RocketletUsersConverter { convertById(userId) { const user = RocketChat.models.Users.findOneById(userId); + return this._convertToRocketlet(user); + } + + convertByUsername(username) { + const user = RocketChat.models.Users.findOneByUsername(username); + + return this._convertToRocketlet(user); + } + + _convertToRocketlet(user) { + if (!user) { + return undefined; + } + + const type = this._convertUserTypeToEnum(user.type); + const status = this._convertStatusConnectionToEnum(user.status); + const statusConnection = this._convertStatusConnectionToEnum(user.statusConnection); + return { - id: user._id + id: user._id, + username: user.username, + emails: user.emails, + type, + isEnabled: user.active, + name: user.name, + roles: user.roles, + status, + statusConnection, + utcOffset: user.utcOffset, + createdAt: user.createdAt, + updatedAt: user._updatedAt, + lastLoginAt: user.lastLogin }; } + + _convertUserTypeToEnum(type) { + switch (type) { + case 'user': + return UserType.USER; + case 'bot': + return UserType.BOT; + default: + throw new Error('Unknown user type of:', type); + } + } + + _convertStatusConnectionToEnum(status) { + switch (status) { + case 'offline': + return UserStatusConnection.OFFLINE; + case 'online': + return UserStatusConnection.ONLINE; + case 'away': + return UserStatusConnection.AWAY; + case 'busy': + return UserStatusConnection.BUSY; + default: + throw new Error('Unknown status type of:', status); + } + } } diff --git a/packages/rocketchat-rocketlets/server/orchestrator.js b/packages/rocketchat-rocketlets/server/orchestrator.js index 7d6c7d73f12b..7bc44068928c 100644 --- a/packages/rocketchat-rocketlets/server/orchestrator.js +++ b/packages/rocketchat-rocketlets/server/orchestrator.js @@ -1,13 +1,14 @@ import { RealRocketletBridges } from './bridges'; -import { RocketletWebsocketNotifier } from './communication'; +import { RocketletsRestApi, RocketletWebsocketNotifier } from './communication'; import { RocketletMessagesConverter, RocketletRoomsConverter, RocketletSettingsConverter, RocketletUsersConverter } from './converters'; -import { RocketletsModel, RocketletRealStorage } from './storage'; +import { RocketletsModel, RocketletsPersistenceModel, RocketletRealStorage } from './storage'; import { RocketletManager } from 'temporary-rocketlets-server/server/RocketletManager'; class RocketletServerOrchestrator { constructor() { this._model = new RocketletsModel(); + this._persistModel = new RocketletsPersistenceModel(); this._storage = new RocketletRealStorage(this._model); this._converters = new Map(); @@ -22,12 +23,17 @@ class RocketletServerOrchestrator { this._communicators = new Map(); this._communicators.set('notifier', new RocketletWebsocketNotifier()); + this._communicators.set('restapi', new RocketletsRestApi(this._manager)); } getModel() { return this._model; } + getPersistenceModel() { + return this._persistModel; + } + getStorage() { return this._storage; } diff --git a/packages/rocketchat-rocketlets/server/storage/index.js b/packages/rocketchat-rocketlets/server/storage/index.js index 45a5e19e9c46..d47a7b1962ca 100644 --- a/packages/rocketchat-rocketlets/server/storage/index.js +++ b/packages/rocketchat-rocketlets/server/storage/index.js @@ -1,4 +1,5 @@ import { RocketletsModel } from './rl-model'; +import { RocketletsPersistenceModel } from './rl-persistence-model'; import { RocketletRealStorage } from './storage'; -export { RocketletsModel, RocketletRealStorage }; +export { RocketletsModel, RocketletsPersistenceModel, RocketletRealStorage }; diff --git a/packages/rocketchat-rocketlets/server/storage/rl-persistence-model.js b/packages/rocketchat-rocketlets/server/storage/rl-persistence-model.js new file mode 100644 index 000000000000..7b70e407c813 --- /dev/null +++ b/packages/rocketchat-rocketlets/server/storage/rl-persistence-model.js @@ -0,0 +1,5 @@ +export class RocketletsPersistenceModel extends RocketChat.models._Base { + constructor() { + super('rocketlets_persistence'); + } +} From 2cf9e5b6b835ce7b4be3a43e692c45a120a8415b Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Thu, 31 Aug 2017 23:59:45 -0500 Subject: [PATCH 06/42] Very basic start of the web interface for the rocketlets, not much done --- .../.npm/package/npm-shrinkwrap.json | 1301 +++++++---------- .../client/orchestrator.js | 19 + .../server/orchestrator.js | 4 + 3 files changed, 592 insertions(+), 732 deletions(-) diff --git a/packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json index 1b48096650dc..788d7c87977a 100644 --- a/packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json +++ b/packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json @@ -329,744 +329,581 @@ "from": "graceful-fs@>=4.1.2 <5.0.0" }, "grpc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.4.1.tgz", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.6.0.tgz", "from": "grpc@>=1.3.1 <2.0.0", "dependencies": { + "abbrev": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", + "from": "abbrev@1" + }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "from": "ajv@^4.9.1" + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "from": "ansi-regex@^2.0.0" + }, + "aproba": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.2.tgz", + "from": "aproba@^1.0.3" + }, + "are-we-there-yet": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "from": "are-we-there-yet@~1.1.2" + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "from": "asn1@~0.2.3" + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "from": "assert-plus@^0.2.0" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "from": "asynckit@^0.4.0" + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "from": "aws-sign2@~0.6.0" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "from": "aws4@^1.2.1" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "from": "balanced-match@^1.0.0" + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "from": "bcrypt-pbkdf@^1.0.0" + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "from": "block-stream@*" + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "from": "boom@2.x.x" + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "from": "brace-expansion@^1.1.7" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "from": "caseless@~0.12.0" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "from": "co@^4.6.0" + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "from": "code-point-at@^1.0.0" + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "from": "combined-stream@~1.0.5" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "from": "concat-map@0.0.1" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "from": "console-control-strings@~1.1.0" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "from": "core-util-is@~1.0.0" + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "from": "cryptiles@2.x.x" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "from": "dashdash@^1.12.0", + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "from": "assert-plus@^1.0.0" + } + } + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "from": "debug@^2.2.0" + }, + "deep-extend": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", + "from": "deep-extend@~0.4.0" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "from": "delayed-stream@~1.0.0" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "from": "delegates@^1.0.0" + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "from": "ecc-jsbn@~0.1.1" + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "from": "extend@~3.0.0" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "from": "extsprintf@1.3.0" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "from": "forever-agent@~0.6.1" + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "from": "form-data@~2.1.1" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "from": "fs.realpath@^1.0.0" + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "from": "fstream@^1.0.2" + }, + "fstream-ignore": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", + "from": "fstream-ignore@^1.0.5" + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "from": "gauge@~2.7.3" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "from": "getpass@^0.1.1", + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "from": "assert-plus@^1.0.0" + } + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "from": "glob@^7.0.5" + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "from": "graceful-fs@^4.1.2" + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "from": "har-schema@^1.0.5" + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "from": "har-validator@~4.2.1" + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "from": "has-unicode@^2.0.0" + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "from": "hawk@~3.1.3" + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "from": "hoek@2.x.x" + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "from": "http-signature@~1.1.0" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "from": "inflight@^1.0.4" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "from": "inherits@~2.0.3" + }, + "ini": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "from": "ini@~1.3.0" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "from": "is-fullwidth-code-point@^1.0.0" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "from": "is-typedarray@~1.0.0" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "from": "isarray@~1.0.0" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "from": "isstream@~0.1.2" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "from": "jsbn@~0.1.0" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "from": "json-schema@0.2.3" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "from": "json-stable-stringify@^1.0.1" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "from": "json-stringify-safe@~5.0.1" + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "from": "jsonify@~0.0.0" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "from": "jsprim@^1.2.2", + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "from": "assert-plus@1.0.0" + } + } + }, + "mime-db": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz", + "from": "mime-db@~1.29.0" + }, + "mime-types": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", + "from": "mime-types@~2.1.7" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "from": "minimatch@^3.0.4" + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "from": "minimist@^1.2.0" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "from": "mkdirp@^0.5.1", + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "from": "minimist@0.0.8" + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "from": "ms@2.0.0" + }, "node-pre-gyp": { "version": "0.6.36", "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz", - "from": "node-pre-gyp@0.6.36", + "from": "node-pre-gyp@0.6.36" + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "from": "nopt@^4.0.1" + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "from": "npmlog@^4.0.2" + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "from": "number-is-nan@^1.0.0" + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "from": "oauth-sign@~0.8.1" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "from": "object-assign@^4.1.0" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "from": "once@^1.3.0" + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "from": "os-homedir@^1.0.0" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "from": "os-tmpdir@^1.0.0" + }, + "osenv": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", + "from": "osenv@^0.1.4" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "from": "path-is-absolute@^1.0.0" + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "from": "performance-now@^0.2.0" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "from": "process-nextick-args@~1.0.6" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "from": "punycode@^1.4.1" + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "from": "qs@~6.4.0" + }, + "rc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", + "from": "rc@^1.1.7" + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "from": "readable-stream@^2.0.6" + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "from": "request@^2.81.0" + }, + "rimraf": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "from": "rimraf@^2.6.1" + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "from": "safe-buffer@~5.1.1" + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "from": "semver@^5.3.0" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "from": "set-blocking@~2.0.0" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "from": "signal-exit@^3.0.0" + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "from": "sntp@1.x.x" + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "from": "sshpk@^1.7.0", + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "from": "assert-plus@^1.0.0" + } + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "from": "string-width@^1.0.1" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "from": "string_decoder@~1.0.3" + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "from": "stringstream@~0.0.4" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "from": "strip-ansi@^3.0.1" + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "from": "strip-json-comments@~2.0.1" + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "from": "tar@^2.2.1" + }, + "tar-pack": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.0.tgz", + "from": "tar-pack@^3.4.0" + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "from": "tough-cookie@~2.3.0" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "from": "tunnel-agent@^0.6.0" + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "from": "tweetnacl@~0.14.0" + }, + "uid-number": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "from": "uid-number@^0.0.6" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "from": "util-deprecate@~1.0.1" + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "from": "uuid@^3.0.0" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "from": "verror@1.10.0", "dependencies": { - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "from": "mkdirp@>=0.5.1 <0.6.0", - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "from": "minimist@0.0.8" - } - } - }, - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "from": "nopt@>=4.0.1 <5.0.0", - "dependencies": { - "abbrev": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", - "from": "abbrev@>=1.0.0 <2.0.0" - }, - "osenv": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", - "from": "osenv@>=0.1.4 <0.2.0", - "dependencies": { - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "from": "os-homedir@>=1.0.0 <2.0.0" - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "from": "os-tmpdir@>=1.0.0 <2.0.0" - } - } - } - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "from": "npmlog@>=4.0.2 <5.0.0", - "dependencies": { - "are-we-there-yet": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "from": "are-we-there-yet@>=1.1.2 <1.2.0", - "dependencies": { - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "from": "delegates@>=1.0.0 <2.0.0" - }, - "readable-stream": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz", - "from": "readable-stream@>=2.0.6 <3.0.0", - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "from": "core-util-is@>=1.0.0 <1.1.0" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "from": "inherits@>=2.0.3 <2.1.0" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "from": "isarray@>=1.0.0 <1.1.0" - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "from": "process-nextick-args@>=1.0.6 <1.1.0" - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "from": "safe-buffer@>=5.1.0 <5.2.0" - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "from": "string_decoder@>=1.0.0 <1.1.0" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "from": "util-deprecate@>=1.0.1 <1.1.0" - } - } - } - } - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "from": "console-control-strings@>=1.1.0 <1.2.0" - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "from": "gauge@>=2.7.3 <2.8.0", - "dependencies": { - "aproba": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.2.tgz", - "from": "aproba@>=1.0.3 <2.0.0" - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "from": "has-unicode@>=2.0.0 <3.0.0" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "from": "object-assign@>=4.1.0 <5.0.0" - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "from": "signal-exit@>=3.0.0 <4.0.0" - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "from": "string-width@>=1.0.1 <2.0.0", - "dependencies": { - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "from": "code-point-at@>=1.0.0 <2.0.0" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "from": "is-fullwidth-code-point@>=1.0.0 <2.0.0", - "dependencies": { - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "from": "number-is-nan@>=1.0.0 <2.0.0" - } - } - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "from": "strip-ansi@>=3.0.1 <4.0.0", - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "from": "ansi-regex@>=2.0.0 <3.0.0" - } - } - }, - "wide-align": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "from": "wide-align@>=1.1.0 <2.0.0" - } - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "from": "set-blocking@>=2.0.0 <2.1.0" - } - } - }, - "rc": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", - "from": "rc@>=1.1.7 <2.0.0", - "dependencies": { - "deep-extend": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", - "from": "deep-extend@>=0.4.0 <0.5.0" - }, - "ini": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", - "from": "ini@>=1.3.0 <1.4.0" - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "from": "minimist@>=1.2.0 <2.0.0" - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "from": "strip-json-comments@>=2.0.1 <2.1.0" - } - } - }, - "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "from": "request@>=2.81.0 <3.0.0", - "dependencies": { - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "from": "aws-sign2@>=0.6.0 <0.7.0" - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "from": "aws4@>=1.2.1 <2.0.0" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "from": "caseless@>=0.12.0 <0.13.0" - }, - "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "from": "combined-stream@>=1.0.5 <1.1.0", - "dependencies": { - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "from": "delayed-stream@>=1.0.0 <1.1.0" - } - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "from": "extend@>=3.0.0 <3.1.0" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "from": "forever-agent@>=0.6.1 <0.7.0" - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "from": "form-data@>=2.1.1 <2.2.0", - "dependencies": { - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "from": "asynckit@>=0.4.0 <0.5.0" - } - } - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "from": "har-validator@>=4.2.1 <4.3.0", - "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "from": "ajv@>=4.9.1 <5.0.0", - "dependencies": { - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "from": "co@>=4.6.0 <5.0.0" - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "from": "json-stable-stringify@>=1.0.1 <2.0.0", - "dependencies": { - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "from": "jsonify@>=0.0.0 <0.1.0" - } - } - } - } - }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "from": "har-schema@>=1.0.5 <2.0.0" - } - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "from": "hawk@>=3.1.3 <3.2.0", - "dependencies": { - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "from": "boom@>=2.0.0 <3.0.0" - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "from": "cryptiles@>=2.0.0 <3.0.0" - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "from": "hoek@>=2.0.0 <3.0.0" - }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "from": "sntp@>=1.0.0 <2.0.0" - } - } - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "from": "http-signature@>=1.1.0 <1.2.0", - "dependencies": { - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "from": "assert-plus@>=0.2.0 <0.3.0" - }, - "jsprim": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", - "from": "jsprim@>=1.2.2 <2.0.0", - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "from": "assert-plus@1.0.0" - }, - "extsprintf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", - "from": "extsprintf@1.0.2" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "from": "json-schema@0.2.3" - }, - "verror": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", - "from": "verror@1.3.6" - } - } - }, - "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "from": "sshpk@>=1.7.0 <2.0.0", - "dependencies": { - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "from": "asn1@>=0.2.3 <0.3.0" - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "from": "assert-plus@>=1.0.0 <2.0.0" - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "from": "bcrypt-pbkdf@>=1.0.0 <2.0.0" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "from": "dashdash@>=1.12.0 <2.0.0" - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "from": "ecc-jsbn@>=0.1.1 <0.2.0" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "from": "getpass@>=0.1.1 <0.2.0" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "from": "jsbn@>=0.1.0 <0.2.0" - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "from": "tweetnacl@>=0.14.0 <0.15.0" - } - } - } - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "from": "is-typedarray@>=1.0.0 <1.1.0" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "from": "isstream@>=0.1.2 <0.2.0" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "from": "json-stringify-safe@>=5.0.1 <5.1.0" - }, - "mime-types": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", - "from": "mime-types@>=2.1.7 <2.2.0", - "dependencies": { - "mime-db": { - "version": "1.27.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", - "from": "mime-db@>=1.27.0 <1.28.0" - } - } - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "from": "oauth-sign@>=0.8.1 <0.9.0" - }, - "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "from": "performance-now@>=0.2.0 <0.3.0" - }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "from": "qs@>=6.4.0 <6.5.0" - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "from": "safe-buffer@>=5.0.1 <6.0.0" - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "from": "stringstream@>=0.0.4 <0.1.0" - }, - "tough-cookie": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", - "from": "tough-cookie@>=2.3.0 <2.4.0", - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "from": "punycode@>=1.4.1 <2.0.0" - } - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "from": "tunnel-agent@>=0.6.0 <0.7.0" - }, - "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "from": "uuid@>=3.0.0 <4.0.0" - } - } - }, - "rimraf": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", - "from": "rimraf@>=2.6.1 <3.0.0", - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "from": "glob@>=7.0.5 <8.0.0", - "dependencies": { - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "from": "fs.realpath@>=1.0.0 <2.0.0" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "from": "inflight@>=1.0.4 <2.0.0", - "dependencies": { - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "from": "wrappy@>=1.0.0 <2.0.0" - } - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "from": "inherits@>=2.0.0 <3.0.0" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "from": "minimatch@>=3.0.0 <4.0.0", - "dependencies": { - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "from": "brace-expansion@>=1.1.7 <2.0.0", - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "from": "balanced-match@>=1.0.0 <2.0.0" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "from": "concat-map@0.0.1" - } - } - } - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "from": "once@>=1.3.0 <2.0.0", - "dependencies": { - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "from": "wrappy@>=1.0.0 <2.0.0" - } - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "from": "path-is-absolute@>=1.0.0 <2.0.0" - } - } - } - } - }, - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "from": "semver@>=5.3.0 <6.0.0" - }, - "tar": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "from": "tar@>=2.2.1 <3.0.0", - "dependencies": { - "block-stream": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "from": "block-stream@*" - }, - "fstream": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "from": "fstream@>=1.0.2 <2.0.0", - "dependencies": { - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "from": "graceful-fs@>=4.1.2 <5.0.0" - } - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "from": "inherits@>=2.0.0 <3.0.0" - } - } - }, - "tar-pack": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.0.tgz", - "from": "tar-pack@>=3.4.0 <4.0.0", - "dependencies": { - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "from": "debug@>=2.2.0 <3.0.0", - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "from": "ms@2.0.0" - } - } - }, - "fstream": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "from": "fstream@>=1.0.10 <2.0.0", - "dependencies": { - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "from": "graceful-fs@>=4.1.2 <5.0.0" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "from": "inherits@>=2.0.0 <2.1.0" - } - } - }, - "fstream-ignore": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", - "from": "fstream-ignore@>=1.0.5 <2.0.0", - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "from": "inherits@>=2.0.0 <3.0.0" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "from": "minimatch@>=3.0.0 <4.0.0", - "dependencies": { - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "from": "brace-expansion@>=1.1.7 <2.0.0", - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "from": "balanced-match@>=1.0.0 <2.0.0" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "from": "concat-map@0.0.1" - } - } - } - } - } - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "from": "once@>=1.0.0 <2.0.0", - "dependencies": { - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "from": "wrappy@>=1.0.0 <2.0.0" - } - } - }, - "readable-stream": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz", - "from": "readable-stream@>=2.1.4 <3.0.0", - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "from": "core-util-is@>=1.0.0 <1.1.0" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "from": "inherits@>=2.0.3 <2.1.0" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "from": "isarray@>=1.0.0 <1.1.0" - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "from": "process-nextick-args@>=1.0.6 <1.1.0" - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "from": "safe-buffer@>=5.1.0 <5.2.0" - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "from": "string_decoder@>=1.0.0 <1.1.0" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "from": "util-deprecate@>=1.0.1 <1.1.0" - } - } - }, - "uid-number": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", - "from": "uid-number@>=0.0.6 <0.0.7" - } - } + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "from": "assert-plus@^1.0.0" } } + }, + "wide-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "from": "wide-align@^1.1.0" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "from": "wrappy@1" } } }, @@ -1270,7 +1107,7 @@ "nan": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", - "from": "nan@>=2.0.0 <3.0.0" + "from": "nan@>=2.6.2 <3.0.0" }, "node-forge": { "version": "0.7.1", @@ -1340,7 +1177,7 @@ "protobufjs": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-5.0.2.tgz", - "from": "protobufjs@>=5.0.0 <6.0.0" + "from": "protobufjs@>=5.0.2 <6.0.0" }, "pump": { "version": "1.0.2", diff --git a/packages/rocketchat-rocketlets/client/orchestrator.js b/packages/rocketchat-rocketlets/client/orchestrator.js index d65a626290fb..3d4010345145 100644 --- a/packages/rocketchat-rocketlets/client/orchestrator.js +++ b/packages/rocketchat-rocketlets/client/orchestrator.js @@ -3,11 +3,30 @@ import { RocketletWebsocketReceiver } from './communication'; class RocketletClientOrchestrator { constructor() { this.ws = new RocketletWebsocketReceiver(this); + + this._addAdminMenuOption(); } getWsListener() { return this.ws; } + + _addAdminMenuOption() { + FlowRouter.route('/admin/rocketlets', { + name: 'rocketlets', + action() { + BlazeLayout.render('main', { center: 'rocketlets' }); + } + }); + + RocketChat.AdminBox.addOption({ + href: 'rocketlets', + i18nLabel: 'rocketlets', + permissionGranted() { + return RocketChat.authz.hasAtLeastOnePermission(['manage-rocketlets']); + } + }); + } } Meteor.startup(function _rlClientOrch() { diff --git a/packages/rocketchat-rocketlets/server/orchestrator.js b/packages/rocketchat-rocketlets/server/orchestrator.js index 7bc44068928c..c9a79eb7af14 100644 --- a/packages/rocketchat-rocketlets/server/orchestrator.js +++ b/packages/rocketchat-rocketlets/server/orchestrator.js @@ -7,6 +7,10 @@ import { RocketletManager } from 'temporary-rocketlets-server/server/RocketletMa class RocketletServerOrchestrator { constructor() { + if (RocketChat.models && RocketChat.models.Permissions) { + RocketChat.models.Permissions.createOrUpdate('manage-rocketlets', ['admin']); + } + this._model = new RocketletsModel(); this._persistModel = new RocketletsPersistenceModel(); this._storage = new RocketletRealStorage(this._model); From 423065cb76efd27b7c8f1b896dbe1a5ecda48e27 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Thu, 7 Sep 2017 11:47:05 -0500 Subject: [PATCH 07/42] Flush out the rocketlet message converters and implement the http accessor --- packages/rocketchat-i18n/i18n/en.i18n.json | 2 + .../server/lib/sendNotificationsOnMessage.js | 2 +- .../client/admin/rocketlets.html | 20 +++ .../client/admin/rocketlets.js | 3 + .../client/orchestrator.js | 17 +-- packages/rocketchat-rocketlets/package.js | 15 ++- .../server/bridges/bridges.js | 6 + .../server/bridges/http.js | 14 ++ .../server/bridges/index.js | 2 + .../server/bridges/messages.js | 2 +- .../server/converters/messages.js | 126 ++++++++++++++++-- .../server/orchestrator.js | 2 +- 12 files changed, 187 insertions(+), 24 deletions(-) create mode 100644 packages/rocketchat-rocketlets/client/admin/rocketlets.html create mode 100644 packages/rocketchat-rocketlets/client/admin/rocketlets.js create mode 100644 packages/rocketchat-rocketlets/server/bridges/http.js diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 9413c0c42a0e..19b5d6bbf61b 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -1339,6 +1339,7 @@ "manage-own-integrations_description": "Permition to allow users to create and edit their own integration or webhooks", "manage-sounds": "Manage Sounds", "manage-sounds_description": "Permission to manage the server sounds", + "Manage_Rocketlets": "Manage Rocketlets", "mention-all": "Mention All", "mention-all_description": "Permission to use the @all mention", "mute-user": "Mute User", @@ -1523,6 +1524,7 @@ "Restart": "Restart", "Restart_the_server": "Restart the server", "Retry_Count": "Retry Count", + "Rocketlets": "Rocketlets", "Role": "Role", "Role_Editing": "Role Editing", "Role_removed": "Role removed", diff --git a/packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js b/packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js index 1083d18d76ec..ddda8b880de7 100644 --- a/packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js +++ b/packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js @@ -31,7 +31,7 @@ function parseMessageText(message, userId) { const user = RocketChat.models.Users.findOneById(userId); const lng = user && user.language || RocketChat.settings.get('language') || 'en'; - if (!message.msg && message.attachments[0]) { + if (!message.msg && message.attachments && message.attachments[0]) { message.msg = message.attachments[0].image_type ? TAPi18n.__('User_uploaded_image', {lng}) : TAPi18n.__('User_uploaded_file', {lng}); } message.msg = RocketChat.callbacks.run('beforeNotifyUser', message.msg); diff --git a/packages/rocketchat-rocketlets/client/admin/rocketlets.html b/packages/rocketchat-rocketlets/client/admin/rocketlets.html new file mode 100644 index 000000000000..62c73ba09a99 --- /dev/null +++ b/packages/rocketchat-rocketlets/client/admin/rocketlets.html @@ -0,0 +1,20 @@ + diff --git a/packages/rocketchat-rocketlets/client/admin/rocketlets.js b/packages/rocketchat-rocketlets/client/admin/rocketlets.js new file mode 100644 index 000000000000..bf10e3895b27 --- /dev/null +++ b/packages/rocketchat-rocketlets/client/admin/rocketlets.js @@ -0,0 +1,3 @@ +Template.rocketlets.onCreated(function() { + console.log('hello'); +}); diff --git a/packages/rocketchat-rocketlets/client/orchestrator.js b/packages/rocketchat-rocketlets/client/orchestrator.js index 3d4010345145..4bedcc9e56b0 100644 --- a/packages/rocketchat-rocketlets/client/orchestrator.js +++ b/packages/rocketchat-rocketlets/client/orchestrator.js @@ -12,16 +12,9 @@ class RocketletClientOrchestrator { } _addAdminMenuOption() { - FlowRouter.route('/admin/rocketlets', { - name: 'rocketlets', - action() { - BlazeLayout.render('main', { center: 'rocketlets' }); - } - }); - RocketChat.AdminBox.addOption({ href: 'rocketlets', - i18nLabel: 'rocketlets', + i18nLabel: 'Rocketlets', permissionGranted() { return RocketChat.authz.hasAtLeastOnePermission(['manage-rocketlets']); } @@ -32,3 +25,11 @@ class RocketletClientOrchestrator { Meteor.startup(function _rlClientOrch() { window.Rocketlets = new RocketletClientOrchestrator(); }); + +// Bah, this has to be done *before* `Meteor.startup` +FlowRouter.route('/admin/rocketlets', { + name: 'rocketlets', + action() { + BlazeLayout.render('main', { center: 'rocketlets' }); + } +}); diff --git a/packages/rocketchat-rocketlets/package.js b/packages/rocketchat-rocketlets/package.js index cebcc6ef2f5f..c1db788185ed 100644 --- a/packages/rocketchat-rocketlets/package.js +++ b/packages/rocketchat-rocketlets/package.js @@ -7,9 +7,12 @@ Package.onUse(function(api) { api.use([ 'ecmascript', 'rocketchat:lib', - 'rocketchat:api' + 'rocketchat:api', + 'templating' ]); + api.use(['reactive-var', 'kadira:flow-router'], 'client'); + api.addFiles('lib/Rocketlets.js', ['client', 'server']); // Storage @@ -58,6 +61,12 @@ Package.onUse(function(api) { 'client/communication/index.js' ], 'client'); + // Client Admin Management + api.addFiles([ + 'client/admin/rocketlets.html', + 'client/admin/rocketlets.js' + ], 'client'); + // Client orchestrator api.addFiles('client/orchestrator.js', 'client'); @@ -66,6 +75,6 @@ Package.onUse(function(api) { Npm.depends({ 'busboy': '0.2.13', - 'temporary-rocketlets-server': '0.1.20', - 'temporary-rocketlets-ts-definition': '0.6.11' + 'temporary-rocketlets-server': '0.1.22', + 'temporary-rocketlets-ts-definition': '0.6.24' }); diff --git a/packages/rocketchat-rocketlets/server/bridges/bridges.js b/packages/rocketchat-rocketlets/server/bridges/bridges.js index 37d83623f62a..07f5d182a9dc 100644 --- a/packages/rocketchat-rocketlets/server/bridges/bridges.js +++ b/packages/rocketchat-rocketlets/server/bridges/bridges.js @@ -1,6 +1,7 @@ import { RocketletBridges } from 'temporary-rocketlets-server/server/bridges'; import { RocketletCommandsBridge } from './commands'; import { RocketletEnvironmentalVariableBridge } from './environmental'; +import { RocketletHttpBridge } from './http'; import { RocketletMessageBridge } from './messages'; import { RocketletPersistenceBridge } from './persistence'; import { RocketletRoomBridge } from './rooms'; @@ -13,6 +14,7 @@ export class RealRocketletBridges extends RocketletBridges { this._cmdBridge = new RocketletCommandsBridge(orch); this._envBridge = new RocketletEnvironmentalVariableBridge(orch); + this._httpBridge = new RocketletHttpBridge(); this._msgBridge = new RocketletMessageBridge(orch); this._persistBridge = new RocketletPersistenceBridge(orch); this._roomBridge = new RocketletRoomBridge(orch); @@ -28,6 +30,10 @@ export class RealRocketletBridges extends RocketletBridges { return this._envBridge; } + getHttpBridge() { + return this._httpBridge; + } + getMessageBridge() { return this._msgBridge; } diff --git a/packages/rocketchat-rocketlets/server/bridges/http.js b/packages/rocketchat-rocketlets/server/bridges/http.js new file mode 100644 index 000000000000..a8bd452765ca --- /dev/null +++ b/packages/rocketchat-rocketlets/server/bridges/http.js @@ -0,0 +1,14 @@ +export class RocketletHttpBridge { + call(info) { + if (!info.request.content && typeof info.request.data === 'object') { + info.request.content = JSON.stringify(info.request.data); + } + + console.log(`The Rocketlet ${ info.rocketletId } is requesting from the outter webs:`, info); + const result = HTTP.call(info.method, info.url, info.request); + + console.log('The result is:', result); + + return result; + } +} diff --git a/packages/rocketchat-rocketlets/server/bridges/index.js b/packages/rocketchat-rocketlets/server/bridges/index.js index 0e3881bb49e1..6f6662360c7b 100644 --- a/packages/rocketchat-rocketlets/server/bridges/index.js +++ b/packages/rocketchat-rocketlets/server/bridges/index.js @@ -1,6 +1,7 @@ import { RealRocketletBridges } from './bridges'; import { RocketletCommandsBridge } from './commands'; import { RocketletEnvironmentalVariableBridge } from './environmental'; +import { RocketletHttpBridge } from './http'; import { RocketletMessageBridge } from './messages'; import { RocketletPersistenceBridge } from './persistence'; import { RocketletRoomBridge } from './rooms'; @@ -11,6 +12,7 @@ export { RealRocketletBridges, RocketletCommandsBridge, RocketletEnvironmentalVariableBridge, + RocketletHttpBridge, RocketletMessageBridge, RocketletPersistenceBridge, RocketletRoomBridge, diff --git a/packages/rocketchat-rocketlets/server/bridges/messages.js b/packages/rocketchat-rocketlets/server/bridges/messages.js index 812e930dc429..84ea8104d7be 100644 --- a/packages/rocketchat-rocketlets/server/bridges/messages.js +++ b/packages/rocketchat-rocketlets/server/bridges/messages.js @@ -4,7 +4,7 @@ export class RocketletMessageBridge { } create(message, rocketletId) { - console.log(`The Rocketlet ${ rocketletId } is creating a new message.`, message); + console.log(`The Rocketlet ${ rocketletId } is creating a new message.`); let msg = this.orch.getConverters().get('messages').convertRocketletMessage(message); diff --git a/packages/rocketchat-rocketlets/server/converters/messages.js b/packages/rocketchat-rocketlets/server/converters/messages.js index 12c8d80234ae..4858e4c18258 100644 --- a/packages/rocketchat-rocketlets/server/converters/messages.js +++ b/packages/rocketchat-rocketlets/server/converters/messages.js @@ -6,20 +6,38 @@ export class RocketletMessagesConverter { convertById(msgId) { const msg = RocketChat.models.Messages.getOneById(msgId); - if (!msg) { + return this.convertMessage(msg); + } + + convertMessage(msgObj) { + if (!msgObj) { return undefined; } - return { - id: msg._id, - text: msg.msg - }; - } + const room = this.orch.getConverters().get('rooms').convertById(msgObj.rid); + const sender = this.orch.getConverters().get('users').convertById(msgObj.u._id); + + let editor; + if (msgObj.editedBy) { + editor = this.orch.getConverters().get('users').convertById(msgObj.editedBy._id); + } + + const attachments = this._convertAttachmentsToRocketlet(msgObj.attachments); - convertMessage(msgObj) { return { id: msgObj._id, - text: msgObj.msg + room, + sender, + text: msgObj.msg, + createdAt: msgObj.ts, + updatedAt: msgObj._updatedAt, + editor, + editedAt: msgObj.editedAt, + emoji: msgObj.emoji, + avatarUrl: msgObj.avatar, + alias: msgObj.alias, + customFields: msgObj.customFields, + attachments }; } @@ -35,14 +53,102 @@ export class RocketletMessagesConverter { throw new Error('Invalid user or room provided on the message.'); } + let editedBy; + if (message.editor) { + const editor = RocketChat.models.Users.findOneById(message.editor.id); + editedBy = { + _id: editor._id, + username: editor.username + }; + } + + const attachments = this._convertRocketletAttachments(message.attachments); + return { _id: message.id || Random.id(), - msg: message.text, rid: room._id, u: { _id: user._id, username: user.username - } + }, + msg: message.text, + ts: message.createdAt || new Date(), + _updatedAt: message.updatedAt || new Date(), + editedBy, + editedAt: message.editedAt, + emoji: message.emoji, + avatar: message.avatarUrl, + alias: message.alias, + customFields: message.customFields, + attachments }; } + + _convertRocketletAttachments(attachments) { + if (typeof attachments === 'undefined' || !Array.isArray(attachments)) { + return undefined; + } + + return attachments.map((attachment) => { + return { + collapsed: attachment.collapsed, + color: attachment.color, + text: attachment.text, + ts: attachment.timestamp, + message_link: attachment.timestampLink, + thumb_url: attachment.thumbnailUrl, + author_name: attachment.author ? attachment.author.name : undefined, + author_link: attachment.author ? attachment.author.link : undefined, + author_icon: attachment.author ? attachment.author.icon : undefined, + title: attachment.title ? attachment.title.value : undefined, + title_link: attachment.title ? attachment.title.link : undefined, + title_link_download: attachment.title ? attachment.title.downloadLink : undefined, + image_url: attachment.imageUrl, + audio_url: attachment.audioUrl, + video_url: attachment.videoUrl, + fields: attachment.fields + }; + }); + } + + _convertAttachmentsToRocketlet(attachments) { + if (typeof attachments === 'undefined' || !Array.isArray(attachments)) { + return undefined; + } + + return attachments.map((attachment) => { + let author; + if (attachment.author_name || attachment.author_link || attachment.author_icon) { + author = { + name: attachment.author_name, + link: attachment.author_link, + icon: attachment.author_icon + }; + } + + let title; + if (attachment.title || attachment.title_link || attachment.title_link_download) { + title = { + value: attachment.title, + link: attachment.title_link, + downloadLink: attachment.title_link_download + }; + } + + return { + collapsed: attachment.collapsed, + color: attachment.color, + text: attachment.text, + timestamp: attachment.ts, + timestampLink: attachment.message_link, + thumbnailUrl: attachment.thumb_url, + author, + title, + imageUrl: attachment.image_url, + audioUrl: attachment.audio_url, + videoUrl: attachment.video_url, + fields: attachment.fields + }; + }); + } } diff --git a/packages/rocketchat-rocketlets/server/orchestrator.js b/packages/rocketchat-rocketlets/server/orchestrator.js index c9a79eb7af14..42a4b2f6f1b3 100644 --- a/packages/rocketchat-rocketlets/server/orchestrator.js +++ b/packages/rocketchat-rocketlets/server/orchestrator.js @@ -64,6 +64,6 @@ Meteor.startup(function _rocketletServerOrchestrator() { global.Rocketlets = new RocketletServerOrchestrator(); global.Rocketlets.getManager().load() - .then(() => console.log('...done! ;)')) + .then(() => console.log('...done! :)')) .catch((err) => console.warn('...failed!', err)); }); From a74db27644b9490bd8c2071d36bc264f2a9601b4 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Fri, 8 Sep 2017 10:44:39 -0500 Subject: [PATCH 08/42] Implement more logic on the rocketlet bridges --- .../server/lib/sendNotificationsOnMessage.js | 2 +- .../client/communication/websockets.js | 1 + packages/rocketchat-rocketlets/package.js | 5 +-- .../server/bridges/commands.js | 18 ++++++++++ .../server/bridges/environmental.js | 18 ++++++++-- .../server/bridges/http.js | 2 +- .../server/bridges/messages.js | 17 +++++++++ .../server/bridges/rooms.js | 12 +++++++ .../server/bridges/settings.js | 22 ++++++++++-- .../server/communication/websockets.js | 4 +++ .../server/converters/settings.js | 36 ++++++++++++++++++- 11 files changed, 127 insertions(+), 10 deletions(-) diff --git a/packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js b/packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js index ddda8b880de7..01929f3aaa77 100644 --- a/packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js +++ b/packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js @@ -31,7 +31,7 @@ function parseMessageText(message, userId) { const user = RocketChat.models.Users.findOneById(userId); const lng = user && user.language || RocketChat.settings.get('language') || 'en'; - if (!message.msg && message.attachments && message.attachments[0]) { + if (!message.msg && Array.isArray(message.attachments) && message.attachments[0]) { message.msg = message.attachments[0].image_type ? TAPi18n.__('User_uploaded_image', {lng}) : TAPi18n.__('User_uploaded_file', {lng}); } message.msg = RocketChat.callbacks.run('beforeNotifyUser', message.msg); diff --git a/packages/rocketchat-rocketlets/client/communication/websockets.js b/packages/rocketchat-rocketlets/client/communication/websockets.js index d661600d5acf..5288636a3d06 100644 --- a/packages/rocketchat-rocketlets/client/communication/websockets.js +++ b/packages/rocketchat-rocketlets/client/communication/websockets.js @@ -6,6 +6,7 @@ export class RocketletWebsocketReceiver { this.streamer.on('command/added', this.onCommandAdded.bind(this)); this.streamer.on('command/disabled', this.onCommandDisabled.bind(this)); this.streamer.on('command/updated', this.onCommandUpdated.bind(this)); + this.streamer.on('command/removed', this.onCommandDisabled.bind(this)); } onCommandAdded(command) { diff --git a/packages/rocketchat-rocketlets/package.js b/packages/rocketchat-rocketlets/package.js index c1db788185ed..0071297ed1a1 100644 --- a/packages/rocketchat-rocketlets/package.js +++ b/packages/rocketchat-rocketlets/package.js @@ -70,11 +70,12 @@ Package.onUse(function(api) { // Client orchestrator api.addFiles('client/orchestrator.js', 'client'); + // Add what this package actually does export api.export('Rocketlets'); }); Npm.depends({ 'busboy': '0.2.13', - 'temporary-rocketlets-server': '0.1.22', - 'temporary-rocketlets-ts-definition': '0.6.24' + 'temporary-rocketlets-server': '0.1.23', + 'temporary-rocketlets-ts-definition': '0.6.25' }); diff --git a/packages/rocketchat-rocketlets/server/bridges/commands.js b/packages/rocketchat-rocketlets/server/bridges/commands.js index 5a15730ed1d3..d1a6728e4af4 100644 --- a/packages/rocketchat-rocketlets/server/bridges/commands.js +++ b/packages/rocketchat-rocketlets/server/bridges/commands.js @@ -70,6 +70,24 @@ export class RocketletCommandsBridge { this.orch.getNotifier().commandAdded(command.command.toLowerCase()); } + unregisterCommand(command, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is unregistering the command: "${ command }"`); + + if (typeof command !== 'string' || command.trim().length === 0) { + throw new Error('Invalid command parameter provided, must be a string.'); + } + + const cmd = command.toLowerCase(); + if (typeof RocketChat.slashCommands.commands[cmd] === 'undefined' || !this.disabledCommands.has(cmd)) { + throw new Error(`Command does not exist in the system currently: ${ cmd }`); + } + + this.disabledCommands.delete(cmd); + delete RocketChat.slashCommands.commands[cmd]; + + this.orch.getNotifier().commandRemoved(cmd); + } + _verifyCommand(command) { if (typeof command !== 'object') { throw new Error('Invalid Slash Command parameter provided, it must be a valid ISlashCommand object.'); diff --git a/packages/rocketchat-rocketlets/server/bridges/environmental.js b/packages/rocketchat-rocketlets/server/bridges/environmental.js index 9b4188e75a85..19b6d34bd490 100644 --- a/packages/rocketchat-rocketlets/server/bridges/environmental.js +++ b/packages/rocketchat-rocketlets/server/bridges/environmental.js @@ -1,20 +1,32 @@ export class RocketletEnvironmentalVariableBridge { constructor(orch) { this.orch = orch; + this.allowed = ['NODE_ENV', 'ROOT_URL', 'INSTANCE_IP']; } getValueByName(envVarName, rocketletId) { console.log(`The Rocketlet ${ rocketletId } is getting the environmental variable value ${ envVarName }.`); - throw new Error('Method not implemented.'); + + if (this.isReadable(envVarName, rocketletId)) { + return process.env[envVarName]; + } + + throw new Error(`The environmental variable "${ envVarName }" is not readable.`); } isReadable(envVarName, rocketletId) { console.log(`The Rocketlet ${ rocketletId } is checking if the environmental variable is readable ${ envVarName }.`); - throw new Error('Method not implemented.'); + + return this.allowed.includes(envVarName.toUpperCase()); } isSet(envVarName, rocketletId) { console.log(`The Rocketlet ${ rocketletId } is checking if the environmental variable is set ${ envVarName }.`); - throw new Error('Method not implemented.'); + + if (this.isReadable(envVarName, rocketletId)) { + return typeof process.env[envVarName] !== 'undefined'; + } + + throw new Error(`The environmental variable "${ envVarName }" is not readable.`); } } diff --git a/packages/rocketchat-rocketlets/server/bridges/http.js b/packages/rocketchat-rocketlets/server/bridges/http.js index a8bd452765ca..3622f4603924 100644 --- a/packages/rocketchat-rocketlets/server/bridges/http.js +++ b/packages/rocketchat-rocketlets/server/bridges/http.js @@ -7,7 +7,7 @@ export class RocketletHttpBridge { console.log(`The Rocketlet ${ info.rocketletId } is requesting from the outter webs:`, info); const result = HTTP.call(info.method, info.url, info.request); - console.log('The result is:', result); + // TODO: Maybe modify the resulting object? :thinking: return result; } diff --git a/packages/rocketchat-rocketlets/server/bridges/messages.js b/packages/rocketchat-rocketlets/server/bridges/messages.js index 84ea8104d7be..63269f3b67a1 100644 --- a/packages/rocketchat-rocketlets/server/bridges/messages.js +++ b/packages/rocketchat-rocketlets/server/bridges/messages.js @@ -20,4 +20,21 @@ export class RocketletMessageBridge { return this.orch.getConverters().get('messages').convertById(messageId); } + + update(message, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is updating a message.`); + + if (!message.editor) { + throw new Error('Invalid editor assigned to the message for the update.'); + } + + if (!message.id || !RocketChat.models.Messages.findOneById(message.id)) { + throw new Error('A message must exist to update.'); + } + + const msg = this.orch.getConverters().get('messages').convertRocketletMessage(message); + const editor = RocketChat.models.Users.findOneById(message.editor.id); + + RocketChat.updateMessage(msg, editor); + } } diff --git a/packages/rocketchat-rocketlets/server/bridges/rooms.js b/packages/rocketchat-rocketlets/server/bridges/rooms.js index c6e8db60ae0f..11108c7d7b55 100644 --- a/packages/rocketchat-rocketlets/server/bridges/rooms.js +++ b/packages/rocketchat-rocketlets/server/bridges/rooms.js @@ -42,4 +42,16 @@ export class RocketletRoomBridge { return this.orch.getConverters().get('rooms').convertByName(roomName); } + + update(room, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is updating a room.`); + + if (!room.id || RocketChat.models.Rooms.findOneById(room.id)) { + throw new Error('A room must exist to update.'); + } + + const rm = this.orch.getConverters().get('rooms').convertRocketletRoom(room); + + RocketChat.models.Rooms.update(rm._id, rm); + } } diff --git a/packages/rocketchat-rocketlets/server/bridges/settings.js b/packages/rocketchat-rocketlets/server/bridges/settings.js index c997bc7f5746..25ea83df39f0 100644 --- a/packages/rocketchat-rocketlets/server/bridges/settings.js +++ b/packages/rocketchat-rocketlets/server/bridges/settings.js @@ -1,6 +1,8 @@ export class RocketletSettingBridge { constructor(orch) { this.orch = orch; + this.allowedGroups = []; + this.allowedSettings = []; } getAll(rocketletId) { @@ -10,7 +12,12 @@ export class RocketletSettingBridge { getOneById(id, rocketletId) { console.log(`The Rocketlet ${ rocketletId } is getting the setting by id ${ id }.`); - throw new Error('Method not implemented.'); + + if (!this.isReadableById(id, rocketletId)) { + throw new Error(`The setting "${ id }" is not readable.`); + } + + return this.orch.getConverters().get('settings').convertById(id); } hideGroup(name, rocketletId) { @@ -20,16 +27,27 @@ export class RocketletSettingBridge { hideSetting(id, rocketletId) { console.log(`The Rocketlet ${ rocketletId } is hidding the setting ${ id }.`); + + if (!this.isReadableById(id, rocketletId)) { + throw new Error(`The setting "${ id }" is not readable.`); + } + throw new Error('Method not implemented.'); } isReadableById(id, rocketletId) { console.log(`The Rocketlet ${ rocketletId } is checking if they can read the setting ${ id }.`); - throw new Error('Method not implemented.'); + + return this.allowedSettings.includes(id); } updateOne(setting, rocketletId) { console.log(`The Rocketlet ${ rocketletId } is updating the setting ${ setting.id } .`); + + if (!this.isReadableById(setting.id, rocketletId)) { + throw new Error(`The setting "${ setting.id }" is not readable.`); + } + throw new Error('Method not implemented.'); } } diff --git a/packages/rocketchat-rocketlets/server/communication/websockets.js b/packages/rocketchat-rocketlets/server/communication/websockets.js index d92da25cae44..5c706c2fb3d0 100644 --- a/packages/rocketchat-rocketlets/server/communication/websockets.js +++ b/packages/rocketchat-rocketlets/server/communication/websockets.js @@ -29,4 +29,8 @@ export class RocketletWebsocketNotifier { commandUpdated(command) { this.streamer.emit('command/updated', command); } + + commandRemoved(command) { + this.streamer.emit('command/removed', command); + } } diff --git a/packages/rocketchat-rocketlets/server/converters/settings.js b/packages/rocketchat-rocketlets/server/converters/settings.js index eec1f01984f2..edce911c6cf5 100644 --- a/packages/rocketchat-rocketlets/server/converters/settings.js +++ b/packages/rocketchat-rocketlets/server/converters/settings.js @@ -1,3 +1,5 @@ +import { SettingType } from 'temporary-rocketlets-ts-definition/settings'; + export class RocketletSettingsConverter { constructor(orch) { this.orch = orch; @@ -7,7 +9,39 @@ export class RocketletSettingsConverter { const setting = RocketChat.models.Settings.findOneById(settingId); return { - id: setting._id + id: setting._id, + type: this._convertTypeToRocketlet(setting.type), + packageValue: setting.packageValue, + values: setting.values, + value: setting.value, + public: setting.public, + hidden: setting.hidden, + group: setting.group, + i18nLabel: setting.i18nLabel, + i18nDescription: setting.i18nDescription, + createdAt: setting.ts, + updatedAt: setting._updatedAt }; } + + _convertTypeToRocketlet(type) { + switch (type) { + case 'boolean': + return SettingType.BOOLEAN; + case 'code': + return SettingType.CODE; + case 'color': + return SettingType.COLOR; + case 'font': + return SettingType.FONT; + case 'int': + return SettingType.NUMBER; + case 'select': + return SettingType.SELECT; + case 'string': + return SettingType.STRING; + default: + return type; + } + } } From 8ddb0905263a2d0bce433207427273254a1dcec3 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Mon, 11 Sep 2017 16:02:30 -0500 Subject: [PATCH 09/42] i18n is now provided via the rocketlets and load them when a rocketlet is added --- packages/rocketchat-api/server/api.js | 9 +++++ .../.npm/package/npm-shrinkwrap.json | 10 +++--- .../client/lib/startup/commands.js | 26 ++++++++------ .../assets/stylesheets/rocketlets.css | 0 .../client/admin/rocketlets.html | 6 +++- .../client/admin/rocketlets.js | 21 ++++++++++- .../client/communication/websockets.js | 7 ++++ .../client/orchestrator.js | 23 ++++++++++++ packages/rocketchat-rocketlets/package.js | 7 ++-- .../server/bridges/activation.js | 35 +++++++++++++++++++ .../server/bridges/bridges.js | 7 ++++ .../server/bridges/index.js | 2 ++ .../server/bridges/settings.js | 23 ++++++++++-- .../server/communication/rest.js | 25 +++++++++++-- .../server/converters/settings.js | 4 +++ 15 files changed, 180 insertions(+), 25 deletions(-) create mode 100644 packages/rocketchat-rocketlets/assets/stylesheets/rocketlets.css create mode 100644 packages/rocketchat-rocketlets/server/bridges/activation.js diff --git a/packages/rocketchat-api/server/api.js b/packages/rocketchat-api/server/api.js index c7816e0afade..d53bd9b6e63e 100644 --- a/packages/rocketchat-api/server/api.js +++ b/packages/rocketchat-api/server/api.js @@ -66,6 +66,15 @@ class API extends Restivus { }; } + notFound(msg) { + return { + statusCode: 404, + body: { + success: false, + error: msg ? msg : 'Resource not found' + } + }; + } unauthorized(msg) { return { diff --git a/packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json index 788d7c87977a..00561635dcdb 100644 --- a/packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json +++ b/packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json @@ -1085,13 +1085,13 @@ "from": "mime@>=1.2.11 <2.0.0" }, "mime-db": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz", - "from": "mime-db@>=1.29.0 <1.30.0" + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "from": "mime-db@>=1.30.0 <1.31.0" }, "mime-types": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", "from": "mime-types@>=2.0.8 <3.0.0" }, "minimatch": { diff --git a/packages/rocketchat-lib/client/lib/startup/commands.js b/packages/rocketchat-lib/client/lib/startup/commands.js index 01d97477c1fa..91456a9eed65 100644 --- a/packages/rocketchat-lib/client/lib/startup/commands.js +++ b/packages/rocketchat-lib/client/lib/startup/commands.js @@ -1,11 +1,17 @@ -Meteor.startup(function _loadDynamicallyDefinedCommands() { - // The reason there is a 500 millisecond delay is so that we are - // a little "easier" on the server during start up - setTimeout(() => { - RocketChat.API.v1.get('commands.list').then(function _loadedCommands(result) { - result.commands.forEach((command) => { - RocketChat.slashCommands.commands[command.command] = command; +//Track logins and when they login, get the commands +(() => { + let oldUserId = null; + + Meteor.autorun(() => { + const newUserId = Meteor.userId(); + if (oldUserId === null && newUserId) { + RocketChat.API.v1.get('commands.list').then(function _loadedCommands(result) { + result.commands.forEach((command) => { + RocketChat.slashCommands.commands[command.command] = command; + }); }); - }); - }, 500); -}); + } + + oldUserId = Meteor.userId(); + }); +})(); diff --git a/packages/rocketchat-rocketlets/assets/stylesheets/rocketlets.css b/packages/rocketchat-rocketlets/assets/stylesheets/rocketlets.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/rocketchat-rocketlets/client/admin/rocketlets.html b/packages/rocketchat-rocketlets/client/admin/rocketlets.html index 62c73ba09a99..74fbb58e9f44 100644 --- a/packages/rocketchat-rocketlets/client/admin/rocketlets.html +++ b/packages/rocketchat-rocketlets/client/admin/rocketlets.html @@ -9,7 +9,11 @@

{{#requiresPermission 'manage-rocketlets'}} -

Hello

+ {{#each rocketlets}} + + {{/each}} {{/requiresPermission}}
diff --git a/packages/rocketchat-rocketlets/client/admin/rocketlets.js b/packages/rocketchat-rocketlets/client/admin/rocketlets.js index bf10e3895b27..a869c96ec1c8 100644 --- a/packages/rocketchat-rocketlets/client/admin/rocketlets.js +++ b/packages/rocketchat-rocketlets/client/admin/rocketlets.js @@ -1,3 +1,22 @@ Template.rocketlets.onCreated(function() { - console.log('hello'); + const instance = this; + this.ready = new ReactiveVar(false); + this.rocketlets = new ReactiveVar([]); + + RocketChat.API.get('rocketlets').then((result) => { + instance.rocketlets.set(result.rocketlets); + }); +}); + +Template.rocketlets.helpers({ + isReady() { + if (Template.instance().ready != null) { + return Template.instance().ready.get(); + } + + return false; + }, + rocketlets() { + return Template.instance().rocketlets.get(); + } }); diff --git a/packages/rocketchat-rocketlets/client/communication/websockets.js b/packages/rocketchat-rocketlets/client/communication/websockets.js index 5288636a3d06..b7aef6dc1dfc 100644 --- a/packages/rocketchat-rocketlets/client/communication/websockets.js +++ b/packages/rocketchat-rocketlets/client/communication/websockets.js @@ -3,12 +3,19 @@ export class RocketletWebsocketReceiver { this.orch = orch; this.streamer = new Meteor.Streamer('rocketlets'); + this.streamer.on('rocketlet/added', this.onRocketletAdded.bind(this)); this.streamer.on('command/added', this.onCommandAdded.bind(this)); this.streamer.on('command/disabled', this.onCommandDisabled.bind(this)); this.streamer.on('command/updated', this.onCommandUpdated.bind(this)); this.streamer.on('command/removed', this.onCommandDisabled.bind(this)); } + onRocketletAdded(rocketletId) { + RocketChat.API.get(`rocketlets/${ rocketletId }`).then((result) => { + this.orch.parseAndLoadLanguages(result.rocketlet.languages); + }); + } + onCommandAdded(command) { RocketChat.API.v1.get('commands.getOne', { command }).then((result) => { RocketChat.slashCommands.commands[command] = result.command; diff --git a/packages/rocketchat-rocketlets/client/orchestrator.js b/packages/rocketchat-rocketlets/client/orchestrator.js index 4bedcc9e56b0..d2ff6dd02113 100644 --- a/packages/rocketchat-rocketlets/client/orchestrator.js +++ b/packages/rocketchat-rocketlets/client/orchestrator.js @@ -5,6 +5,7 @@ class RocketletClientOrchestrator { this.ws = new RocketletWebsocketReceiver(this); this._addAdminMenuOption(); + setTimeout(() => this._loadLanguages(), 500); } getWsListener() { @@ -20,6 +21,28 @@ class RocketletClientOrchestrator { } }); } + + _loadLanguages() { + if (!Meteor.user()) { + return; + } + + RocketChat.API.get('rocketlets?languagesOnly=true').then((info) => { + info.rocketlets.forEach((rlInfo) => this.parseAndLoadLanguages(rlInfo.languages)); + }); + } + + parseAndLoadLanguages(languages) { + Object.keys(languages).forEach((key) => { + try { + const json = JSON.parse(languages[key]); + + TAPi18next.addResourceBundle(key, 'project', json); + } catch (e) { + // Failed to parse the json + } + }); + } } Meteor.startup(function _rlClientOrch() { diff --git a/packages/rocketchat-rocketlets/package.js b/packages/rocketchat-rocketlets/package.js index 0071297ed1a1..5ea4ba27e3e2 100644 --- a/packages/rocketchat-rocketlets/package.js +++ b/packages/rocketchat-rocketlets/package.js @@ -25,6 +25,7 @@ Package.onUse(function(api) { // Bridges api.addFiles([ + 'server/bridges/activation.js', 'server/bridges/bridges.js', 'server/bridges/commands.js', 'server/bridges/environmental.js', @@ -67,6 +68,8 @@ Package.onUse(function(api) { 'client/admin/rocketlets.js' ], 'client'); + api.addFiles('assets/stylesheets/rocketlets.css', 'client'); + // Client orchestrator api.addFiles('client/orchestrator.js', 'client'); @@ -76,6 +79,6 @@ Package.onUse(function(api) { Npm.depends({ 'busboy': '0.2.13', - 'temporary-rocketlets-server': '0.1.23', - 'temporary-rocketlets-ts-definition': '0.6.25' + 'temporary-rocketlets-server': '0.1.26', + 'temporary-rocketlets-ts-definition': '0.6.26' }); diff --git a/packages/rocketchat-rocketlets/server/bridges/activation.js b/packages/rocketchat-rocketlets/server/bridges/activation.js new file mode 100644 index 000000000000..6833622fbece --- /dev/null +++ b/packages/rocketchat-rocketlets/server/bridges/activation.js @@ -0,0 +1,35 @@ +export class RocketletActivationBridge { + constructor(orch) { + this.orch = orch; + } + + rocketletEnabled(rocketlet) { + console.log(`The Rocketlet ${ rocketlet.getName() } (${ rocketlet.getID() }) has been enabled.`); + } + + rocketletDisabled(rocketlet) { + console.log(`The Rocketlet ${ rocketlet.getName() } (${ rocketlet.getID() }) has been disabled.`); + } + + rocketletLoaded(rocketlet, enabled) { + console.log(`The Rocketlet ${ rocketlet.getName() } (${ rocketlet.getID() }) has been loaded and enabled? ${ enabled }`); + + if (enabled) { + this.orch.getNotifier().rocketletAdded(rocketlet.getID()); + } + } + + rocketletUpdated(rocketlet, enabled) { + console.log(`The Rocketlet ${ rocketlet.getName() } (${ rocketlet.getID() }) has been updated and enabled? ${ enabled }`); + + if (enabled) { + this.orch.getNotifier().rocketletUpdated(rocketlet.getID()); + } + } + + rocketletRemoved(rocketlet) { + console.log(`The Rocketlet ${ rocketlet.getName() } (${ rocketlet.getID() }) has been removed.`); + + this.orch.getNotifier().rocketletRemoved(rocketlet.getID()); + } +} diff --git a/packages/rocketchat-rocketlets/server/bridges/bridges.js b/packages/rocketchat-rocketlets/server/bridges/bridges.js index 07f5d182a9dc..3afa40d44a97 100644 --- a/packages/rocketchat-rocketlets/server/bridges/bridges.js +++ b/packages/rocketchat-rocketlets/server/bridges/bridges.js @@ -1,4 +1,6 @@ import { RocketletBridges } from 'temporary-rocketlets-server/server/bridges'; + +import { RocketletActivationBridge } from './activation'; import { RocketletCommandsBridge } from './commands'; import { RocketletEnvironmentalVariableBridge } from './environmental'; import { RocketletHttpBridge } from './http'; @@ -12,6 +14,7 @@ export class RealRocketletBridges extends RocketletBridges { constructor(orch) { super(); + this._actBridge = new RocketletActivationBridge(orch); this._cmdBridge = new RocketletCommandsBridge(orch); this._envBridge = new RocketletEnvironmentalVariableBridge(orch); this._httpBridge = new RocketletHttpBridge(); @@ -42,6 +45,10 @@ export class RealRocketletBridges extends RocketletBridges { return this._persistBridge; } + getRocketletActivationBridge() { + return this._actBridge; + } + getRoomBridge() { return this._roomBridge; } diff --git a/packages/rocketchat-rocketlets/server/bridges/index.js b/packages/rocketchat-rocketlets/server/bridges/index.js index 6f6662360c7b..f464cffcb328 100644 --- a/packages/rocketchat-rocketlets/server/bridges/index.js +++ b/packages/rocketchat-rocketlets/server/bridges/index.js @@ -1,4 +1,5 @@ import { RealRocketletBridges } from './bridges'; +import { RocketletActivationBridge } from './activation'; import { RocketletCommandsBridge } from './commands'; import { RocketletEnvironmentalVariableBridge } from './environmental'; import { RocketletHttpBridge } from './http'; @@ -10,6 +11,7 @@ import { RocketletUserBridge } from './users'; export { RealRocketletBridges, + RocketletActivationBridge, RocketletCommandsBridge, RocketletEnvironmentalVariableBridge, RocketletHttpBridge, diff --git a/packages/rocketchat-rocketlets/server/bridges/settings.js b/packages/rocketchat-rocketlets/server/bridges/settings.js index 25ea83df39f0..0971e0cb9e21 100644 --- a/packages/rocketchat-rocketlets/server/bridges/settings.js +++ b/packages/rocketchat-rocketlets/server/bridges/settings.js @@ -2,12 +2,29 @@ export class RocketletSettingBridge { constructor(orch) { this.orch = orch; this.allowedGroups = []; - this.allowedSettings = []; + this.disallowedSettings = [ + 'Accounts_RegistrationForm_SecretURL', 'CROWD_APP_USERNAME', 'CROWD_APP_PASSWORD', 'Direct_Reply_Username', + 'Direct_Reply_Password', 'SMTP_Username', 'SMTP_Password', 'FileUpload_S3_AWSAccessKeyId', 'FileUpload_S3_AWSSecretAccessKey', + 'FileUpload_S3_BucketURL', 'FileUpload_GoogleStorage_Bucket', 'FileUpload_GoogleStorage_AccessId', + 'FileUpload_GoogleStorage_Secret', 'GoogleVision_ServiceAccount', 'Allow_Invalid_SelfSigned_Certs', 'GoogleTagManager_id', + 'Bugsnag_api_key', 'LDAP_CA_Cert', 'LDAP_Reject_Unauthorized', 'LDAP_Domain_Search_User', 'LDAP_Domain_Search_Password', + 'Livechat_secret_token', 'Livechat_Knowledge_Apiai_Key', 'AutoTranslate_GoogleAPIKey', 'MapView_GMapsAPIKey', + 'Meta_fb_app_id', 'Meta_google-site-verification', 'Meta_msvalidate01', 'Accounts_OAuth_Dolphin_secret', + 'Accounts_OAuth_Drupal_secret', 'Accounts_OAuth_Facebook_secret', 'Accounts_OAuth_Github_secret', 'API_GitHub_Enterprise_URL', + 'Accounts_OAuth_GitHub_Enterprise_secret', 'API_Gitlab_URL', 'Accounts_OAuth_Gitlab_secret', 'Accounts_OAuth_Google_secret', + 'Accounts_OAuth_Linkedin_secret', 'Accounts_OAuth_Meteor_secret', 'Accounts_OAuth_Twitter_secret', 'API_Wordpress_URL', + 'Accounts_OAuth_Wordpress_secret', 'Push_apn_passphrase', 'Push_apn_key', 'Push_apn_cert', 'Push_apn_dev_passphrase', + 'Push_apn_dev_key', 'Push_apn_dev_cert', 'Push_gcm_api_key', 'Push_gcm_project_number', 'SAML_Custom_Default_cert', + 'SAML_Custom_Default_private_key', 'SlackBridge_APIToken', 'Smarsh_Email', 'SMS_Twilio_Account_SID', 'SMS_Twilio_authToken' + ]; } getAll(rocketletId) { console.log(`The Rocketlet ${ rocketletId } is getting all the settings.`); - throw new Error('Method not implemented.'); + + return RocketChat.models.Settings.find({ _id: { $nin: this.disallowedSettings } }).fetch().map((s) => { + this.orch.getConverters().get('settings').convertToRocketlet(s); + }); } getOneById(id, rocketletId) { @@ -38,7 +55,7 @@ export class RocketletSettingBridge { isReadableById(id, rocketletId) { console.log(`The Rocketlet ${ rocketletId } is checking if they can read the setting ${ id }.`); - return this.allowedSettings.includes(id); + return !this.disallowedSettings.includes(id); } updateOne(setting, rocketletId) { diff --git a/packages/rocketchat-rocketlets/server/communication/rest.js b/packages/rocketchat-rocketlets/server/communication/rest.js index 0b6bc5153796..50aff66c52b9 100644 --- a/packages/rocketchat-rocketlets/server/communication/rest.js +++ b/packages/rocketchat-rocketlets/server/communication/rest.js @@ -40,7 +40,19 @@ export class RocketletsRestApi { this.api.addRoute('', { authRequired: true }, { get() { - const rocketlets = manager.get().map(prl => prl.getInfo()); + const rocketlets = manager.get().map(prl => { + if (this.queryParams.languagesOnly) { + return { + id: prl.getID(), + languages: prl.getStorageItem().languageFiles + }; + } else { + const info = prl.getInfo(); + info.languages = prl.getStorageItem().languageFiles; + + return info; + } + }); return { success: true, rocketlets }; }, @@ -60,9 +72,16 @@ export class RocketletsRestApi { this.api.addRoute(':id', { authRequired: true }, { get() { console.log('Getting:', this.urlParams.id); - const rocketlet = manager.getOneById(this.urlParams.id).getInfo(); + const prl = manager.getOneById(this.urlParams.id); - return { success: true, rocketlet }; + if (prl) { + const info = prl.getInfo(); + info.languages = prl.getStorageItem().languageFiles; + + return { success: true, rocketlet: info }; + } else { + return RocketChat.API.v1.notFound(`No Rocketlet found by the id of: ${ this.urlParams.id }`); + } }, post() { console.log('Updating:', this.urlParams.id); diff --git a/packages/rocketchat-rocketlets/server/converters/settings.js b/packages/rocketchat-rocketlets/server/converters/settings.js index edce911c6cf5..f6a6d3dabdda 100644 --- a/packages/rocketchat-rocketlets/server/converters/settings.js +++ b/packages/rocketchat-rocketlets/server/converters/settings.js @@ -8,6 +8,10 @@ export class RocketletSettingsConverter { convertById(settingId) { const setting = RocketChat.models.Settings.findOneById(settingId); + return this.convertToRocketlet(setting); + } + + convertToRocketlet(setting) { return { id: setting._id, type: this._convertTypeToRocketlet(setting.type), From 361a645ed33a7f95cc917b200ebd5bc8a77bb97b Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Thu, 14 Sep 2017 11:54:59 -0500 Subject: [PATCH 10/42] Add a manage page and add the initial settings to be managed, needs more work --- packages/rocketchat-i18n/i18n/en.i18n.json | 7 + .../client/lib/RestApiClient.js | 6 +- .../assets/stylesheets/rocketlets.css | 4 + .../client/admin/rocketletManage.html | 230 ++++++++++++++++++ .../client/admin/rocketletManage.js | 111 +++++++++ .../client/admin/rocketlets.html | 2 +- .../client/admin/rocketlets.js | 12 + .../client/communication/websockets.js | 4 +- .../client/orchestrator.js | 15 +- packages/rocketchat-rocketlets/package.js | 10 +- .../server/communication/rest.js | 106 +++++++- .../server/orchestrator.js | 2 +- 12 files changed, 498 insertions(+), 11 deletions(-) create mode 100644 packages/rocketchat-rocketlets/client/admin/rocketletManage.html create mode 100644 packages/rocketchat-rocketlets/client/admin/rocketletManage.js diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 19b5d6bbf61b..996f1c24dc84 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -227,6 +227,7 @@ "Audio_message": "Audio message", "Auth_Token": "Auth Token", "Author": "Author", + "Author_Information": "Author Information", "Authorization_URL": "Authorization URL", "Authorize": "Authorize", "Auto_Load_Images": "Auto Load Images", @@ -263,6 +264,7 @@ "Back_to_integrations": "Back to integrations", "Back_to_integration_detail": "Back to the integration detail", "Back_to_login": "Back to login", + "Back_to_Manage_Rocketlets": "Back to Manage Rocketlets", "Back_to_permissions": "Back to permissions", "Backup_codes": "Backup codes", "Beta_feature_Depends_on_Video_Conference_to_be_enabled": "Beta feature. Depends on Video Conference to be enabled.", @@ -1340,6 +1342,7 @@ "manage-sounds": "Manage Sounds", "manage-sounds_description": "Permission to manage the server sounds", "Manage_Rocketlets": "Manage Rocketlets", + "Manage_the_Rocketlet": "Manage the Rocketlet", "mention-all": "Mention All", "mention-all_description": "Permission to use the @all mention", "mute-user": "Mute User", @@ -1525,6 +1528,8 @@ "Restart_the_server": "Restart the server", "Retry_Count": "Retry Count", "Rocketlets": "Rocketlets", + "Rocketlet_Information": "Rocketlet Information", + "Rocketlets_Settings": "Rocketlet's Settings", "Role": "Role", "Role_Editing": "Role Editing", "Role_removed": "Role removed", @@ -1726,6 +1731,7 @@ "Success": "Success", "Success_message": "Success message", "Sunday": "Sunday", + "Support": "Support", "Survey": "Survey", "Survey_instructions": "Rate each question according to your satisfaction, 1 meaning you are completely unsatisfied and 5 meaning you are completely satisfied.", "Symbols": "Symbols", @@ -1960,6 +1966,7 @@ "WebRTC_Enable_Private": "Enable for Private Channels", "WebRTC_Servers": "STUN/TURN Servers", "WebRTC_Servers_Description": "A list of STUN and TURN servers separated by comma.
Username, password and port are allowed in the format `username:password@stun:host:port` or `username:password@turn:host:port`.", + "Website": "Website", "Wednesday": "Wednesday", "Welcome": "Welcome %s.", "Welcome_to_the": "Welcome to the", diff --git a/packages/rocketchat-lib/client/lib/RestApiClient.js b/packages/rocketchat-lib/client/lib/RestApiClient.js index ab353e69cb12..f19c49b84d66 100644 --- a/packages/rocketchat-lib/client/lib/RestApiClient.js +++ b/packages/rocketchat-lib/client/lib/RestApiClient.js @@ -3,6 +3,10 @@ RocketChat.API = { return RocketChat.API._jqueryCall('GET', endpoint, params); }, + post(endpoint, params, body) { + return RocketChat.API._jqueryCall('POST', endpoint, params, body); + }, + _jqueryCall(method, endpoint, params, body) { let query = ''; if (params) { @@ -22,7 +26,7 @@ RocketChat.API = { 'X-User-Id': localStorage['Meteor.userId'], 'X-Auth-Token': localStorage['Meteor.loginToken'] }, - data: body, + data: JSON.stringify(body), success: function _rlGetSuccess(result) { resolve(result); }, diff --git a/packages/rocketchat-rocketlets/assets/stylesheets/rocketlets.css b/packages/rocketchat-rocketlets/assets/stylesheets/rocketlets.css index e69de29bb2d1..09e0ffc6fb2d 100644 --- a/packages/rocketchat-rocketlets/assets/stylesheets/rocketlets.css +++ b/packages/rocketchat-rocketlets/assets/stylesheets/rocketlets.css @@ -0,0 +1,4 @@ +input.rocketlet-author-name { + width: auto !important; + display: inline-block !important; +} diff --git a/packages/rocketchat-rocketlets/client/admin/rocketletManage.html b/packages/rocketchat-rocketlets/client/admin/rocketletManage.html new file mode 100644 index 000000000000..608a4b5e836c --- /dev/null +++ b/packages/rocketchat-rocketlets/client/admin/rocketletManage.html @@ -0,0 +1,230 @@ + diff --git a/packages/rocketchat-rocketlets/client/admin/rocketletManage.js b/packages/rocketchat-rocketlets/client/admin/rocketletManage.js new file mode 100644 index 000000000000..4203dc91d588 --- /dev/null +++ b/packages/rocketchat-rocketlets/client/admin/rocketletManage.js @@ -0,0 +1,111 @@ +Template.rocketletManage.onCreated(function() { + const instance = this; + this.ready = new ReactiveVar(false); + this.rocketlet = new ReactiveVar({}); + this.settings = new ReactiveVar({}); + + const id = FlowRouter.getParam('rocketletId'); + + console.log(id); + + const got = { info: false, settings: false }; + + RocketChat.API.get(`rocketlets/${ id }`).then((result) => { + instance.rocketlet.set(result.rocketlet); + console.log(result.rocketlet); + + got.info = true; + if (got.info && got.settings) { + this.ready.set(true); + } + }); + + RocketChat.API.get(`rocketlets/${ id }/settings`).then((result) => { + Object.keys(result.settings).forEach((k) => { + result.settings[k].oldValue = result.settings[k].value; + }); + + instance.settings.set(result.settings); + console.log(instance.settings.get()); + + got.settings = true; + if (got.info && got.settings) { + this.ready.set(true); + } + }); +}); + +Template.rocketletManage.helpers({ + isReady() { + if (Template.instance().ready != null) { + return Template.instance().ready.get(); + } + + return false; + }, + rocketlet() { + return Template.instance().rocketlet.get(); + }, + settings() { + return Object.values(Template.instance().settings.get()); + }, + parseDescription(i18nDescription) { + const item = RocketChat.Markdown.parseNotEscaped({ html: t(i18nDescription) }); + + item.tokens.forEach((t) => item.html = item.html.replace(t.token, t.text)); + + return item.html; + } +}); + +Template.rocketletManage.events({ + 'click .expand': (e) => { + $(e.currentTarget).closest('.section').removeClass('section-collapsed'); + $(e.currentTarget).closest('button').removeClass('expand').addClass('collapse').find('span').text(TAPi18n.__('Collapse')); + $('.CodeMirror').each((index, codeMirror) => codeMirror.CodeMirror.refresh()); + }, + + 'click .collapse': (e) => { + $(e.currentTarget).closest('.section').addClass('section-collapsed'); + $(e.currentTarget).closest('button').addClass('expand').removeClass('collapse').find('span').text(TAPi18n.__('Expand')); + }, + + 'click .save': (e, t) => { + const toSave = []; + + Object.keys(t.settings.get()).forEach((k) => { + const setting = t.settings.get()[k]; + if (setting.hasChanged) { + toSave.push(setting); + } + }); + + if (toSave.length === 0) { + console.log('Nothing to save..'); + return; + } + + const rocketletId = FlowRouter.getParam('rocketletId'); + RocketChat.API.post(`rocketlets/${ rocketletId }/settings`, undefined, { settings: toSave }).then((result) => { + console.log('Updating results:', result); + }); + }, + + 'change .input-monitor, keyup .input-monitor': _.throttle(function(e, t) { + let value = _.trim($(e.target).val()); + switch (this.type) { + case 'int': + value = parseInt(value); + break; + case 'boolean': + value = value === '1'; + } + + const setting = t.settings.get()[this.id]; + setting.value = value; + + if (setting.oldValue !== setting.value) { + t.settings.get()[this.id].hasChanged = true; + } + }, 500) +}); diff --git a/packages/rocketchat-rocketlets/client/admin/rocketlets.html b/packages/rocketchat-rocketlets/client/admin/rocketlets.html index 74fbb58e9f44..29be20cdabed 100644 --- a/packages/rocketchat-rocketlets/client/admin/rocketlets.html +++ b/packages/rocketchat-rocketlets/client/admin/rocketlets.html @@ -11,7 +11,7 @@

{{#requiresPermission 'manage-rocketlets'}} {{#each rocketlets}} {{/each}} {{/requiresPermission}} diff --git a/packages/rocketchat-rocketlets/client/admin/rocketlets.js b/packages/rocketchat-rocketlets/client/admin/rocketlets.js index a869c96ec1c8..1aabdf0d8bb1 100644 --- a/packages/rocketchat-rocketlets/client/admin/rocketlets.js +++ b/packages/rocketchat-rocketlets/client/admin/rocketlets.js @@ -20,3 +20,15 @@ Template.rocketlets.helpers({ return Template.instance().rocketlets.get(); } }); + +Template.rocketlets.events({ + 'click .manage'() { + const rl = this; + + if (rl && rl.id) { + FlowRouter.go(`/admin/rocketlets/${ rl.id }`); + } else { + // show an error ? I don't think this should ever happen + } + } +}); diff --git a/packages/rocketchat-rocketlets/client/communication/websockets.js b/packages/rocketchat-rocketlets/client/communication/websockets.js index b7aef6dc1dfc..0cffd616287f 100644 --- a/packages/rocketchat-rocketlets/client/communication/websockets.js +++ b/packages/rocketchat-rocketlets/client/communication/websockets.js @@ -11,8 +11,8 @@ export class RocketletWebsocketReceiver { } onRocketletAdded(rocketletId) { - RocketChat.API.get(`rocketlets/${ rocketletId }`).then((result) => { - this.orch.parseAndLoadLanguages(result.rocketlet.languages); + RocketChat.API.get(`rocketlets/${ rocketletId }/languages`).then((result) => { + this.orch.parseAndLoadLanguages(result.languages); }); } diff --git a/packages/rocketchat-rocketlets/client/orchestrator.js b/packages/rocketchat-rocketlets/client/orchestrator.js index d2ff6dd02113..4c702c0fad2a 100644 --- a/packages/rocketchat-rocketlets/client/orchestrator.js +++ b/packages/rocketchat-rocketlets/client/orchestrator.js @@ -5,7 +5,13 @@ class RocketletClientOrchestrator { this.ws = new RocketletWebsocketReceiver(this); this._addAdminMenuOption(); - setTimeout(() => this._loadLanguages(), 500); + + const loadLangs = setInterval(() => { + if (Meteor.user()) { + clearInterval(loadLangs); + this._loadLanguages(); + } + }, 50); } getWsListener() { @@ -56,3 +62,10 @@ FlowRouter.route('/admin/rocketlets', { BlazeLayout.render('main', { center: 'rocketlets' }); } }); + +FlowRouter.route('/admin/rocketlets/:rocketletId', { + name: 'rocketlet-manage', + action() { + BlazeLayout.render('main', { center: 'rocketletManage' }); + } +}); diff --git a/packages/rocketchat-rocketlets/package.js b/packages/rocketchat-rocketlets/package.js index 5ea4ba27e3e2..46de00cdc6bd 100644 --- a/packages/rocketchat-rocketlets/package.js +++ b/packages/rocketchat-rocketlets/package.js @@ -11,7 +11,7 @@ Package.onUse(function(api) { 'templating' ]); - api.use(['reactive-var', 'kadira:flow-router'], 'client'); + api.use(['reactive-var', 'kadira:flow-router', 'underscore'], 'client'); api.addFiles('lib/Rocketlets.js', ['client', 'server']); @@ -65,7 +65,9 @@ Package.onUse(function(api) { // Client Admin Management api.addFiles([ 'client/admin/rocketlets.html', - 'client/admin/rocketlets.js' + 'client/admin/rocketlets.js', + 'client/admin/rocketletManage.html', + 'client/admin/rocketletManage.js' ], 'client'); api.addFiles('assets/stylesheets/rocketlets.css', 'client'); @@ -79,6 +81,6 @@ Package.onUse(function(api) { Npm.depends({ 'busboy': '0.2.13', - 'temporary-rocketlets-server': '0.1.26', - 'temporary-rocketlets-ts-definition': '0.6.26' + 'temporary-rocketlets-server': '0.1.27', + 'temporary-rocketlets-ts-definition': '0.6.27' }); diff --git a/packages/rocketchat-rocketlets/server/communication/rest.js b/packages/rocketchat-rocketlets/server/communication/rest.js index 50aff66c52b9..29efe7eed749 100644 --- a/packages/rocketchat-rocketlets/server/communication/rest.js +++ b/packages/rocketchat-rocketlets/server/communication/rest.js @@ -76,7 +76,6 @@ export class RocketletsRestApi { if (prl) { const info = prl.getInfo(); - info.languages = prl.getStorageItem().languageFiles; return { success: true, rocketlet: info }; } else { @@ -95,5 +94,110 @@ export class RocketletsRestApi { return { success: false, item }; } }); + + this.api.addRoute(':id/languages', { authRequired: true }, { + get() { + console.log(`Getting ${ this.urlParams.id }'s languages..`); + const prl = manager.getOneById(this.urlParams.id); + + if (prl) { + const languages = prl.getStorageItem().languageFiles || {}; + + return { success: true, languages }; + } else { + return RocketChat.API.v1.notFound(`No Rocketlet found by the id of: ${ this.urlParams.id }`); + } + } + }); + + this.api.addRoute(':id/settings', { authRequired: true }, { + get() { + console.log(`Getting ${ this.urlParams.id }'s settings..`); + const prl = manager.getOneById(this.urlParams.id); + + if (prl) { + const settings = Object.assign({}, prl.getStorageItem().settings); + + Object.keys(settings).forEach((k) => { + if (settings[k].hidden) { + delete settings[k]; + } + }); + + return { success: true, settings }; + } else { + return RocketChat.API.v1.notFound(`No Rocketlet found by the id of: ${ this.urlParams.id }`); + } + }, + post() { + console.log(`Updating ${ this.urlParams.id }'s settings..`); + if (!this.bodyParams || !this.bodyParams.settings) { + return RocketChat.API.v1.failure('The settings to update must be present.'); + } + + const prl = manager.getOneById(this.urlParams.id); + + if (!prl) { + return RocketChat.API.v1.notFound(`No Rocketlet found by the id of: ${ this.urlParams.id }`); + } + + const settings = prl.getStorageItem().settings; + + const updated = []; + this.bodyParams.settings.forEach((s) => { + if (settings[s.id]) { + Promise.await(manager.getSettingsManager().updateRocketletSetting(this.urlParams.id, s)); + // Updating? + updated.push(s); + } + }); + + return { success: true, updated }; + } + }); + + this.api.addRoute(':id/settings/:settingId', { authRequired: true }, { + get() { + console.log(`Getting the Rocketlet ${ this.urlParams.id }'s setting ${ this.urlParams.settingId }`); + + try { + const setting = manager.getSettingsManager().getRocketletSetting(this.urlParams.id, this.urlParams.settingId); + + return { + success: true, + setting + }; + } catch (e) { + if (e.message.includes('No setting found')) { + return RocketChat.API.v1.notFound(`No Setting found on the Rocketlet by the id of: "${ this.urlParams.settingId }"`); + } else if (e.message.includes('No Rocketlet found')) { + return RocketChat.API.v1.notFound(`No Rocketlet found by the id of: ${ this.urlParams.id }`); + } else { + return RocketChat.API.v1.failure(e.message); + } + } + }, + post() { + console.log(`Updating the Rocketlet ${ this.urlParams.id }'s setting ${ this.urlParams.settingId }`); + + if (!this.bodyParams.setting) { + return RocketChat.API.v1.failure('Setting to update to must be present on the posted body.'); + } + + try { + Promise.await(manager.getSettingsManager().updateRocketletSetting(this.urlParams.id, this.bodyParams.setting)); + + return { success: true }; + } catch (e) { + if (e.message.includes('No setting found')) { + return RocketChat.API.v1.notFound(`No Setting found on the Rocketlet by the id of: "${ this.urlParams.settingId }"`); + } else if (e.message.includes('No Rocketlet found')) { + return RocketChat.API.v1.notFound(`No Rocketlet found by the id of: ${ this.urlParams.id }`); + } else { + return RocketChat.API.v1.failure(e.message); + } + } + } + }); } } diff --git a/packages/rocketchat-rocketlets/server/orchestrator.js b/packages/rocketchat-rocketlets/server/orchestrator.js index 42a4b2f6f1b3..c9a79eb7af14 100644 --- a/packages/rocketchat-rocketlets/server/orchestrator.js +++ b/packages/rocketchat-rocketlets/server/orchestrator.js @@ -64,6 +64,6 @@ Meteor.startup(function _rocketletServerOrchestrator() { global.Rocketlets = new RocketletServerOrchestrator(); global.Rocketlets.getManager().load() - .then(() => console.log('...done! :)')) + .then(() => console.log('...done! ;)')) .catch((err) => console.warn('...failed!', err)); }); From 5d86782786ebac7727c49b3442792a60938efb91 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Fri, 15 Sep 2017 10:09:27 -0500 Subject: [PATCH 11/42] Update to the new internal translations structure --- .../rocketchat-rocketlets/client/admin/rocketletManage.js | 2 +- packages/rocketchat-rocketlets/client/orchestrator.js | 4 +--- packages/rocketchat-rocketlets/server/communication/rest.js | 6 +++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/rocketchat-rocketlets/client/admin/rocketletManage.js b/packages/rocketchat-rocketlets/client/admin/rocketletManage.js index 4203dc91d588..bc57b50e23ec 100644 --- a/packages/rocketchat-rocketlets/client/admin/rocketletManage.js +++ b/packages/rocketchat-rocketlets/client/admin/rocketletManage.js @@ -50,7 +50,7 @@ Template.rocketletManage.helpers({ return Object.values(Template.instance().settings.get()); }, parseDescription(i18nDescription) { - const item = RocketChat.Markdown.parseNotEscaped({ html: t(i18nDescription) }); + const item = RocketChat.Markdown.parseMessageNotEscaped({ html: t(i18nDescription) }); item.tokens.forEach((t) => item.html = item.html.replace(t.token, t.text)); diff --git a/packages/rocketchat-rocketlets/client/orchestrator.js b/packages/rocketchat-rocketlets/client/orchestrator.js index 4c702c0fad2a..611b4013d96c 100644 --- a/packages/rocketchat-rocketlets/client/orchestrator.js +++ b/packages/rocketchat-rocketlets/client/orchestrator.js @@ -41,9 +41,7 @@ class RocketletClientOrchestrator { parseAndLoadLanguages(languages) { Object.keys(languages).forEach((key) => { try { - const json = JSON.parse(languages[key]); - - TAPi18next.addResourceBundle(key, 'project', json); + TAPi18next.addResourceBundle(key, 'project', languages[key]); } catch (e) { // Failed to parse the json } diff --git a/packages/rocketchat-rocketlets/server/communication/rest.js b/packages/rocketchat-rocketlets/server/communication/rest.js index 29efe7eed749..6ce815a68102 100644 --- a/packages/rocketchat-rocketlets/server/communication/rest.js +++ b/packages/rocketchat-rocketlets/server/communication/rest.js @@ -44,11 +44,11 @@ export class RocketletsRestApi { if (this.queryParams.languagesOnly) { return { id: prl.getID(), - languages: prl.getStorageItem().languageFiles + languages: prl.getStorageItem().languageContent }; } else { const info = prl.getInfo(); - info.languages = prl.getStorageItem().languageFiles; + info.languages = prl.getStorageItem().languageContent; return info; } @@ -101,7 +101,7 @@ export class RocketletsRestApi { const prl = manager.getOneById(this.urlParams.id); if (prl) { - const languages = prl.getStorageItem().languageFiles || {}; + const languages = prl.getStorageItem().languageContent || {}; return { success: true, languages }; } else { From df42f903793fc43d57488e6e2dd281c83baf14d3 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Mon, 18 Sep 2017 12:21:46 -0500 Subject: [PATCH 12/42] Add the enable method for commands --- packages/rocketchat-rocketlets/package.js | 4 +-- .../server/bridges/commands.js | 29 +++++++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/packages/rocketchat-rocketlets/package.js b/packages/rocketchat-rocketlets/package.js index 46de00cdc6bd..3e8b874429a9 100644 --- a/packages/rocketchat-rocketlets/package.js +++ b/packages/rocketchat-rocketlets/package.js @@ -81,6 +81,6 @@ Package.onUse(function(api) { Npm.depends({ 'busboy': '0.2.13', - 'temporary-rocketlets-server': '0.1.27', - 'temporary-rocketlets-ts-definition': '0.6.27' + 'temporary-rocketlets-server': '0.1.29', + 'temporary-rocketlets-ts-definition': '0.6.29' }); diff --git a/packages/rocketchat-rocketlets/server/bridges/commands.js b/packages/rocketchat-rocketlets/server/bridges/commands.js index d1a6728e4af4..c5d6ba2a5ea7 100644 --- a/packages/rocketchat-rocketlets/server/bridges/commands.js +++ b/packages/rocketchat-rocketlets/server/bridges/commands.js @@ -9,11 +9,30 @@ export class RocketletCommandsBridge { doesCommandExist(command, rocketletId) { console.log(`The Rocketlet ${ rocketletId } is checking if "${ command }" command exists.`); - if (typeof command !== 'string') { + if (typeof command !== 'string' || command.length === 0) { return false; } - return typeof RocketChat.slashCommands.commands[command.toLowerCase()] === 'object'; + const cmd = command.toLowerCase(); + return typeof RocketChat.slashCommands.commands[cmd] === 'object' || this.disabledCommands.has(cmd); + } + + enableCommand(command, rocketletId) { + console.log(`The Rocketlet ${ rocketletId } is attempting to enable the command: "${ command }"`); + + if (typeof command !== 'string' || command.trim().length === 0) { + throw new Error('Invalid command parameter provided, must be a string.'); + } + + const cmd = command.toLowerCase(); + if (!this.disabledCommands.has(cmd)) { + throw new Error(`The command is not currently disabled: "${ cmd }"`); + } + + RocketChat.slashCommands.commands[cmd] = this.disabledCommands.get(cmd); + this.disabledCommands.delete(cmd); + + this.orch.getNotifier().commandUpdated(cmd); } disableCommand(command, rocketletId) { @@ -25,7 +44,7 @@ export class RocketletCommandsBridge { const cmd = command.toLowerCase(); if (typeof RocketChat.slashCommands.commands[cmd] === 'undefined') { - throw new Error(`Command does not exist in the system currently (or it is disabled): ${ cmd }`); + throw new Error(`Command does not exist in the system currently (or it is disabled): "${ cmd }"`); } this.disabledCommands.set(cmd, RocketChat.slashCommands.commands[cmd]); @@ -42,7 +61,7 @@ export class RocketletCommandsBridge { const cmd = command.toLowerCase(); if (typeof RocketChat.slashCommands.commands[cmd] === 'undefined') { - throw new Error(`Command does not exist in the system currently (or it is disabled): ${ cmd }`); + throw new Error(`Command does not exist in the system currently (or it is disabled): "${ cmd }"`); } const item = RocketChat.slashCommands.commands[cmd]; @@ -79,7 +98,7 @@ export class RocketletCommandsBridge { const cmd = command.toLowerCase(); if (typeof RocketChat.slashCommands.commands[cmd] === 'undefined' || !this.disabledCommands.has(cmd)) { - throw new Error(`Command does not exist in the system currently: ${ cmd }`); + throw new Error(`Command does not exist in the system currently: "${ cmd }"`); } this.disabledCommands.delete(cmd); From b8553d7ac07ca4e9f2a6e34f2dc73da45e557487 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Mon, 30 Oct 2017 14:38:14 -0500 Subject: [PATCH 13/42] Remove the local docker file --- .docker/Dockerfile.local | 51 ---------------------------------------- 1 file changed, 51 deletions(-) delete mode 100644 .docker/Dockerfile.local diff --git a/.docker/Dockerfile.local b/.docker/Dockerfile.local deleted file mode 100644 index cbf1f2a93d0e..000000000000 --- a/.docker/Dockerfile.local +++ /dev/null @@ -1,51 +0,0 @@ -FROM ubuntu:16.04 as builder - -RUN apt update && apt install curl git bzip2 -y - -RUN set -x \ -&& curl https://install.meteor.com | sed s/--progress-bar/-sL/g | /bin/sh \ -&& export PATH="$HOME/.meteor:$PATH" - -COPY . /app - -WORKDIR /app - -RUN set -x \ -&& meteor npm i --unsafe-perm - -RUN set -x \ -&& meteor build --allow-superuser --headless --directory /tmp/build - -FROM rocketchat/base:4 - -ENV RC_VERSION 0.59.0-develop - -MAINTAINER buildmaster@rocket.chat - -COPY --from=builder /tmp/build/bundle /app/bundle - -RUN set -x \ - && ls -l /app \ - && cd /app/bundle/programs/server \ - && npm install \ - && npm cache clear \ - && chown -R rocketchat:rocketchat /app - -USER rocketchat - -VOLUME /app/uploads - -WORKDIR /app/bundle - -# needs a mongoinstance - defaults to container linking with alias 'mongo' -ENV DEPLOY_METHOD=docker \ - NODE_ENV=production \ - MONGO_URL=mongodb://mongo:27017/rocketchat \ - HOME=/tmp \ - PORT=3000 \ - ROOT_URL=http://localhost:3000 \ - Accounts_AvatarStorePath=/app/uploads - -EXPOSE 3000 - -CMD ["node", "main.js"] From d74cc942fa79a2a413fb89511b46b64cedf7a5e6 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Thu, 2 Nov 2017 02:26:17 -0500 Subject: [PATCH 14/42] Implmement the discovery layout for the Rocketlets --- .../.npm/package/npm-shrinkwrap.json | 52 ++++++----- .../client/admin/rocketlets.html | 48 ++++++++-- .../client/imports/components/discovery.css | 93 +++++++++++++++++++ .../client/imports/components/tab.css | 62 +++++++++++++ .../client/imports/general/variables.css | 7 +- packages/rocketchat-theme/client/main.css | 4 + 6 files changed, 232 insertions(+), 34 deletions(-) create mode 100644 packages/rocketchat-theme/client/imports/components/discovery.css create mode 100644 packages/rocketchat-theme/client/imports/components/tab.css diff --git a/packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json b/packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json index 2617915b67c1..b2d682c623e3 100644 --- a/packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json +++ b/packages/rocketchat-google-vision/.npm/package/npm-shrinkwrap.json @@ -1,8 +1,8 @@ { "dependencies": { "ajv": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz", "from": "ajv@>=5.1.0 <6.0.0" }, "ansi-regex": { @@ -247,6 +247,11 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", "from": "fast-deep-equal@>=1.0.0 <2.0.0" }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "from": "fast-json-stable-stringify@>=2.0.0 <3.0.0" + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -285,7 +290,14 @@ "globby": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "from": "globby@>=6.1.0 <7.0.0" + "from": "globby@>=6.1.0 <7.0.0", + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "from": "pify@>=2.0.0 <3.0.0" + } + } }, "google-auth-library": { "version": "0.10.0", @@ -919,8 +931,8 @@ } }, "gtoken": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-1.2.2.tgz", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-1.2.3.tgz", "from": "gtoken@>=1.2.1 <2.0.0" }, "har-schema": { @@ -1023,21 +1035,11 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", "from": "json-schema-traverse@>=0.3.0 <0.4.0" }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "from": "json-stable-stringify@>=1.0.1 <2.0.0" - }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "from": "json-stringify-safe@>=5.0.1 <5.1.0" }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "from": "jsonify@>=0.0.0 <0.1.0" - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -1079,8 +1081,8 @@ "from": "long@>=3.0.0 <4.0.0" }, "make-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.0.0.tgz", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.1.0.tgz", "from": "make-dir@>=1.0.0 <2.0.0" }, "methmeth": { @@ -1091,7 +1093,7 @@ "mime": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "from": "mime@>=1.2.11 <2.0.0" + "from": "mime@>=1.4.1 <2.0.0" }, "mime-db": { "version": "1.30.0", @@ -1164,9 +1166,9 @@ "from": "performance-now@>=2.1.0 <3.0.0" }, "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "from": "pify@>=2.3.0 <3.0.0" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "from": "pify@>=3.0.0 <4.0.0" }, "pinkie": { "version": "2.0.4", @@ -1229,8 +1231,8 @@ "from": "request@>=2.79.0 <3.0.0" }, "retry-request": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-3.0.1.tgz", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-3.1.0.tgz", "from": "retry-request@>=3.0.0 <4.0.0" }, "rgb-hex": { @@ -1249,8 +1251,8 @@ "from": "signal-exit@>=3.0.2 <4.0.0" }, "sntp": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", "from": "sntp@>=2.0.0 <3.0.0" }, "split-array-stream": { diff --git a/packages/rocketchat-rocketlets/client/admin/rocketlets.html b/packages/rocketchat-rocketlets/client/admin/rocketlets.html index 29be20cdabed..3b7d14a659cd 100644 --- a/packages/rocketchat-rocketlets/client/admin/rocketlets.html +++ b/packages/rocketchat-rocketlets/client/admin/rocketlets.html @@ -9,16 +9,48 @@

{{#requiresPermission 'manage-rocketlets'}} - {{#each rocketlets}} - - {{/each}} +
+
+
+
+
+
+ +
+
+ {{#each rocketlets}} +
+
+
+
+
+ +
+
+ {{/each}} +
{{/requiresPermission}}
- {{#with flexData}} - {{> flexTabBar}} - {{/with}} diff --git a/packages/rocketchat-theme/client/imports/components/discovery.css b/packages/rocketchat-theme/client/imports/components/discovery.css new file mode 100644 index 000000000000..282b9ce89791 --- /dev/null +++ b/packages/rocketchat-theme/client/imports/components/discovery.css @@ -0,0 +1,93 @@ +.rc-discovery { + justify-content: center; + + &__empty { + padding: 40px; + + text-align: center; + + color: var(--color-gray); + } + + &-wrap { + display: flex; + + margin: 0 -12px; + flex-wrap: wrap; + justify-content: flex-start; + } + + &__container { + flex: 1 1 100%; + } + + &__item { + min-width: 304px; + margin: 12px; + padding: 10px; + + border-radius: 2px; + background: #f7f8fa; + + &:hover &__image { + transform: scale(1.1); + } + + &__image-wrap { + overflow: hidden; + + height: 128px; + } + + &__image { + height: 128px; + + transition: all 0.3s; + + border-radius: 2px; + background: #cccccc; + + background: url(http://www.clickgratis.com.br/fotos-imagens/gatinho/aHR0cDovL3d3dy5jb21vZmF6ZXIub3JnL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDEyLzA3L2dhdGluaG8tcGVyc2EuanBn.jpg); + background-repeat: no-repeat; + background-position: 50%; + background-size: cover; + } + + &__footer { + display: flex; + + padding: 10px 10px 0; + + font-weight: 500; + line-height: 20px; + align-items: center; + + &__title { + margin-bottom: 4px; + + font-size: 18px; + } + + &__description { + color: #9ea2a8; + + font-size: 14px; + } + } + + & .rc-button { + flex: 0; + + width: 20px; + height: 20px; + + color: #1d74f5; + border-color: #1d74f5; + border-radius: 4px; + + & .rc-icon { + font-size: 1rem; + } + } + } +} diff --git a/packages/rocketchat-theme/client/imports/components/tab.css b/packages/rocketchat-theme/client/imports/components/tab.css new file mode 100644 index 000000000000..2d82549d594d --- /dev/null +++ b/packages/rocketchat-theme/client/imports/components/tab.css @@ -0,0 +1,62 @@ +.rc-tabs { + position: relative; + + display: flex; + + margin: 0 calc(var(--tabs-padding) / -2); + padding: calc(var(--tabs-padding) / 2); + + list-style: none; + + color: var(--color-gray); + + font-size: 14px; + + &::before { + position: absolute; + bottom: 0; + + width: 100%; + height: 2px; + + content: ''; + + background: var(--color-gray-light); + } + + &__tab { + position: relative; + + margin: calc(var(--tabs-padding) / 2); + padding: 0 5px; + + cursor: pointer; + transition: all 0.3s; + + &-link { + color: inherit !important; + } + + &:hover { + opacity: 0.5; + } + + &.active, + &:active { + color: #1d74f5; + + &::before { + position: absolute; + bottom: calc(var(--tabs-padding) * -1); + left: 0; + + width: 100%; + height: 2px; + + content: ''; + + background: #1d74f5; + } + } + } +} diff --git a/packages/rocketchat-theme/client/imports/general/variables.css b/packages/rocketchat-theme/client/imports/general/variables.css index 4735fc17660f..0af2b71c45aa 100644 --- a/packages/rocketchat-theme/client/imports/general/variables.css +++ b/packages/rocketchat-theme/client/imports/general/variables.css @@ -4,7 +4,7 @@ */ --color-darkest: #1f2329; - --color-dark: #2f343d; + --color-dark: #2f343d; --color-dark-medium: #414852; --color-dark-light: #6c727a; --color-gray: #9ea2a8; @@ -273,4 +273,9 @@ --message-box-editing-color: #fff5df; --message-box-popover-title-text-color: var(--color-gray); --message-box-popover-title-text-size: 0.75rem; + + /* + * Tabs + */ + --tabs-padding: 1rem; } diff --git a/packages/rocketchat-theme/client/main.css b/packages/rocketchat-theme/client/main.css index dc41e7515e1d..9e8732f7b90a 100644 --- a/packages/rocketchat-theme/client/main.css +++ b/packages/rocketchat-theme/client/main.css @@ -38,5 +38,9 @@ @import 'imports/components/modal/full-modal.css'; @import 'imports/components/modal/create-channel.css'; +/* Tabs */ +@import 'imports/components/tab.css'; +@import 'imports/components/discovery.css'; + /* RTL */ @import 'imports/general/rtl.css'; From 990aa6000406f2f62fa2dccfddad286b7377ccc6 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Thu, 2 Nov 2017 17:41:18 -0500 Subject: [PATCH 15/42] Fix the discovery add button, thanks to @ggazzo --- .../rocketchat-theme/client/imports/components/discovery.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-theme/client/imports/components/discovery.css b/packages/rocketchat-theme/client/imports/components/discovery.css index 282b9ce89791..27bc32f9b0e6 100644 --- a/packages/rocketchat-theme/client/imports/components/discovery.css +++ b/packages/rocketchat-theme/client/imports/components/discovery.css @@ -76,7 +76,7 @@ } & .rc-button { - flex: 0; + flex: 0 0 auto; width: 20px; height: 20px; From eb3e20c0c9a28af7708db78326abdbf0cfa9c03f Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Fri, 3 Nov 2017 11:24:31 -0500 Subject: [PATCH 16/42] Change the icons over to the template format --- .../client/admin/rocketlets.html | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/rocketchat-rocketlets/client/admin/rocketlets.html b/packages/rocketchat-rocketlets/client/admin/rocketlets.html index 3b7d14a659cd..2917283995a8 100644 --- a/packages/rocketchat-rocketlets/client/admin/rocketlets.html +++ b/packages/rocketchat-rocketlets/client/admin/rocketlets.html @@ -10,7 +10,7 @@

{{#requiresPermission 'manage-rocketlets'}}
-
+
@@ -21,9 +21,7 @@

@@ -37,12 +35,10 @@

From b1b70c712e53750bc24b5ead055c14fefa3e227b Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Thu, 9 Nov 2017 16:10:04 -0600 Subject: [PATCH 17/42] Update the rocketlet packages and improve the storage query --- packages/rocketchat-rocketlets/client/admin/rocketlets.html | 2 +- packages/rocketchat-rocketlets/package.js | 4 ++-- packages/rocketchat-rocketlets/server/communication/rest.js | 6 ++++++ packages/rocketchat-rocketlets/server/storage/storage.js | 4 ++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/rocketchat-rocketlets/client/admin/rocketlets.html b/packages/rocketchat-rocketlets/client/admin/rocketlets.html index 2917283995a8..54bc7bbd26eb 100644 --- a/packages/rocketchat-rocketlets/client/admin/rocketlets.html +++ b/packages/rocketchat-rocketlets/client/admin/rocketlets.html @@ -37,7 +37,7 @@

-
diff --git a/packages/rocketchat-rocketlets/package.js b/packages/rocketchat-rocketlets/package.js index 3e8b874429a9..22cd4e8a1120 100644 --- a/packages/rocketchat-rocketlets/package.js +++ b/packages/rocketchat-rocketlets/package.js @@ -81,6 +81,6 @@ Package.onUse(function(api) { Npm.depends({ 'busboy': '0.2.13', - 'temporary-rocketlets-server': '0.1.29', - 'temporary-rocketlets-ts-definition': '0.6.29' + 'temporary-rocketlets-server': '0.1.32', + 'temporary-rocketlets-ts-definition': '0.6.30' }); diff --git a/packages/rocketchat-rocketlets/server/communication/rest.js b/packages/rocketchat-rocketlets/server/communication/rest.js index 6ce815a68102..732bef420a22 100644 --- a/packages/rocketchat-rocketlets/server/communication/rest.js +++ b/packages/rocketchat-rocketlets/server/communication/rest.js @@ -95,6 +95,12 @@ export class RocketletsRestApi { } }); + this.api.addRoute(':id/icon', { authRequired: true }, { + get() { + return { success: false }; + } + }); + this.api.addRoute(':id/languages', { authRequired: true }, { get() { console.log(`Getting ${ this.urlParams.id }'s languages..`); diff --git a/packages/rocketchat-rocketlets/server/storage/storage.js b/packages/rocketchat-rocketlets/server/storage/storage.js index 0ac51c5e0a48..78ba07fd8793 100644 --- a/packages/rocketchat-rocketlets/server/storage/storage.js +++ b/packages/rocketchat-rocketlets/server/storage/storage.js @@ -39,7 +39,7 @@ export class RocketletRealStorage extends RocketletStorage { let doc; try { - doc = this.db.findOneById(id); + doc = this.db.findOne({ $or: [ {_id: id }, { id } ]}); } catch (e) { return reject(e); } @@ -47,7 +47,7 @@ export class RocketletRealStorage extends RocketletStorage { if (doc) { resolve(doc); } else { - reject(new Error(`Nothing found by the id: ${ id }`)); + reject(new Error(`No Rocketlet found by the id: ${ id }`)); } }); } From 37fab88475dd407d9179f0a5153baa28092a3b70 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Mon, 13 Nov 2017 17:13:08 -0600 Subject: [PATCH 18/42] Display the Rocketlet's icon file in the list of rocketlets --- .../client/admin/rocketletInstall.html | 3 +++ .../client/admin/rocketletInstall.js | 4 ++++ .../client/admin/rocketlets.html | 4 ++-- .../rocketchat-rocketlets/client/admin/rocketlets.js | 4 ++++ packages/rocketchat-rocketlets/client/orchestrator.js | 7 +++++++ packages/rocketchat-rocketlets/package.js | 8 +++++--- .../server/communication/rest.js | 11 ++++++++++- 7 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 packages/rocketchat-rocketlets/client/admin/rocketletInstall.html create mode 100644 packages/rocketchat-rocketlets/client/admin/rocketletInstall.js diff --git a/packages/rocketchat-rocketlets/client/admin/rocketletInstall.html b/packages/rocketchat-rocketlets/client/admin/rocketletInstall.html new file mode 100644 index 000000000000..597805a242dc --- /dev/null +++ b/packages/rocketchat-rocketlets/client/admin/rocketletInstall.html @@ -0,0 +1,3 @@ + diff --git a/packages/rocketchat-rocketlets/client/admin/rocketletInstall.js b/packages/rocketchat-rocketlets/client/admin/rocketletInstall.js new file mode 100644 index 000000000000..0e6e1f3d796a --- /dev/null +++ b/packages/rocketchat-rocketlets/client/admin/rocketletInstall.js @@ -0,0 +1,4 @@ +Template.rocketletInstall.onCreated(function() { + const instance = this; + instance.status = new ReactiveVar(false); +}); diff --git a/packages/rocketchat-rocketlets/client/admin/rocketlets.html b/packages/rocketchat-rocketlets/client/admin/rocketlets.html index 54bc7bbd26eb..334c339d326c 100644 --- a/packages/rocketchat-rocketlets/client/admin/rocketlets.html +++ b/packages/rocketchat-rocketlets/client/admin/rocketlets.html @@ -20,7 +20,7 @@

- @@ -30,7 +30,7 @@

-
+