Replace outgoing scripts by new format

pull/2481/head
Rodrigo Nascimento 9 years ago
parent 77b7c72033
commit b460e363f1
  1. 2
      i18n/en.i18n.json
  2. 24
      packages/rocketchat-integrations/client/views/integrationsOutgoing.coffee
  3. 31
      packages/rocketchat-integrations/client/views/integrationsOutgoing.html
  4. 4
      packages/rocketchat-integrations/server/api/api.coffee
  5. 12
      packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee
  6. 16
      packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee
  7. 111
      packages/rocketchat-integrations/server/triggers.coffee

@ -467,12 +467,10 @@
"Powered_by" : "Powered by",
"Preferences" : "Preferences",
"Preferences_saved" : "Preferences saved",
"Prepare_Outgoing_Request" : "Prepare Outgoing Request",
"Privacy" : "Privacy",
"Private_Groups" : "Private Groups",
"Private_Groups_list" : "List of Private Groups",
"Process_Incoming_Request" : "Process Incoming Request",
"Process_Outgoing_Response" : "Process Outgoing Response",
"Profile" : "Profile",
"Profile_saved_successfully" : "Profile saved successfully",
"Proudly_developed" : "Proudly developed with Meteor",

@ -70,6 +70,24 @@ Template.integrationsOutgoing.helpers
return hljs.highlight('json', JSON.stringify(data, null, 2)).value
editorOptions: ->
return {} =
lineNumbers: true
mode: "javascript"
gutters: [
# "CodeMirror-lint-markers"
"CodeMirror-linenumbers"
"CodeMirror-foldgutter"
]
# lint: true
foldGutter: true
lineWrapping: true
matchBrackets: true
autoCloseBrackets: true
matchTags: true,
showTrailingSpace: true
highlightSelectionMatches: true
Template.integrationsOutgoing.events
"blur input": (e, t) ->
@ -119,8 +137,7 @@ Template.integrationsOutgoing.events
triggerWords = $('[name=triggerWords]').val().trim()
urls = $('[name=urls]').val().trim()
token = $('[name=token]').val().trim()
prepareOutgoingRequestScript = $('[name=prepareOutgoingRequestScript]').val().trim()
processOutgoingResponseScript = $('[name=processOutgoingResponseScript]').val().trim()
script = $('[name=script]').val().trim()
if username is ''
return toastr.error TAPi18n.__("The_username_is_required")
@ -152,8 +169,7 @@ Template.integrationsOutgoing.events
triggerWords: triggerWords if triggerWords isnt ''
urls: urls if urls isnt ''
token: token if token isnt ''
prepareOutgoingRequestScript: prepareOutgoingRequestScript if prepareOutgoingRequestScript isnt ''
processOutgoingResponseScript: processOutgoingResponseScript if processOutgoingResponseScript isnt ''
script: script if script isnt ''
params = Template.instance().data.params?()
if params?.id?

