From 3e360a2ebbba6410b62ebb0b136fc591ff7f90dc Mon Sep 17 00:00:00 2001 From: Gunnar Sveinsson Date: Fri, 10 Oct 2025 20:56:15 +0200 Subject: [PATCH] Allow project originators to delete comments on their projects --- app/controllers/comments_controller.rb | 2 +- app/models/ability.rb | 3 +++ app/views/comments/_comment.html.haml | 3 +++ spec/features/comment_spec.rb | 30 ++++++++++++++++++++++++++ spec/models/ability_spec.rb | 23 ++++++++++++++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 131b21c92..15403b864 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -38,7 +38,7 @@ def destroy @comment.destroy respond_to do |format| - format.html { redirect_to comments_path, notice: 'Comment was successfully deleted.' } + format.html { redirect_back fallback_location: root_path, notice: 'Comment was successfully deleted.' } end end diff --git a/app/models/ability.rb b/app/models/ability.rb index 9393ea30e..f246a8eab 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -35,6 +35,9 @@ def initialize(user) can :read, Update, author_id: user.id can :manage, Project, originator_id: user.id can %i[create update], Comment, commenter_id: user.id + can :destroy, Comment do |comment| + comment.project.originator_id == user.id + end can %i[update add_keyword delete_keyword advance recess add_episode delete_episode], Project do |project| project.users.include? user diff --git a/app/views/comments/_comment.html.haml b/app/views/comments/_comment.html.haml index 8533196da..93a42c133 100644 --- a/app/views/comments/_comment.html.haml +++ b/app/views/comments/_comment.html.haml @@ -14,6 +14,9 @@ | %a{ 'href' => 'javascript:void(0)', 'data-target' => "#editComment#{dom_id(comment)}", 'data-toggle' => 'modal', type: 'button' } Edit + - if can? :destroy, comment + | + = link_to 'Delete', comment_path(comment), method: :delete, data: { confirm: 'Are you sure you want to delete this comment?' } %p :markdown #{ enrich_markdown(markdown: comment.text) } diff --git a/spec/features/comment_spec.rb b/spec/features/comment_spec.rb index ca2fd5ed8..a16ac84c2 100644 --- a/spec/features/comment_spec.rb +++ b/spec/features/comment_spec.rb @@ -75,4 +75,34 @@ expect(page).to have_text comment_text end end + + scenario 'project originator can delete comments on their project', :js do + other_user = create(:user) + comment = create(:comment, commenter: other_user, commentable: project) + + visit project_path(nil, project) + + within("li#comment_#{comment.id}") do + click_on 'Delete' + end + + page.driver.browser.switch_to.alert.accept + + expect(page).to have_current_path(project_path(nil, project), ignore_query: true) + expect(page).to have_text 'Comment was successfully deleted' + expect(page).to have_no_css("li#comment_#{comment.id}") + expect(Comment.exists?(comment.id)).to be false + end + + scenario 'non-originator cannot delete comments on others projects', :js do + other_user = create(:user) + other_project = create(:idea, originator: other_user) + comment = create(:comment, commenter: other_user, commentable: other_project) + + visit project_path(nil, other_project) + + within("li#comment_#{comment.id}") do + expect(page).to have_no_link 'Delete' + end + end end diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index ac8434444..8f1c805fc 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -55,4 +55,27 @@ it { is_expected.to be_able_to(:manage, Announcement.new) } it { is_expected.to be_able_to(:manage, Faq.new) } end + + context 'when user is project originator' do + let(:user) { create(:user) } + let(:other_user) { create(:user) } + let(:own_project) { create(:project, originator: user) } + let(:foreign_project) { create(:project, originator: other_user) } + + context 'when on own project' do + let(:own_comment_on_own_project) { create(:comment, commenter: user, commentable: own_project) } + let(:comment_on_own_project) { create(:comment, commenter: other_user, commentable: own_project) } + + it { is_expected.to be_able_to(:destroy, own_comment_on_own_project) } + it { is_expected.to be_able_to(:destroy, comment_on_own_project) } + end + + context 'when on foreign project' do + let(:own_comment_on_foreign_project) { create(:comment, commenter: user, commentable: foreign_project) } + let(:comment_on_foreign_project) { create(:comment, commenter: other_user, commentable: foreign_project) } + + it { is_expected.not_to be_able_to(:destroy, own_comment_on_foreign_project) } + it { is_expected.not_to be_able_to(:destroy, comment_on_foreign_project) } + end + end end