mushy 0.21.2 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,262 +1,254 @@
1
1
  require 'ferrum'
2
2
 
3
- module Mushy
4
-
5
- class Browser < Flux
6
-
7
- def self.details
8
- {
9
- name: 'Browser',
10
- title: 'Use a browser',
11
- fluxGroup: { name: 'Web' },
12
- description: 'Visit a page in a browser.',
13
- config: {
14
- url: {
15
- description: 'The URL to visit.',
16
- type: 'text',
17
- value: 'https://www.google.com',
18
- },
19
- headless: {
20
- description: 'Run this browser headless.',
21
- type: 'boolean',
22
- shrink: true,
23
- value: '',
24
- },
25
- timeout: {
26
- description: 'The default timeout (in seconds) before closing the browser. Default is 5 seconds.',
27
- type: 'integer',
28
- shrink: true,
29
- value: '',
30
- },
31
- execute: {
32
- description: 'Javascript to run after the page is loaded.',
33
- type: 'textarea',
34
- shrink: true,
35
- value: '',
36
- },
37
- cookies: {
38
- description: 'Cookies for the web request. These can be received from a previous browser event with {{cookies}}, or can be typed manually.',
39
- type: 'editgrid',
40
- shrink: true,
41
- value: [],
42
- editors: [
43
- { id: 'name', target: 'name', field: { type: 'text', value: '', default: '' } },
44
- { id: 'value', target: 'value', field: { type: 'text', value: '', default: '' } },
45
- { id: 'domain', target: 'domain', field: { type: 'text', value: '', default: '' } },
46
- { id: 'path', target: 'path', field: { type: 'text', value: '', default: '' } },
47
- { id: 'expires', target: 'expires', field: { type: 'text', value: '', default: '' } },
48
- { id: 'size', target: 'size', field: { type: 'integer', value: 0, default: 0 } },
49
- { id: 'httpOnly', target: 'httpOnly', field: { type: 'boolean', value: false, default: false } },
50
- { id: 'secure', target: 'secure', field: { type: 'boolean', value: true, default: true } },
51
- { id: 'sameSite', target: 'sameSite', field: { type: 'text', value: 'None', default: 'None' } },
52
- { id: 'priority', target: 'priority', field: { type: 'text', value: 'Medium', default: 'Medium' } },
53
- ],
54
- },
55
- carry_cookies_from: {
56
- description: 'Carry the cookies from this path in the event. Defaults to "cookies".',
57
- type: 'text',
58
- shrink: true,
59
- value: '',
60
- },
61
- headers: {
62
- description: 'Headers for the web request. These can be received from a previous browser event with {{headers}}, or can be typed manually.',
63
- type: 'keyvalue',
64
- shrink: true,
65
- value: {},
66
- },
67
- carry_headers_from: {
68
- description: 'Carry the headers from this path in the event. Defaults to "headers".',
69
- type: 'text',
70
- shrink: true,
71
- value: '',
72
- },
73
- wait_before_closing: {
74
- description: 'Wait this many seconds before closing the browser.',
75
- type: 'integer',
76
- shrink: true,
77
- value: '',
78
- },
3
+ class Mushy::Browser < Mushy::Flux
4
+ def self.details
5
+ {
6
+ name: 'Browser',
7
+ title: 'Use a browser',
8
+ fluxGroup: { name: 'Web' },
9
+ description: 'Visit a page in a browser.',
10
+ config: {
11
+ url: {
12
+ description: 'The URL to visit.',
13
+ type: 'text',
14
+ value: 'https://www.google.com'
15
+ },
16
+ headless: {
17
+ description: 'Run this browser headless.',
18
+ type: 'boolean',
19
+ shrink: true,
20
+ value: ''
21
+ },
22
+ timeout: {
23
+ description: 'The default timeout (in seconds) before closing the browser. Default is 5 seconds.',
24
+ type: 'integer',
25
+ shrink: true,
26
+ value: ''
27
+ },
28
+ execute: {
29
+ description: 'Javascript to run after the page is loaded.',
30
+ type: 'textarea',
31
+ shrink: true,
32
+ value: ''
33
+ },
34
+ cookies: {
35
+ description: 'Cookies for the web request. These can be received from a previous browser event with {{cookies}}, or can be typed manually.',
36
+ type: 'editgrid',
37
+ shrink: true,
38
+ value: [],
39
+ editors: [
40
+ { id: 'name', target: 'name', field: { type: 'text', value: '', default: '' } },
41
+ { id: 'value', target: 'value', field: { type: 'text', value: '', default: '' } },
42
+ { id: 'domain', target: 'domain', field: { type: 'text', value: '', default: '' } },
43
+ { id: 'path', target: 'path', field: { type: 'text', value: '', default: '' } },
44
+ { id: 'expires', target: 'expires', field: { type: 'text', value: '', default: '' } },
45
+ { id: 'size', target: 'size', field: { type: 'integer', value: 0, default: 0 } },
46
+ { id: 'httpOnly', target: 'httpOnly', field: { type: 'boolean', value: false, default: false } },
47
+ { id: 'secure', target: 'secure', field: { type: 'boolean', value: true, default: true } },
48
+ { id: 'sameSite', target: 'sameSite', field: { type: 'text', value: 'None', default: 'None' } },
49
+ { id: 'priority', target: 'priority', field: { type: 'text', value: 'Medium', default: 'Medium' } },
50
+ ]
51
+ },
52
+ carry_cookies_from: {
53
+ description: 'Carry the cookies from this path in the event. Defaults to "cookies".',
54
+ type: 'text',
55
+ shrink: true,
56
+ value: ''
57
+ },
58
+ headers: {
59
+ description: 'Headers for the web request. These can be received from a previous browser event with {{headers}}, or can be typed manually.',
60
+ type: 'keyvalue',
61
+ shrink: true,
62
+ value: {}
63
+ },
64
+ carry_headers_from: {
65
+ description: 'Carry the headers from this path in the event. Defaults to "headers".',
66
+ type: 'text',
67
+ shrink: true,
68
+ value: ''
69
+ },
70
+ wait_before_closing: {
71
+ description: 'Wait this many seconds before closing the browser.',
72
+ type: 'integer',
73
+ shrink: true,
74
+ value: ''
75
+ }
76
+ },
77
+ examples: {
78
+ 'Successful Call' => {
79
+ description: 'This will open https://www.google.com and return the result.',
80
+ config: { url: "https://www.google.com" },
81
+ result: {
82
+ url: 'https://www.google.com/',
83
+ status: 200,
84
+ title: 'Google',
85
+ cookies: [
86
+ {
87
+ name: '1P_JAR',
88
+ value: '2021-10-06-12',
89
+ domain: '.google.com',
90
+ path: '/',
91
+ expires: 1636117150.583117,
92
+ size: 19,
93
+ httpOnly: false,
94
+ secure: true,
95
+ session: false,
96
+ sameSite: 'None',
97
+ priority: 'Medium'
98
+ }
99
+ ],
100
+ headers: {},
101
+ time: 1.486214604,
102
+ body: '<html itemscope="" itemtype="http://schema.org/WebPage" lang="en">...</html>'
103
+ }
79
104
  },
80
- examples: {
81
- "Successful Call" => {
82
- description: 'This will open https://www.google.com and return the result.',
83
- config: {
84
- url: "https://www.google.com",
85
- },
86
- result: {
87
- "url": "https://www.google.com/",
88
- "status": 200,
89
- "title": "Google",
90
- "cookies": [
91
- {
92
- "name": "1P_JAR",
93
- "value": "2021-10-06-12",
94
- "domain": ".google.com",
95
- "path": "/",
96
- "expires": 1636117150.583117,
97
- "size": 19,
98
- "httpOnly": false,
99
- "secure": true,
100
- "session": false,
101
- "sameSite": "None",
102
- "priority": "Medium"
103
- },
104
- ],
105
- "headers": {},
106
- "time": 1.486214604,
107
- "body": "<html itemscope=\"\" itemtype=\"http://schema.org/WebPage\" lang=\"en\">...</html>"
108
- }
109
- },
110
- "Login To a Site" => {
111
- description: 'This will open https://www.yoursitepleasethankyou.com, login using javascript, and then return the state of the browser after logging in.',
112
- input: {
113
- url: "https://www.yoursitepleasethankyou.com",
114
- username: "MYUSERNAME",
115
- password: "MYPASSWORD",
116
- },
117
- config: {
118
- url: "{{url}}",
119
- timeout: 10,
120
- execute: "$('#username').val('{{username}}');
105
+ 'Login To a Site' => {
106
+ description: 'This will open https://www.yoursitepleasethankyou.com, login using javascript, and then return the state of the browser after logging in.',
107
+ input: {
108
+ url: 'https://www.yoursitepleasethankyou.com',
109
+ username: 'MYUSERNAME',
110
+ password: 'MYPASSWORD'
111
+ },
112
+ config: {
113
+ url: '{{url}}',
114
+ timeout: 10,
115
+ execute: "$('#username').val('{{username}}');
121
116
  $('#next').click();
122
117
  $('#password').val('{{password}}');
123
118
  $('#login').click();"
124
- },
125
- result: {
126
- "url": "https://yoursitepleasethankyou/",
127
- "status": 200,
128
- "title": "",
129
- "cookies": [
130
- {
131
- "name": "session_id",
132
- "value": "1jfujsx5xbnuxmsjmgjhzfpi",
133
- "domain": ".yoursitepleasethankyou",
134
- "path": "/",
135
- "expires": -1,
136
- "size": 41,
137
- "httpOnly": true,
138
- "secure": true,
139
- "session": true,
140
- "sameSite": "Lax",
141
- "priority": "Medium"
142
- }
143
- ],
144
- "headers": {},
145
- "time": 4.633920809,
146
- "body": "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head>...</html>"
147
- }
148
- },
149
- "Access a Page After Logging In" => {
150
- description: 'This will open a page using cookies from the previous request. Note that the cookies came from another browser flux event.',
151
- input: {
152
- "url": "https://yoursitepleasethankyou/",
153
- "cookies": [
154
- {
155
- "name": "session_id",
156
- "value": "1jfujsx5xbnuxmsjmgjhzfpi",
157
- "domain": ".yoursitepleasethankyou",
158
- "path": "/",
159
- "expires": -1,
160
- "size": 41,
161
- "httpOnly": true,
162
- "secure": true,
163
- "session": true,
164
- "sameSite": "Lax",
165
- "priority": "Medium"
166
- }
167
- ],
168
- },
169
- config: {
170
- url: "https://www.yoursitepleasethankyou.com/myaccount",
171
- carry_cookies_from: "{{cookies}}"
172
- },
173
- result: {
174
- "url": "https://yoursitepleasethankyou/",
175
- "status": 200,
176
- "title": "",
177
- "cookies": [
178
- {
179
- "name": "session_id",
180
- "value": "1jfujsx5xbnuxmsjmgjhzfpi",
181
- "domain": ".yoursitepleasethankyou",
182
- "path": "/",
183
- "expires": -1,
184
- "size": 41,
185
- "httpOnly": true,
186
- "secure": true,
187
- "session": true,
188
- "sameSite": "Lax",
189
- "priority": "Medium"
190
- }
191
- ],
192
- "headers": {},
193
- "time": 4.633920809,
194
- "body": "<html><head></head>Your name is John Doe...</html>"
195
- }
196
- }
197
- }
119
+ },
120
+ result: {
121
+ url: 'https://yoursitepleasethankyou/',
122
+ status: 200,
123
+ title: '',
124
+ cookies: [
125
+ {
126
+ name: 'session_id',
127
+ value: '1jfujsx5xbnuxmsjmgjhzfpi',
128
+ domain: '.yoursitepleasethankyou',
129
+ path: '/',
130
+ expires: -1,
131
+ size: 41,
132
+ httpOnly: true,
133
+ secure: true,
134
+ session: true,
135
+ sameSite: 'Lax',
136
+ priority: 'Medium'
137
+ }
138
+ ],
139
+ headers: {},
140
+ time: 4.633920809,
141
+ body: '<html xmlns="http://www.w3.org/1999/xhtml"><head></head>...</html>'
142
+ }
143
+ },
144
+ 'Access a Page After Logging In' => {
145
+ description: 'This will open a page using cookies from the previous request. Note that the cookies came from another browser flux event.',
146
+ input: {
147
+ url: 'https://yoursitepleasethankyou/',
148
+ cookies: [
149
+ {
150
+ name: 'session_id',
151
+ value: '1jfujsx5xbnuxmsjmgjhzfpi',
152
+ domain: '.yoursitepleasethankyou',
153
+ path: '/',
154
+ expires: -1,
155
+ size: 41,
156
+ httpOnly: true,
157
+ secure: true,
158
+ session: true,
159
+ sameSite: 'Lax',
160
+ priority: 'Medium'
161
+ }
162
+ ]
163
+ },
164
+ config: {
165
+ url: 'https://www.yoursitepleasethankyou.com/myaccount',
166
+ carry_cookies_from: '{{cookies}}'
167
+ },
168
+ result: {
169
+ url: 'https://yoursitepleasethankyou/',
170
+ status: 200,
171
+ title: '',
172
+ cookies: [
173
+ {
174
+ name: 'session_id',
175
+ value: '1jfujsx5xbnuxmsjmgjhzfpi',
176
+ domain: '.yoursitepleasethankyou',
177
+ path: '/',
178
+ expires: -1,
179
+ size: 41,
180
+ httpOnly: true,
181
+ secure: true,
182
+ session: true,
183
+ sameSite: 'Lax',
184
+ priority: 'Medium'
185
+ }
186
+ ],
187
+ headers: {},
188
+ time: 4.633920809,
189
+ body: '<html><head></head>Your name is John Doe...</html>'
190
+ }
191
+ }
198
192
  }
199
- end
200
-
201
- def process event, config
202
-
203
- timeout = config[:timeout] ? config[:timeout].to_i : 5
193
+ }
194
+ end
204
195
 
205
- browser = Ferrum::Browser.new(
206
- headless: (config[:headless].to_s != 'false'),
207
- timeout: timeout)
196
+ def process event, config
197
+ timeout = config[:timeout] ? config[:timeout].to_i : 5
208
198
 
209
- get_the_cookies_from(event, config).each { |c| browser.cookies.set(c) }
199
+ browser = Ferrum::Browser.new(
200
+ headless: (config[:headless].to_s != 'false'),
201
+ timeout: timeout
202
+ )
210
203
 
211
- browser.headers.add get_the_headers_from(event, config)
204
+ get_the_cookies_from(event, config).each { |c| browser.cookies.set(c) }
212
205
 
213
- the_start = Time.now
214
- browser.goto config[:url]
215
- time = Time.now - the_start
206
+ browser.headers.add get_the_headers_from(event, config)
216
207
 
217
- browser.execute(config[:execute]) if config[:execute]
208
+ the_start = Time.now.utc
209
+ browser.goto config[:url]
210
+ time = Time.now.utc - the_start
218
211
 
219
- sleep(config[:wait_before_closing].to_i) if config[:wait_before_closing] && config[:wait_before_closing].to_i > 0
212
+ browser.execute(config[:execute]) if config[:execute]
220
213
 
221
- result = {
222
- url: browser.url,
223
- status: browser.network.status,
224
- title: browser.frames[0].title,
225
- cookies: browser.cookies.all.map { |k, v| v.instance_variable_get('@attributes') },
226
- headers: browser.headers.get,
227
- time: time,
228
- body: browser.body
229
- }
214
+ sleep(config[:wait_before_closing].to_i) if config[:wait_before_closing]&.to_i&.positive?
230
215
 
231
- result = adjust( { browser: browser, result: result, config: config } )
216
+ result = {
217
+ url: browser.url,
218
+ status: browser.network.status,
219
+ title: browser.frames[0].title,
220
+ cookies: browser.cookies.all.map { |_, v| v.instance_variable_get('@attributes') },
221
+ headers: browser.headers.get,
222
+ time: time,
223
+ body: browser.body
224
+ }
232
225
 
233
- browser.quit
226
+ result = adjust({ browser: browser, result: result, config: config })
234
227
 
235
- result
236
- end
228
+ browser.quit
237
229
 
238
- def adjust input
239
- input[:result]
240
- end
241
-
242
- def get_the_cookies_from event, config
243
- carry_cookies_from = config[:carry_cookies_from].to_s == '' ? 'cookies' : config[:carry_cookies_from]
244
- cookies = event[carry_cookies_from.to_sym]
245
- cookies = [] unless cookies.is_a?(Array)
246
- config[:cookies] = [] unless config[:cookies].is_a?(Array)
247
- config[:cookies].each { |x| cookies << x }
248
- cookies
249
- end
230
+ result
231
+ end
250
232
 
251
- def get_the_headers_from event, config
252
- carry_headers_from = config[:carry_headers_from].to_s == '' ? 'headers' : config[:carry_headers_from]
253
- headers = event[carry_headers_from.to_sym]
254
- headers = {} unless headers.is_a?(Hash)
255
- config[:headers] = {} unless config[:headers].is_a?(Hash)
256
- config[:headers].each { |k, v| headers[k] = v }
257
- headers
258
- end
233
+ def adjust(input)
234
+ input[:result]
235
+ end
259
236
 
237
+ def get_the_cookies_from(event, config)
238
+ carry_cookies_from = config[:carry_cookies_from].to_s == '' ? 'cookies' : config[:carry_cookies_from]
239
+ cookies = event[carry_cookies_from.to_sym]
240
+ cookies = [] unless cookies.is_a?(Array)
241
+ config[:cookies] = [] unless config[:cookies].is_a?(Array)
242
+ config[:cookies].each { |x| cookies << x }
243
+ cookies
260
244
  end
261
245
 
262
- end
246
+ def get_the_headers_from(event, config)
247
+ carry_headers_from = config[:carry_headers_from].to_s == '' ? 'headers' : config[:carry_headers_from]
248
+ headers = event[carry_headers_from.to_sym]
249
+ headers = {} unless headers.is_a?(Hash)
250
+ config[:headers] = {} unless config[:headers].is_a?(Hash)
251
+ config[:headers].each { |k, v| headers[k] = v }
252
+ headers
253
+ end
254
+ end
@@ -1,76 +1,68 @@
1
1
  require 'csv'
2
2
 
3
- module Mushy
4
-
5
- class BuildCsv < Flux
6
-
7
- def self.details
8
- {
9
- name: 'BuildCsv',
10
- title: "Build CSV",
11
- description: 'Build a CSV.',
12
- fluxGroup: { name: 'CSV' },
13
- config: {
14
- input_path: {
15
- description: 'The path to the set of records to include in the CSV.',
16
- type: 'text',
17
- value: 'records',
18
- },
19
- output_path: {
20
- description: 'The path to the CSV content in the outgoing event.',
21
- type: 'text',
22
- value: 'records',
23
- },
24
- headers: {
25
- description: 'The values to include in the CSV, as well as the header values.',
26
- type: 'keyvalue',
27
- value: {},
28
- },
29
- header_row: {
30
- description: 'Include a header row?',
31
- type: 'boolean',
32
- value: true,
33
- },
3
+ class Mushy::BuildCsv < Mushy::Flux
4
+ def self.details
5
+ {
6
+ name: 'BuildCsv',
7
+ title: 'Build CSV',
8
+ description: 'Build a CSV.',
9
+ fluxGroup: { name: 'CSV' },
10
+ config: {
11
+ input_path: {
12
+ description: 'The path to the set of records to include in the CSV.',
13
+ type: 'text',
14
+ value: 'records'
15
+ },
16
+ output_path: {
17
+ description: 'The path to the CSV content in the outgoing event.',
18
+ type: 'text',
19
+ value: 'records'
20
+ },
21
+ headers: {
22
+ description: 'The values to include in the CSV, as well as the header values.',
23
+ type: 'keyvalue',
24
+ value: {}
25
+ },
26
+ header_row: {
27
+ description: 'Include a header row?',
28
+ type: 'boolean',
29
+ value: true
30
+ }
31
+ },
32
+ examples: {
33
+ 'Build a Simple CSV' => {
34
+ description: 'Converts a set of records to a CSV.',
35
+ input: {
36
+ things: [
37
+ { name: 'Apple', color: 'Red' },
38
+ { name: 'Banana', color: 'Yellow' },
39
+ { name: 'Pear', color: 'Green' }
40
+ ]
41
+ },
42
+ config: {
43
+ input_path: 'things',
44
+ output_path: 'records',
45
+ headers: { name: 'Name', color: 'Color' },
46
+ header_row: true
47
+ },
48
+ result: {
49
+ records: 'Name,Color\nApple,Red\nBanana,Yellow\nPear,Green\n'
50
+ }
34
51
  },
35
- examples: {
36
- "Build a Simple CSV" => {
37
- description: 'Converts a set of records to a CSV.',
38
- input: {
39
- things: [
40
- { name: "Apple", color:"Red" },
41
- { name: "Banana", color: "Yellow" },
42
- { name: "Pear", color: "Green" }
43
- ]
44
- },
45
- config: {
46
- input_path: "things",
47
- output_path: "records",
48
- headers: { name: "Name", color: "Color" },
49
- header_row: true
50
- },
51
- result: {
52
- records: "Name,Color\nApple,Red\nBanana,Yellow\nPear,Green\n"
53
- }
54
- },
55
- }
56
52
  }
57
- end
58
-
59
- def process event, config
60
- records = event[config[:input_path].to_sym] || event[config[:input_path].to_s]
53
+ }
54
+ end
61
55
 
62
- headers = config[:headers]
56
+ def process(event, config)
57
+ records = event[config[:input_path].to_sym] || event[config[:input_path].to_s]
63
58
 
64
- {
65
- config[:output_path] => CSV.generate do |c|
66
- if config[:header_row].to_s == 'true'
67
- c << headers.map { |h| h[1] }
68
- end
69
- records.each { |x| c << headers.map { |h| x[h[0].to_sym] || x[h[0].to_s] } }
70
- end
71
- }
72
- end
59
+ headers = config[:headers]
73
60
 
61
+ {
62
+ config[:output_path] => CSV.generate do |c|
63
+ c << headers.map { |h| h[1] } if config[:header_row].to_s == 'true'
64
+ records.each { |x| c << headers.map { |h| x[h[0].to_sym] || x[h[0].to_s] } }
65
+ end
66
+ }
74
67
  end
75
-
76
- end
68
+ end