diff --git a/app/assets/stylesheets/stories.scss b/app/assets/stylesheets/stories.scss
index a37e7e97..503a5812 100644
--- a/app/assets/stylesheets/stories.scss
+++ b/app/assets/stylesheets/stories.scss
@@ -60,6 +60,10 @@
padding-bottom: 1.3em;
}
+.modal strong {
+ font-weight: bold;
+}
+
.new_story,
.edit_story {
display: grid;
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 84537228..b9c352bd 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -1,6 +1,6 @@
class ProjectsController < ApplicationController
before_action :authenticate_user!
- before_action :find_project, only: [:show, :edit, :update, :sort, :sort_stories, :destroy, :new_sub_project, :toggle_archive, :toggle_locked]
+ before_action :find_project, only: [:show, :edit, :update, :sort, :sort_stories, :destroy, :new_sub_project, :toggle_archive, :toggle_locked, :open_delete_modal]
before_action :ensure_unarchived!, only: [:edit, :new_sub_project, :update]
def index
@@ -70,9 +70,14 @@ def create
end
def destroy
- @project.destroy
respond_to do |format|
- format.html { redirect_to projects_path, notice: "Project was successfully destroyed." }
+ if @project.title.strip.eql?(params.dig(:project, :title)&.strip)
+ @project.destroy
+ flash[:success] = "Project was successfully destroyed."
+ else
+ flash[:error] = "Make sure you added the correct project's title"
+ end
+ format.html { redirect_to projects_path }
end
end
@@ -104,6 +109,10 @@ def new_sub_project
@sub = Project.new(parent_id: @project)
end
+ # GET /projects/1/open_delete_modal.js
+ def open_delete_modal
+ end
+
private
def find_project
diff --git a/app/views/projects/_delete_form.html.erb b/app/views/projects/_delete_form.html.erb
new file mode 100644
index 00000000..ec2694bd
--- /dev/null
+++ b/app/views/projects/_delete_form.html.erb
@@ -0,0 +1,12 @@
+<%= form_with(model: project, method: :delete) do |f| %>
+ This action cannot be undone.
+ This will permanently delete the <%= project.title %> project,
+ stories, and associated estimations.
+
+
+ <%= f.label :title, raw("Please type #{project.title} to confirm.") %>
+ <%= f.text_field :title, value: "", placeholder: "Project's title", autofocus: true, required: true %>
+
+
+ <%= f.submit "I understand the consequences, delete this project", class: "button magenta" %>
+<% end %>
diff --git a/app/views/projects/open_delete_modal.js.erb b/app/views/projects/open_delete_modal.js.erb
new file mode 100644
index 00000000..a2887254
--- /dev/null
+++ b/app/views/projects/open_delete_modal.js.erb
@@ -0,0 +1,3 @@
+(function(){
+ showModal("Are you absolutely sure?", "<%= j(render('delete_form', project: @project)) %>")
+})()
diff --git a/app/views/projects/show.html.erb b/app/views/projects/show.html.erb
index 1bb4c6bb..79402b60 100644
--- a/app/views/projects/show.html.erb
+++ b/app/views/projects/show.html.erb
@@ -112,7 +112,7 @@
<% if is_unlocked?(@project) %>
<%= link_unless_archived(@project, "Add Sub-Project", project_new_sub_project_path(@project), classes: :green) unless @project.parent_id.present? %>
- <%= link_unless_archived(@project, "Delete Project", project_path(@project.id), classes: "delete magenta", method: :delete, remote: true, data_attr: { confirm: 'Are you sure?' }, id: "delete") %>
+ <%= link_unless_archived(@project, "Delete Project", open_delete_modal_project_path(@project.id), classes: "delete magenta", remote: true) %>
<% end %>
<% unless @project.parent_id %>
diff --git a/config/routes.rb b/config/routes.rb
index 86c0cca9..0608541a 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -24,6 +24,7 @@
patch :toggle_locked
get :new_clone
post :clone
+ get :open_delete_modal
end
get :new_sub_project
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index ffe9b248..c2b8d54e 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -124,9 +124,29 @@
describe "#destroy" do
it "deletes the project" do
expect {
- delete :destroy, params: {id: project.id}
+ delete :destroy, params: {id: project.id, project: {title: project.title}}
}.to change(Project, :count).by(-1)
end
+
+ it "deletes stripped project's title" do
+ project.update(title: " foo bar ")
+ expect {
+ delete :destroy, params: {id: project.id, project: {title: "foo bar"}}
+ }.to change(Project, :count).by(-1)
+ end
+
+ it "deletes stripped project's params" do
+ project.update(title: "foo bar")
+ expect {
+ delete :destroy, params: {id: project.id, project: {title: "foo bar "}}
+ }.to change(Project, :count).by(-1)
+ end
+
+ it "does not delete the project" do
+ expect {
+ delete :destroy, params: {id: project.id}
+ }.not_to change(Project, :count)
+ end
end
describe "#show" do
diff --git a/spec/features/projects_manage_spec.rb b/spec/features/projects_manage_spec.rb
index ac4bb97f..78ce59ec 100644
--- a/spec/features/projects_manage_spec.rb
+++ b/spec/features/projects_manage_spec.rb
@@ -50,19 +50,27 @@
end
context "when the project is unarchived" do
- it "allows me to delete a project", js: false do
+ it "does not delete a project" do
+ project.update(title: "Awesome Project's Title")
visit project_path(id: project.id)
+
click_link "Delete Project"
- expect(Project.count).to eq 0
+ expect(page).to have_content "Are you absolutely sure?"
+ fill_in "project_title", with: "Random Project's Title"
+ click_button "I understand the consequences, delete this project"
+
+ expect(page).to have_content "Make sure you added the correct project's title"
end
it "allows me to delete a project" do
visit project_path(id: project.id)
- accept_confirm do
- click_link "Delete Project"
- end
- expect(page).not_to have_content "Delete Project"
- expect(Project.count).to eq 0
+
+ click_link "Delete Project"
+ expect(page).to have_content "Are you absolutely sure?"
+ fill_in "project_title", with: project.title
+ click_button "I understand the consequences, delete this project"
+
+ expect(page).to have_content "Project was successfully destroyed."
end
it "allows editing the project's title inline" do