From 9f3760cfd8e991182f4eb5ff59fe368f09d3208b Mon Sep 17 00:00:00 2001 From: Rafael dos Santos Silva Date: Thu, 8 Dec 2022 17:14:43 -0300 Subject: [PATCH] FEATURE: Allow category moderators to set auto deletion topic timers (#19383) Co-authored-by: Penar Musaraj --- .../app/controllers/edit-topic-timer.js | 4 +- .../tests/acceptance/topic-edit-timer-test.js | 50 ++++++++++++++++++- app/controllers/topics_controller.rb | 4 ++ app/models/topic_timer.rb | 4 ++ spec/requests/topics_controller_spec.rb | 43 ++++++++++++++++ 5 files changed, 102 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse/app/controllers/edit-topic-timer.js b/app/assets/javascripts/discourse/app/controllers/edit-topic-timer.js index 50e30cd5b03..d6ebfa9c431 100644 --- a/app/assets/javascripts/discourse/app/controllers/edit-topic-timer.js +++ b/app/assets/javascripts/discourse/app/controllers/edit-topic-timer.js @@ -47,7 +47,7 @@ export default Controller.extend(ModalFunctionality, { }); } - if (this.currentUser.staff) { + if (this.model.details.can_delete) { types.push({ id: DELETE_STATUS_TYPE, name: I18n.t("topic.auto_delete.title"), @@ -59,7 +59,7 @@ export default Controller.extend(ModalFunctionality, { name: I18n.t("topic.auto_bump.title"), }); - if (this.currentUser.staff) { + if (this.model.details.can_delete) { types.push({ id: DELETE_REPLIES_TYPE, name: I18n.t("topic.auto_delete_replies.title"), diff --git a/app/assets/javascripts/discourse/tests/acceptance/topic-edit-timer-test.js b/app/assets/javascripts/discourse/tests/acceptance/topic-edit-timer-test.js index 7143b3002e1..728de641e58 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/topic-edit-timer-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/topic-edit-timer-test.js @@ -11,6 +11,8 @@ import { click, fillIn, visit } from "@ember/test-helpers"; import { test } from "qunit"; import selectKit from "discourse/tests/helpers/select-kit-helper"; import I18n from "I18n"; +import { cloneJSON } from "discourse-common/lib/object"; +import topicFixtures from "discourse/tests/fixtures/topic"; acceptance("Topic - Edit timer", function (needs) { let clock = null; @@ -28,6 +30,10 @@ acceptance("Topic - Edit timer", function (needs) { category_id: null, }) ); + + const topicResponse = cloneJSON(topicFixtures["/t/54077.json"]); + topicResponse.details.can_delete = false; + server.get("/t/54077.json", () => helper.response(topicResponse)); }); needs.hooks.beforeEach(() => { @@ -294,7 +300,7 @@ acceptance("Topic - Edit timer", function (needs) { test("TL4 can't auto-delete", async function (assert) { updateCurrentUser({ moderator: false, admin: false, trust_level: 4 }); - await visit("/t/internationalization-localization"); + await visit("/t/short-topic-with-two-posts/54077"); await click(".toggle-admin-menu"); await click(".admin-topic-timer-update button"); @@ -305,6 +311,48 @@ acceptance("Topic - Edit timer", function (needs) { assert.ok(!timerType.rowByValue("delete").exists()); }); + test("Category Moderator can auto-delete replies", async function (assert) { + updateCurrentUser({ moderator: false, admin: false, trust_level: 4 }); + + await visit("/t/internationalization-localization"); + await click(".toggle-admin-menu"); + await click(".admin-topic-timer-update button"); + + const timerType = selectKit(".select-kit.timer-type"); + + await timerType.expand(); + + assert.ok(timerType.rowByValue("delete_replies").exists()); + }); + + test("TL4 can't auto-delete replies", async function (assert) { + updateCurrentUser({ moderator: false, admin: false, trust_level: 4 }); + + await visit("/t/short-topic-with-two-posts/54077"); + await click(".toggle-admin-menu"); + await click(".admin-topic-timer-update button"); + + const timerType = selectKit(".select-kit.timer-type"); + + await timerType.expand(); + + assert.ok(!timerType.rowByValue("delete_replies").exists()); + }); + + test("Category Moderator can auto-delete", async function (assert) { + updateCurrentUser({ moderator: false, admin: false, trust_level: 4 }); + + await visit("/t/internationalization-localization"); + await click(".toggle-admin-menu"); + await click(".admin-topic-timer-update button"); + + const timerType = selectKit(".select-kit.timer-type"); + + await timerType.expand(); + + assert.ok(timerType.rowByValue("delete").exists()); + }); + test("auto delete", async function (assert) { updateCurrentUser({ moderator: true }); const timerType = selectKit(".select-kit.timer-type"); diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb index 67c844dbe61..d2b3caeb243 100644 --- a/app/controllers/topics_controller.rb +++ b/app/controllers/topics_controller.rb @@ -497,6 +497,10 @@ class TopicsController < ApplicationController topic = Topic.find_by(id: params[:topic_id]) guardian.ensure_can_moderate!(topic) + if TopicTimer.destructive_types.values.include?(status_type) + guardian.ensure_can_delete!(topic) + end + options = { by_user: current_user, based_on_last_post: based_on_last_post diff --git a/app/models/topic_timer.rb b/app/models/topic_timer.rb index 05f0226fd15..82a00e8dc3c 100644 --- a/app/models/topic_timer.rb +++ b/app/models/topic_timer.rb @@ -98,6 +98,10 @@ class TopicTimer < ActiveRecord::Base @_private_types ||= types.only(:reminder, :clear_slow_mode) end + def self.destructive_types + @_destructive_types ||= types.only(:delete, :delete_replies) + end + def public_type? !!self.class.public_types[self.status_type] end diff --git a/spec/requests/topics_controller_spec.rb b/spec/requests/topics_controller_spec.rb index 6f086d212b2..af824cd5d5e 100644 --- a/spec/requests/topics_controller_spec.rb +++ b/spec/requests/topics_controller_spec.rb @@ -3999,6 +3999,9 @@ RSpec.describe TopicsController do end context 'when logged in as a TL4 user' do + before do + SiteSetting.enable_category_group_moderation = true + end it "raises an error if the user can't see the topic" do user.update!(trust_level: TrustLevel[4]) sign_in(user) @@ -4013,6 +4016,46 @@ RSpec.describe TopicsController do expect(response.status).to eq(403) expect(response.parsed_body["error_type"]).to eq('invalid_access') end + + it "allows a category moderator to create a delete timer" do + user.update!(trust_level: TrustLevel[4]) + topic.category.update!(reviewable_by_group: user.groups.first) + + sign_in(user) + + post "/t/#{topic.id}/timer.json", params: { + time: 10, + status_type: 'delete' + } + + expect(response.status).to eq(200) + end + + it "raises an error setting a delete timer" do + user.update!(trust_level: TrustLevel[4]) + sign_in(user) + + post "/t/#{topic.id}/timer.json", params: { + time: 10, + status_type: 'delete' + } + + expect(response.status).to eq(403) + expect(response.parsed_body["error_type"]).to eq('invalid_access') + end + + it "raises an error setting delete_replies timer" do + user.update!(trust_level: TrustLevel[4]) + sign_in(user) + + post "/t/#{topic.id}/timer.json", params: { + time: 10, + status_type: 'delete_replies' + } + + expect(response.status).to eq(403) + expect(response.parsed_body["error_type"]).to eq('invalid_access') + end end end