Merge branch 'master' of github.com:cantino/huginn

Andrew Cantino 9 gadi atpakaļ
vecāks
revīzija
4afed4ae68

+ 10 - 7
app/assets/stylesheets/application.css.scss.erb

@@ -264,17 +264,20 @@ h2 .scenario, a span.label.scenario {
264 264
   width: 200px;
265 265
 }
266 266
 
267
-$services:            twitter     37signals   github      tumblr      dropbox   wunderlist;
268
-$service-colors:      #55acee     #8fc857     #444444     #2c4762     #007EE5   #ED5F27;
267
+$service-colors: (
268
+  twitter:      #55acee,
269
+  37signals:    #8fc857,
270
+  github:       #444444,
271
+  tumblr:       #2c4762,
272
+  dropbox:      #007EE5,
273
+  wunderlist:   #ED5F27
274
+);
269 275
 
270 276
 @mixin services {
271
-  @each $service in $services {
272
-    $i: index($services, $service);
273
-    $service-color: nth($service-colors, $i);
274
-
277
+  @each $service, $color in $service-colors {
275 278
     &.service-#{$service} {
276 279
       color: #fff;
277
-      background-color: $service-color;
280
+      background-color: $color;
278 281
     }
279 282
   }
280 283
 }

+ 26 - 5
app/models/agents/post_agent.rb

@@ -2,8 +2,7 @@ module Agents
2 2
   class PostAgent < Agent
3 3
     include WebRequestConcern
4 4
 
5
-    cannot_create_events!
6
-
5
+    can_dry_run!
7 6
     default_schedule "never"
8 7
 
9 8
     description <<-MD
@@ -15,6 +14,9 @@ module Agents
15 14
 
16 15
       By default, non-GETs will be sent with form encoding (`application/x-www-form-urlencoded`).  Change `content_type` to `json` to send JSON instead.  Change `content_type` to `xml` to send XML, where the name of the root element may be specified using `xml_root`, defaulting to `post`.
17 16
 
17
+      If `emit_events` is set to `true`, the server response will be emitted as an Event and can be fed to a WebsiteAgent for parsing (using its `data_from_event` and `type` options). No data processing
18
+      will be attempted by this Agent, so the Event's "body" value will always be raw text.
19
+
18 20
       Other Options:
19 21
 
20 22
         * `headers` - When present, it should be a hash of headers to send with the request.
@@ -23,7 +25,17 @@ module Agents
23 25
         * `user_agent` - A custom User-Agent name (default: "Faraday v#{Faraday::VERSION}").
24 26
     MD
25 27
 
26
-    event_description "Does not produce events."
28
+    event_description <<-MD
29
+      Events look like this:
30
+        {
31
+          "status": 200,
32
+          "headers": {
33
+            "Content-Type": "text/html",
34
+            ...
35
+          },
36
+          "body": "<html>Some data...</html>"
37
+        }
38
+    MD
27 39
 
28 40
     def default_options
29 41
       {
@@ -35,7 +47,8 @@ module Agents
35 47
           'key' => 'value',
36 48
           'something' => 'the event contained {{ somekey }}'
37 49
         },
38
-        'headers' => {}
50
+        'headers' => {},
51
+        'emit_events' => 'false'
39 52
       }
40 53
     end
41 54
 
@@ -56,6 +69,10 @@ module Agents
56 69
         errors.add(:base, "if provided, payload must be a hash")
57 70
       end
58 71
 
72
+      if options.has_key?('emit_events') && boolify(options['emit_events']).nil?
73
+        errors.add(:base, "if provided, emit_events must be true or false")
74
+      end
75
+
59 76
       unless %w[post get put delete patch].include?(method)
60 77
         errors.add(:base, "method must be 'post', 'get', 'put', 'delete', or 'patch'")
61 78
       end
@@ -112,9 +129,13 @@ module Agents
112 129
         error "Invalid method '#{method}'"
113 130
       end
114 131
 
115
-      faraday.run_request(method.to_sym, url, body, headers) { |request|
132
+      response = faraday.run_request(method.to_sym, url, body, headers) { |request|
116 133
         request.params.update(params) if params
117 134
       }
135
+
136
+      if boolify(interpolated['emit_events'])
137
+        create_event payload: { body: response.body, headers: response.headers, status: response.status }
138
+      end
118 139
     end
119 140
   end
120 141
 end

+ 2 - 0
app/models/agents/website_agent.rb

@@ -59,6 +59,8 @@ module Agents
59 59
             "description": { "path": "results.data[*].description" }
60 60
           }
61 61
 
62
+      The `extract` option can be skipped for the JSON type, causing the full JSON response to be returned.
63
+
62 64
       # Scraping Text
63 65
 
64 66
       When parsing text, each sub-hash should contain a `regexp` and `index`.  Output text is matched against the regular expression repeatedly from the beginning through to the end, collecting a captured group specified by `index` in each match.  Each index should be either an integer or a string name which corresponds to <code>(?&lt;<em>name</em>&gt;...)</code>.  For example, to parse lines of <code><em>word</em>: <em>definition</em></code>, the following should work:

+ 52 - 1
spec/models/agents/post_agent_spec.rb

@@ -50,7 +50,7 @@ describe Agents::PostAgent do
50 50
           raise "unexpected Content-Type: #{content_type}"
51 51
         end
52 52
       end
53
-      { status: 200, body: "ok" }
53
+      { status: 200, body: "<html>a webpage!</html>", headers: { 'Content-Type' => 'text/html' } }
54 54
     }
55 55
   end
56 56
 
@@ -186,6 +186,40 @@ describe Agents::PostAgent do
186 186
 
187 187
       expect(@sent_requests[:get][0].data).to eq(@checker.options['payload'].to_query)
188 188
     end
189
+
190
+    describe "emitting events" do
191
+      context "when emit_events is not set to true" do
192
+        it "does not emit events" do
193
+          expect {
194
+            @checker.check
195
+          }.not_to change { @checker.events.count }
196
+        end
197
+      end
198
+
199
+      context "when emit_events is set to true" do
200
+        before do
201
+          @checker.options['emit_events'] = 'true'
202
+          @checker.save!
203
+        end
204
+
205
+        it "emits the response status" do
206
+          expect {
207
+            @checker.check
208
+          }.to change { @checker.events.count }.by(1)
209
+          expect(@checker.events.last.payload['status']).to eq 200
210
+        end
211
+
212
+        it "emits the body" do
213
+          @checker.check
214
+          expect(@checker.events.last.payload['body']).to eq '<html>a webpage!</html>'
215
+        end
216
+
217
+        it "emits the response headers" do
218
+          @checker.check
219
+          expect(@checker.events.last.payload['headers']).to eq({ 'Content-Type' => 'text/html' })
220
+        end
221
+      end
222
+    end
189 223
   end
190 224
 
191 225
   describe "#working?" do
@@ -286,5 +320,22 @@ describe Agents::PostAgent do
286 320
       @checker.options['headers'] = { "Authorization" => "foo bar" }
287 321
       expect(@checker).to be_valid
288 322
     end
323
+
324
+    it "requires emit_events to be true or false" do
325
+      @checker.options['emit_events'] = 'what?'
326
+      expect(@checker).not_to be_valid
327
+
328
+      @checker.options.delete('emit_events')
329
+      expect(@checker).to be_valid
330
+
331
+      @checker.options['emit_events'] = 'true'
332
+      expect(@checker).to be_valid
333
+
334
+      @checker.options['emit_events'] = 'false'
335
+      expect(@checker).to be_valid
336
+
337
+      @checker.options['emit_events'] = true
338
+      expect(@checker).to be_valid
339
+    end
289 340
   end
290 341
 end