From c4635fdf26e141e86281ed38a12f77e01699b84b Mon Sep 17 00:00:00 2001 From: Pablo Brasero Date: Tue, 9 Jun 2026 18:03:07 +0100 Subject: [PATCH] Implement complex update rules, as per user blocks --- app/abilities/ability.rb | 5 +- .../moderation_zones_controller.rb | 25 +++- config/locales/en.yml | 4 + .../moderation_zones_controller_test.rb | 118 +++++++++++++++++- 4 files changed, 144 insertions(+), 8 deletions(-) diff --git a/app/abilities/ability.rb b/app/abilities/ability.rb index 01d0de6b3..9953cb0f5 100644 --- a/app/abilities/ability.rb +++ b/app/abilities/ability.rb @@ -64,7 +64,10 @@ class Ability can :update, UserBlock, :creator => user can :update, UserBlock, :revoker => user can :update, UserBlock, :active? => true - can :manage, ModerationZone + can [:read, :create, :destroy], ModerationZone + can :update, ModerationZone, :creator => user + can :update, ModerationZone, :revoker => user + can :update, ModerationZone, :active? => true end if user.administrator? diff --git a/app/controllers/moderation_zones_controller.rb b/app/controllers/moderation_zones_controller.rb index 369dce088..bd2ece7e2 100644 --- a/app/controllers/moderation_zones_controller.rb +++ b/app/controllers/moderation_zones_controller.rb @@ -36,7 +36,16 @@ class ModerationZonesController < ApplicationController def update check_revocation(@moderation_zone, moderation_zone_params) - if @moderation_zone.update(moderation_zone_params) + if cannot?(:update, @moderation_zone) + flash[:error] = @moderation_zone.revoker ? t(".only_creator_or_revoker_can_edit") : t(".only_creator_can_edit") + redirect_to moderation_zones_url + elsif current_user != @moderation_zone.creator && updating_without_revoking?(@moderation_zone, moderation_zone_params) + flash[:error] = t(".only_creator_can_edit_without_revoking") + redirect_to moderation_zones_url + elsif reactivating?(@moderation_zone, moderation_zone_params) + flash[:error] = t(".no_reactivation") + redirect_to moderation_zones_url + elsif @moderation_zone.update(moderation_zone_params) redirect_to moderation_zones_url, :notice => t(".success"), :status => :see_other else render :edit, :status => :unprocessable_content @@ -61,4 +70,18 @@ class ModerationZonesController < ApplicationController duplicate.assign_attributes(modzone_params) modzone.revoker = current_user if previously_active && !duplicate.active? end + + def updating_without_revoking?(modzone, modzone_params) + duplicate = modzone.dup + previously_active = duplicate.active? + duplicate.assign_attributes(modzone_params) + previously_active && duplicate.active? + end + + def reactivating?(modzone, modzone_params) + duplicate = modzone.dup + previously_active = duplicate.active? + duplicate.assign_attributes(modzone_params) + !previously_active && duplicate.active? + end end diff --git a/config/locales/en.yml b/config/locales/en.yml index dedbee211..5f9a72664 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3876,6 +3876,10 @@ en: heading: "Editing moderation zone %{name}" update: success: "Moderation zone updated." + only_creator_can_edit: "Only the moderator who created this moderation zone can edit it." + only_creator_can_edit_without_revoking: "Only the moderator who created this moderation zone can edit it without revoking." + only_creator_or_revoker_can_edit: "Only the moderators who created or revoked this moderation zone can edit it." + no_reactivation: "This moderation zone is inactive and cannot be reactivated." helper: short: ended: "ended" diff --git a/test/controllers/moderation_zones_controller_test.rb b/test/controllers/moderation_zones_controller_test.rb index 01bc0d462..a6bd8cabd 100644 --- a/test/controllers/moderation_zones_controller_test.rb +++ b/test/controllers/moderation_zones_controller_test.rb @@ -172,8 +172,9 @@ class ModerationZonesControllerTest < ActionDispatch::IntegrationTest # with a simpler request (eg: with empty params) but, for the sake of # doing it properly, let's have everyting in place except for the only detail # that the user is not a moderator. - session_for(create(:user)) - moderation_zone = create(:moderation_zone, :ends_at => 1.week.from_now) + creator = create(:user) + moderation_zone = create(:moderation_zone, :ends_at => 1.week.from_now, :creator => creator) + session_for(creator) patch( moderation_zone_url(moderation_zone), @@ -190,8 +191,9 @@ class ModerationZonesControllerTest < ActionDispatch::IntegrationTest end test "update, as moderator" do - session_for(create(:moderator_user)) - moderation_zone = create(:moderation_zone, :ends_at => 1.week.from_now) + creator = create(:moderator_user) + moderation_zone = create(:moderation_zone, :ends_at => 1.week.from_now, :creator => creator) + session_for(creator) patch( moderation_zone_url(moderation_zone), @@ -212,8 +214,9 @@ class ModerationZonesControllerTest < ActionDispatch::IntegrationTest end test "update, with errors" do - session_for(create(:moderator_user)) - moderation_zone = create(:moderation_zone, :ends_at => 1.week.from_now) + creator = create(:moderator_user) + moderation_zone = create(:moderation_zone, :ends_at => 1.week.from_now, :creator => creator) + session_for(creator) patch( moderation_zone_url(moderation_zone), @@ -252,4 +255,107 @@ class ModerationZonesControllerTest < ActionDispatch::IntegrationTest moderation_zone.reload assert_equal revoker, moderation_zone.revoker end + + test "update, by non-creator, of inactive+unrevoked record" do + updater = create(:moderator_user) + moderation_zone = create(:moderation_zone, :reason => "Initial reason", :ends_at => 1.week.ago) + session_for(updater) + + patch( + moderation_zone_url(moderation_zone), + :params => { + :moderation_zone => { + :reason => "Updated reason" + } + } + ) + assert_redirected_to moderation_zones_url + assert_equal "Only the moderator who created this moderation zone can edit it.", flash[:error] + + moderation_zone.reload + assert_equal "Initial reason", moderation_zone.reason + end + + test "update, by creator, of inactive+revoked record" do + creator = create(:moderator_user) + moderation_zone = create(:moderation_zone, :reason => "Initial reason", :creator => creator, :ends_at => 1.week.ago) + session_for(creator) + + patch( + moderation_zone_url(moderation_zone), + :params => { + :moderation_zone => { + :reason => "Updated reason" + } + } + ) + + assert_redirected_to moderation_zones_url + assert_nil flash[:error] + + moderation_zone.reload + assert_equal "Updated reason", moderation_zone.reason + end + + test "update, by non-creator, of revoked record" do + updater = create(:moderator_user) + revoker = create(:moderator_user) + moderation_zone = create(:moderation_zone, :reason => "Initial reason", :ends_at => 1.week.ago, :revoker => revoker) + session_for(updater) + + patch( + moderation_zone_url(moderation_zone), + :params => { + :moderation_zone => { + :reason => "Updated reason" + } + } + ) + assert_redirected_to moderation_zones_url + assert_equal "Only the moderators who created or revoked this moderation zone can edit it.", flash[:error] + + moderation_zone.reload + assert_equal "Initial reason", moderation_zone.reason + end + + test "update, by non-creator, of active record" do + updater = create(:moderator_user) + moderation_zone = create(:moderation_zone, :reason => "Initial reason", :ends_at => 1.week.from_now) + session_for(updater) + + patch( + moderation_zone_url(moderation_zone), + :params => { + :moderation_zone => { + :reason => "Updated reason", + :period => 1.week.from_now + } + } + ) + assert_redirected_to moderation_zones_url + assert_equal "Only the moderator who created this moderation zone can edit it without revoking.", flash[:error] + + moderation_zone.reload + assert_equal "Initial reason", moderation_zone.reason + end + + test "update to reactivate" do + creator = create(:moderator_user) + moderation_zone = create(:moderation_zone, :creator => creator, :ends_at => 1.week.ago) + session_for(creator) + + patch( + moderation_zone_url(moderation_zone), + :params => { + :moderation_zone => { + :period => 1.week.from_now + } + } + ) + assert_redirected_to moderation_zones_url + assert_equal "This moderation zone is inactive and cannot be reactivated.", flash[:error] + + moderation_zone.reload + assert_not_predicate moderation_zone, :active? + end end -- 2.47.3