@@ -97,7 +97,7 @@ class ScenariosController < ApplicationController |
||
97 | 97 |
|
98 | 98 |
def destroy |
99 | 99 |
@scenario = current_user.scenarios.find(params[:id]) |
100 |
- @scenario.destroy |
|
100 |
+ @scenario.destroy_with_mode(params[:mode]) |
|
101 | 101 |
|
102 | 102 |
respond_to do |format| |
103 | 103 |
format.html { redirect_to scenarios_path } |
@@ -16,7 +16,25 @@ class Scenario < ActiveRecord::Base |
||
16 | 16 |
|
17 | 17 |
validate :agents_are_owned |
18 | 18 |
|
19 |
- protected |
|
19 |
+ def destroy_with_mode(mode) |
|
20 |
+ case mode |
|
21 |
+ when 'all_agents' |
|
22 |
+ Agent.destroy(agents.pluck(:id)) |
|
23 |
+ when 'unique_agents' |
|
24 |
+ Agent.destroy(unique_agent_ids) |
|
25 |
+ end |
|
26 |
+ |
|
27 |
+ destroy |
|
28 |
+ end |
|
29 |
+ |
|
30 |
+ private |
|
31 |
+ |
|
32 |
+ def unique_agent_ids |
|
33 |
+ agents.joins(:scenario_memberships) |
|
34 |
+ .group('scenario_memberships.agent_id') |
|
35 |
+ .having('count(scenario_memberships.agent_id) = 1') |
|
36 |
+ .pluck('scenario_memberships.agent_id') |
|
37 |
+ end |
|
20 | 38 |
|
21 | 39 |
def agents_are_owned |
22 | 40 |
errors.add(:agents, "must be owned by you") unless agents.all? {|s| s.user == user } |
@@ -0,0 +1,46 @@ |
||
1 |
+<div id="confirm-scenario-deletion-<%= scenario.id %>" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true"> |
|
2 |
+ <div class="modal-dialog"> |
|
3 |
+ <div class="modal-content"> |
|
4 |
+ <%= form_for(scenario, url: scenario_path(scenario), method: :delete) do |f| %> |
|
5 |
+ <div class="modal-header"> |
|
6 |
+ <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> |
|
7 |
+ <h4 class="modal-title"> |
|
8 |
+ <% if @scenario && @scenario == scenario %> |
|
9 |
+ How do you want to delete this Scenario? |
|
10 |
+ <% else %> |
|
11 |
+ How do you want to delete the Scenario '<%= scenario.name %>'? |
|
12 |
+ <% end %> |
|
13 |
+ </h4> |
|
14 |
+ </div> |
|
15 |
+ <div class="modal-body"> |
|
16 |
+ <div class="radio"> |
|
17 |
+ <%= label_tag do %> |
|
18 |
+ <%= radio_button_tag :mode, '', true %> |
|
19 |
+ <h4><span class="label label-success">Scenario only</span></h4> |
|
20 |
+ Only delete the Scenerio, keep the Agents. |
|
21 |
+ <% end %> |
|
22 |
+ </div> |
|
23 |
+ <div class="radio"> |
|
24 |
+ <%= label_tag do %> |
|
25 |
+ <%= radio_button_tag :mode, :unique_agents %> |
|
26 |
+ <h4><span class="label label-warning">Scenario and unique Agents</span></h4> |
|
27 |
+ Also deletes Agents that are used in this Scenario only. |
|
28 |
+ <% end %> |
|
29 |
+ </div> |
|
30 |
+ <div class="radio"> |
|
31 |
+ <%= label_tag do %> |
|
32 |
+ <%= radio_button_tag :mode, :all_agents %> |
|
33 |
+ <h4><span class="label label-danger">Scenario and all included Agents</span></h4> |
|
34 |
+ Deletes Scenario and all included Agents, even if they are used in different Scenarios. |
|
35 |
+ <% end %> |
|
36 |
+ </div> |
|
37 |
+ </div> |
|
38 |
+ <div class="modal-footer"> |
|
39 |
+ <%= f.button 'Abort', class: 'btn btn-default', 'data-dismiss' => 'modal' %> |
|
40 |
+ <%= f.submit 'Delete', class: 'btn btn-danger' %> |
|
41 |
+ </div> |
|
42 |
+ <% end %> |
|
43 |
+ </div> |
|
44 |
+ </div> |
|
45 |
+</div> |
|
46 |
+ |
@@ -31,8 +31,9 @@ |
||
31 | 31 |
<%= link_to 'Show', scenario, class: "btn btn-default" %> |
32 | 32 |
<%= link_to 'Edit', edit_scenario_path(scenario), class: "btn btn-default" %> |
33 | 33 |
<%= link_to 'Share', share_scenario_path(scenario), class: "btn btn-default" %> |
34 |
- <%= 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" %> |
|
34 |
+ <%= link_to 'Delete', '#', data: { toggle: 'modal', target: "#confirm-scenario-deletion-#{scenario.id}"}, class: "btn btn-default" %> |
|
35 | 35 |
</div> |
36 |
+ <%= render 'scenarios/confirm_deletion_modal', scenario: scenario %> |
|
36 | 37 |
</td> |
37 | 38 |
</tr> |
38 | 39 |
<% end %> |
@@ -23,8 +23,9 @@ |
||
23 | 23 |
<%= link_to icon_tag('glyphicon-refresh') + ' Update', new_scenario_imports_path(url: @scenario.source_url), class: "btn btn-default" %> |
24 | 24 |
<% end %> |
25 | 25 |
<%= link_to icon_tag('glyphicon-share-alt') + ' Share', share_scenario_path(@scenario), class: "btn btn-default" %> |
26 |
- <%= link_to icon_tag('glyphicon-trash') + ' 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" %> |
|
26 |
+ <%= link_to icon_tag('glyphicon-trash') + ' Delete', '#', data: { toggle: 'modal', target: "#confirm-scenario-deletion-#{@scenario.id}"}, class: "btn btn-default" %> |
|
27 | 27 |
</div> |
28 | 28 |
</div> |
29 | 29 |
</div> |
30 | 30 |
</div> |
31 |
+<%= render 'scenarios/confirm_deletion_modal', scenario: @scenario %> |
@@ -150,5 +150,11 @@ describe ScenariosController do |
||
150 | 150 |
delete :destroy, :id => scenarios(:jane_weather).to_param |
151 | 151 |
}.to raise_error(ActiveRecord::RecordNotFound) |
152 | 152 |
end |
153 |
+ |
|
154 |
+ it "passes the mode to the model" do |
|
155 |
+ expect { |
|
156 |
+ delete :destroy, id: scenarios(:bob_weather).to_param, mode: 'all_agents' |
|
157 |
+ }.to change(Agent, :count).by(-2) |
|
158 |
+ end |
|
153 | 159 |
end |
154 | 160 |
end |
@@ -6,6 +6,10 @@ jane_rain_notifier_agent_scenario_membership: |
||
6 | 6 |
agent: jane_rain_notifier_agent |
7 | 7 |
scenario: jane_weather |
8 | 8 |
|
9 |
+jane_rain_notifier_agent_scenario_membership_duplicate: |
|
10 |
+ agent: jane_weather_agent |
|
11 |
+ scenario: jane_weather_duplicate |
|
12 |
+ |
|
9 | 13 |
bob_weather_agent_scenario_membership: |
10 | 14 |
agent: bob_weather_agent |
11 | 15 |
scenario: bob_weather |
@@ -5,6 +5,12 @@ jane_weather: |
||
5 | 5 |
public: false |
6 | 6 |
guid: random-guid-generated-by-bob |
7 | 7 |
|
8 |
+jane_weather_duplicate: |
|
9 |
+ name: Jane's duplicated, incomplete weather alert Scenario |
|
10 |
+ user: jane |
|
11 |
+ public: false |
|
12 |
+ guid: random-guid-generated-by-jane2 |
|
13 |
+ |
|
8 | 14 |
bob_weather: |
9 | 15 |
name: Bob's weather alert Scenario |
10 | 16 |
user: bob |
@@ -64,4 +64,35 @@ describe Scenario do |
||
64 | 64 |
}.to change { users(:bob).reload.scenario_count }.by(-1) |
65 | 65 |
end |
66 | 66 |
end |
67 |
+ |
|
68 |
+ context '#unique_agents' do |
|
69 |
+ it "equals agents when no agents are shared" do |
|
70 |
+ agent_ids = scenarios(:bob_weather).agents.map(&:id).sort |
|
71 |
+ unique_agent_ids = scenarios(:bob_weather).send(:unique_agent_ids).sort |
|
72 |
+ expect(agent_ids).to eq(unique_agent_ids) |
|
73 |
+ end |
|
74 |
+ |
|
75 |
+ it "includes only agents that are not present in two scnearios" do |
|
76 |
+ unique_agent_ids = scenarios(:jane_weather).send(:unique_agent_ids) |
|
77 |
+ expect(unique_agent_ids).to eq([agents(:jane_rain_notifier_agent).id]) |
|
78 |
+ end |
|
79 |
+ |
|
80 |
+ it "returns no agents when all are also used in a different scenario" do |
|
81 |
+ expect(scenarios(:jane_weather_duplicate).send(:unique_agent_ids)).to eq([]) |
|
82 |
+ end |
|
83 |
+ end |
|
84 |
+ |
|
85 |
+ context '#destroy_with_mode' do |
|
86 |
+ it "only destroys the scenario when no mode is passed" do |
|
87 |
+ expect { scenarios(:jane_weather).destroy_with_mode('') }.not_to change(Agent, :count) |
|
88 |
+ end |
|
89 |
+ |
|
90 |
+ it "only destroys unique agents when 'unique_agents' is passed" do |
|
91 |
+ expect { scenarios(:jane_weather).destroy_with_mode('unique_agents') }.to change(Agent, :count).by(-1) |
|
92 |
+ end |
|
93 |
+ |
|
94 |
+ it "destroys all agents when 'all_agents' is passed" do |
|
95 |
+ expect { scenarios(:jane_weather).destroy_with_mode('all_agents') }.to change(Agent, :count).by(-2) |
|
96 |
+ end |
|
97 |
+ end |
|
67 | 98 |
end |