From fbb1fb9270fbf3a5c659c8ce8e7df7bf82cb3cd4 Mon Sep 17 00:00:00 2001 From: Roman Rizzi Date: Tue, 20 Oct 2020 06:52:03 -0300 Subject: [PATCH] FIX: Ensure slow mode duration is correctly edited and displayed. (#10945) * FIX: Ensure slow mode duration is correctly edited and displayed. This commit fixes a bug where you were forced to set hours, minutes, and seconds or you won't be able to set the slow mode. Also, the duration was not displayed correctly due to the seconds not being truncated. Additionally, we'll always display the hours, minutes, and seconds inputs for clarity and remove the blue banner. * Set slow mode modal tweaks. Uses labels instead of placeholders. Input fields only visible when custom option selected. Replace "Custom Duration" with "Pick Duration". Additionally, place the `Set slow mode` button at the bottom of the topic actions menu. * Perform the slow_mode validation also on the client-side before saving trying to save the post. This way, the post won't be staged. --- .../discourse/app/controllers/composer.js | 12 ++++++++++++ .../app/controllers/edit-slow-mode.js | 12 +++++++++++- .../discourse/app/helpers/slow-mode.js | 17 ++++++++++++----- .../app/templates/modal/edit-slow-mode.hbs | 18 +++++++----------- .../discourse/app/widgets/topic-admin-menu.js | 16 ++++++++-------- app/assets/stylesheets/common/base/modal.scss | 2 +- config/locales/client.en.yml | 10 +++++----- config/locales/server.en.yml | 2 +- 8 files changed, 57 insertions(+), 32 deletions(-) diff --git a/app/assets/javascripts/discourse/app/controllers/composer.js b/app/assets/javascripts/discourse/app/controllers/composer.js index 20df538a971..f79b5b09e2b 100644 --- a/app/assets/javascripts/discourse/app/controllers/composer.js +++ b/app/assets/javascripts/discourse/app/controllers/composer.js @@ -28,6 +28,7 @@ import { isTesting } from "discourse-common/config/environment"; import EmberObject, { computed, action } from "@ember/object"; import deprecated from "discourse-common/lib/deprecated"; import bootbox from "bootbox"; +import { cannotPostAgain } from "discourse/helpers/slow-mode"; function loadDraft(store, opts) { let promise = Promise.resolve(); @@ -646,6 +647,17 @@ export default Controller.extend({ return; } + const topic = composer.topic; + + if (topic && topic.slow_mode_seconds && topic.user_last_posted_at) { + if (cannotPostAgain(topic.slow_mode_seconds, topic.user_last_posted_at)) { + const message = I18n.t("composer.slow_mode.error"); + + bootbox.alert(message); + return; + } + } + composer.set("disableDrafts", true); // for now handle a very narrow use case diff --git a/app/assets/javascripts/discourse/app/controllers/edit-slow-mode.js b/app/assets/javascripts/discourse/app/controllers/edit-slow-mode.js index 5460fd27ae1..4cf17bf2395 100644 --- a/app/assets/javascripts/discourse/app/controllers/edit-slow-mode.js +++ b/app/assets/javascripts/discourse/app/controllers/edit-slow-mode.js @@ -74,6 +74,10 @@ export default Controller.extend(ModalFunctionality, { this.setProperties(fromSeconds(seconds)); }, + _parseValue(value) { + return parseInt(value, 10) || 0; + }, + @action setSlowModeDuration(duration) { if (duration !== "custom") { @@ -88,7 +92,13 @@ export default Controller.extend(ModalFunctionality, { @action enableSlowMode() { this.set("saveDisabled", true); - const seconds = toSeconds(this.hours, this.minutes, this.seconds); + + const seconds = toSeconds( + this._parseValue(this.hours), + this._parseValue(this.minutes), + this._parseValue(this.seconds) + ); + Topic.setSlowMode(this.model.id, seconds) .catch(popupAjaxError) .then(() => { diff --git a/app/assets/javascripts/discourse/app/helpers/slow-mode.js b/app/assets/javascripts/discourse/app/helpers/slow-mode.js index fa37871788d..c8f138805ac 100644 --- a/app/assets/javascripts/discourse/app/helpers/slow-mode.js +++ b/app/assets/javascripts/discourse/app/helpers/slow-mode.js @@ -1,14 +1,14 @@ export function fromSeconds(seconds) { let initialSeconds = seconds; - let hours = initialSeconds / 3600; + let hours = Math.trunc(initialSeconds / 3600); if (hours >= 1) { initialSeconds = initialSeconds - 3600 * hours; } else { hours = 0; } - let minutes = initialSeconds / 60; + let minutes = Math.trunc(initialSeconds / 60); if (minutes >= 1) { initialSeconds = initialSeconds - 60 * minutes; } else { @@ -19,12 +19,19 @@ export function fromSeconds(seconds) { } export function toSeconds(hours, minutes, seconds) { - const hoursAsSeconds = parseInt(hours, 10) * 60 * 60; - const minutesAsSeconds = parseInt(minutes, 10) * 60; + const hoursAsSeconds = hours * 60 * 60; + const minutesAsSeconds = minutes * 60; - return parseInt(seconds, 10) + hoursAsSeconds + minutesAsSeconds; + return seconds + hoursAsSeconds + minutesAsSeconds; } export function durationTextFromSeconds(seconds) { return moment.duration(seconds, "seconds").humanize(); } + +export function cannotPostAgain(duration, last_posted_at) { + let threshold = new Date(last_posted_at); + threshold = new Date(threshold.getTime() + duration * 1000); + + return new Date() < threshold; +} diff --git a/app/assets/javascripts/discourse/app/templates/modal/edit-slow-mode.hbs b/app/assets/javascripts/discourse/app/templates/modal/edit-slow-mode.hbs index 17d751bd030..29cd5fcb399 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/edit-slow-mode.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/edit-slow-mode.hbs @@ -15,18 +15,14 @@ {{#if showCustomSelect}}
- {{d-icon "hourglass-end"}} - {{input value=hours type="number" class="input-small" placeholder=(i18n "topic.slow_mode_update.hours")}} - {{input value=minutes type="number" class="input-small" placeholder=(i18n "topic.slow_mode_update.minutes")}} - {{input value=seconds type="number" class="input-small" placeholder=(i18n "topic.slow_mode_update.seconds")}} -
- {{/if}} + + {{input value=hours type="number" class="input-small"}} - {{#if model.slow_mode_seconds}} -
- - {{i18n "topic.slow_mode_update.current" hours=hours minutes=minutes seconds=seconds}} - + + {{input value=minutes type="number" class="input-small"}} + + + {{input value=seconds type="number" class="input-small"}}
{{/if}} {{/d-modal-body}} diff --git a/app/assets/javascripts/discourse/app/widgets/topic-admin-menu.js b/app/assets/javascripts/discourse/app/widgets/topic-admin-menu.js index 0c7e3c4fe46..6d9447e0d15 100644 --- a/app/assets/javascripts/discourse/app/widgets/topic-admin-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/topic-admin-menu.js @@ -164,14 +164,6 @@ export default createWidget("topic-admin-menu", { }); } - this.addActionButton({ - className: "topic-admin-slow-mode", - buttonClass: "popup-menu-btn", - action: "showTopicSlowModeUpdate", - icon: "hourglass-end", - label: "actions.slow_mode", - }); - if (topic.get("deleted") && details.get("can_recover")) { this.addActionButton({ className: "topic-admin-recover", @@ -278,6 +270,14 @@ export default createWidget("topic-admin-menu", { }); } + this.addActionButton({ + className: "topic-admin-slow-mode", + buttonClass: "popup-menu-btn", + action: "showTopicSlowModeUpdate", + icon: "hourglass-end", + label: "actions.slow_mode", + }); + if (this.currentUser.get("staff")) { this.addActionButton({ icon: "list", diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index f2c51704031..17a02f480bd 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -822,6 +822,6 @@ } .input-small { - width: 15%; + width: 10%; } } diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 96373937460..8fac38b924c 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1925,6 +1925,7 @@ en: slow_mode: title: "This topic is in slow mode." body: "After submitting a post, you'll need to wait %{duration} before being able to post again." + error: "You recently posted on this topic, which is in slow mode. Please wait so other users can have their chance to participate." admin_options_title: "Optional staff settings for this topic" @@ -2320,19 +2321,18 @@ en: title: "Slow Mode" select: "Duration:" description: "Users will have to wait to be able to post again." - current: "Current duration is %{hours} hours, %{minutes} minutes, and %{seconds} seconds." save: "Save" remove: "Disable" - hours: "Hours" - minutes: "Minutes" - seconds: "Seconds" + hours: "Hours:" + minutes: "Minutes:" + seconds: "Seconds:" durations: 15_minutes: "15 Minutes" 1_hour: "1 Hour" 4_hours: "4 Hours" 1_day: "1 Day" 1_week: "1 Week" - custom: "Pick Duration" + custom: "Custom Duration" slow_mode_notice: duration: "You need to wait %{duration} between posts in this topic" topic_status_update: diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 786519aa456..af99227a883 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -340,7 +340,7 @@ en: removed_direct_reply_full_quotes: "Automatically removed quote of whole previous post." secure_upload_not_allowed_in_public_topic: "Sorry, the following secure upload(s) cannot be used in a public topic: %{upload_filenames}." create_pm_on_existing_topic: "Sorry, you can't create a PM on an existing topic." - slow_mode_enabled: "You recently posted on this topic, which is in slow mode. Please wait so other users can have their chance to participate." + slow_mode_enabled: "This topic is in slow mode." just_posted_that: "is too similar to what you recently posted" invalid_characters: "contains invalid characters"