Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEW] Integrations, both incoming and outgoing, now have access to the models. Example: Users.findOneById(id) #6420

Merged
merged 4 commits into from
Mar 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## NEXT

- [NEW] Integrations, both incoming and outgoing, now have access to the models. Example: `Users.findOneById(id)` (#6336)
- [FIX] Incoming integrations would break when trying to use the `Store` feature.

## 0.54.1 - 2017-Mar-23

- [FIX] Images on attachments were not loading except for uploaded files.
Expand Down
2 changes: 1 addition & 1 deletion packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1670,4 +1670,4 @@
"your_message_optional": "your message (optional)",
"Your_password_is_wrong": "Your password is wrong!",
"Your_push_was_sent_to_s_devices": "Your push was sent to %s devices"
}
}
72 changes: 37 additions & 35 deletions packages/rocketchat-integrations/server/api/api.coffee
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
vm = Npm.require('vm')
moment = require('moment')

compiledScripts = {}

getIntegrationScript = (integration) ->
compiledScript = compiledScripts[integration._id]
if compiledScript? and +compiledScript._updatedAt is +integration._updatedAt
return compiledScript.script

script = integration.scriptCompiled
vmScript = undefined
buildSandbox = (store = {}) ->
sandbox =
_: _
s: s
console: console
console: console,
moment: moment,
Store:
set: (key, val) ->
return store[key] = val
Expand All @@ -26,17 +22,36 @@ getIntegrationScript = (integration) ->
return {} =
error: e

Object.keys(RocketChat.models).filter((k) ->
return !k.startsWith('_')
).forEach (k) =>
sandbox[k] = RocketChat.models[k]

return {} =
store: store,
sandbox: sandbox

getIntegrationScript = (integration) ->
compiledScript = compiledScripts[integration._id]
if compiledScript? and +compiledScript._updatedAt is +integration._updatedAt
return compiledScript.script

script = integration.scriptCompiled
vmScript = undefined
sandboxItems = buildSandbox()

try
logger.incoming.info 'Will evaluate script of Trigger', integration.name
logger.incoming.debug script

vmScript = vm.createScript script, 'script.js'

vmScript.runInNewContext sandbox
vmScript.runInNewContext sandboxItems.sandbox

if sandbox.Script?
if sandboxItems.sandbox.Script?
compiledScripts[integration._id] =
script: new sandbox.Script()
script: new sandboxItems.sandbox.Script()
store: sandboxItems.store
_updatedAt: integration._updatedAt

return compiledScripts[integration._id].script
Expand All @@ -47,7 +62,7 @@ getIntegrationScript = (integration) ->
logger.incoming.error e.stack.replace(/^/gm, ' ')
throw RocketChat.API.v1.failure 'error-evaluating-script'

if not sandbox.Script?
if not sandboxItems.sandbox.Script?
logger.incoming.error '[Class "Script" not in Trigger', integration.name, ']'
throw RocketChat.API.v1.failure 'class-script-not-found'

Expand Down Expand Up @@ -133,9 +148,9 @@ removeIntegration = (options, user) ->


executeIntegrationRest = ->
logger.incoming.info 'Post integration', @integration.name
logger.incoming.debug '@urlParams', @urlParams
logger.incoming.debug '@bodyParams', @bodyParams
logger.incoming.info 'Post integration:', @integration.name
logger.incoming.debug '@urlParams:', @urlParams
logger.incoming.debug '@bodyParams:', @bodyParams

if @integration.enabled isnt true
return {} =
Expand All @@ -148,13 +163,13 @@ executeIntegrationRest = ->
avatar: @integration.avatar
emoji: @integration.emoji


if @integration.scriptEnabled is true and @integration.scriptCompiled? and @integration.scriptCompiled.trim() isnt ''
script = undefined
try
script = getIntegrationScript(@integration)
catch e
return e
logger.incoming.warn e
return RocketChat.API.v1.failure e.message

request =
url:
Expand All @@ -174,24 +189,11 @@ executeIntegrationRest = ->
username: @user.username

try
sandbox =
_: _
s: s
console: console
Store:
set: (key, val) ->
return store[key] = val
get: (key) ->
return store[key]
HTTP: (method, url, options) ->
try
return {} =
result: HTTP.call method, url, options
catch e
return {} =
error: e
script: script
request: request
sandboxItems = buildSandbox(compiledScripts[@integration._id].store)
sandbox = sandboxItems.sandbox
sandbox.script = script
sandbox.request = request

result = vm.runInNewContext('script.process_incoming_request({ request: request })', sandbox, { timeout: 3000 })

if result?.error?
Expand Down
49 changes: 21 additions & 28 deletions packages/rocketchat-integrations/server/lib/triggerHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,7 @@ RocketChat.integrations.triggerHandler = new class RocketChatIntegrationHandler
return message;
}

getIntegrationScript(integration) {
const compiledScript = this.compiledScripts[integration._id];
if (compiledScript && +compiledScript._updatedAt === +integration._updatedAt) {
return compiledScript.script;
}

const script = integration.scriptCompiled;
const store = {};
buildSandbox(store = {}) {
const sandbox = {
_, s, console, moment,
Store: {
Expand All @@ -212,6 +205,22 @@ RocketChat.integrations.triggerHandler = new class RocketChatIntegrationHandler
}
};

Object.keys(RocketChat.models).filter(k => !k.startsWith('_')).forEach(k => {
sandbox[k] = RocketChat.models[k];
});

return { store, sandbox };
}

getIntegrationScript(integration) {
const compiledScript = this.compiledScripts[integration._id];
if (compiledScript && +compiledScript._updatedAt === +integration._updatedAt) {
return compiledScript.script;
}

const script = integration.scriptCompiled;
const { store, sandbox } = this.buildSandbox();

let vmScript;
try {
logger.outgoing.info('Will evaluate script of Trigger', integration.name);
Expand Down Expand Up @@ -275,26 +284,10 @@ RocketChat.integrations.triggerHandler = new class RocketChatIntegrationHandler
}

try {
const store = this.compiledScripts[integration._id].store;
const sandbox = {
_, s, console, moment,
Store: {
set: (key, val) => store[key] = val,
get: (key) => store[key]
},
HTTP: (method, url, options) => {
try {
return {
result: HTTP.call(method, url, options)
};
} catch (error) {
return { error };
}
},
script,
method,
params
};
const { sandbox } = this.buildSandbox(this.compiledScripts[integration._id].store);
sandbox.script = script;
sandbox.method = method;
sandbox.params = params;

this.updateHistory({ historyId, step: `execute-script-before-running-${method}` });
const result = this.vm.runInNewContext('script[method](params)', sandbox, { timeout: 3000 });
Expand Down