@ -74,15 +74,30 @@
</div>
</div>
<div class="input-line double-col">
<label>{{_ "Prepare_Outgoing_Request"}} ({{_ "optional"}})</label>
<label>{{_ "Script"}} ({{_ "optional"}})</label>
<div>
<textarea rows="4" style="height: auto" name="prepareOutgoingRequestScript" value="{{data.prepareOutgoingRequestScript}}"></textarea>
</div>
</div>
<div class="input-line double-col">
<label>{{_ "Process_Outgoing_Response"}} ({{_ "optional"}})</label>
<div>
<textarea rows="4" style="height: auto" name="processOutgoingResponseScript" value="{{data.processOutgoingResponseScript}}"></textarea>
<div class="code-mirror-box">
<div class="title">
{{_ "Script"}}
</div>
{{> CodeMirror name="script" options=editorOptions code=data.script }}
<div class="buttons">
<button class="button button-primary button-fullscreen">
Full Screen
</button>
<button class="button button-primary button-restore">
Exit Full Screen
</button>
</div>
</div>
{{#if data.scriptError}}
<div class="code-error-box">
<div class="title">
{{data.scriptError.name}}
</div>
<pre>{{data.scriptError.codeFrame}}</pre>
</div>
{{/if}}
</div>
</div>
<div class="input-line double-col">

@ -1,3 +1,5 @@
vm = Npm.require('vm')
compiledScripts = {}
getIntegrationScript = (integration) ->
@ -37,8 +39,6 @@ getIntegrationScript = (integration) ->
throw RocketChat.API.v1.failure 'class-script-not-found'
vm = Npm.require('vm')
Api = new Restivus
enableCors: true
apiPath: 'hooks/'

@ -32,6 +32,18 @@ Meteor.methods
integration.triggerWords = _.without integration.triggerWords, [undefined]
if integration.script isnt ''
try
babelOptions = Babel.getDefaultOptions()
babelOptions.externalHelpers = false
integration.scriptCompiled = Babel.compile(integration.script, babelOptions).code
integration.scriptError = undefined
catch e
integration.scriptCompiled = undefined
integration.scriptError = _.pick e, 'name', 'message', 'pos', 'loc', 'codeFrame'
if integration.channel?
record = undefined
channelType = integration.channel[0]

@ -40,6 +40,17 @@ Meteor.methods
if not RocketChat.models.Integrations.findOne(integrationId)?
throw new Meteor.Error 'invalid_integration', '[methods] updateOutgoingIntegration -> integration not found'
if integration.script isnt ''
try
babelOptions = Babel.getDefaultOptions()
babelOptions.externalHelpers = false
integration.scriptCompiled = Babel.compile(integration.script, babelOptions).code
integration.scriptError = undefined
catch e
integration.scriptCompiled = undefined
integration.scriptError = _.pick e, 'name', 'message', 'pos', 'loc', 'codeFrame'
if integration.channel?
record = undefined
@ -79,8 +90,9 @@ Meteor.methods
userId: user._id
urls: integration.urls
token: integration.token
prepareOutgoingRequestScript: integration.prepareOutgoingRequestScript
processOutgoingResponseScript: integration.processOutgoingResponseScript
script: integration.script
scriptCompiled: integration.scriptCompiled
scriptError: integration.scriptError
triggerWords: integration.triggerWords
_updatedAt: new Date
_updatedBy: RocketChat.models.Users.findOne @userId, {fields: {username: 1}}

@ -1,28 +1,25 @@
vm = Npm.require('vm')
triggers = {}
compiledScripts = {}
executeScript = (scriptContent, name, sandbox) ->
script = undefined
vmScript = undefined
try
script = "result = (function() {\n"+scriptContent+"\n}());"
vmScript = vm.createScript script, 'script.js'
logger.outgoing.info 'will execute script ' + name
logger.outgoing.debug script
logger.outgoing.debug 'with context', sandbox
catch e
logger.outgoing.error "[Error evaluating Script:]"
logger.outgoing.error script.replace(/^/gm, ' ')
logger.outgoing.error "\n[Stack:]"
logger.outgoing.error e.stack.replace(/^/gm, ' ')
return
getIntegrationScript = (integration) ->
compiledScript = compiledScripts[integration._id]
if compiledScript? and +compiledScript._updatedAt is +integration._updatedAt
return compiledScript.script
try
sandbox._ = _
sandbox.s = s
sandbox.console = console
sandbox.HTTP = (method, url, options) ->
script = integration.scriptCompiled
vmScript = undefined
store = {}
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
@ -30,15 +27,68 @@ executeScript = (scriptContent, name, sandbox) ->
return {} =
error: e
try
logger.outgoing.info 'will evaluate script'
logger.outgoing.debug script
vmScript = vm.createScript script, 'script.js'
vmScript.runInNewContext sandbox
logger.outgoing.debug 'result', sandbox.result
return sandbox.result
if sandbox.Script?
compiledScripts[integration._id] =
script: new sandbox.Script()
_updatedAt: integration._updatedAt
return compiledScripts[integration._id].script
catch e
logger.outgoing.error "[Error running Script:]"
logger.outgoing.error "[Error evaluating Script:]"
logger.outgoing.error script.replace(/^/gm, ' ')
logger.outgoing.error "\n[Stack:]"
logger.outgoing.error "[Stack:]"
logger.outgoing.error e.stack.replace(/^/gm, ' ')
throw new Meteor.Error 'error-evaluating-script'
if not sandbox.Script?
logger.outgoing.error "[Class 'Script' not found]"
throw new Meteor.Error 'class-script-not-found'
triggers = {}
hasScriptAndMethod = (integration, method) ->
if not integration.scriptCompiled? or integration.scriptCompiled.trim() is ''
return false
script = undefined
try
script = getIntegrationScript(integration)
catch e
return
return script[method]?
executeScript = (integration, method, params) ->
script = undefined
try
script = getIntegrationScript(integration)
catch e
return
if not script[method]?
logger.outgoing.error "[Method '#{method}' not found]"
return
try
result = script[method](params)
logger.outgoing.debug 'result', result
return result
catch e
logger.incoming.error "[Error running Script:]"
logger.incoming.error integration.scriptCompiled.replace(/^/gm, ' ')
logger.incoming.error "[Stack:]"
logger.incoming.error e.stack.replace(/^/gm, ' ')
return
@ -113,13 +163,11 @@ ExecuteTriggerUrl = (url, trigger, message, room, tries=0) ->
headers:
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36'
if trigger.prepareOutgoingRequestScript? and trigger.prepareOutgoingRequestScript.trim() isnt ''
trigger.store ?= {}
if hasScriptAndMethod(trigger, 'prepare_outgoing_request')
sandbox =
request: opts
store: trigger.store
opts = executeScript trigger.prepareOutgoingRequestScript, 'prepareOutgoingRequestScript', sandbox
opts = executeScript trigger, 'prepare_outgoing_request', sandbox
if not opts?
return
@ -132,7 +180,7 @@ ExecuteTriggerUrl = (url, trigger, message, room, tries=0) ->
HTTP.call opts.method, opts.url, opts, (error, result) ->
scriptResult = undefined
if trigger.processOutgoingResponseScript? and trigger.processOutgoingResponseScript.trim() isnt ''
if hasScriptAndMethod(trigger, 'process_outgoing_response')
sandbox =
request: opts
response:
@ -141,9 +189,8 @@ ExecuteTriggerUrl = (url, trigger, message, room, tries=0) ->
content: result.data
content_raw: result.content
headers: result.headers
store: trigger.store
scriptResult = executeScript trigger.processOutgoingResponseScript, 'processOutgoingResponseScript', sandbox
scriptResult = executeScript trigger, 'process_outgoing_response', sandbox
if scriptResult?.content
sendMessage scriptResult.content

Loading…
Cancel
Save