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"