From 837a7af44464153e9245cc8de474ba32be6d10ef Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 Oct 2025 09:21:48 +0200 Subject: [PATCH 01/12] Remove unused by_author scope from Poll::Answer The "by_author" scope in Poll::Answer is no longer used anywhere in the code. Its last occurrence was removed in commit 69eaf66b93 ("Remove redundant max_votes validation from Poll::Answer") --- app/models/poll/answer.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/poll/answer.rb b/app/models/poll/answer.rb index 664e2f426..129959f12 100644 --- a/app/models/poll/answer.rb +++ b/app/models/poll/answer.rb @@ -12,6 +12,5 @@ class Poll::Answer < ApplicationRecord validates :answer, inclusion: { in: ->(poll_answer) { poll_answer.option.possible_answers }}, if: ->(poll_answer) { poll_answer.option.present? } - scope :by_author, ->(author_id) { where(author_id: author_id) } scope :by_question, ->(question_id) { where(question_id: question_id) } end From de1401f8e6954f41e61360d9eb8b4fa6e6989a47 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 Oct 2025 09:32:26 +0200 Subject: [PATCH 02/12] Remove unused by_author scope from Poll::PartialResult The "by_author" scope in Poll::PartialResult is no longer used anywhere in the code. Its usage was replaced by Poll::Answer.by_author in commit 6bc4f5b30747 ("adds Poll::Answer model for web users"). --- app/models/poll/partial_result.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/poll/partial_result.rb b/app/models/poll/partial_result.rb index d671d6184..b24f39bb1 100644 --- a/app/models/poll/partial_result.rb +++ b/app/models/poll/partial_result.rb @@ -15,7 +15,6 @@ class Poll::PartialResult < ApplicationRecord validates :origin, inclusion: { in: ->(*) { VALID_ORIGINS }} validates :option, uniqueness: { scope: [:booth_assignment_id, :date] }, allow_nil: true - scope :by_author, ->(author_id) { where(author_id: author_id) } scope :by_question, ->(question_id) { where(question_id: question_id) } before_save :update_logs From 1e5c14ba8a2d9b7a90e3473a03b72af395cfbc2e Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 Oct 2025 09:39:27 +0200 Subject: [PATCH 03/12] Remove unused by_author scope from Poll::Recount The "by_author" scope in Poll::Recount is no longer used anywhere in the code. It was introduced in commit 6c297ae7899 ("Add Poll Recount model, factory and spec") but has never been referenced since. --- app/models/poll/recount.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/models/poll/recount.rb b/app/models/poll/recount.rb index 5e1692792..5eaaa4e04 100644 --- a/app/models/poll/recount.rb +++ b/app/models/poll/recount.rb @@ -12,8 +12,6 @@ class Poll::Recount < ApplicationRecord scope :booth, -> { where(origin: "booth") } scope :letter, -> { where(origin: "letter") } - scope :by_author, ->(author_id) { where(author_id: author_id) } - before_save :update_logs def update_logs From 151b12bd35d5d36cc75f63ec6829aa60c7e04359 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 Oct 2025 10:23:38 +0200 Subject: [PATCH 04/12] Remove unused by_email scope from VerifiedUser The "by_email" scope in VerifiedUser is no longer used anywhere in the code. Its last occurrence was removed in commit 76daee1fb04 ("removes unmasked emails and phones in forms"). --- app/models/verified_user.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/models/verified_user.rb b/app/models/verified_user.rb index 205c2dfe9..847baed42 100644 --- a/app/models/verified_user.rb +++ b/app/models/verified_user.rb @@ -1,7 +1,5 @@ class VerifiedUser < ApplicationRecord scope :by_user, ->(user) { where(document_number: user.document_number) } - - scope :by_email, ->(email) { where(email: email) } scope :by_phone, ->(phone) { where(phone: phone) } def self.phone?(user) From c4368b077a2f55b2a02d3d8885124c7e98914d1c Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 Oct 2025 10:38:50 +0200 Subject: [PATCH 05/12] Remove unused by_geozone_id scope from Poll The "by_geozone_id" scope in Poll is no longer used anywhere in the code. It was first introduced in commit 20cb0440150e ("adds search and filter for poll questions") and later moved to the Poll model in commit d02450596048 ("moves geozones from poll question to poll in models"), but has never been referenced since. --- app/models/poll.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/poll.rb b/app/models/poll.rb index 8012f2fcd..71f031a56 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -71,7 +71,6 @@ class Poll < ApplicationRecord scope :expired, -> { where(ends_at: ...Time.current) } scope :recounting, -> { where(ends_at: (RECOUNT_DURATION.ago)...Time.current) } scope :published, -> { where(published: true) } - scope :by_geozone_id, ->(geozone_id) { where(geozones: { id: geozone_id }.joins(:geozones)) } scope :public_for_api, -> { all } scope :not_budget, -> { where(budget_id: nil) } scope :created_by_admin, -> { where(related_type: nil) } From 29f4edd466ac6a07df8f45daff13eeda9755e379 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 Oct 2025 10:50:36 +0200 Subject: [PATCH 06/12] Remove unused scopes from Legislation::Proposal The "for_render", "sort_by_hot_score" and "sort_by_most_commented" scopes in Legislation::Proposal are no longer used anywhere in the code. They were all introduced in commit 335399e571 ("Created Legislation Proposals model") and have never been referenced since. --- app/models/legislation/proposal.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/models/legislation/proposal.rb b/app/models/legislation/proposal.rb index 63dc9221b..1f4fb6808 100644 --- a/app/models/legislation/proposal.rb +++ b/app/models/legislation/proposal.rb @@ -40,11 +40,8 @@ class Legislation::Proposal < ApplicationRecord before_save :calculate_hot_score, :calculate_confidence_score - scope :for_render, -> { includes(:tags) } - scope :sort_by_hot_score, -> { reorder(hot_score: :desc) } scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc) } scope :sort_by_created_at, -> { reorder(created_at: :desc) } - scope :sort_by_most_commented, -> { reorder(comments_count: :desc) } scope :sort_by_title, -> { reorder(title: :asc) } scope :sort_by_id, -> { reorder(id: :asc) } scope :sort_by_supports, -> { reorder(cached_votes_score: :desc) } From 8938b781c3cef50922f28096a6f7d3fdb003618a Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 Oct 2025 13:59:49 +0200 Subject: [PATCH 07/12] Remove unused created_by scope from Proposal The "created_by" scope in Proposal is no longer used anywhere in the code. It was introduced in 77dd604 and its last usage was dropped in commit 64258baf977 ("Refactor getting the public activity information"). --- app/models/proposal.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/proposal.rb b/app/models/proposal.rb index ef4bcbfb5..8359afd4e 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -89,7 +89,6 @@ class Proposal < ApplicationRecord scope :draft, -> { excluding(published) } scope :not_supported_by_user, ->(user) { where.not(id: user.find_voted_items(votable_type: "Proposal")) } - scope :created_by, ->(author) { where(author: author) } def publish update!(published_at: Time.current) From 41837344681d01ccc18a06e734243ac4c0bd8571 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 Oct 2025 14:10:47 +0200 Subject: [PATCH 08/12] Remove unused sort_by_most_commented scope from Debate The "sort_by_most_commented" scope in Debate is no longer used anywhere in the code. Its last use was removed in commit b89f39bfef ("Removes unused orders from debates controller") --- app/models/debate.rb | 1 - config/locales/en/general.yml | 1 - config/locales/es/general.yml | 1 - spec/models/debate_spec.rb | 14 -------------- 4 files changed, 17 deletions(-) diff --git a/app/models/debate.rb b/app/models/debate.rb index 7cba511d8..c40438400 100644 --- a/app/models/debate.rb +++ b/app/models/debate.rb @@ -38,7 +38,6 @@ class Debate < ApplicationRecord scope :sort_by_hot_score, -> { reorder(hot_score: :desc) } scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc) } scope :sort_by_created_at, -> { reorder(created_at: :desc) } - scope :sort_by_most_commented, -> { reorder(comments_count: :desc) } scope :sort_by_relevance, -> { all } scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) } scope :sort_by_recommendations, -> { order(cached_votes_total: :desc) } diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index ae79e1ba7..269452fb7 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -88,7 +88,6 @@ en: confidence_score: highest rated created_at: newest hot_score: most active - most_commented: most commented relevance: relevance recommendations: recommendations recommendations: diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index dd7e63c3e..9bcb5566a 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -88,7 +88,6 @@ es: confidence_score: Mejor valorados created_at: Nuevos hot_score: Más activos - most_commented: Más comentados relevance: Más relevantes recommendations: Recomendaciones recommendations: diff --git a/spec/models/debate_spec.rb b/spec/models/debate_spec.rb index 91761dc4f..acf266689 100644 --- a/spec/models/debate_spec.rb +++ b/spec/models/debate_spec.rb @@ -650,20 +650,6 @@ describe Debate do expect(results).to eq [newest, recent, oldest] end - - it "is able to reorder by most commented after searching" do - least_commented = create(:debate, title: "stop corruption", cached_votes_up: 1, comments_count: 1) - most_commented = create(:debate, title: "stop corruption", cached_votes_up: 2, comments_count: 100) - some_comments = create(:debate, title: "stop corruption", cached_votes_up: 3, comments_count: 10) - - results = Debate.search("stop corruption") - - expect(results).to eq [some_comments, most_commented, least_commented] - - results = results.sort_by_most_commented - - expect(results).to eq [most_commented, some_comments, least_commented] - end end context "no results" do From 0332160627ad05792cc5218a5b7c0251b1222e46 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 Oct 2025 14:23:19 +0200 Subject: [PATCH 09/12] Remove unused by_official_level scope from Proposal The "by_official_level" scope in Proposal is no longer used anywhere in the code. Its last use was removed in commit 9f1f912d84 ("Remove official level filter from advanced search"). --- app/models/concerns/filterable.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/models/concerns/filterable.rb b/app/models/concerns/filterable.rb index 92f419ef3..6f730641c 100644 --- a/app/models/concerns/filterable.rb +++ b/app/models/concerns/filterable.rb @@ -2,10 +2,7 @@ module Filterable extend ActiveSupport::Concern included do - scope :by_date_range, ->(date_range) { where(created_at: date_range) } - scope :by_official_level, ->(official_level) do - where(users: { official_level: official_level }).joins(:author) - end + scope :by_date_range, ->(date_range) { where(created_at: date_range) } end class_methods do From a3a44f527b7439e09f1c03035e14d82348bf1ab5 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 24 Oct 2025 09:47:52 +0200 Subject: [PATCH 10/12] Give purpose to previously unused on_budget_investments scope The "on_budget_investments" scope in Activity has never been used anywhere in the codebase. It was introduced in commit d9d38482b34 ("extends Activity to include Investment valuations") but no references were ever added. Instead of removing it, we make use of the scope by adding the missing "Budget investments" filter to the admin Activity section. This aligns it with the rest of the activity filters and gives the scope the purpose it was originally intended for. --- app/controllers/admin/activity_controller.rb | 2 +- config/locales/en/admin.yml | 1 + config/locales/es/admin.yml | 1 + spec/system/admin/activity_spec.rb | 71 ++++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) diff --git a/app/controllers/admin/activity_controller.rb b/app/controllers/admin/activity_controller.rb index 5cb86abc5..99e97c535 100644 --- a/app/controllers/admin/activity_controller.rb +++ b/app/controllers/admin/activity_controller.rb @@ -1,5 +1,5 @@ class Admin::ActivityController < Admin::BaseController - has_filters %w[all on_users on_proposals on_debates on_comments on_system_emails] + has_filters %w[all on_users on_proposals on_debates on_comments on_budget_investments on_system_emails] def show @activity = Activity.for_render.send(@current_filter) diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index d6917a5e5..44fb8d57a 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -62,6 +62,7 @@ en: filter: Show filters: all: All + on_budget_investments: Investment projects on_comments: Comments on_debates: Debates on_proposals: Proposals diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 8db768fed..6fbc020c5 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -62,6 +62,7 @@ es: filter: Mostrar filters: all: Todos + on_budget_investments: Proyectos de gasto on_comments: Comentarios on_debates: Debates on_proposals: Propuestas diff --git a/spec/system/admin/activity_spec.rb b/spec/system/admin/activity_spec.rb index e92270c2b..8789af663 100644 --- a/spec/system/admin/activity_spec.rb +++ b/spec/system/admin/activity_spec.rb @@ -378,4 +378,75 @@ describe "Admin activity" do end end end + + context "Budget investments" do + scenario "Shows moderation activity on budget investments" do + investment = create(:budget_investment, description: "

Investment description

") + + visit budget_investment_path(investment.budget, investment) + + within "#budget_investment_#{investment.id}" do + accept_confirm("Are you sure? Hide") { click_button "Hide" } + end + + expect(page).to have_css "#budget_investment_#{investment.id}.faded" + + visit admin_activity_path + + within first("tbody tr") do + expect(page).to have_content(investment.title) + expect(page).to have_content("Hidden") + expect(page).to have_content(admin.user.username) + expect(page).to have_css("p", exact_text: "Investment description") + end + end + + scenario "Shows moderation activity from moderation screen" do + investment1 = create(:budget_investment) + investment2 = create(:budget_investment) + investment3 = create(:budget_investment) + + visit moderation_budget_investments_path(filter: "all") + + within "#investment_#{investment1.id}" do + check "budget_investment_#{investment1.id}_check" + end + + within "#investment_#{investment3.id}" do + check "budget_investment_#{investment3.id}_check" + end + + accept_confirm("Are you sure? Hide budget investments") do + click_button "Hide budget investments" + end + + expect(page).not_to have_content(investment1.title) + + visit admin_activity_path(filter: "on_budget_investments") + + expect(page).to have_content(investment1.title) + expect(page).not_to have_content(investment2.title) + expect(page).to have_content(investment3.title) + end + + scenario "Shows admin restores" do + investment = create(:budget_investment, :hidden) + + visit admin_hidden_budget_investments_path + + within "#budget_investment_#{investment.id}" do + accept_confirm("Are you sure? Restore") { click_button "Restore" } + end + + expect(page).to have_content "There are no hidden budget investments" + + visit admin_activity_path + + within first("tbody tr") do + expect(page).to have_content(investment.title) + expect(page).to have_content("Restored") + expect(page).to have_content(admin.user.username) + end + end + end end From a9129158c12fc68f9c33f0942a811217522cf6ee Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 14 Nov 2025 13:41:37 +0100 Subject: [PATCH 11/12] Make moderation tests easier to read - reuse aria-labels instead of DOM selectors when checking moderation checkboxes - drop redundant 'first' in the within --- spec/system/admin/activity_spec.rb | 392 ++++++++++++----------------- 1 file changed, 166 insertions(+), 226 deletions(-) diff --git a/spec/system/admin/activity_spec.rb b/spec/system/admin/activity_spec.rb index 8789af663..850043ad8 100644 --- a/spec/system/admin/activity_spec.rb +++ b/spec/system/admin/activity_spec.rb @@ -1,7 +1,7 @@ require "rails_helper" describe "Admin activity" do - let(:admin) { create(:administrator) } + let(:admin) { create(:administrator, user: create(:user, username: "Admin Smith")) } before do login_as(admin.user) @@ -9,135 +9,117 @@ describe "Admin activity" do context "Proposals" do scenario "Shows moderation activity on proposals" do - proposal = create(:proposal, description: "

Description with html tag

") + proposal = create(:proposal, description: "

Description with html tag

", title: "Sample proposal") visit proposal_path(proposal) - within("#proposal_#{proposal.id}") do - accept_confirm("Are you sure? Hide \"#{proposal.title}\"") { click_button "Hide" } - end - expect(page).to have_css("#proposal_#{proposal.id}.faded") + accept_confirm('Are you sure? Hide "Sample proposal"') { click_button "Hide" } - visit admin_activity_path + expect(page).to have_css "#proposal_#{proposal.id}.faded" - within first("tbody tr") do - expect(page).to have_content(proposal.title) - expect(page).to have_content("Hidden") - expect(page).to have_content(admin.user.username) - expect(page).to have_css("p", exact_text: "Description with html tag") + visit admin_activity_path(filter: "on_proposals") + + within "tbody tr" do + expect(page).to have_content "Sample proposal" + expect(page).to have_content "Hidden" + expect(page).to have_content "Admin Smith" + expect(page).to have_css "p", exact_text: "Description with html tag" end end scenario "Shows moderation activity from moderation screen" do - proposal1 = create(:proposal) - proposal2 = create(:proposal) - proposal3 = create(:proposal) + create(:proposal, title: "Sample proposal 1") + create(:proposal, title: "Sample proposal 2") + create(:proposal, title: "Sample proposal 3") visit moderation_proposals_path(filter: "all") - within("#proposal_#{proposal1.id}") do - check "proposal_#{proposal1.id}_check" - end - - within("#proposal_#{proposal3.id}") do - check "proposal_#{proposal3.id}_check" - end - + check "Sample proposal 1" + check "Sample proposal 3" accept_confirm("Are you sure? Hide proposals") { click_button "Hide proposals" } - expect(page).not_to have_content(proposal1.title) + expect(page).not_to have_content "Sample proposal 1" - visit admin_activity_path + visit admin_activity_path(filter: "on_proposals") - expect(page).to have_content(proposal1.title) - expect(page).not_to have_content(proposal2.title) - expect(page).to have_content(proposal3.title) + expect(page).to have_content "Sample proposal 1" + expect(page).not_to have_content "Sample proposal 2" + expect(page).to have_content "Sample proposal 3" end scenario "Shows admin restores" do - proposal = create(:proposal, :hidden) + create(:proposal, :hidden, title: "Sample proposal") visit admin_hidden_proposals_path - within("#proposal_#{proposal.id}") do - accept_confirm("Are you sure? Restore") { click_button "Restore" } - end + accept_confirm("Are you sure? Restore") { click_button "Restore" } expect(page).to have_content "There are no hidden proposals" - visit admin_activity_path + visit admin_activity_path(filter: "on_proposals") - within first("tbody tr") do - expect(page).to have_content(proposal.title) - expect(page).to have_content("Restored") - expect(page).to have_content(admin.user.username) + within "tbody tr" do + expect(page).to have_content "Sample proposal" + expect(page).to have_content "Restored" + expect(page).to have_content "Admin Smith" end end end context "Debates" do scenario "Shows moderation activity on debates" do - debate = create(:debate) + debate = create(:debate, title: "Sample debate") visit debate_path(debate) - within("#debate_#{debate.id}") do - accept_confirm("Are you sure? Hide \"#{debate.title}\"") { click_button "Hide" } - end - expect(page).to have_css("#debate_#{debate.id}.faded") + accept_confirm('Are you sure? Hide "Sample debate"') { click_button "Hide" } - visit admin_activity_path + expect(page).to have_css "#debate_#{debate.id}.faded" - within first("tbody tr") do - expect(page).to have_content(debate.title) - expect(page).to have_content("Hidden") - expect(page).to have_content(admin.user.username) + visit admin_activity_path(filter: "on_debates") + + within "tbody tr" do + expect(page).to have_content "Sample debate" + expect(page).to have_content "Hidden" + expect(page).to have_content "Admin Smith" end end scenario "Shows moderation activity from moderation screen" do - debate1 = create(:debate) - debate2 = create(:debate) - debate3 = create(:debate) + create(:debate, title: "Sample debate 1") + create(:debate, title: "Sample debate 2") + create(:debate, title: "Sample debate 3") visit moderation_debates_path(filter: "all") - within("#debate_#{debate1.id}") do - check "debate_#{debate1.id}_check" - end - - within("#debate_#{debate3.id}") do - check "debate_#{debate3.id}_check" - end - + check "Sample debate 1" + check "Sample debate 3" accept_confirm("Are you sure? Hide debates") { click_button "Hide debates" } - expect(page).not_to have_content(debate1.title) + expect(page).not_to have_content "Sample debate 1" - visit admin_activity_path + visit admin_activity_path(filter: "on_debates") - expect(page).to have_content(debate1.title) - expect(page).not_to have_content(debate2.title) - expect(page).to have_content(debate3.title) + expect(page).to have_content "Sample debate 1" + expect(page).not_to have_content "Sample debate 2" + expect(page).to have_content "Sample debate 3" end scenario "Shows admin restores" do - debate = create(:debate, :hidden) + create(:debate, :hidden, title: "Sample debate") visit admin_hidden_debates_path - within("#debate_#{debate.id}") do - accept_confirm("Are you sure? Restore") { click_button "Restore" } - end + accept_confirm("Are you sure? Restore") { click_button "Restore" } expect(page).to have_content "There are no hidden debates" - visit admin_activity_path + visit admin_activity_path(filter: "on_debates") - within first("tbody tr") do - expect(page).to have_content(debate.title) - expect(page).to have_content("Restored") - expect(page).to have_content(admin.user.username) + within "tbody tr" do + expect(page).to have_content "Sample debate" + expect(page).to have_content "Restored" + expect(page).to have_content "Admin Smith" end end end @@ -145,186 +127,159 @@ describe "Admin activity" do context "Comments" do scenario "Shows moderation activity on comments" do debate = create(:debate) - comment = create(:comment, commentable: debate) + comment = create(:comment, commentable: debate, body: "Sample comment") visit debate_path(debate) - within("#comment_#{comment.id}") do - accept_confirm("Are you sure? Hide \"#{comment.body}\"") { click_button "Hide" } - expect(page).to have_css(".faded") + within "#comment_#{comment.id}" do + accept_confirm('Are you sure? Hide "Sample comment"') { click_button "Hide" } + expect(page).to have_css ".faded" end - visit admin_activity_path + visit admin_activity_path(filter: "on_comments") - within first("tbody tr") do - expect(page).to have_content(comment.body) - expect(page).to have_content("Hidden") - expect(page).to have_content(admin.user.username) + within "tbody tr" do + expect(page).to have_content "Sample comment" + expect(page).to have_content "Hidden" + expect(page).to have_content "Admin Smith" end end scenario "Shows moderation activity from moderation screen" do comment1 = create(:comment, body: "SPAM") - comment2 = create(:comment) + create(:comment, body: "Not Spam") comment3 = create(:comment, body: "Offensive!") visit moderation_comments_path(filter: "all") - within("#comment_#{comment1.id}") do - check "comment_#{comment1.id}_check" - end - - within("#comment_#{comment3.id}") do - check "comment_#{comment3.id}_check" - end - + check "comment_#{comment1.id}_check" + check "comment_#{comment3.id}_check" accept_confirm("Are you sure? Hide comments") { click_button "Hide comments" } - expect(page).not_to have_content(comment1.body) + expect(page).not_to have_content "SPAM" - visit admin_activity_path + visit admin_activity_path(filter: "on_comments") - expect(page).to have_content(comment1.body) - expect(page).not_to have_content(comment2.body) - expect(page).to have_content(comment3.body) + expect(page).to have_content "SPAM" + expect(page).not_to have_content "Not Spam" + expect(page).to have_content "Offensive!" end scenario "Shows admin restores" do - comment = create(:comment, :hidden) + create(:comment, :hidden, body: "Sample comment") visit admin_hidden_comments_path - within("#comment_#{comment.id}") do - accept_confirm("Are you sure? Restore") { click_button "Restore" } - end + accept_confirm("Are you sure? Restore") { click_button "Restore" } expect(page).to have_content "There are no hidden comments" - visit admin_activity_path + visit admin_activity_path(filter: "on_comments") - within first("tbody tr") do - expect(page).to have_content(comment.body) - expect(page).to have_content("Restored") - expect(page).to have_content(admin.user.username) + within "tbody tr" do + expect(page).to have_content "Sample comment" + expect(page).to have_content "Restored" + expect(page).to have_content "Admin Smith" end end end context "User" do scenario "Shows moderation activity on users" do - proposal = create(:proposal, author: create(:user, username: "Sam")) + proposal = create(:proposal, author: create(:user, username: "Sam", email: "sam@example.com")) visit proposal_path(proposal) - within("#proposal_#{proposal.id}") do - accept_confirm("Are you sure? This will hide the user \"Sam\" and all their contents.") do - click_button "Block author" - end - - expect(page).to have_current_path(proposals_path) + accept_confirm('Are you sure? This will hide the user "Sam" and all their contents.') do + click_button "Block author" end - visit admin_activity_path + expect(page).to have_current_path proposals_path - within first("tbody tr") do + visit admin_activity_path(filter: "on_users") + + within "tbody tr" do expect(page).to have_content("Blocked") - expect(page).to have_content(proposal.author.username) - expect(page).to have_content(proposal.author.email) - expect(page).to have_content(admin.user.username) - expect(page).not_to have_content(proposal.title) + expect(page).to have_content "Sam" + expect(page).to have_content "sam@example.com" + expect(page).to have_content "Admin Smith" + expect(page).not_to have_content proposal.title end end scenario "Shows moderation activity from moderation screen" do - user = create(:user) + create(:user, username: "Sam", email: "sam@example.com") - visit moderation_users_path(search: user.username) + visit moderation_users_path(search: "Sam") - within("#moderation_users") do - accept_confirm { click_button "Block" } - end + accept_confirm { click_button "Block" } expect(page).to have_content "The user has been blocked" - visit admin_activity_path + visit admin_activity_path(filter: "on_users") - within first("tbody tr") do - expect(page).to have_content(user.username) - expect(page).to have_content(user.email) - expect(page).to have_content(admin.user.username) + within "tbody tr" do + expect(page).to have_content "Sam" + expect(page).to have_content "sam@example.com" + expect(page).to have_content "Admin Smith" end end scenario "Shows moderation activity from proposals moderation screen" do - proposal1 = create(:proposal) - proposal2 = create(:proposal) - proposal3 = create(:proposal) + proposal1 = create(:proposal, title: "Sample proposal 1") + proposal2 = create(:proposal, title: "Sample proposal 2") + proposal3 = create(:proposal, title: "Sample proposal 3") visit moderation_proposals_path(filter: "all") - within("#proposal_#{proposal1.id}") do - check "proposal_#{proposal1.id}_check" - end - - within("#proposal_#{proposal3.id}") do - check "proposal_#{proposal3.id}_check" - end + check "Sample proposal 1" + check "Sample proposal 3" accept_confirm("Are you sure? Block authors") { click_button "Block authors" } - expect(page).not_to have_content(proposal1.author.username) + expect(page).not_to have_content "Sample proposal 1" - visit admin_activity_path + visit admin_activity_path(filter: "on_users") - expect(page).to have_content(proposal1.author.username) - expect(page).to have_content(proposal1.author.email) - expect(page).to have_content(proposal3.author.username) - expect(page).to have_content(proposal3.author.email) - expect(page).not_to have_content(proposal2.author.username) + expect(page).to have_content proposal1.author.username + expect(page).to have_content proposal1.author.email + expect(page).to have_content proposal3.author.username + expect(page).to have_content proposal3.author.email + expect(page).not_to have_content proposal2.author.username end scenario "Shows moderation activity from debates moderation screen" do - debate1 = create(:debate) - debate2 = create(:debate) - debate3 = create(:debate) + debate1 = create(:debate, title: "Sample debate 1") + debate2 = create(:debate, title: "Sample debate 2") + debate3 = create(:debate, title: "Sample debate 3") visit moderation_debates_path(filter: "all") - within("#debate_#{debate1.id}") do - check "debate_#{debate1.id}_check" - end - - within("#debate_#{debate3.id}") do - check "debate_#{debate3.id}_check" - end + check "Sample debate 1" + check "Sample debate 3" accept_confirm("Are you sure? Block authors") { click_button "Block authors" } - expect(page).not_to have_content(debate1.author.username) + expect(page).not_to have_content debate1.author.username visit admin_activity_path - expect(page).to have_content(debate1.author.username) - expect(page).to have_content(debate1.author.email) - expect(page).to have_content(debate3.author.username) - expect(page).to have_content(debate3.author.email) - expect(page).not_to have_content(debate2.author.username) + expect(page).to have_content debate1.author.username + expect(page).to have_content debate1.author.email + expect(page).to have_content debate3.author.username + expect(page).to have_content debate3.author.email + expect(page).not_to have_content debate2.author.username end scenario "Shows moderation activity from comments moderation screen" do - comment1 = create(:comment, body: "SPAM") + comment1 = create(:comment) comment2 = create(:comment) - comment3 = create(:comment, body: "Offensive!") + comment3 = create(:comment) visit moderation_comments_path(filter: "all") - within("#comment_#{comment1.id}") do - check "comment_#{comment1.id}_check" - end - - within("#comment_#{comment3.id}") do - check "comment_#{comment3.id}_check" - end + check "comment_#{comment1.id}_check" + check "comment_#{comment3.id}_check" accept_confirm("Are you sure? Block authors") { click_button "Block authors" } @@ -332,31 +287,29 @@ describe "Admin activity" do visit admin_activity_path - expect(page).to have_content(comment1.author.username) - expect(page).to have_content(comment1.author.email) - expect(page).to have_content(comment3.author.username) - expect(page).to have_content(comment3.author.email) - expect(page).not_to have_content(comment2.author.username) + expect(page).to have_content comment1.author.username + expect(page).to have_content comment1.author.email + expect(page).to have_content comment3.author.username + expect(page).to have_content comment3.author.email + expect(page).not_to have_content comment2.author.username end scenario "Shows admin restores" do - user = create(:user, :hidden) + create(:user, :hidden, username: "Sam", email: "sam@example.com") visit admin_hidden_users_path - within("#user_#{user.id}") do - accept_confirm("Are you sure? Restore") { click_button "Restore" } - end + accept_confirm("Are you sure? Restore") { click_button "Restore" } expect(page).to have_content "There are no hidden users" - visit admin_activity_path + visit admin_activity_path(filter: "on_users") - within first("tbody tr") do - expect(page).to have_content(user.username) - expect(page).to have_content(user.email) - expect(page).to have_content("Restored") - expect(page).to have_content(admin.user.username) + within "tbody tr" do + expect(page).to have_content "Sam" + expect(page).to have_content "sam@example.com" + expect(page).to have_content "Restored" + expect(page).to have_content "Admin Smith" end end end @@ -369,83 +322,70 @@ describe "Admin activity" do body: "Proposal A Notification Body") proposal_notification.moderate_system_email(admin.user) - visit admin_activity_path + visit admin_activity_path(filter: "on_system_emails") - within first("tbody tr") do - expect(page).to have_content(proposal_notification.title) - expect(page).to have_content("Hidden") - expect(page).to have_content(admin.user.username) + within "tbody tr" do + expect(page).to have_content "Proposal A Title" + expect(page).to have_content "Hidden" + expect(page).to have_content "Admin Smith" end end end context "Budget investments" do scenario "Shows moderation activity on budget investments" do - investment = create(:budget_investment, description: "

Investment description

") + investment = create(:budget_investment, title: "Sample investment") visit budget_investment_path(investment.budget, investment) - within "#budget_investment_#{investment.id}" do - accept_confirm("Are you sure? Hide") { click_button "Hide" } - end + accept_confirm('Are you sure? Hide "Sample investment"') { click_button "Hide" } expect(page).to have_css "#budget_investment_#{investment.id}.faded" - visit admin_activity_path + visit admin_activity_path(filter: "on_budget_investments") - within first("tbody tr") do - expect(page).to have_content(investment.title) - expect(page).to have_content("Hidden") - expect(page).to have_content(admin.user.username) - expect(page).to have_css("p", exact_text: "Investment description") + within "tbody tr" do + expect(page).to have_content "Sample investment" + expect(page).to have_content "Hidden" + expect(page).to have_content "Admin Smith" end end scenario "Shows moderation activity from moderation screen" do - investment1 = create(:budget_investment) - investment2 = create(:budget_investment) - investment3 = create(:budget_investment) + create(:budget_investment, title: "Sample investment 1") + create(:budget_investment, title: "Sample investment 2") + create(:budget_investment, title: "Sample investment 3") visit moderation_budget_investments_path(filter: "all") - within "#investment_#{investment1.id}" do - check "budget_investment_#{investment1.id}_check" - end + check "Sample investment 1" + check "Sample investment 3" + accept_confirm("Are you sure? Hide budget investments") { click_button "Hide budget investments" } - within "#investment_#{investment3.id}" do - check "budget_investment_#{investment3.id}_check" - end - - accept_confirm("Are you sure? Hide budget investments") do - click_button "Hide budget investments" - end - - expect(page).not_to have_content(investment1.title) + expect(page).not_to have_content "Sample investment 1" visit admin_activity_path(filter: "on_budget_investments") - expect(page).to have_content(investment1.title) - expect(page).not_to have_content(investment2.title) - expect(page).to have_content(investment3.title) + expect(page).to have_content "Sample investment 1" + expect(page).not_to have_content "Sample investment 2" + expect(page).to have_content "Sample investment 3" end scenario "Shows admin restores" do - investment = create(:budget_investment, :hidden) + create(:budget_investment, :hidden, title: "Sample investment") visit admin_hidden_budget_investments_path - within "#budget_investment_#{investment.id}" do - accept_confirm("Are you sure? Restore") { click_button "Restore" } - end + accept_confirm("Are you sure? Restore") { click_button "Restore" } expect(page).to have_content "There are no hidden budget investments" - visit admin_activity_path + visit admin_activity_path(filter: "on_budget_investments") - within first("tbody tr") do - expect(page).to have_content(investment.title) - expect(page).to have_content("Restored") - expect(page).to have_content(admin.user.username) + within "tbody tr" do + expect(page).to have_content "Sample investment" + expect(page).to have_content "Restored" + expect(page).to have_content "Admin Smith" end end end From 4e455578d1c8ff69d14bba832c2507e3e1bc68a7 Mon Sep 17 00:00:00 2001 From: taitus Date: Fri, 14 Nov 2025 11:46:11 +0100 Subject: [PATCH 12/12] Rename User.by_authors to with_ids The "by_authors" scope was the last remaining name from the removed family of `by_author` scopes. It no longer reflects its purpose: it simply loads users by IDs. --- app/models/community.rb | 4 ++-- app/models/user.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/community.rb b/app/models/community.rb index 48a6029d3..1852aa4f0 100644 --- a/app/models/community.rb +++ b/app/models/community.rb @@ -49,8 +49,8 @@ class Community < ApplicationRecord end def users_who_topics_author - author_ids = topics.pluck(:author_id) - User.by_authors(author_ids) + ids = topics.pluck(:author_id) + User.with_ids(ids) end def author_from_community diff --git a/app/models/user.rb b/app/models/user.rb index 7af90cdbe..f97e811c7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -111,7 +111,7 @@ class User < ApplicationRecord scope :erased, -> { where.not(erased_at: nil) } scope :active, -> { excluding(erased) } scope :public_for_api, -> { all } - scope :by_authors, ->(author_ids) { where(id: author_ids) } + scope :with_ids, ->(ids) { where(id: ids) } scope :by_comments, ->(commentables) do joins(:comments).where("comments.commentable": commentables).distinct end