Browse Source

UserLocationAgent: Receive events and accept POST via WebRequestsController.

Show the POST URL on the details page while at it.

The old user_location_updates URLs still work.

This addresses #490.
Akinori MUSHA 10 years ago
parent
commit
f720291b49

+ 9 - 0
app/assets/javascripts/application.js.coffee.erb

@@ -215,3 +215,12 @@ $(document).ready ->
       showEventCreation()
     else
       hideEventCreation()
+
+  $('.selectable-text').each ->
+    $(this).click ->
+      range = document.createRange()
+      range.setStartBefore(this.firstChild)
+      range.setEndAfter(this.lastChild)
+      sel = window.getSelection()
+      sel.removeAllRanges();
+      sel.addRange(range)

+ 1 - 3
app/controllers/user_location_updates_controller.rb

@@ -6,9 +6,7 @@ class UserLocationUpdatesController < ApplicationController
     if user
       secret = params[:secret]
       user.agents.of_type(Agents::UserLocationAgent).find_all {|agent| agent.options[:secret] == secret }.each do |agent|
-        agent.create_event :payload => params.except(:controller, :action, :secret, :user_id, :format),
-                           :lat => params[:latitude],
-                           :lng => params[:longitude]
+        agent.trigger_web_request(params.except(:action, :controller, :user_id, :format), request.method_symbol.to_s, request.format.to_s)
       end
       render :text => "ok"
     else

+ 31 - 2
app/models/agents/user_location_agent.rb

@@ -2,7 +2,6 @@ require 'securerandom'
 
 module Agents
   class UserLocationAgent < Agent
-    cannot_receive_events!
     cannot_be_scheduled!
 
     description do
@@ -40,5 +39,35 @@ module Agents
     def validate_options
       errors.add(:base, "secret is required and must be longer than 4 characters") unless options['secret'].present? && options['secret'].length > 4
     end
+
+    def receive(incoming_events)
+      incoming_events.each do |event|
+        interpolate_with(event) do
+          handle_payload event.payload
+        end
+      end
+    end
+
+    def receive_web_request(params, method, format)
+      params = params.symbolize_keys
+      if method != 'post'
+        return ['Not Found', 404]
+      end
+      if interpolated['secret'] != params[:secret]
+        return ['Not Authorized', 401]
+      end
+
+      handle_payload params.except(:secret)
+
+      return ['ok', 200]
+    end
+
+    private
+
+    def handle_payload(payload)
+      if payload[:latitude].present? && payload[:longitude].present?
+        create_event payload: payload, lat: payload[:latitude].to_f, lng: payload[:longitude].to_f
+      end
+    end
   end
-end
+end

+ 10 - 0
app/views/agents/agent_views/user_location_agent/_show.html.erb

@@ -24,3 +24,13 @@
     No events found.
   </p>
 <% end %>
+
+<h3>POST URL</h3>
+
+<p>
+  Location data containing <code>latitude</code> and <code>longitude</code> can be posted to this URL:<br/>
+
+  <ul>
+    <li><code class="selectable-text"><%= web_requests_url(user_id: @agent.user_id, agent_id: @agent.id, secret: @agent.options['secret']) %></code></li>
+  </ul>
+</p>

+ 1 - 1
config/routes.rb

@@ -62,7 +62,7 @@ Huginn::Application.routes.draw do
 
   get "/worker_status" => "worker_status#show"
 
-  post "/users/:user_id/update_location/:secret" => "user_location_updates#create"
+  post "/users/:user_id/update_location/:secret" => "user_location_updates#create" # legacy
 
   match  "/users/:user_id/web_requests/:agent_id/:secret" => "web_requests#handle_request", :as => :web_requests, :via => [:get, :post, :put, :delete]
   post "/users/:user_id/webhooks/:agent_id/:secret" => "web_requests#handle_request" # legacy

+ 48 - 0
spec/models/agents/user_location_agent_spec.rb

@@ -0,0 +1,48 @@
+require 'spec_helper'
+
+describe Agents::UserLocationAgent do
+  before do
+    @agent = Agent.build_for_type('Agents::UserLocationAgent', users(:bob), :name => 'something', :options => { :secret => 'my_secret' })
+    @agent.save!
+  end
+
+  it 'receives an event' do
+    event = Event.new
+    event.agent = agents(:bob_weather_agent)
+    event.created_at = Time.now
+    event.payload = { 'longitude' => 123, 'latitude' => 45, 'something' => 'else' }
+
+    lambda {
+      @agent.receive([event])
+    }.should change { @agent.events.count }.by(1)
+
+    @agent.events.last.payload.should == { 'longitude' => 123, 'latitude' => 45, 'something' => 'else' }
+    @agent.events.last.lat.should == 45
+    @agent.events.last.lng.should == 123
+  end
+
+  it 'does not accept a web request that is not POST' do
+    %w[get put delete patch].each { |method|
+      content, status, content_type = @agent.receive_web_request({ 'secret' => 'my_secret' }, method, 'application/json')
+      status.should == 404
+    }
+  end
+
+  it 'requires a valid secret for a web request' do
+    content, status, content_type = @agent.receive_web_request({ 'secret' => 'fake' }, 'post', 'application/json')
+    status.should == 401
+
+    content, status, content_type = @agent.receive_web_request({ 'secret' => 'my_secret' }, 'post', 'application/json')
+    status.should == 200
+  end
+
+  it 'creates an event on a web request' do
+    lambda {
+      @agent.receive_web_request({ 'secret' => 'my_secret', 'longitude' => 123, 'latitude' => 45, 'something' => 'else' }, 'post', 'application/json')
+    }.should change { @agent.events.count }.by(1)
+
+    @agent.events.last.payload.should == { 'longitude' => 123, 'latitude' => 45, 'something' => 'else' }
+    @agent.events.last.lat.should == 45
+    @agent.events.last.lng.should == 123
+  end
+end