Prevent comments by the staff account from being hidden (#19698)

* don't show hide/unhide on comments made by staff account

* block staff account comments from being hidden on the backend as well

* moar specs
This commit is contained in:
PJ 2023-07-10 11:46:46 +01:00 committed by GitHub
parent 5fe3a04287
commit b0b1ace7d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 138 additions and 18 deletions

View file

@ -194,6 +194,10 @@ class Comment < ApplicationRecord
ancestry && Comment.exists?(id: ancestry)
end
def by_staff_account?
user == User.staff_account
end
def privileged_reaction_counts
@privileged_reaction_counts ||= reactions.privileged_category.group(:category).count
end

View file

@ -37,7 +37,7 @@ class CommentPolicy < ApplicationPolicy
end
def hide?
user_commentable_author?
user_commentable_author? && !record.by_staff_account?
end
alias unhide? hide?

View file

@ -31,23 +31,24 @@
<ul class="m-0">
<li><a href="<%= contextual_comment_url(comment, article: @article) %>" class="crayons-link crayons-link--block permalink-copybtn" aria-label="<%= t("views.comments.menu.copy.aria_label", user: comment.user.name) %>" data-no-instant><%= t("views.comments.menu.copy.text") %></a></li>
<li class="comment-actions hidden" data-user-id="<%= comment.user_id %>" data-action="settings-button" data-path="<%= URL.comment(comment) %>/settings" aria-label="<%= t("views.comments.menu.settings.aria_label", user: comment.user.name) %>"></li>
<% action = comment.hidden_by_commentable_user ? "unhide" : "hide" %>
<li class="comment-actions hidden" data-action="hide-button" data-commentable-user-id="<%= commentable&.user_id %>" data-user-id="<%= comment.user_id %>">
<% if comment.hidden_by_commentable_user %>
<a href="#" class="crayons-link crayons-link--block unhide-comment" data-hide-type="unhide" data-comment-id="<%= comment.id %>" aria-label="<%= t("views.comments.menu.action.aria_label", action: t("views.comments.menu.action.unhide"), user: comment.user.name) %>">
<%= t("views.comments.menu.action.unhide_text") %>
</a>
<% else %>
<button
class="flex justify-between crayons-link crayons-link--block w-100 bg-transparent border-0 hide-comment"
data-hide-type="hide"
data-comment-id="<%= comment.id %>"
data-comment-url="<%= URL.url(comment.path) %>"
aria-label="<%= t("views.comments.menu.action.aria_label", action: t("views.comments.menu.action.hide"), user: comment.user.name) %>">
<%= t("views.comments.menu.action.hide_text") %>
</button>
<% end %>
</li>
<% unless comment.by_staff_account? %>
<li class="comment-actions hidden" data-action="hide-button" data-commentable-user-id="<%= commentable&.user_id %>" data-user-id="<%= comment.user_id %>">
<% if comment.hidden_by_commentable_user %>
<a href="#" class="crayons-link crayons-link--block unhide-comment" data-hide-type="unhide" data-comment-id="<%= comment.id %>" aria-label="<%= t("views.comments.menu.action.aria_label", action: t("views.comments.menu.action.unhide"), user: comment.user.name) %>">
<%= t("views.comments.menu.action.unhide_text") %>
</a>
<% else %>
<button
class="flex justify-between crayons-link crayons-link--block w-100 bg-transparent border-0 hide-comment"
data-hide-type="hide"
data-comment-id="<%= comment.id %>"
data-comment-url="<%= URL.url(comment.path) %>"
aria-label="<%= t("views.comments.menu.action.aria_label", action: t("views.comments.menu.action.hide"), user: comment.user.name) %>">
<%= t("views.comments.menu.action.hide_text") %>
</button>
<% end %>
</li>
<% end %>
<li class="mod-actions hidden mod-actions-comment-button" data-path="<%= URL.comment(comment) %>/mod" aria-label="<%= t("views.comments.menu.moderate.aria_label", user: comment.user.name) %>"></li>
<li class="report-abuse-link-wrapper" data-path="/report-abuse?url=<%= URL.comment(comment) %>" aria-label="<%= t("views.comments.menu.report.aria_label", user: comment.user.name) %>"></li>
<li class="current-user-actions"></li>

View file

@ -38,5 +38,16 @@ describe('Hiding/unhiding comments on an article', () => {
cy.findByRole('img', { name: 'Expand' }).should('not.exist');
});
context('when the comment was made by the staff account', () => {
beforeEach(() => {
cy.visit('/admin_mcadmin/staff-commented-article-slug');
});
it('does not allow the user to hide comments made by the staff account', () => {
cy.findByRole('button', { name: 'Toggle dropdown menu' }).click();
cy.findByRole('button', { name: /Hide/ }).should('not.exist');
});
});
});
});

View file

@ -614,4 +614,23 @@ RSpec.describe Comment do
expect(comment.reload.root_exists?).to be(false)
end
end
describe "#by_staff_account?" do
let(:regular_user) { create(:user) }
let(:staff_account) { create(:user) }
let(:comment) { build(:comment, user: regular_user) }
let(:staff_comment) { build(:comment, user: staff_account) }
before do
allow(User).to receive(:staff_account).and_return(staff_account)
end
it "returns true if comment is by the staff account" do
expect(staff_comment.by_staff_account?).to be(true)
end
it "returns false if comment is not by the staff account" do
expect(comment.by_staff_account?).to be(false)
end
end
end

View file

@ -130,5 +130,18 @@ RSpec.describe CommentPolicy, type: :policy do
it { is_expected.to permit_actions(%i[hide unhide create]) }
it { is_expected.to forbid_actions(%i[edit update destroy delete_confirm moderate]) }
it { is_expected.to forbid_actions(%i[moderator_create admin_delete]) }
context "when comment author is the staff account" do
let(:staff_account) { create(:user) }
let(:comment) { build_stubbed(:comment, commentable: article, user: staff_account) }
before do
allow(User).to receive(:staff_account).and_return(staff_account)
end
it { is_expected.to permit_actions([:create]) }
it { is_expected.to forbid_actions(%i[hide unhide edit update destroy delete_confirm]) }
it { is_expected.to forbid_actions(%i[moderate moderator_create admin_delete]) }
end
end
end

View file

@ -445,6 +445,27 @@ RSpec.describe "Comments" do
expect(child_comment.hidden_by_commentable_user).to be false
end
end
context "with comment by staff account" do
let(:staff_account) { create(:user) }
let(:commentable_author) { create(:user) }
let(:article) { create(:article, user: commentable_author) }
let(:comment) { create(:comment, commentable: article, user: staff_account) }
before do
allow(User).to receive(:staff_account).and_return(staff_account)
sign_in commentable_author
end
it "does not permit hiding the comment" do
expect do
patch "/comments/#{comment.id}/hide", headers: { HTTP_ACCEPT: "application/json" }
end.to raise_error(Pundit::NotAuthorizedError)
comment.reload
expect(comment.hidden_by_commentable_user).to be false
end
end
end
describe "PATCH /comments/:comment_id/unhide" do

View file

@ -207,6 +207,26 @@ end
##############################################################################
seeder.create_if_doesnt_exist(User, "email", "staff-account@forem.local") do
staff_account = User.create!(
name: "Sloan",
email: "staff-account@forem.local",
username: "sloan",
profile_image: Rails.root.join("app/assets/images/#{rand(1..40)}.png").open,
confirmed_at: Time.current,
registered_at: Time.current,
password: "password",
password_confirmation: "password",
saw_onboarding: true,
checked_code_of_conduct: true,
checked_terms_and_conditions: true,
)
Settings::Community.staff_user_id = staff_account.id
end
##############################################################################
seeder.create_if_doesnt_exist(Organization, "slug", "bachmanity") do
organization = Organization.create!(
name: "Bachmanity",
@ -586,6 +606,37 @@ end
##############################################################################
seeder.create_if_doesnt_exist(Article, "slug", "staff-commented-article-slug") do
markdown = <<~MARKDOWN
---
title: Test article with Staff Account Comment
published: true
cover_image: #{Faker::Company.logo}
---
#{Faker::Hipster.paragraph(sentence_count: 2)}
#{Faker::Markdown.random}
#{Faker::Hipster.paragraph(sentence_count: 2)}
MARKDOWN
article = Article.create!(
body_markdown: markdown,
featured: true,
show_comments: true,
user_id: admin_user.id,
slug: "staff-commented-article-slug",
)
staff_comment_attributes = {
body_markdown: Faker::Hipster.paragraph(sentence_count: 1),
user_id: User.staff_account.id,
commentable_id: article.id,
commentable_type: "Article"
}
Comment.create!(staff_comment_attributes)
end
##############################################################################
seeder.create_if_doesnt_exist(Article, "slug", "unfeatured-article-slug") do
markdown = <<~MARKDOWN
---