mirror of
https://github.com/Fishwaldo/huginn.git
synced 2025-03-15 19:31:26 +00:00
Merge branch 'master' into human_task_agent
This commit is contained in:
commit
d766eb6cd3
30 changed files with 421 additions and 130 deletions
|
@ -8,13 +8,14 @@
|
|||
#= require ./worker-checker
|
||||
#= require_self
|
||||
|
||||
setupJsonEditor = ->
|
||||
window.setupJsonEditor = ($editor = $(".live-json-editor")) ->
|
||||
JSONEditor.prototype.ADD_IMG = '<%= image_path 'json-editor/add.png' %>'
|
||||
JSONEditor.prototype.DELETE_IMG = '<%= image_path 'json-editor/delete.png' %>'
|
||||
if $(".live-json-editor").length
|
||||
window.jsonEditor = new JSONEditor($(".live-json-editor"), 400, 500)
|
||||
window.jsonEditor.doTruncation true
|
||||
window.jsonEditor.showFunctionButtons()
|
||||
if $editor.length
|
||||
jsonEditor = new JSONEditor($editor, $editor.data('width') || 400, $editor.data('height') || 500)
|
||||
jsonEditor.doTruncation true
|
||||
jsonEditor.showFunctionButtons()
|
||||
return jsonEditor
|
||||
|
||||
hideSchedule = ->
|
||||
$(".schedule-region select").hide()
|
||||
|
@ -45,7 +46,7 @@ showEventDescriptions = ->
|
|||
|
||||
$(document).ready ->
|
||||
# JSON Editor
|
||||
setupJsonEditor()
|
||||
window.jsonEditor = setupJsonEditor()
|
||||
|
||||
# Select2 Selects
|
||||
$(".select2").select2(width: 'resolve')
|
||||
|
@ -54,7 +55,35 @@ $(document).ready ->
|
|||
if $(".flash").length
|
||||
setTimeout((-> $(".flash").slideUp(-> $(".flash").remove())), 5000)
|
||||
|
||||
# Agent Show
|
||||
# Agent Navigation
|
||||
$agentNavigate = $('#agent-navigate')
|
||||
$agentNavigate.typeahead(
|
||||
minLength: 0,
|
||||
items: 15,
|
||||
source: agentNames
|
||||
).on("change", (e) ->
|
||||
if agentPaths[$agentNavigate.val()]
|
||||
$('#agent-navigate').closest(".navbar-search").find(".spinner").show()
|
||||
navigationData = agentPaths[$agentNavigate.val()]
|
||||
if !(navigationData instanceof Object) || !navigationData.method || navigationData.method == 'GET'
|
||||
window.location = navigationData.url || navigationData
|
||||
else
|
||||
$("<a href='#{navigationData.url}' data-method='#{navigationData.method}'></a>").appendTo($("body")).click()
|
||||
|
||||
).on("focus", (e) ->
|
||||
$agentNavigate.val ''
|
||||
).on("blur", (e) ->
|
||||
$agentNavigate.val ''
|
||||
)
|
||||
|
||||
# Pressing '/' selects the search box.
|
||||
$("body").on "keypress", (e) ->
|
||||
if e.keyCode == 47 # The '/' key
|
||||
if e.target.nodeName == "BODY"
|
||||
e.preventDefault()
|
||||
$agentNavigate.focus()
|
||||
|
||||
# Agent Show
|
||||
fetchLogs = (e) ->
|
||||
agentId = $(e.target).closest("[data-agent-id]").data("agent-id")
|
||||
e.preventDefault()
|
||||
|
@ -76,16 +105,19 @@ $(document).ready ->
|
|||
$("#logs .spinner").stop(true, true).fadeOut ->
|
||||
$("#logs .refresh, #logs .clear").show()
|
||||
|
||||
$(".agent-show #show-tabs a[href='#logs']").on "click", fetchLogs
|
||||
$("#logs .refresh").on "click", fetchLogs
|
||||
$("#logs .clear").on "click", clearLogs
|
||||
$(".agent-show #show-tabs a[href='#logs'], #logs .refresh").on "click", fetchLogs
|
||||
$(".agent-show #logs .clear").on "click", clearLogs
|
||||
|
||||
if tab = window.location.href.match(/tab=(\w+)\b/i)?[1]
|
||||
if tab in ["details", "logs"]
|
||||
$(".agent-show .nav-tabs li a[href='##{tab}']").click()
|
||||
|
||||
# Editing Agents
|
||||
$("#agent_source_ids").on "change", showEventDescriptions
|
||||
|
||||
$("#agent_type").on "change", ->
|
||||
if window.jsonEditor?
|
||||
$(".spinner").fadeIn();
|
||||
$("#agent-spinner").fadeIn();
|
||||
$("#agent_source_ids").select2("val", {});
|
||||
$(".event-descriptions").html("").hide()
|
||||
$.getJSON "/agents/type_details", { type: $(@).val() }, (json) =>
|
||||
|
@ -104,7 +136,7 @@ $(document).ready ->
|
|||
window.jsonEditor.json = json.options
|
||||
window.jsonEditor.rebuild()
|
||||
|
||||
$(".spinner").stop(true, true).fadeOut();
|
||||
$("#agent-spinner").stop(true, true).fadeOut();
|
||||
|
||||
$("#agent_type").change() if $("#agent_type").length
|
||||
|
||||
|
|
|
@ -51,10 +51,6 @@ table.events {
|
|||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
#job-indicator, #event-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
img.odin {
|
||||
position: relative;
|
||||
top: -32px;
|
||||
|
@ -86,14 +82,30 @@ img.spinner {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
span.not-applicable:after {
|
||||
color: #bbbbbb;
|
||||
content: "n/a";
|
||||
}
|
||||
|
||||
// Navbar
|
||||
|
||||
#job-indicator, #event-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-search > .spinner {
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
right: 1px;
|
||||
}
|
||||
|
||||
// Flash
|
||||
|
||||
.flash {
|
||||
position: fixed;
|
||||
width: 500px;
|
||||
width: 210px;
|
||||
z-index: 99999;
|
||||
top: 1px;
|
||||
margin-left: 250px;
|
||||
right: 20px;
|
||||
|
||||
.alert {
|
||||
}
|
||||
|
@ -109,4 +121,4 @@ img.spinner {
|
|||
&.refresh {
|
||||
margin: 0 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,16 @@ class AgentsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def handle_details_post
|
||||
@agent = current_user.agents.find(params[:id])
|
||||
if @agent.respond_to?(:handle_details_post)
|
||||
render :json => @agent.handle_details_post(params) || {}
|
||||
else
|
||||
@agent.error "#handle_details_post called on an instance of #{@agent.class} that does not define it."
|
||||
head 500
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
agent = current_user.agents.find(params[:id])
|
||||
Agent.async_check(agent.id)
|
||||
|
|
|
@ -11,7 +11,7 @@ module ApplicationHelper
|
|||
if agent.working?
|
||||
'<span class="label label-success">Yes</span>'.html_safe
|
||||
else
|
||||
'<span class="label label-warning">No</span>'.html_safe
|
||||
link_to '<span class="label label-warning">No</span>'.html_safe, agent_path(agent, :tab => (agent.recent_error_logs? ? 'logs' : 'details'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ class SystemMailer < ActionMailer::Base
|
|||
default :from => ENV['EMAIL_FROM_ADDRESS'] || 'you@example.com'
|
||||
|
||||
def send_message(options)
|
||||
@lines = options[:lines]
|
||||
@groups = options[:groups]
|
||||
@headline = options[:headline]
|
||||
mail :to => options[:to], :subject => options[:subject]
|
||||
end
|
||||
|
|
|
@ -88,7 +88,11 @@ class Agent < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def create_event(attrs)
|
||||
events.create!({ :user => user }.merge(attrs))
|
||||
if can_create_events?
|
||||
events.create!({ :user => user }.merge(attrs))
|
||||
else
|
||||
error "This Agent cannot create events!"
|
||||
end
|
||||
end
|
||||
|
||||
def validate_schedule
|
||||
|
@ -117,7 +121,7 @@ class Agent < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def last_event_at
|
||||
@memoized_last_event_at ||= events.select(:created_at).first.try(:created_at)
|
||||
@memoized_last_event_at ||= most_recent_event.try(:created_at)
|
||||
end
|
||||
|
||||
def default_schedule
|
||||
|
@ -140,6 +144,14 @@ class Agent < ActiveRecord::Base
|
|||
!cannot_receive_events?
|
||||
end
|
||||
|
||||
def cannot_create_events?
|
||||
self.class.cannot_create_events?
|
||||
end
|
||||
|
||||
def can_create_events?
|
||||
!cannot_create_events?
|
||||
end
|
||||
|
||||
def set_last_checked_event_id
|
||||
if newest_event_id = Event.order("id desc").limit(1).pluck(:id).first
|
||||
self.last_checked_event_id = newest_event_id
|
||||
|
@ -170,6 +182,14 @@ class Agent < ActiveRecord::Base
|
|||
@default_schedule
|
||||
end
|
||||
|
||||
def cannot_create_events!
|
||||
@cannot_create_events = true
|
||||
end
|
||||
|
||||
def cannot_create_events?
|
||||
!!@cannot_create_events
|
||||
end
|
||||
|
||||
def cannot_receive_events!
|
||||
@cannot_receive_events = true
|
||||
end
|
||||
|
|
|
@ -3,6 +3,8 @@ module Agents
|
|||
MAIN_KEYS = %w[title message text main value].map(&:to_sym)
|
||||
default_schedule "5am"
|
||||
|
||||
cannot_create_events!
|
||||
|
||||
description <<-MD
|
||||
The DigestEmailAgent collects any Events sent to it and sends them all via email when run.
|
||||
The email will be sent to your account's address and will have a `subject` and an optional `headline` before
|
||||
|
@ -37,30 +39,28 @@ module Agents
|
|||
|
||||
def check
|
||||
if self.memory[:queue] && self.memory[:queue].length > 0
|
||||
lines = self.memory[:queue].map {|item| present(item) }
|
||||
groups = self.memory[:queue].map { |payload| present(payload) }
|
||||
log "Sending digest mail to #{user.email}"
|
||||
SystemMailer.delay.send_message(:to => user.email, :subject => options[:subject], :headline => options[:headline], :lines => lines)
|
||||
SystemMailer.delay.send_message(:to => user.email, :subject => options[:subject], :headline => options[:headline], :groups => groups)
|
||||
self.memory[:queue] = []
|
||||
end
|
||||
end
|
||||
|
||||
def present(item)
|
||||
if item.is_a?(Hash)
|
||||
def present(payload)
|
||||
if payload.is_a?(Hash)
|
||||
payload = ActiveSupport::HashWithIndifferentAccess.new(payload)
|
||||
MAIN_KEYS.each do |key|
|
||||
if item.has_key?(key)
|
||||
return "#{item[key]}" + ((item.length > 1 && item.length < 5) ? " (#{present_hash item, key})" : "")
|
||||
elsif item.has_key?(key.to_s)
|
||||
return "#{item[key.to_s]}" + ((item.length > 1 && item.length < 5) ? " (#{present_hash item, key.to_s})" : "")
|
||||
end
|
||||
return { :title => payload[key].to_s, :entries => present_hash(payload, key) } if payload.has_key?(key)
|
||||
end
|
||||
present_hash item
|
||||
|
||||
{ :title => "Event", :entries => present_hash(payload) }
|
||||
else
|
||||
item.to_s
|
||||
{ :title => payload.to_s, :entries => [] }
|
||||
end
|
||||
end
|
||||
|
||||
def present_hash(hash, skip_key = nil)
|
||||
hash.to_a.sort_by {|a| a.first.to_s }.map { |k, v| "#{k}: #{v}" unless [skip_key].include?(k) }.compact.to_sentence
|
||||
hash.to_a.sort_by {|a| a.first.to_s }.map { |k, v| "#{k}: #{v}" unless k.to_s == skip_key.to_s }.compact
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
32
app/models/agents/manual_event_agent.rb
Normal file
32
app/models/agents/manual_event_agent.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
module Agents
|
||||
class ManualEventAgent < Agent
|
||||
cannot_be_scheduled!
|
||||
cannot_receive_events!
|
||||
|
||||
description <<-MD
|
||||
Use this Agent to manually create Events for testing or other purposes.
|
||||
MD
|
||||
|
||||
event_description "User determined"
|
||||
|
||||
def default_options
|
||||
{ "no options" => "are needed" }
|
||||
end
|
||||
|
||||
def handle_details_post(params)
|
||||
if params[:payload]
|
||||
create_event(:payload => params[:payload])
|
||||
{ :success => true }
|
||||
else
|
||||
{ :success => false, :error => "You must provide a JSON payload" }
|
||||
end
|
||||
end
|
||||
|
||||
def working?
|
||||
true
|
||||
end
|
||||
|
||||
def validate_options
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,6 +1,7 @@
|
|||
module Agents
|
||||
class PostAgent < Agent
|
||||
cannot_be_scheduled!
|
||||
cannot_create_events!
|
||||
|
||||
description <<-MD
|
||||
Post Agent receives events from other agents and send those events as the contents of a post request to a specified url. `post_url` field must specify where you would like to receive post requests and do not forget to include URI scheme (`http` or `https`)
|
||||
|
|
|
@ -4,6 +4,7 @@ require 'securerandom'
|
|||
module Agents
|
||||
class TwilioAgent < Agent
|
||||
cannot_be_scheduled!
|
||||
cannot_create_events!
|
||||
|
||||
description <<-MD
|
||||
The TwilioAgent receives and collects events and sends them via text message or gives you a call when scheduled.
|
||||
|
|
|
@ -47,8 +47,9 @@
|
|||
<div class="control-group">
|
||||
<%= f.label :sources, :class => 'control-label' %>
|
||||
<div class="controls link-region" data-can-receive-events="<%= @agent.can_receive_events? %>">
|
||||
<% eventSources = (current_user.agents - [@agent]).find_all { |a| a.can_create_events? } %>
|
||||
<%= f.select(:source_ids,
|
||||
options_for_select((current_user.agents - [@agent]).map {|s| [s.name, s.id] },
|
||||
options_for_select(eventSources.map {|s| [s.name, s.id] },
|
||||
@agent.source_ids),
|
||||
{}, { :multiple => true, :size => 5, :class => 'span4 select2' }) %>
|
||||
<span class='cannot-receive-events text-info'>This type of Agent cannot receive events.</span>
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<h3>Manually Create Events</h3>
|
||||
|
||||
<h4 id='event-creation-status'></h4>
|
||||
|
||||
<%= form_tag handle_details_post_agent_path(@agent), :id => "create-event-form" do %>
|
||||
<div class="control-group">
|
||||
<textarea rows="10" id="payload" name="payload" class="span8 payload-editor" data-height="200">
|
||||
{}
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<div class='form-actions' style='clear: both'>
|
||||
<%= submit_tag "Submit", :class => "btn btn-primary" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
var payloadJsonEditor = window.setupJsonEditor($(".payload-editor"));
|
||||
$("#create-event-form").submit(function (e) {
|
||||
e.preventDefault();
|
||||
var $form = $("#create-event-form");
|
||||
var $status = $("#event-creation-status");
|
||||
$.ajax({
|
||||
url: $form.attr('action'),
|
||||
method: "post",
|
||||
data: { payload: JSON.parse($form.find("textarea").val()) },
|
||||
dataType: "JSON",
|
||||
success: function(json) {
|
||||
if (json.success) {
|
||||
$status.text("Success!");
|
||||
} else {
|
||||
$status.text("An error occurred: " + json.error);
|
||||
}
|
||||
},
|
||||
error: function(response) {
|
||||
$status.text("An error occurred: " + response.responseText)
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -4,7 +4,7 @@
|
|||
<div class="page-header">
|
||||
<h2>
|
||||
Editing your <%= @agent.short_type %>
|
||||
<%= image_tag "spinner-arrows.gif", :class => "spinner" %>
|
||||
<%= image_tag "spinner-arrows.gif", :class => "spinner", :id => 'agent-spinner' %>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -8,53 +8,71 @@
|
|||
<table class='table table-striped'>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Schedule</th>
|
||||
<th>Last Check</th>
|
||||
<th>Last Event Out</th>
|
||||
<th>Last Event In</th>
|
||||
<th>Events</th>
|
||||
<th>Schedule</th>
|
||||
<th>Events Created</th>
|
||||
<th>Working?</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
||||
<% @agents.each do |agent| %>
|
||||
<tr>
|
||||
<td>
|
||||
<%= agent.name %>
|
||||
<br/>
|
||||
<span class='muted'><%= agent.short_type.titleize %></span>
|
||||
</td>
|
||||
<td>
|
||||
<% if agent.cannot_be_scheduled? %>
|
||||
N/A
|
||||
<tr>
|
||||
<td>
|
||||
<%= agent.name %>
|
||||
<br/>
|
||||
<span class='muted'><%= agent.short_type.titleize %></span>
|
||||
</td>
|
||||
<td>
|
||||
<% if agent.can_be_scheduled? %>
|
||||
<%= agent.schedule.to_s.humanize.titleize %>
|
||||
<% else %>
|
||||
<span class='not-applicable'></span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<% if agent.can_be_scheduled? %>
|
||||
<%= agent.last_check_at ? time_ago_in_words(agent.last_check_at) + " ago" : "never" %>
|
||||
<% else %>
|
||||
<span class='not-applicable'></span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<% if agent.can_create_events? %>
|
||||
<%= agent.last_event_at ? time_ago_in_words(agent.last_event_at) + " ago" : "never" %>
|
||||
<% else %>
|
||||
<span class='not-applicable'></span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<% if agent.can_receive_events? %>
|
||||
<%= agent.last_receive_at ? time_ago_in_words(agent.last_receive_at) + " ago" : "never" %>
|
||||
<% else %>
|
||||
<span class='not-applicable'></span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<% if agent.can_create_events? %>
|
||||
<%= link_to(agent.events_count || 0, events_path(:agent => agent.to_param)) %>
|
||||
<% else %>
|
||||
<span class='not-applicable'></span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td><%= working(agent) %></td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<%= link_to 'Show', agent_path(agent), class: "btn btn-mini" %>
|
||||
<%= link_to 'Edit', edit_agent_path(agent), class: "btn btn-mini" %>
|
||||
<%= link_to 'Delete', agent_path(agent), method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-mini" %>
|
||||
<% if agent.can_be_scheduled? %>
|
||||
<%= link_to 'Run', run_agent_path(agent, :return => "index"), method: :post, class: "btn btn-mini" %>
|
||||
<% else %>
|
||||
<%= agent.last_check_at ? time_ago_in_words(agent.last_check_at) + " ago" : "never" %>
|
||||
<%= link_to 'Run', "#", class: "btn btn-mini disabled" %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td><%= agent.last_event_at ? time_ago_in_words(agent.last_event_at) + " ago" : "never" %></td>
|
||||
<td>
|
||||
<% if agent.cannot_receive_events? %>
|
||||
N/A
|
||||
<% else %>
|
||||
<%= agent.last_receive_at ? time_ago_in_words(agent.last_receive_at) + " ago" : "never" %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td><%= link_to(agent.events_count || 0, events_path(:agent => agent.to_param)) %></td>
|
||||
<td><%= (agent.schedule || "n/a").to_s.humanize.titleize %></td>
|
||||
<td><%= working(agent) %></td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<%= link_to 'Show', agent_path(agent), class: "btn btn-mini" %>
|
||||
<%= link_to 'Edit', edit_agent_path(agent), class: "btn btn-mini" %>
|
||||
<%= link_to 'Delete', agent_path(agent), method: :delete, data: {confirm: 'Are you sure?'}, class: "btn btn-mini" %>
|
||||
<% if agent.can_be_scheduled? %>
|
||||
<%= link_to 'Run', run_agent_path(agent, :return => "index"), method: :post, class: "btn btn-mini" %>
|
||||
<% else %>
|
||||
<%= link_to 'Run', "#", class: "btn btn-mini disabled" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<div class="page-header">
|
||||
<h2>
|
||||
Create a new Agent
|
||||
<%= image_tag "spinner-arrows.gif", :class => "spinner" %>
|
||||
<%= image_tag "spinner-arrows.gif", :class => "spinner", :id => 'agent-spinner' %>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<% end %>
|
||||
<li><a href="#logs" data-toggle="tab" data-agent-id="<%= @agent.id %>"><i class='icon-list-alt'></i> Logs</a></li>
|
||||
|
||||
<% if @agent.events.count > 0 %>
|
||||
<% if @agent.can_create_events? && @agent.events.count > 0 %>
|
||||
<li><%= link_to '<i class="icon-random"></i> Events'.html_safe, events_path(:agent => @agent.to_param) %></li>
|
||||
<% end %>
|
||||
<li><%= link_to '<i class="icon-chevron-left"></i> Back'.html_safe, agents_path %></li>
|
||||
|
@ -29,7 +29,7 @@
|
|||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if @agent.events.count > 0 %>
|
||||
<% if @agent.can_create_events? && @agent.events.count > 0 %>
|
||||
<li>
|
||||
<%= link_to '<i class="icon-trash"></i> Delete all events'.html_safe, remove_events_agent_path(@agent), method: :delete, data: {confirm: 'Are you sure you want to delete ALL events for this Agent?'}, :tabindex => "-1" %>
|
||||
</li>
|
||||
|
@ -70,38 +70,60 @@
|
|||
<%= @agent.short_type.titleize %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Schedule:</b>
|
||||
<%= (@agent.schedule || "n/a").humanize.titleize %>
|
||||
</p>
|
||||
<% if @agent.can_be_scheduled? %>
|
||||
<p>
|
||||
<b>Schedule:</b>
|
||||
<%= (@agent.schedule || "n/a").humanize.titleize %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Last checked:</b>
|
||||
<% if @agent.cannot_be_scheduled? %>
|
||||
N/A
|
||||
<% else %>
|
||||
<p>
|
||||
<b>Last checked:</b>
|
||||
<%= @agent.last_check_at ? time_ago_in_words(@agent.last_check_at) + " ago" : "never" %>
|
||||
<% end %>
|
||||
</p>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<p>
|
||||
<b>Last event created:</b>
|
||||
<%= @agent.last_event_at ? time_ago_in_words(@agent.last_event_at) + " ago" : "never" %>
|
||||
</p>
|
||||
<% if @agent.can_create_events? %>
|
||||
<p>
|
||||
<b>Last event created:</b>
|
||||
<%= @agent.last_event_at ? time_ago_in_words(@agent.last_event_at) + " ago" : "never" %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<p>
|
||||
<b>Last received event:</b>
|
||||
<% if @agent.cannot_receive_events? %>
|
||||
N/A
|
||||
<% else %>
|
||||
<% if @agent.can_receive_events? %>
|
||||
<p>
|
||||
<b>Last received event:</b>
|
||||
<%= @agent.last_receive_at ? time_ago_in_words(@agent.last_receive_at) + " ago" : "never" %>
|
||||
<% end %>
|
||||
</p>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<p>
|
||||
<b>Event count:</b>
|
||||
<%= link_to @agent.events.count, events_path(:agent => @agent.to_param) %>
|
||||
</p>
|
||||
<% if @agent.can_create_events? %>
|
||||
<p>
|
||||
<b>Events created:</b>
|
||||
<%= link_to @agent.events.count, events_path(:agent => @agent.to_param) %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<% if @agent.can_receive_events? %>
|
||||
<p>
|
||||
<b>Event sources:</b>
|
||||
<% if @agent.sources.length %>
|
||||
<%= @agent.sources.map { |source_agent| link_to(source_agent.name, agent_path(source_agent)) }.to_sentence.html_safe %>
|
||||
<% else %>
|
||||
None
|
||||
<% end %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<% if @agent.can_create_events? %>
|
||||
<p>
|
||||
<b>Event receivers:</b>
|
||||
<% if @agent.receivers.length %>
|
||||
<%= @agent.receivers.map { |receiver_agent| link_to(receiver_agent.name, agent_path(receiver_agent)) }.to_sentence.html_safe %>
|
||||
<% else %>
|
||||
None
|
||||
<% end %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<p>
|
||||
<b>Working:</b>
|
||||
|
@ -110,12 +132,12 @@
|
|||
|
||||
<p>
|
||||
<b>Options:</b>
|
||||
<pre><%= JSON.pretty_generate @agent.options %></pre>
|
||||
<pre><%= JSON.pretty_generate @agent.options || {} %></pre>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Memory:</b>
|
||||
<pre><%= JSON.pretty_generate @agent.memory %></pre>
|
||||
<pre><%= JSON.pretty_generate @agent.memory || {} %></pre>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
</tr>
|
||||
|
||||
<% @events.each do |event| %>
|
||||
<% next unless event.agent %>
|
||||
<tr>
|
||||
<td><%= link_to event.agent.name, agent_path(event.agent) %></td>
|
||||
<td><%= time_ago_in_words event.created_at %> ago</td>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<p>
|
||||
<b>Payload:</b>
|
||||
<pre><%= JSON.pretty_generate @event.payload %></pre>
|
||||
<pre><%= JSON.pretty_generate @event.payload || {} %></pre>
|
||||
</p>
|
||||
|
||||
<% if @event.lat && @event.lng %>
|
||||
|
|
|
@ -9,11 +9,18 @@
|
|||
|
||||
<ul class="nav pull-right">
|
||||
<% if user_signed_in? %>
|
||||
|
||||
<form class="navbar-search pull-left">
|
||||
<input type="text" class="search-query" id='agent-navigate' autocomplete="off" placeholder="Search">
|
||||
<%= image_tag "spinner-arrows.gif", :class => "spinner" %>
|
||||
</form>
|
||||
|
||||
<li id='job-indicator'>
|
||||
<a href="/delayed_job">
|
||||
<span class="badge"><i class="icon-refresh icon-white"></i> <span class='number'>0</span></span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li id='event-indicator'>
|
||||
<a href="#">
|
||||
<span class="badge"><i class="icon-random icon-white"></i> <span class='number'>0</span> new events</span>
|
||||
|
@ -35,6 +42,10 @@
|
|||
<% end %>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<%= link_to 'About', 'https://github.com/cantino/huginn', :tabindex => "-1" %>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<% if user_signed_in? %>
|
||||
<%= link_to 'Logout', destroy_user_session_path, :method => :delete, :tabindex => "-1" %>
|
||||
|
@ -45,3 +56,4 @@
|
|||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -32,5 +32,21 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var agentPaths = {};
|
||||
<% if current_user -%>
|
||||
var myAgents = <%= Utils.jsonify(current_user.agents.inject({}) {|m, a| m[a.name] = agent_path(a) unless a.new_record?; m }) %>;
|
||||
$.extend(agentPaths, myAgents);
|
||||
<% end -%>
|
||||
agentPaths["All Agents Index"] = <%= Utils.jsonify agents_path %>;
|
||||
agentPaths["New Agent"] = <%= Utils.jsonify new_agent_path %>;
|
||||
agentPaths["Account"] = <%= Utils.jsonify edit_user_registration_path %>;
|
||||
agentPaths["Events Index"] = <%= Utils.jsonify events_path %>;
|
||||
agentPaths["View Agent Diagram"] = <%= Utils.jsonify diagram_agents_path %>;
|
||||
agentPaths["Run Event Propagation"] = { url: <%= Utils.jsonify propagate_agents_path %>, method: 'POST' };
|
||||
var agentNames = [];
|
||||
$.each(agentPaths, function(name, v) { agentNames.push(name); });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -7,10 +7,15 @@
|
|||
<% if @headline %>
|
||||
<h1><%= @headline %></h1>
|
||||
<% end %>
|
||||
<% @lines.each do |line| %>
|
||||
<p>
|
||||
<%= line %>
|
||||
</p>
|
||||
<% @groups.each do |group| %>
|
||||
<div style='margin-bottom: 10px;'>
|
||||
<div><%= group[:title] %></div>
|
||||
<% group[:entries].each do |entry| %>
|
||||
<div style='margin-left: 10px;'>
|
||||
<%= entry %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</body>
|
||||
</html>
|
|
@ -1,5 +1,7 @@
|
|||
<% if @headline %><%= @headline %>
|
||||
|
||||
<% end %><% @lines.each do |line| %><%= line %>
|
||||
|
||||
<% end %><% @groups.each do |group| %><%= group[:title] %>
|
||||
<% group[:entries].each do |entry| %> <%= entry %>
|
||||
<% end %>
|
||||
|
||||
<% end %>
|
|
@ -2,6 +2,7 @@ Huginn::Application.routes.draw do
|
|||
resources :agents do
|
||||
member do
|
||||
post :run
|
||||
post :handle_details_post
|
||||
delete :remove_events
|
||||
end
|
||||
|
||||
|
|
|
@ -70,4 +70,8 @@ module Utils
|
|||
result
|
||||
end
|
||||
end
|
||||
|
||||
def self.jsonify(thing)
|
||||
thing.to_json.gsub('</', '<\/').html_safe
|
||||
end
|
||||
end
|
|
@ -18,6 +18,22 @@ describe AgentsController do
|
|||
end
|
||||
end
|
||||
|
||||
describe "POST handle_details_post" do
|
||||
it "passes control to handle_details_post on the agent" do
|
||||
sign_in users(:bob)
|
||||
post :handle_details_post, :id => agents(:bob_manual_event_agent).to_param, :payload => { :foo => "bar" }
|
||||
JSON.parse(response.body).should == { "success" => true }
|
||||
agents(:bob_manual_event_agent).events.last.payload.should == { :foo => "bar" }
|
||||
end
|
||||
|
||||
it "can only be accessed by the Agent's owner" do
|
||||
sign_in users(:jane)
|
||||
lambda {
|
||||
post :handle_details_post, :id => agents(:bob_manual_event_agent).to_param, :payload => { :foo => :bar }
|
||||
}.should raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET show" do
|
||||
it "only shows Agents for the current user" do
|
||||
sign_in users(:bob)
|
||||
|
|
5
spec/fixtures/agents.yml
vendored
5
spec/fixtures/agents.yml
vendored
|
@ -92,3 +92,8 @@ bob_twitter_user_agent:
|
|||
:oauth_token => "---",
|
||||
:oauth_token_secret => "---"
|
||||
}.to_yaml.inspect %>
|
||||
|
||||
bob_manual_event_agent:
|
||||
type: Agents::ManualEventAgent
|
||||
user: bob
|
||||
name: "Bob's event testing agent"
|
||||
|
|
|
@ -114,13 +114,23 @@ describe Agent do
|
|||
end
|
||||
|
||||
describe "#create_event" do
|
||||
it "should use the checker's user" do
|
||||
checker = Agents::SomethingSource.new(:name => "something")
|
||||
checker.user = users(:bob)
|
||||
checker.save!
|
||||
before do
|
||||
@checker = Agents::SomethingSource.new(:name => "something")
|
||||
@checker.user = users(:bob)
|
||||
@checker.save!
|
||||
end
|
||||
|
||||
checker.check
|
||||
Event.last.user.should == checker.user
|
||||
it "should use the checker's user" do
|
||||
@checker.check
|
||||
Event.last.user.should == @checker.user
|
||||
end
|
||||
|
||||
it "should log an error if the Agent has been marked with 'cannot_create_events!'" do
|
||||
mock(@checker).can_create_events? { false }
|
||||
lambda {
|
||||
@checker.check
|
||||
}.should_not change { Event.count }
|
||||
@checker.logs.first.message.should =~ /cannot create events/i
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@ describe Agents::DigestEmailAgent do
|
|||
@checker.save!
|
||||
end
|
||||
|
||||
after do
|
||||
ActionMailer::Base.deliveries = []
|
||||
end
|
||||
|
||||
describe "#receive" do
|
||||
it "queues any payloads it receives" do
|
||||
event1 = Event.new
|
||||
|
@ -33,14 +37,38 @@ describe Agents::DigestEmailAgent do
|
|||
Agents::DigestEmailAgent.async_check(@checker.id)
|
||||
ActionMailer::Base.deliveries.should == []
|
||||
|
||||
@checker.memory[:queue] = ["Something you should know about", { :title => "Foo", :url => "http://google.com", :bar => 2 }, { "message" => "hi", :woah => "there" }]
|
||||
@checker.memory[:queue] = ["Something you should know about",
|
||||
{ :title => "Foo", :url => "http://google.com", :bar => 2 },
|
||||
{ "message" => "hi", :woah => "there" },
|
||||
{ "test" => 2 }]
|
||||
@checker.save!
|
||||
|
||||
Agents::DigestEmailAgent.async_check(@checker.id)
|
||||
ActionMailer::Base.deliveries.last.to.should == ["bob@example.com"]
|
||||
ActionMailer::Base.deliveries.last.subject.should == "something interesting"
|
||||
get_message_part(ActionMailer::Base.deliveries.last, /plain/).strip.should == "Something you should know about\n\nFoo (bar: 2 and url: http://google.com)\n\nhi (woah: there)"
|
||||
@checker.reload.memory[:queue].should == []
|
||||
get_message_part(ActionMailer::Base.deliveries.last, /plain/).strip.should == "Something you should know about\n\nFoo\n bar: 2\n url: http://google.com\n\nhi\n woah: there\n\nEvent\n test: 2"
|
||||
@checker.reload.memory[:queue].should be_empty
|
||||
end
|
||||
|
||||
it "can receive complex events and send them on" do
|
||||
stub_request(:any, /wunderground/).to_return(:body => File.read(Rails.root.join("spec/data_fixtures/weather.json")), :status => 200)
|
||||
stub.any_instance_of(Agents::WeatherAgent).is_tomorrow?(anything) { true }
|
||||
@checker.sources << agents(:bob_weather_agent)
|
||||
|
||||
Agent.async_check(agents(:bob_weather_agent).id)
|
||||
|
||||
Agent.receive!
|
||||
@checker.reload.memory[:queue].should_not be_empty
|
||||
|
||||
Agents::DigestEmailAgent.async_check(@checker.id)
|
||||
|
||||
plain_email_text = get_message_part(ActionMailer::Base.deliveries.last, /plain/).strip
|
||||
html_email_text = get_message_part(ActionMailer::Base.deliveries.last, /html/).strip
|
||||
|
||||
plain_email_text.should =~ /avehumidity/
|
||||
html_email_text.should =~ /avehumidity/
|
||||
|
||||
@checker.reload.memory[:queue].should be_empty
|
||||
end
|
||||
end
|
||||
end
|
|
@ -69,10 +69,6 @@ describe Agents::PeakDetectorAgent do
|
|||
:pattern => { :filter => "something" })
|
||||
@agent.memory[:peaks][:something].length.should == 2
|
||||
end
|
||||
|
||||
it "works on real world data" do
|
||||
pending "need examples"
|
||||
end
|
||||
end
|
||||
|
||||
describe "validation" do
|
||||
|
@ -95,4 +91,4 @@ describe Agents::PeakDetectorAgent do
|
|||
@agent.should_not be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -52,8 +52,12 @@
|
|||
display: block;
|
||||
float: right;
|
||||
text-decoration: none;
|
||||
padding-left: 5px;
|
||||
padding: 0 5px;
|
||||
border: 0 !important;
|
||||
color: blue;
|
||||
|
||||
&:hover {
|
||||
background-color: #bbb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue