Rocketlets: Initial structure for the rocketlets package inside of Rocket.Chat.

pull/9666/head
Bradley Hilton 8 years ago
parent 76b22c2962
commit 2678365dfe
No known key found for this signature in database
GPG Key ID: 0666B2C24C43C358
  1. 1
      .eslintrc
  2. 1
      .meteor/packages
  3. 1
      .meteor/versions
  4. 1
      packages/rocketchat-api/package.js
  5. 6
      packages/rocketchat-api/server/api.js
  6. 85
      packages/rocketchat-api/server/v1/commands.js
  7. 1
      packages/rocketchat-lib/lib/slashCommand.js
  8. 1
      packages/rocketchat-rocketlets/.gitignore
  9. 12
      packages/rocketchat-rocketlets/client/communication/websockets.js
  10. 2
      packages/rocketchat-rocketlets/lib/Rocketlets.js
  11. 41
      packages/rocketchat-rocketlets/package.js
  12. 84
      packages/rocketchat-rocketlets/server/bridges/commands.js
  13. 3
      packages/rocketchat-rocketlets/server/bridges/index.js
  14. 5
      packages/rocketchat-rocketlets/server/communication/index.js
  15. 8
      packages/rocketchat-rocketlets/server/communication/rest.js
  16. 16
      packages/rocketchat-rocketlets/server/communication/websockets.js
  17. 9
      packages/rocketchat-rocketlets/server/converters/index.js
  18. 21
      packages/rocketchat-rocketlets/server/converters/messages.js
  19. 13
      packages/rocketchat-rocketlets/server/converters/rooms.js
  20. 13
      packages/rocketchat-rocketlets/server/converters/users.js
  21. 5
      packages/rocketchat-rocketlets/server/models/Rocketlets.js
  22. 42
      packages/rocketchat-rocketlets/server/orchestrator.js
  23. 5
      packages/rocketchat-slashcommands-archiveroom/server.js
  24. 5
      packages/rocketchat-slashcommands-create/server.js
  25. 2
      packages/rocketchat-slashcommands-help/server.js
  26. 7
      packages/rocketchat-slashcommands-invite/server.js
  27. 10
      packages/rocketchat-slashcommands-inviteall/server.js
  28. 3
      packages/rocketchat-slashcommands-join/server.js
  29. 5
      packages/rocketchat-slashcommands-kick/server.js
  30. 15
      packages/rocketchat-slashcommands-leave/leave.js

@ -133,6 +133,7 @@
"ReactiveVar" : false,
"RocketChat" : true,
"RocketChatFile" : false,
"Rocketlets" : false,
"RoomHistoryManager" : false,
"RoomManager" : false,
"s" : false,

@ -93,6 +93,7 @@ rocketchat:oembed
rocketchat:otr
rocketchat:push-notifications
rocketchat:reactions
rocketchat:rocketlets
rocketchat:sandstorm
rocketchat:slackbridge
rocketchat:slashcommands-archive

@ -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

@ -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');

@ -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,

@ -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 });
}
});

@ -26,6 +26,7 @@ Meteor.methods({
method: 'slashCommand'
});
}
return RocketChat.slashCommands.run(command.cmd, command.params, command.msg);
}
});

@ -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);
}
}

@ -0,0 +1,2 @@
// Please see both server and client's repsective "orchestrator" file for the contents
Rocketlets = {};

@ -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'
});

@ -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);
};
}
}

@ -0,0 +1,3 @@
import { RocketletCommandsBridge } from './commands';
export { RocketletCommandsBridge };

@ -0,0 +1,5 @@
import { RocketletWebsocketNotifier } from './websockets';
export {
RocketletWebsocketNotifier
};

@ -0,0 +1,8 @@
/* Rocketlets.API = new RocketChat.API.ApiClass({
version: 'rocketlets',
useDefaultAuth: true,
prettyJson: true,
enableCors: false,
auth: RocketChat.API.getUserAuth()
});
*/

@ -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);
}
}

@ -0,0 +1,9 @@
import { RocketletMessagesConverter } from './messages';
import { RocketletRoomsConverter } from './rooms';
import { RocketletUsersConverter } from './users';
export {
RocketletMessagesConverter,
RocketletRoomsConverter,
RocketletUsersConverter
};

@ -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
};
}
}

@ -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
};
}
}

@ -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
};
}
}

@ -0,0 +1,5 @@
export class RocketletsModel extends RocketChat.models._Base {
constructor() {
super('rocketlets');
}
}

@ -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! :)');
});

@ -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'
});

@ -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'
});

@ -45,4 +45,6 @@ RocketChat.slashCommands.add('help', function Help(command, params, item) {
});
});
}, {
description: 'Show_the_keyboard_shortcut_list'
});

@ -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'
});

@ -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;

@ -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'
});

@ -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'
});

@ -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' });

Loading…
Cancel
Save