mirror of
https://github.com/Fishwaldo/huginn.git
synced 2025-03-15 19:31:26 +00:00
allow exporting of a set of Agents with their links from a Scenario; Scenario guid is now generated and copied to export, as well as a source link when public
This commit is contained in:
parent
eb49a8b203
commit
663250227d
19 changed files with 331 additions and 83 deletions
|
@ -1,4 +1,6 @@
|
|||
class ScenariosController < ApplicationController
|
||||
skip_before_filter :authenticate_user!, :only => :export
|
||||
|
||||
def index
|
||||
@scenarios = current_user.scenarios.page(params[:page])
|
||||
|
||||
|
@ -27,10 +29,8 @@ class ScenariosController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# Share is a work in progress!
|
||||
def share
|
||||
@scenario = current_user.scenarios.find(params[:id])
|
||||
@agents = @scenario.agents.preload(:scenarios).page(params[:page])
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
|
@ -38,6 +38,19 @@ class ScenariosController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def export
|
||||
@scenario = Scenario.find(params[:id])
|
||||
raise ActiveRecord::RecordNotFound unless @scenario.public? || (current_user && current_user.id == @scenario.user_id)
|
||||
|
||||
@exporter = AgentsExporter.new(:name => @scenario.name,
|
||||
:description => @scenario.description,
|
||||
:guid => @scenario.guid,
|
||||
:source_url => @scenario.public? && export_scenario_url(@scenario),
|
||||
:agents => @scenario.agents)
|
||||
response.headers['Content-Disposition'] = 'attachment; filename="' + @exporter.filename + '"'
|
||||
render :json => JSON.pretty_generate(@exporter.as_json)
|
||||
end
|
||||
|
||||
def edit
|
||||
@scenario = current_user.scenarios.find(params[:id])
|
||||
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
class Scenario < ActiveRecord::Base
|
||||
attr_accessible :name, :agent_ids
|
||||
attr_accessible :name, :agent_ids, :description, :public
|
||||
|
||||
belongs_to :user, :counter_cache => :scenario_count, :inverse_of => :scenarios
|
||||
has_many :scenario_memberships, :dependent => :destroy, :inverse_of => :scenario
|
||||
has_many :agents, :through => :scenario_memberships, :inverse_of => :scenarios
|
||||
|
||||
before_save :make_guid
|
||||
|
||||
validates_presence_of :name, :user
|
||||
|
||||
validate :agents_are_owned
|
||||
|
||||
protected
|
||||
|
||||
def make_guid
|
||||
self.guid = SecureRandom.hex unless guid.present?
|
||||
end
|
||||
|
||||
def agents_are_owned
|
||||
errors.add(:agents, "must be owned by you") unless agents.all? {|s| s.user == user }
|
||||
end
|
||||
|
|
|
@ -12,11 +12,28 @@
|
|||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<%= f.label :name %>
|
||||
<%= f.text_field :name, :class => 'form-control' %>
|
||||
<%= f.text_field :name, :class => 'form-control', :placeholder => "Name your Scenario" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="form-group">
|
||||
<%= f.label :description, "Optional Description" %>
|
||||
<%= f.text_area :description, :rows => 10, :class => 'form-control', :placeholder => "Optionally describe what this set of Agents will do" %>
|
||||
</div>
|
||||
|
||||
<div class="checkbox">
|
||||
<%= f.label :public do %>
|
||||
<%= f.check_box :public %> Share this Scenario publicly
|
||||
<% end %>
|
||||
<span class="glyphicon glyphicon-question-sign hover-help" data-content="When selected, this Scenario and all Agents in it will be made public. An export URL will be available to share with other Huginn users. Be very careful that you do not have secret credentials stored in these Agents' options. Instead, use Credentials by reference."></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
|
|
|
@ -20,14 +20,16 @@
|
|||
|
||||
<% @scenarios.each do |scenario| %>
|
||||
<tr>
|
||||
<td><span class='label label-info'><%= scenario.name %></span></td>
|
||||
<td>
|
||||
<%= link_to(scenario.name, scenario, class: "label label-info") %>
|
||||
</td>
|
||||
<td><%= link_to pluralize(scenario.agents.count, "agent"), scenario %></td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-xs" style="float: right">
|
||||
<%= link_to 'Show', scenario, class: "btn btn-default" %>
|
||||
<%= link_to 'Edit', edit_scenario_path(scenario), class: "btn btn-default" %>
|
||||
<%= link_to 'Share', share_scenario_path(scenario), class: "btn btn-default" %>
|
||||
<%= link_to 'Delete', scenario_path(scenario), method: :delete, data: {confirm: 'Are you sure?'}, class: "btn btn-default" %>
|
||||
<%= link_to 'Delete', scenario_path(scenario), method: :delete, data: { confirm: "This will remove the '#{scenario.name}' Scenerio from all Agents and delete it. Are you sure?" }, class: "btn btn-default" %>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -5,6 +5,22 @@
|
|||
<h2>Share <span class='label label-info scenario'><%= @scenario.name %></span> with the world</h2>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<strong>Please be sure that none of the Agents in this Scenario have sensitive data in their settings before sharing!</strong>
|
||||
</p>
|
||||
|
||||
<% if @scenario.public? %>
|
||||
<p>
|
||||
This Scenario is public. You can <%= link_to "download and share your export file", export_scenario_path(@scenario) %>, or give out this URL:
|
||||
</p>
|
||||
|
||||
<form onsubmit='return false;'>
|
||||
<input type='text' class='form-control' value='<%= export_scenario_url(@scenario) %>' onclick="return this.select();"/>
|
||||
</form>
|
||||
<% else %>
|
||||
This Scenario is not public. You can share it by <%= link_to "downloading and sharing your export file", export_scenario_path(@scenario) %>.
|
||||
<% end %>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
|
|
|
@ -2,20 +2,19 @@
|
|||
<div class='row'>
|
||||
<div class='col-md-12'>
|
||||
<div class="page-header">
|
||||
<h2>Scenario <span class='label label-info scenario'><%= @scenario.name %></span></h2>
|
||||
<h2><%= "Public" if @scenario.public? %> Scenario <span class='label label-info scenario'><%= @scenario.name %></span></h2>
|
||||
</div>
|
||||
|
||||
<%= render 'agents/table', :returnTo => scenario_path(@scenario) %>
|
||||
|
||||
<br/>
|
||||
|
||||
<div class="btn-group">
|
||||
<%= link_to '<span class="glyphicon glyphicon-chevron-left"></span> Back'.html_safe, scenarios_path, class: "btn btn-default" %>
|
||||
<%= link_to '<span class="glyphicon glyphicon-edit"></span> Edit'.html_safe, edit_scenario_path(@scenario), class: "btn btn-default" %>
|
||||
<%= link_to '<span class="glyphicon glyphicon-share-alt"></span> Share'.html_safe, share_scenario_path(@scenario), class: "btn btn-default" %>
|
||||
<%= link_to '<span class="glyphicon glyphicon-trash"></span> Delete'.html_safe, scenario_path(@scenario), method: :delete, data: { confirm: "This will remove the '#{@scenario.name}' Scenerio from all Agents and delete it. Are you sure?" }, class: "btn btn-default" %>
|
||||
</div>
|
||||
|
||||
<div class="page-header">
|
||||
<h3>Agents</h3>
|
||||
</div>
|
||||
|
||||
<%= render 'agents/table', :returnTo => scenario_path(@scenario) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -29,6 +29,7 @@ Huginn::Application.routes.draw do
|
|||
resources :scenarios do
|
||||
member do
|
||||
get :share
|
||||
get :export
|
||||
end
|
||||
end
|
||||
|
||||
|
|
8
db/migrate/20140531232016_add_fields_to_scenarios.rb
Normal file
8
db/migrate/20140531232016_add_fields_to_scenarios.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
class AddFieldsToScenarios < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :scenarios, :description, :text
|
||||
add_column :scenarios, :public, :boolean, :default => false, :null => false
|
||||
add_column :scenarios, :guid, :string, :null => false
|
||||
add_column :scenarios, :source_url, :string
|
||||
end
|
||||
end
|
142
db/schema.rb
142
db/schema.rb
|
@ -9,23 +9,23 @@
|
|||
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
||||
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
||||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20140408150825) do
|
||||
ActiveRecord::Schema.define(version: 20140531232016) do
|
||||
|
||||
create_table "agent_logs", :force => true do |t|
|
||||
t.integer "agent_id", :null => false
|
||||
t.text "message", :null => false
|
||||
t.integer "level", :default => 3, :null => false
|
||||
create_table "agent_logs", force: true do |t|
|
||||
t.integer "agent_id", null: false
|
||||
t.text "message", limit: 16777215, null: false
|
||||
t.integer "level", default: 3, null: false
|
||||
t.integer "inbound_event_id"
|
||||
t.integer "outbound_event_id"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
create_table "agents", :force => true do |t|
|
||||
create_table "agents", force: true do |t|
|
||||
t.integer "user_id"
|
||||
t.text "options"
|
||||
t.text "options", limit: 16777215
|
||||
t.string "type"
|
||||
t.string "name"
|
||||
t.string "schedule"
|
||||
|
@ -33,73 +33,62 @@ ActiveRecord::Schema.define(:version => 20140408150825) do
|
|||
t.datetime "last_check_at"
|
||||
t.datetime "last_receive_at"
|
||||
t.integer "last_checked_event_id"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.text "memory", :limit => 2147483647
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.text "memory", limit: 2147483647
|
||||
t.datetime "last_web_request_at"
|
||||
t.integer "keep_events_for", :default => 0, :null => false
|
||||
t.datetime "last_event_at"
|
||||
t.datetime "last_error_log_at"
|
||||
t.boolean "propagate_immediately", :default => false, :null => false
|
||||
t.boolean "disabled", :default => false, :null => false
|
||||
t.integer "keep_events_for", default: 0, null: false
|
||||
t.boolean "propagate_immediately", default: false, null: false
|
||||
t.boolean "disabled", default: false, null: false
|
||||
end
|
||||
|
||||
add_index "agents", ["schedule"], :name => "index_agents_on_schedule"
|
||||
add_index "agents", ["type"], :name => "index_agents_on_type"
|
||||
add_index "agents", ["user_id", "created_at"], :name => "index_agents_on_user_id_and_created_at"
|
||||
add_index "agents", ["schedule"], name: "index_agents_on_schedule", using: :btree
|
||||
add_index "agents", ["type"], name: "index_agents_on_type", using: :btree
|
||||
add_index "agents", ["user_id", "created_at"], name: "index_agents_on_user_id_and_created_at", using: :btree
|
||||
|
||||
create_table "delayed_jobs", :force => true do |t|
|
||||
t.integer "priority", :default => 0
|
||||
t.integer "attempts", :default => 0
|
||||
t.text "handler", :limit => 16777215
|
||||
t.text "last_error"
|
||||
create_table "delayed_jobs", force: true do |t|
|
||||
t.integer "priority", default: 0
|
||||
t.integer "attempts", default: 0
|
||||
t.text "handler", limit: 16777215
|
||||
t.text "last_error", limit: 16777215
|
||||
t.datetime "run_at"
|
||||
t.datetime "locked_at"
|
||||
t.datetime "failed_at"
|
||||
t.string "locked_by"
|
||||
t.string "queue"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority"
|
||||
add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree
|
||||
|
||||
create_table "events", :force => true do |t|
|
||||
create_table "events", force: true do |t|
|
||||
t.integer "user_id"
|
||||
t.integer "agent_id"
|
||||
t.decimal "lat", :precision => 15, :scale => 10
|
||||
t.decimal "lng", :precision => 15, :scale => 10
|
||||
t.text "payload", :limit => 16777215
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.decimal "lat", precision: 15, scale: 10
|
||||
t.decimal "lng", precision: 15, scale: 10
|
||||
t.text "payload", limit: 2147483647
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "expires_at"
|
||||
end
|
||||
|
||||
add_index "events", ["agent_id", "created_at"], :name => "index_events_on_agent_id_and_created_at"
|
||||
add_index "events", ["expires_at"], :name => "index_events_on_expires_at"
|
||||
add_index "events", ["user_id", "created_at"], :name => "index_events_on_user_id_and_created_at"
|
||||
add_index "events", ["agent_id", "created_at"], name: "index_events_on_agent_id_and_created_at", using: :btree
|
||||
add_index "events", ["expires_at"], name: "index_events_on_expires_at", using: :btree
|
||||
add_index "events", ["user_id", "created_at"], name: "index_events_on_user_id_and_created_at", using: :btree
|
||||
|
||||
create_table "links", :force => true do |t|
|
||||
create_table "links", force: true do |t|
|
||||
t.integer "source_id"
|
||||
t.integer "receiver_id"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.integer "event_id_at_creation", :default => 0, :null => false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.integer "event_id_at_creation", default: 0, null: false
|
||||
end
|
||||
|
||||
add_index "links", ["receiver_id", "source_id"], :name => "index_links_on_receiver_id_and_source_id"
|
||||
add_index "links", ["source_id", "receiver_id"], :name => "index_links_on_source_id_and_receiver_id"
|
||||
|
||||
create_table "user_credentials", :force => true do |t|
|
||||
t.integer "user_id", :null => false
|
||||
t.string "credential_name", :null => false
|
||||
t.text "credential_value", :null => false
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.string "mode", :default => "text", :null => false
|
||||
end
|
||||
|
||||
add_index "user_credentials", ["user_id", "credential_name"], :name => "index_user_credentials_on_user_id_and_credential_name", :unique => true
|
||||
add_index "links", ["receiver_id", "source_id"], name: "index_links_on_receiver_id_and_source_id", using: :btree
|
||||
add_index "links", ["source_id", "receiver_id"], name: "index_links_on_source_id_and_receiver_id", using: :btree
|
||||
|
||||
create_table "scenario_memberships", force: true do |t|
|
||||
t.integer "agent_id", null: false
|
||||
|
@ -109,37 +98,52 @@ ActiveRecord::Schema.define(:version => 20140408150825) do
|
|||
end
|
||||
|
||||
create_table "scenarios", force: true do |t|
|
||||
t.string "name", null: false
|
||||
t.integer "user_id", null: false
|
||||
t.string "name", null: false
|
||||
t.integer "user_id", null: false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.text "description"
|
||||
t.boolean "public", default: false, null: false
|
||||
t.string "guid", null: false
|
||||
t.string "source_url"
|
||||
end
|
||||
|
||||
create_table "users", :force => true do |t|
|
||||
t.string "email", :default => "", :null => false
|
||||
t.string "encrypted_password", :default => "", :null => false
|
||||
create_table "user_credentials", force: true do |t|
|
||||
t.integer "user_id", null: false
|
||||
t.string "credential_name", null: false
|
||||
t.text "credential_value", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.string "mode", default: "text", null: false
|
||||
end
|
||||
|
||||
add_index "user_credentials", ["user_id", "credential_name"], name: "index_user_credentials_on_user_id_and_credential_name", unique: true, using: :btree
|
||||
|
||||
create_table "users", force: true do |t|
|
||||
t.string "email", default: "", null: false
|
||||
t.string "encrypted_password", default: "", null: false
|
||||
t.string "reset_password_token"
|
||||
t.datetime "reset_password_sent_at"
|
||||
t.datetime "remember_created_at"
|
||||
t.integer "sign_in_count", :default => 0
|
||||
t.integer "sign_in_count", default: 0
|
||||
t.datetime "current_sign_in_at"
|
||||
t.datetime "last_sign_in_at"
|
||||
t.string "current_sign_in_ip"
|
||||
t.string "last_sign_in_ip"
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
t.boolean "admin", :default => false, :null => false
|
||||
t.integer "failed_attempts", :default => 0
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.boolean "admin", default: false, null: false
|
||||
t.integer "failed_attempts", default: 0
|
||||
t.string "unlock_token"
|
||||
t.datetime "locked_at"
|
||||
t.string "username", :null => false
|
||||
t.string "invitation_code", :null => false
|
||||
t.string "username", null: false
|
||||
t.string "invitation_code", null: false
|
||||
t.integer "scenario_count", default: 0, null: false
|
||||
end
|
||||
|
||||
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
|
||||
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
|
||||
add_index "users", ["unlock_token"], :name => "index_users_on_unlock_token", :unique => true
|
||||
add_index "users", ["username"], :name => "index_users_on_username", :unique => true
|
||||
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
|
||||
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
|
||||
add_index "users", ["unlock_token"], name: "index_users_on_unlock_token", unique: true, using: :btree
|
||||
add_index "users", ["username"], name: "index_users_on_username", unique: true, using: :btree
|
||||
|
||||
end
|
||||
|
|
53
lib/agents_exporter.rb
Normal file
53
lib/agents_exporter.rb
Normal file
|
@ -0,0 +1,53 @@
|
|||
class AgentsExporter
|
||||
attr_accessor :options
|
||||
|
||||
def initialize(options)
|
||||
self.options = options
|
||||
end
|
||||
|
||||
# Filename should have no commas or special characters to support Content-Disposition on older browsers.
|
||||
def filename
|
||||
((options[:name] || '').downcase.gsub(/[^a-z0-9_-]/, '-').gsub(/-+/, '-').gsub(/^-|-$/, '').presence || 'exported-agents') + ".json"
|
||||
end
|
||||
|
||||
def as_json(opts = {})
|
||||
{
|
||||
:name => options[:name].presence || 'No name provided',
|
||||
:description => options[:description].presence || 'No description provided',
|
||||
:source_url => options[:source_url],
|
||||
:guid => options[:guid],
|
||||
:exported_at => Time.now.utc.iso8601,
|
||||
:agents => agents.map { |agent| agent_as_json(agent) },
|
||||
:links => links
|
||||
}
|
||||
end
|
||||
|
||||
def agents
|
||||
options[:agents].to_a
|
||||
end
|
||||
|
||||
def links
|
||||
agent_ids = agents.map(&:id)
|
||||
|
||||
contained_links = agents.map.with_index do |agent, index|
|
||||
agent.links_as_source.where(:receiver_id => agent_ids).map do |link|
|
||||
{ :source => index, :receiver => agent_ids.index(link.receiver_id) }
|
||||
end
|
||||
end
|
||||
|
||||
contained_links.flatten.compact
|
||||
end
|
||||
|
||||
def agent_as_json(agent)
|
||||
{
|
||||
:type => agent.type,
|
||||
:name => agent.name,
|
||||
:schedule => agent.schedule,
|
||||
:keep_events_for => agent.keep_events_for,
|
||||
:propagate_immediately => agent.propagate_immediately,
|
||||
:disabled => agent.disabled,
|
||||
:source_system_agent_id => agent.id,
|
||||
:options => agent.options
|
||||
}
|
||||
end
|
||||
end
|
|
@ -32,6 +32,59 @@ describe ScenariosController do
|
|||
end
|
||||
end
|
||||
|
||||
describe "GET share" do
|
||||
it "only displays Scenario share information for the current user" do
|
||||
get :share, :id => scenarios(:bob_weather).to_param
|
||||
assigns(:scenario).should eq(scenarios(:bob_weather))
|
||||
|
||||
lambda {
|
||||
get :share, :id => scenarios(:jane_weather).to_param
|
||||
}.should raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET export" do
|
||||
it "returns a JSON file download from an instantiated AgentsExporter" do
|
||||
get :export, :id => scenarios(:bob_weather).to_param
|
||||
assigns(:exporter).options[:name].should == scenarios(:bob_weather).name
|
||||
assigns(:exporter).options[:description].should == scenarios(:bob_weather).description
|
||||
assigns(:exporter).options[:agents].should == scenarios(:bob_weather).agents
|
||||
assigns(:exporter).options[:guid].should == scenarios(:bob_weather).guid
|
||||
assigns(:exporter).options[:source_url].should be_false
|
||||
response.headers['Content-Disposition'].should == 'attachment; filename="bob-s-weather-alert-scenario.json"'
|
||||
response.headers['Content-Type'].should == 'application/json; charset=utf-8'
|
||||
JSON.parse(response.body)["name"].should == scenarios(:bob_weather).name
|
||||
end
|
||||
|
||||
it "only exports private Scenarios for the current user" do
|
||||
get :export, :id => scenarios(:bob_weather).to_param
|
||||
assigns(:scenario).should eq(scenarios(:bob_weather))
|
||||
|
||||
lambda {
|
||||
get :export, :id => scenarios(:jane_weather).to_param
|
||||
}.should raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
describe "public exports" do
|
||||
before do
|
||||
scenarios(:jane_weather).update_attribute :public, true
|
||||
end
|
||||
|
||||
it "exports public scenarios for other users when logged in" do
|
||||
get :export, :id => scenarios(:jane_weather).to_param
|
||||
assigns(:scenario).should eq(scenarios(:jane_weather))
|
||||
assigns(:exporter).options[:source_url].should == export_scenario_url(scenarios(:jane_weather))
|
||||
end
|
||||
|
||||
it "exports public scenarios for other users when logged out" do
|
||||
sign_out :user
|
||||
get :export, :id => scenarios(:jane_weather).to_param
|
||||
assigns(:scenario).should eq(scenarios(:jane_weather))
|
||||
assigns(:exporter).options[:source_url].should == export_scenario_url(scenarios(:jane_weather))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET edit" do
|
||||
it "only shows Scenarios for the current user" do
|
||||
get :edit, :id => scenarios(:bob_weather).to_param
|
||||
|
@ -67,9 +120,10 @@ describe ScenariosController do
|
|||
|
||||
describe "PUT update" do
|
||||
it "updates attributes on Scenarios for the current user" do
|
||||
post :update, :id => scenarios(:bob_weather).to_param, :scenario => { :name => "new_name" }
|
||||
post :update, :id => scenarios(:bob_weather).to_param, :scenario => { :name => "new_name", :public => "1" }
|
||||
response.should redirect_to(scenario_path(scenarios(:bob_weather)))
|
||||
scenarios(:bob_weather).reload.name.should == "new_name"
|
||||
scenarios(:bob_weather).should be_public
|
||||
|
||||
lambda {
|
||||
post :update, :id => scenarios(:jane_weather).to_param, :scenario => { :name => "new_name" }
|
||||
|
|
6
spec/fixtures/scenarios.yml
vendored
6
spec/fixtures/scenarios.yml
vendored
|
@ -1,7 +1,13 @@
|
|||
jane_weather:
|
||||
name: Jane's weather alert Scenario
|
||||
user: jane
|
||||
description: Jane's weather alert system
|
||||
public: false
|
||||
guid: random-guid-generated-by-bob
|
||||
|
||||
bob_weather:
|
||||
name: Bob's weather alert Scenario
|
||||
user: bob
|
||||
description: Bob's weather alert system
|
||||
public: false
|
||||
guid: random-guid-generated-by-jane
|
||||
|
|
58
spec/lib/agents_exporter_spec.rb
Normal file
58
spec/lib/agents_exporter_spec.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe AgentsExporter do
|
||||
describe "#as_json" do
|
||||
let(:name) { "My set of Agents" }
|
||||
let(:description) { "These Agents work together nicely!" }
|
||||
let(:guid) { "some-guid" }
|
||||
let(:source_url) { "http://yourhuginn.com/scenarios/2/export.json" }
|
||||
let(:agent_list) { [agents(:jane_weather_agent), agents(:jane_rain_notifier_agent)] }
|
||||
let(:exporter) { AgentsExporter.new(:agents => agent_list, :name => name, :description => description, :source_url => source_url, :guid => guid) }
|
||||
|
||||
it "outputs a structure containing name, description, the date, all agents & their links" do
|
||||
data = exporter.as_json
|
||||
data[:name].should == name
|
||||
data[:description].should == description
|
||||
data[:source_url].should == source_url
|
||||
data[:guid].should == guid
|
||||
Time.parse(data[:exported_at]).should be_within(2).of(Time.now.utc)
|
||||
data[:links].should == [{ :source => 0, :receiver => 1 }]
|
||||
data[:agents].should == agent_list.map { |agent| exporter.agent_as_json(agent) }
|
||||
data[:agents].all? { |agent_json| agent_json[:source_system_agent_id] && agent_json[:type] && agent_json[:name] }.should be_true
|
||||
end
|
||||
|
||||
it "does not output links to other agents" do
|
||||
Link.create!(:source_id => agents(:jane_weather_agent).id, :receiver_id => agents(:jane_website_agent).id)
|
||||
Link.create!(:source_id => agents(:jane_website_agent).id, :receiver_id => agents(:jane_rain_notifier_agent).id)
|
||||
|
||||
exporter.as_json[:links].should == [{ :source => 0, :receiver => 1 }]
|
||||
end
|
||||
end
|
||||
|
||||
describe "#filename" do
|
||||
it "strips special characters" do
|
||||
AgentsExporter.new(:name => "ƏfooƐƕƺbar").filename.should == "foo-bar.json"
|
||||
end
|
||||
|
||||
it "strips punctuation" do
|
||||
AgentsExporter.new(:name => "foo,bar").filename.should == "foo-bar.json"
|
||||
end
|
||||
|
||||
it "strips leading and trailing dashes" do
|
||||
AgentsExporter.new(:name => ",foo,").filename.should == "foo.json"
|
||||
end
|
||||
|
||||
it "has a default when options[:name] is nil" do
|
||||
AgentsExporter.new(:name => nil).filename.should == "exported-agents.json"
|
||||
end
|
||||
|
||||
it "has a default when the result is empty" do
|
||||
AgentsExporter.new(:name => "").filename.should == "exported-agents.json"
|
||||
AgentsExporter.new(:name => "Ə").filename.should == "exported-agents.json"
|
||||
AgentsExporter.new(:name => "-").filename.should == "exported-agents.json"
|
||||
AgentsExporter.new(:name => ",,").filename.should == "exported-agents.json"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -26,6 +26,17 @@ describe Scenario do
|
|||
end
|
||||
end
|
||||
|
||||
describe "guid" do
|
||||
it "gets created before_save, but only if it's not present" do
|
||||
scenario = users(:bob).scenarios.new(:name => "some scenario")
|
||||
scenario.guid.should be_nil
|
||||
scenario.save!
|
||||
scenario.guid.should_not be_nil
|
||||
|
||||
lambda { scenario.save! }.should_not change { scenario.reload.guid }
|
||||
end
|
||||
end
|
||||
|
||||
describe "counters" do
|
||||
before do
|
||||
@scenario = users(:bob).scenarios.new(:name => "some scenario")
|
||||
|
|
Loading…
Add table
Reference in a new issue