From eb898e5523eaf5e9d7e62bf598f1605da757c88c Mon Sep 17 00:00:00 2001
From: Martin Brennan <mjrbrennan@gmail.com>
Date: Thu, 1 Jul 2021 13:18:38 +1000
Subject: [PATCH] FIX: Reorder and hide topic timer options (#13597)

This PR changes the order of the topic timer options
into a more logical order when the topic is open/closed.

Also, we are now hiding the "Schedule Publishing" option
if the topic is not a private message or in a private category.
It does not make sense to schedule publishing to a different
category for a public topic.
---
 .../app/controllers/edit-topic-timer.js       |  94 +++++++++-----
 .../tests/acceptance/topic-edit-timer-test.js | 121 +++++++++++++++++-
 config/locales/client.en.yml                  |   2 +-
 3 files changed, 176 insertions(+), 41 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 96ce3817ef2..b3ca2cd512a 100644
--- a/app/assets/javascripts/discourse/app/controllers/edit-topic-timer.js
+++ b/app/assets/javascripts/discourse/app/controllers/edit-topic-timer.js
@@ -20,53 +20,77 @@ export default Controller.extend(ModalFunctionality, {
   loading: false,
   isPublic: "true",
 
-  @discourseComputed("model.closed")
-  publicTimerTypes(closed) {
-    let types = [
-      {
-        id: CLOSE_STATUS_TYPE,
-        name: I18n.t(
-          closed ? "topic.temp_open.title" : "topic.auto_close.title"
-        ),
-      },
-    ];
+  @discourseComputed(
+    "model.closed",
+    "model.category",
+    "model.isPrivateMessage",
+    "model.invisible"
+  )
+  publicTimerTypes(closed, category, isPrivateMessage, invisible) {
+    let types = [];
 
     if (!closed) {
+      types.push({
+        id: CLOSE_STATUS_TYPE,
+        name: I18n.t("topic.auto_close.title"),
+      });
       types.push({
         id: CLOSE_AFTER_LAST_POST_STATUS_TYPE,
         name: I18n.t("topic.auto_close_after_last_post.title"),
       });
     }
 
-    types.push(
-      {
+    if (closed) {
+      types.push({
         id: OPEN_STATUS_TYPE,
-        name: I18n.t(
-          closed ? "topic.auto_reopen.title" : "topic.temp_close.title"
-        ),
-      },
-      {
+        name: I18n.t("topic.auto_reopen.title"),
+      });
+    }
+
+    if (this.currentUser.staff) {
+      types.push({
+        id: DELETE_STATUS_TYPE,
+        name: I18n.t("topic.auto_delete.title"),
+      });
+    }
+
+    types.push({
+      id: BUMP_TYPE,
+      name: I18n.t("topic.auto_bump.title"),
+    });
+
+    if (this.currentUser.staff) {
+      types.push({
+        id: DELETE_REPLIES_TYPE,
+        name: I18n.t("topic.auto_delete_replies.title"),
+      });
+    }
+
+    if (closed) {
+      types.push({
+        id: CLOSE_STATUS_TYPE,
+        name: I18n.t("topic.temp_open.title"),
+      });
+    }
+
+    if (!closed) {
+      types.push({
+        id: OPEN_STATUS_TYPE,
+        name: I18n.t("topic.temp_close.title"),
+      });
+    }
+
+    if (
+      (category && category.read_restricted) ||
+      isPrivateMessage ||
+      invisible
+    ) {
+      types.push({
         id: PUBLISH_TO_CATEGORY_STATUS_TYPE,
         name: I18n.t("topic.publish_to_category.title"),
-      },
-      {
-        id: BUMP_TYPE,
-        name: I18n.t("topic.auto_bump.title"),
-      }
-    );
-
-    if (this.currentUser.get("staff")) {
-      types.push(
-        {
-          id: DELETE_STATUS_TYPE,
-          name: I18n.t("topic.auto_delete.title"),
-        },
-        {
-          id: DELETE_REPLIES_TYPE,
-          name: I18n.t("topic.auto_delete_replies.title"),
-        }
-      );
+      });
     }
+
     return types;
   },
 
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 b06464376ef..6614ed59420 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
@@ -121,12 +121,12 @@ acceptance("Topic - Edit timer", function (needs) {
     assert.ok(regex2.test(html2));
   });
 
-  test("schedule", async function (assert) {
+  test("schedule publish to category - visible for a PM", async function (assert) {
     updateCurrentUser({ moderator: true });
     const timerType = selectKit(".select-kit.timer-type");
     const categoryChooser = selectKit(".modal-body .category-chooser");
 
-    await visit("/t/internationalization-localization");
+    await visit("/t/pm-for-testing/12");
     await click(".toggle-admin-menu");
     await click(".admin-topic-timer-update button");
 
@@ -141,14 +141,110 @@ acceptance("Topic - Edit timer", function (needs) {
 
     await click("#tap_tile_start_of_next_business_week");
 
-    const regex = /will be published to #dev/g;
     const text = queryAll(".edit-topic-timer-modal .topic-timer-info")
       .text()
       .trim();
-    assert.ok(regex.test(text));
+
+    // this needs to be done because there is no simple way to get the
+    // plain text version of a translation with HTML
+    let el = document.createElement("p");
+    el.innerHTML = I18n.t(
+      "topic.status_update_notice.auto_publish_to_category",
+      {
+        categoryUrl: "/c/dev/7",
+        categoryName: "dev",
+        timeLeft: "in 6 days",
+      }
+    );
+
+    assert.equal(text, el.innerText);
   });
 
-  test("schedule - last custom date and time", async function (assert) {
+  test("schedule publish to category - visible for a private category", async function (assert) {
+    updateCurrentUser({ moderator: true });
+    const timerType = selectKit(".select-kit.timer-type");
+    const categoryChooser = selectKit(".modal-body .category-chooser");
+
+    // has private category id 24 (shared drafts)
+    await visit("/t/some-topic/9");
+    await click(".toggle-admin-menu");
+    await click(".admin-topic-timer-update button");
+
+    await timerType.expand();
+    await timerType.selectRowByValue("publish_to_category");
+
+    assert.equal(categoryChooser.header().label(), "uncategorized");
+    assert.equal(categoryChooser.header().value(), null);
+
+    await categoryChooser.expand();
+    await categoryChooser.selectRowByValue("7");
+
+    await click("#tap_tile_start_of_next_business_week");
+
+    const text = queryAll(".edit-topic-timer-modal .topic-timer-info")
+      .text()
+      .trim();
+
+    // this needs to be done because there is no simple way to get the
+    // plain text version of a translation with HTML
+    let el = document.createElement("p");
+    el.innerHTML = I18n.t(
+      "topic.status_update_notice.auto_publish_to_category",
+      {
+        categoryUrl: "/c/dev/7",
+        categoryName: "dev",
+        timeLeft: "in 6 days",
+      }
+    );
+
+    assert.equal(text, el.innerText);
+  });
+
+  test("schedule publish to category - visible for an unlisted public topic", async function (assert) {
+    updateCurrentUser({ moderator: true });
+    const timerType = selectKit(".select-kit.timer-type");
+    const categoryChooser = selectKit(".modal-body .category-chooser");
+
+    await visit("/t/internationalization-localization/280");
+
+    // make topic not visible
+    await click(".toggle-admin-menu");
+    await click(".topic-admin-visible .btn");
+
+    await click(".toggle-admin-menu");
+    await click(".admin-topic-timer-update button");
+
+    await timerType.expand();
+    await timerType.selectRowByValue("publish_to_category");
+
+    assert.equal(categoryChooser.header().label(), "uncategorized");
+    assert.equal(categoryChooser.header().value(), null);
+
+    await categoryChooser.expand();
+    await categoryChooser.selectRowByValue("7");
+
+    await click("#tap_tile_start_of_next_business_week");
+
+    const text = queryAll(".edit-topic-timer-modal .topic-timer-info")
+      .text()
+      .trim();
+
+    // this needs to be done because there is no simple way to get the
+    // plain text version of a translation with HTML
+    let el = document.createElement("p");
+    el.innerHTML = I18n.t(
+      "topic.status_update_notice.auto_publish_to_category",
+      {
+        categoryUrl: "/c/dev/7",
+        categoryName: "dev",
+        timeLeft: "in 6 days",
+      }
+    );
+
+    assert.equal(text, el.innerText);
+  });
+
+  test("schedule publish to category - last custom date and time", async function (assert) {
     updateCurrentUser({ moderator: true });
 
     await visit("/t/internationalization-localization");
@@ -183,6 +279,21 @@ acceptance("Topic - Edit timer", function (needs) {
     assert.ok(regex.test(text));
   });
 
+  test("schedule publish to category - does not show for a public topic", async function (assert) {
+    updateCurrentUser({ moderator: true });
+    const timerType = selectKit(".select-kit.timer-type");
+
+    await visit("/t/internationalization-localization");
+    await click(".toggle-admin-menu");
+    await click(".admin-topic-timer-update button");
+
+    await timerType.expand();
+    assert.notOk(
+      timerType.rowByValue("publish_to_category").exists(),
+      "publish to category is not shown for a public topic"
+    );
+  });
+
   test("TL4 can't auto-delete", async function (assert) {
     updateCurrentUser({ moderator: false, admin: false, trust_level: 4 });
 
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 56aba8372d8..91f1d145f48 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -2566,7 +2566,7 @@ en:
       temp_open:
         title: "Open Temporarily"
       auto_reopen:
-        title: "Auto-open Topic"
+        title: "Auto-Open Topic"
       temp_close:
         title: "Close Temporarily"
       auto_close: