From 4af77f1e3854c564c8404e08b83e786fd25a7bfe Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Fri, 5 Feb 2021 10:12:56 +1000 Subject: [PATCH] FEATURE: Allow durations < 1 hour and < 1 day for topic timers where duration is specified (auto delete replies, close based on last post) (#11961) This PR allows entering a float value for topic timers e.g. 0.5 for 30 minutes when entering hours, 0.5 for 12 hours when entering days. This is achieved by adding a new column to store the duration of a topic timer in minutes instead of the ambiguous both hours and days that it could be before. This PR has ommitted the post migration to delete the duration column in topic timers; it will be done in a subsequent PR to ensure that no data is lost if the UPDATE query to set duration_mintues fails. I have to keep the old keyword of duration in set_or_create_topic_timer for backwards compat, will remove at a later date after plugins are updated. --- .../app/components/edit-topic-timer-form.js | 40 ++++++++++++----- .../app/components/topic-timer-info.js | 8 +--- .../app/controllers/edit-topic-timer.js | 22 ++++------ .../discourse/app/controllers/topic.js | 8 +--- .../discourse/app/models/topic-timer.js | 8 ++-- .../components/edit-topic-timer-form.hbs | 4 +- .../app/templates/modal/edit-topic-timer.hbs | 1 - .../discourse/app/templates/topic.hbs | 2 +- .../tests/acceptance/topic-edit-timer-test.js | 2 +- app/controllers/topics_controller.rb | 5 ++- app/jobs/regular/delete_replies.rb | 4 +- app/models/topic.rb | 43 +++++++++++++++---- app/models/topic_timer.rb | 6 ++- app/serializers/topic_timer_serializer.rb | 2 +- app/services/topic_status_updater.rb | 4 +- ...628_add_duration_minutes_to_topic_timer.rb | 16 +++++++ lib/post_creator.rb | 4 +- spec/components/post_creator_spec.rb | 2 +- spec/jobs/delete_replies_spec.rb | 2 +- spec/models/topic_spec.rb | 2 +- spec/requests/topics_controller_spec.rb | 10 ++--- spec/services/topic_status_updater_spec.rb | 2 +- 22 files changed, 125 insertions(+), 72 deletions(-) create mode 100644 db/migrate/20210203031628_add_duration_minutes_to_topic_timer.rb diff --git a/app/assets/javascripts/discourse/app/components/edit-topic-timer-form.js b/app/assets/javascripts/discourse/app/components/edit-topic-timer-form.js index 514defb1132..cbc8f744a40 100644 --- a/app/assets/javascripts/discourse/app/components/edit-topic-timer-form.js +++ b/app/assets/javascripts/discourse/app/components/edit-topic-timer-form.js @@ -7,7 +7,7 @@ import { PUBLISH_TO_CATEGORY_STATUS_TYPE, } from "discourse/controllers/edit-topic-timer"; import { FORMAT } from "select-kit/components/future-date-input-selector"; -import discourseComputed from "discourse-common/utils/decorators"; +import discourseComputed, { on } from "discourse-common/utils/decorators"; import { equal, or, readOnly } from "@ember/object/computed"; import I18n from "I18n"; import { action } from "@ember/object"; @@ -26,7 +26,19 @@ export default Component.extend({ showTimeOnly: or("autoOpen", "autoDelete", "autoBump"), showFutureDateInput: or("showTimeOnly", "publishToCategory", "autoClose"), useDuration: or("isBasedOnLastPost", "autoDeleteReplies"), - originalTopicTimerTime: null, + duration: null, + + @on("init") + preloadDuration() { + if (!this.useDuration || !this.topicTimer.duration_minutes) { + return; + } + if (this.durationType === "days") { + this.set("duration", this.topicTimer.duration_minutes / 60 / 24); + } else { + this.set("duration", this.topicTimer.duration_minutes / 60); + } + }, @discourseComputed("autoDeleteReplies") durationType(autoDeleteReplies) { @@ -93,13 +105,12 @@ export default Component.extend({ @discourseComputed( "topicTimer.updateTime", - "topicTimer.duration", - "useDuration", - "durationType" + "topicTimer.duration_minutes", + "useDuration" ) - executeAt(updateTime, duration, useDuration, durationType) { + executeAt(updateTime, duration, useDuration) { if (useDuration) { - return moment().add(parseFloat(duration), durationType).format(FORMAT); + return moment().add(parseFloat(duration), "minutes").format(FORMAT); } else { return updateTime; } @@ -107,13 +118,13 @@ export default Component.extend({ @discourseComputed( "isBasedOnLastPost", - "topicTimer.duration", + "topicTimer.duration_minutes", "topic.last_posted_at" ) willCloseImmediately(isBasedOnLastPost, duration, lastPostedAt) { if (isBasedOnLastPost && duration) { let closeDate = moment(lastPostedAt); - closeDate = closeDate.add(duration, "hours"); + closeDate = closeDate.add(duration, "minutes"); return closeDate < moment(); } }, @@ -140,7 +151,7 @@ export default Component.extend({ "willCloseImmediately", "topicTimer.category_id", "useDuration", - "topicTimer.duration" + "topicTimer.duration_minutes" ) showTopicStatusInfo( statusType, @@ -178,4 +189,13 @@ export default Component.extend({ }); this.onChangeInput(type, time); }, + + @action + durationChanged(newDuration) { + if (this.durationType === "days") { + this.set("topicTimer.duration_minutes", newDuration * 60 * 24); + } else { + this.set("topicTimer.duration_minutes", newDuration * 60); + } + }, }); diff --git a/app/assets/javascripts/discourse/app/components/topic-timer-info.js b/app/assets/javascripts/discourse/app/components/topic-timer-info.js index f8d315bf2ac..a0c5809a993 100644 --- a/app/assets/javascripts/discourse/app/components/topic-timer-info.js +++ b/app/assets/javascripts/discourse/app/components/topic-timer-info.js @@ -63,15 +63,11 @@ export default Component.extend({ } else if (minutesLeft > 2) { rerenderDelay = 60000; } - let durationHours = parseInt(this.duration, 0) || 0; - - if (isDeleteRepliesType) { - durationHours *= 24; - } + let durationMinutes = parseInt(this.durationMinutes, 0) || 0; let options = { timeLeft: duration.humanize(true), - duration: moment.duration(durationHours, "hours").humanize(), + duration: moment.duration(durationMinutes, "minutes").humanize(), }; const categoryId = this.categoryId; 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 1f2b86789c4..3f154f0b2e6 100644 --- a/app/assets/javascripts/discourse/app/controllers/edit-topic-timer.js +++ b/app/assets/javascripts/discourse/app/controllers/edit-topic-timer.js @@ -60,24 +60,24 @@ export default Controller.extend(ModalFunctionality, { topicTimer: alias("model.topic_timer"), - _setTimer(time, duration, statusType, basedOnLastPost, categoryId) { + _setTimer(time, durationMinutes, statusType, basedOnLastPost, categoryId) { this.set("loading", true); - TopicTimer.updateStatus( + TopicTimer.update( this.get("model.id"), time, basedOnLastPost, statusType, categoryId, - duration + durationMinutes ) .then((result) => { - if (time || duration) { + if (time || durationMinutes) { this.send("closeModal"); setProperties(this.topicTimer, { execute_at: result.execute_at, - duration: result.duration, + duration_minutes: result.duration_minutes, category_id: result.category_id, }); @@ -131,14 +131,10 @@ export default Controller.extend(ModalFunctionality, { this.set("topicTimer.updateTime", time); }, - onChangeDuration(value) { - this.set("topicTimer.duration", value); - }, - saveTimer() { if ( !this.get("topicTimer.updateTime") && - !this.get("topicTimer.duration") + !this.get("topicTimer.duration_minutes") ) { this.flash( I18n.t("topic.topic_status_update.time_frame_required"), @@ -148,9 +144,9 @@ export default Controller.extend(ModalFunctionality, { } if ( - this.get("topicTimer.duration") && + this.get("topicTimer.duration_minutes") && !this.get("topicTimer.updateTime") && - this.get("topicTimer.duration") < 1 + this.get("topicTimer.duration_minutes") <= 0 ) { this.flash( I18n.t("topic.topic_status_update.min_duration"), @@ -161,7 +157,7 @@ export default Controller.extend(ModalFunctionality, { this._setTimer( this.get("topicTimer.updateTime"), - this.get("topicTimer.duration"), + this.get("topicTimer.duration_minutes"), this.get("topicTimer.status_type"), this.get("topicTimer.based_on_last_post"), this.get("topicTimer.category_id") diff --git a/app/assets/javascripts/discourse/app/controllers/topic.js b/app/assets/javascripts/discourse/app/controllers/topic.js index e071c22bddd..94431e093de 100644 --- a/app/assets/javascripts/discourse/app/controllers/topic.js +++ b/app/assets/javascripts/discourse/app/controllers/topic.js @@ -1099,13 +1099,7 @@ export default Controller.extend(bufferedProperty("model"), { }, removeTopicTimer(statusType, topicTimer) { - TopicTimer.updateStatus( - this.get("model.id"), - null, - null, - statusType, - null - ) + TopicTimer.update(this.get("model.id"), null, null, statusType, null) .then(() => this.set(`model.${topicTimer}`, EmberObject.create({}))) .catch((error) => popupAjaxError(error)); }, diff --git a/app/assets/javascripts/discourse/app/models/topic-timer.js b/app/assets/javascripts/discourse/app/models/topic-timer.js index a0685521aa9..7ba6a8bab92 100644 --- a/app/assets/javascripts/discourse/app/models/topic-timer.js +++ b/app/assets/javascripts/discourse/app/models/topic-timer.js @@ -4,13 +4,13 @@ import { ajax } from "discourse/lib/ajax"; const TopicTimer = RestModel.extend({}); TopicTimer.reopenClass({ - updateStatus( + update( topicId, time, basedOnLastPost, statusType, categoryId, - duration + durationMinutes ) { let data = { time, @@ -23,8 +23,8 @@ TopicTimer.reopenClass({ if (categoryId) { data.category_id = categoryId; } - if (duration) { - data.duration = duration; + if (durationMinutes) { + data.duration_minutes = durationMinutes; } return ajax({ diff --git a/app/assets/javascripts/discourse/app/templates/components/edit-topic-timer-form.hbs b/app/assets/javascripts/discourse/app/templates/components/edit-topic-timer-form.hbs index 8c16a8aab62..e3f678f9688 100644 --- a/app/assets/javascripts/discourse/app/templates/components/edit-topic-timer-form.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/edit-topic-timer-form.hbs @@ -24,7 +24,7 @@ {{#if useDuration}}
- {{text-field id="topic_timer_duration" class="topic-timer-duration" type="number" value=topicTimer.duration min="1"}} + {{text-field id="topic_timer_duration" class="topic-timer-duration" type="number" value=duration min="0.1" step="0.1" onChange=durationChanged}}
{{/if}} {{#if willCloseImmediately}} @@ -39,7 +39,7 @@ statusType=statusType executeAt=executeAt basedOnLastPost=topicTimer.based_on_last_post - duration=topicTimer.duration + durationMinutes=topicTimer.duration_minutes categoryId=topicTimer.category_id }} diff --git a/app/assets/javascripts/discourse/app/templates/modal/edit-topic-timer.hbs b/app/assets/javascripts/discourse/app/templates/modal/edit-topic-timer.hbs index aae0a18f8bc..60386d1d9cb 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/edit-topic-timer.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/edit-topic-timer.hbs @@ -5,7 +5,6 @@ timerTypes=publicTimerTypes onChangeStatusType=(action "onChangeStatusType") onChangeInput=(action "onChangeInput") - onChangeDuration=(action "onChangeDuration") }}