mirror of
https://github.com/discourse/discourse.git
synced 2025-09-06 10:50:21 +08:00
UX: Allow users to remove a remind me topic timer.
This commit is contained in:
parent
f5a2ed99b0
commit
b0557c6692
12 changed files with 213 additions and 108 deletions
|
@ -0,0 +1,50 @@
|
||||||
|
import { default as computed, observes, on } from "ember-addons/ember-computed-decorators";
|
||||||
|
|
||||||
|
import {
|
||||||
|
PUBLISH_TO_CATEGORY_STATUS_TYPE,
|
||||||
|
OPEN_STATUS_TYPE,
|
||||||
|
DELETE_STATUS_TYPE,
|
||||||
|
REMINDER_TYPE,
|
||||||
|
CLOSE_STATUS_TYPE
|
||||||
|
} from 'discourse/controllers/edit-topic-timer';
|
||||||
|
|
||||||
|
export default Ember.Component.extend({
|
||||||
|
selection: Ember.computed.alias('topicTimer.status_type'),
|
||||||
|
autoOpen: Ember.computed.equal('selection', OPEN_STATUS_TYPE),
|
||||||
|
autoClose: Ember.computed.equal('selection', CLOSE_STATUS_TYPE),
|
||||||
|
autoDelete: Ember.computed.equal('selection', DELETE_STATUS_TYPE),
|
||||||
|
publishToCategory: Ember.computed.equal('selection', PUBLISH_TO_CATEGORY_STATUS_TYPE),
|
||||||
|
reminder: Ember.computed.equal('selection', REMINDER_TYPE),
|
||||||
|
showTimeOnly: Ember.computed.or('autoOpen', 'autoDelete', 'reminder'),
|
||||||
|
|
||||||
|
@computed('topicTimer.updateTime', 'loading', 'publishToCategory', 'topicTimer.category_id')
|
||||||
|
saveDisabled(updateTime, loading, publishToCategory, topicTimerCategoryId) {
|
||||||
|
return Ember.isEmpty(updateTime) ||
|
||||||
|
loading ||
|
||||||
|
(publishToCategory && !topicTimerCategoryId);
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed("topic.visible")
|
||||||
|
excludeCategoryId(visible) {
|
||||||
|
if (visible) return this.get('topic.category_id');
|
||||||
|
},
|
||||||
|
|
||||||
|
@on('init')
|
||||||
|
@observes("topicTimer", "topicTimer.execute_at", "topicTimer.duration")
|
||||||
|
_setUpdateTime() {
|
||||||
|
let time = null;
|
||||||
|
const executeAt = this.get('topicTimer.execute_at');
|
||||||
|
|
||||||
|
if (executeAt && this.get("topicTimer.based_on_last_post")) {
|
||||||
|
time = this.get("topicTimer.duration");
|
||||||
|
} else if (executeAt) {
|
||||||
|
const closeTime = moment(executeAt);
|
||||||
|
|
||||||
|
if (closeTime > moment()) {
|
||||||
|
time = closeTime.format("YYYY-MM-DD HH:mm");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set("topicTimer.updateTime", time);
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,67 +1,51 @@
|
||||||
import { default as computed, observes } from "ember-addons/ember-computed-decorators";
|
import { default as computed } from "ember-addons/ember-computed-decorators";
|
||||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||||
import TopicTimer from 'discourse/models/topic-timer';
|
import TopicTimer from 'discourse/models/topic-timer';
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
|
|
||||||
export const CLOSE_STATUS_TYPE = 'close';
|
export const CLOSE_STATUS_TYPE = 'close';
|
||||||
const OPEN_STATUS_TYPE = 'open';
|
export const OPEN_STATUS_TYPE = 'open';
|
||||||
export const PUBLISH_TO_CATEGORY_STATUS_TYPE = 'publish_to_category';
|
export const PUBLISH_TO_CATEGORY_STATUS_TYPE = 'publish_to_category';
|
||||||
const DELETE_STATUS_TYPE = 'delete';
|
export const DELETE_STATUS_TYPE = 'delete';
|
||||||
const REMINDER_TYPE = 'reminder';
|
export const REMINDER_TYPE = 'reminder';
|
||||||
|
|
||||||
export default Ember.Controller.extend(ModalFunctionality, {
|
export default Ember.Controller.extend(ModalFunctionality, {
|
||||||
loading: false,
|
loading: false,
|
||||||
updateTime: null,
|
isPublic: "true",
|
||||||
topicTimer: Ember.computed.alias("model.topic_timer"),
|
|
||||||
selection: Ember.computed.alias('model.topic_timer.status_type'),
|
|
||||||
autoOpen: Ember.computed.equal('selection', OPEN_STATUS_TYPE),
|
|
||||||
autoClose: Ember.computed.equal('selection', CLOSE_STATUS_TYPE),
|
|
||||||
autoDelete: Ember.computed.equal('selection', DELETE_STATUS_TYPE),
|
|
||||||
publishToCategory: Ember.computed.equal('selection', PUBLISH_TO_CATEGORY_STATUS_TYPE),
|
|
||||||
reminder: Ember.computed.equal('selection', REMINDER_TYPE),
|
|
||||||
|
|
||||||
showTimeOnly: Ember.computed.or('autoOpen', 'autoDelete', 'reminder'),
|
|
||||||
|
|
||||||
@computed("model.closed")
|
@computed("model.closed")
|
||||||
timerTypes(closed) {
|
publicTimerTypes(closed) {
|
||||||
return [
|
return [
|
||||||
{ id: CLOSE_STATUS_TYPE, name: I18n.t(closed ? 'topic.temp_open.title' : 'topic.auto_close.title'), },
|
{ id: CLOSE_STATUS_TYPE, name: I18n.t(closed ? 'topic.temp_open.title' : 'topic.auto_close.title'), },
|
||||||
{ id: OPEN_STATUS_TYPE, name: I18n.t(closed ? 'topic.auto_reopen.title' : 'topic.temp_close.title') },
|
{ id: OPEN_STATUS_TYPE, name: I18n.t(closed ? 'topic.auto_reopen.title' : 'topic.temp_close.title') },
|
||||||
{ id: PUBLISH_TO_CATEGORY_STATUS_TYPE, name: I18n.t('topic.publish_to_category.title') },
|
{ id: PUBLISH_TO_CATEGORY_STATUS_TYPE, name: I18n.t('topic.publish_to_category.title') },
|
||||||
{ id: DELETE_STATUS_TYPE, name: I18n.t('topic.auto_delete.title') },
|
{ id: DELETE_STATUS_TYPE, name: I18n.t('topic.auto_delete.title') }
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
@computed()
|
||||||
|
privateTimerTypes() {
|
||||||
|
return [
|
||||||
{ id: REMINDER_TYPE, name: I18n.t('topic.reminder.title') }
|
{ id: REMINDER_TYPE, name: I18n.t('topic.reminder.title') }
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed('updateTime', 'loading', 'publishToCategory', 'topicTimer.category_id')
|
@computed("isPublic", 'publicTimerTypes', 'privateTimerTypes')
|
||||||
saveDisabled(updateTime, loading, publishToCategory, topicTimerCategoryId) {
|
selections(isPublic, publicTimerTypes, privateTimerTypes) {
|
||||||
return Ember.isEmpty(updateTime) ||
|
if (isPublic === 'true') {
|
||||||
loading ||
|
return publicTimerTypes;
|
||||||
(publishToCategory && !topicTimerCategoryId);
|
} else {
|
||||||
},
|
return privateTimerTypes;
|
||||||
|
|
||||||
@computed("model.visible")
|
|
||||||
excludeCategoryId(visible) {
|
|
||||||
if (visible) return this.get('model.category_id');
|
|
||||||
},
|
|
||||||
|
|
||||||
@observes("topicTimer.execute_at", "topicTimer.duration")
|
|
||||||
_setUpdateTime() {
|
|
||||||
if (!this.get('topicTimer.execute_at')) return;
|
|
||||||
|
|
||||||
let time = null;
|
|
||||||
|
|
||||||
if (this.get("topicTimer.based_on_last_post")) {
|
|
||||||
time = this.get("topicTimer.duration");
|
|
||||||
} else if (this.get("topicTimer.execute_at")) {
|
|
||||||
const closeTime = moment(this.get('topicTimer.execute_at'));
|
|
||||||
|
|
||||||
if (closeTime > moment()) {
|
|
||||||
time = closeTime.format("YYYY-MM-DD HH:mm");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
this.set("updateTime", time);
|
@computed('isPublic', 'model.topic_timer', 'model.private_topic_timer')
|
||||||
|
topicTimer(isPublic, publicTopicTimer, privateTopicTimer) {
|
||||||
|
if (isPublic === 'true') {
|
||||||
|
return publicTopicTimer;
|
||||||
|
} else {
|
||||||
|
return privateTopicTimer;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_setTimer(time, statusType) {
|
_setTimer(time, statusType) {
|
||||||
|
@ -85,10 +69,11 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
||||||
|
|
||||||
this.set('model.closed', result.closed);
|
this.set('model.closed', result.closed);
|
||||||
} else {
|
} else {
|
||||||
|
const topicTimer = this.get('isPublic') === 'true' ? 'topic_timer' : 'private_topic_timer';
|
||||||
|
this.set(`model.${topicTimer}`, Ember.Object.create({}));
|
||||||
|
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
topicTimer: Ember.Object.create({}),
|
|
||||||
selection: null,
|
selection: null,
|
||||||
updateTime: null
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
@ -98,11 +83,11 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
saveTimer() {
|
saveTimer() {
|
||||||
this._setTimer(this.get("updateTime"), this.get('selection'));
|
this._setTimer(this.get("topicTimer.updateTime"), this.get('topicTimer.status_type'));
|
||||||
},
|
},
|
||||||
|
|
||||||
removeTimer() {
|
removeTimer() {
|
||||||
this._setTimer(null, this.get('selection'));
|
this._setTimer(null, this.get('topicTimer.status_type'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -54,6 +54,7 @@ const TopicRoute = Discourse.Route.extend({
|
||||||
showTopicStatusUpdate() {
|
showTopicStatusUpdate() {
|
||||||
const model = this.modelFor('topic');
|
const model = this.modelFor('topic');
|
||||||
model.set('topic_timer', Ember.Object.create(model.get('topic_timer')));
|
model.set('topic_timer', Ember.Object.create(model.get('topic_timer')));
|
||||||
|
model.set('private_topic_timer', Ember.Object.create(model.get('private_topic_timer')));
|
||||||
showModal('edit-topic-timer', { model });
|
showModal('edit-topic-timer', { model });
|
||||||
this.controllerFor('modal').set('modalClass', 'edit-topic-timer-modal');
|
this.controllerFor('modal').set('modalClass', 'edit-topic-timer-modal');
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<form>
|
||||||
|
<div class="control-group">
|
||||||
|
{{combo-box content=timerTypes value=selection width="50%"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{{#if showTimeOnly}}
|
||||||
|
{{future-date-input
|
||||||
|
input=topicTimer.updateTime
|
||||||
|
statusType=selection
|
||||||
|
includeWeekend=true
|
||||||
|
basedOnLastPost=false}}
|
||||||
|
{{else if publishToCategory}}
|
||||||
|
<div class="control-group">
|
||||||
|
<label>{{i18n 'topic.topic_status_update.publish_to'}}</label>
|
||||||
|
{{category-select-box
|
||||||
|
value=topicTimer.category_id
|
||||||
|
excludeCategoryId=excludeCategoryId}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{future-date-input
|
||||||
|
input=topicTimer.updateTime
|
||||||
|
statusType=selection
|
||||||
|
includeWeekend=true
|
||||||
|
categoryId=topicTimer.category_id
|
||||||
|
basedOnLastPost=false}}
|
||||||
|
{{else if autoClose}}
|
||||||
|
{{future-date-input
|
||||||
|
input=topicTimer.updateTime
|
||||||
|
statusType=selection
|
||||||
|
includeWeekend=true
|
||||||
|
basedOnLastPost=topicTimer.based_on_last_post
|
||||||
|
lastPostedAt=model.last_posted_at}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</form>
|
|
@ -1,54 +1,35 @@
|
||||||
<form>
|
{{#d-modal-body title="topic.topic_status_update.title" autoFocus="false"}}
|
||||||
{{#d-modal-body title="topic.topic_status_update.title" autoFocus="false"}}
|
<div class="radios">
|
||||||
<div class="control-group">
|
<label for="public-topic-timer">
|
||||||
{{combo-box content=timerTypes value=selection width="50%"}}
|
{{radio-button id='public-topic-timer' name="topic-timer" value="true" selection=isPublic}}
|
||||||
</div>
|
<b>{{i18n 'topic.topic_status_update.public_timer_types'}}</b>
|
||||||
|
</label>
|
||||||
|
|
||||||
<div>
|
<label for="private-topic-timer">
|
||||||
{{#if showTimeOnly}}
|
{{radio-button id='private-topic-timer' name="topic-timer" value="false" selection=isPublic}}
|
||||||
{{future-date-input
|
<b>{{i18n 'topic.topic_status_update.private_timer_types'}}</b>
|
||||||
input=updateTime
|
</label>
|
||||||
statusType=selection
|
|
||||||
includeWeekend=true
|
|
||||||
basedOnLastPost=false}}
|
|
||||||
{{else if publishToCategory}}
|
|
||||||
<div class="control-group">
|
|
||||||
<label>{{i18n 'topic.topic_status_update.publish_to'}}</label>
|
|
||||||
{{category-select-box
|
|
||||||
value=topicTimer.category_id
|
|
||||||
excludeCategoryId=excludeCategoryId}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{future-date-input
|
|
||||||
input=updateTime
|
|
||||||
statusType=selection
|
|
||||||
includeWeekend=true
|
|
||||||
categoryId=topicTimer.category_id
|
|
||||||
basedOnLastPost=false}}
|
|
||||||
{{else if autoClose}}
|
|
||||||
{{future-date-input
|
|
||||||
input=updateTime
|
|
||||||
statusType=selection
|
|
||||||
includeWeekend=true
|
|
||||||
basedOnLastPost=topicTimer.based_on_last_post
|
|
||||||
lastPostedAt=model.last_posted_at}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
{{/d-modal-body}}
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
{{d-button class="btn-primary"
|
|
||||||
disabled=saveDisabled
|
|
||||||
label="topic.topic_status_update.save"
|
|
||||||
action="saveTimer"}}
|
|
||||||
|
|
||||||
{{d-modal-cancel close=(action "closeModal")}}
|
|
||||||
{{conditional-loading-spinner size="small" condition=loading}}
|
|
||||||
|
|
||||||
{{#if topicTimer.execute_at}}
|
|
||||||
{{d-button class="pull-right btn-danger"
|
|
||||||
action="removeTimer"
|
|
||||||
label='topic.topic_status_update.remove'}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
|
{{edit-topic-timer-form
|
||||||
|
topic=model
|
||||||
|
topicTimer=topicTimer
|
||||||
|
timerTypes=selections
|
||||||
|
updateTime=updateTime
|
||||||
|
closeModal="closeModal"}}
|
||||||
|
{{/d-modal-body}}
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
{{d-button class="btn-primary"
|
||||||
|
disabled=saveDisabled
|
||||||
|
label="topic.topic_status_update.save"
|
||||||
|
action="saveTimer"}}
|
||||||
|
|
||||||
|
{{conditional-loading-spinner size="small" condition=loading}}
|
||||||
|
|
||||||
|
{{#if topicTimer.execute_at}}
|
||||||
|
{{d-button class="pull-right btn-danger"
|
||||||
|
action="removeTimer"
|
||||||
|
label='topic.topic_status_update.remove'}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
|
@ -199,12 +199,21 @@
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{topic-timer-info
|
{{#if model.private_topic_timer.execute_at}}
|
||||||
statusType=model.topic_timer.status_type
|
{{topic-timer-info
|
||||||
executeAt=model.topic_timer.execute_at
|
statusType=model.private_topic_timer.status_type
|
||||||
basedOnLastPost=model.topic_timer.based_on_last_post
|
executeAt=model.private_topic_timer.execute_at
|
||||||
duration=model.topic_timer.duration
|
duration=model.private_topic_timer.duration}}
|
||||||
categoryId=model.topic_timer.category_id}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if model.topic_timer.execute_at}}
|
||||||
|
{{topic-timer-info
|
||||||
|
statusType=model.topic_timer.status_type
|
||||||
|
executeAt=model.topic_timer.execute_at
|
||||||
|
basedOnLastPost=model.topic_timer.based_on_last_post
|
||||||
|
duration=model.topic_timer.duration
|
||||||
|
categoryId=model.topic_timer.category_id}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{#if session.showSignupCta}}
|
{{#if session.showSignupCta}}
|
||||||
{{! replace "Log In to Reply" with the infobox }}
|
{{! replace "Log In to Reply" with the infobox }}
|
||||||
|
|
|
@ -8,8 +8,18 @@
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.radios {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
|
vertical-align: middle;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
padding-right: 5px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn.pull-right {
|
.btn.pull-right {
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
|
|
||||||
.topic-status-info {
|
.topic-status-info {
|
||||||
border-top: 1px solid $primary-low;
|
border-top: 1px solid $primary-low;
|
||||||
padding-top: 10px;
|
padding: 10px 0px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
max-width: 757px;
|
max-width: 757px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -411,6 +411,7 @@ class Topic < ActiveRecord::Base
|
||||||
def reload(options = nil)
|
def reload(options = nil)
|
||||||
@post_numbers = nil
|
@post_numbers = nil
|
||||||
@public_topic_timer = nil
|
@public_topic_timer = nil
|
||||||
|
@private_topic_timer = nil
|
||||||
super(options)
|
super(options)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1002,6 +1003,10 @@ SQL
|
||||||
@public_topic_timer ||= topic_timers.find_by(deleted_at: nil, public_type: true)
|
@public_topic_timer ||= topic_timers.find_by(deleted_at: nil, public_type: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def private_topic_timer(user)
|
||||||
|
@private_topic_Timer ||= topic_timers.find_by(deleted_at: nil, public_type: false, user_id: user.id)
|
||||||
|
end
|
||||||
|
|
||||||
def delete_topic_timer(status_type, by_user: Discourse.system_user)
|
def delete_topic_timer(status_type, by_user: Discourse.system_user)
|
||||||
options = { status_type: status_type }
|
options = { status_type: status_type }
|
||||||
options.merge!(user: by_user) unless TopicTimer.public_types[status_type]
|
options.merge!(user: by_user) unless TopicTimer.public_types[status_type]
|
||||||
|
|
|
@ -61,6 +61,7 @@ class TopicViewSerializer < ApplicationSerializer
|
||||||
:message_archived,
|
:message_archived,
|
||||||
:tags,
|
:tags,
|
||||||
:topic_timer,
|
:topic_timer,
|
||||||
|
:private_topic_timer,
|
||||||
:unicode_title,
|
:unicode_title,
|
||||||
:message_bus_last_id,
|
:message_bus_last_id,
|
||||||
:participant_count
|
:participant_count
|
||||||
|
@ -242,6 +243,15 @@ class TopicViewSerializer < ApplicationSerializer
|
||||||
TopicTimerSerializer.new(object.topic.public_topic_timer, root: false)
|
TopicTimerSerializer.new(object.topic.public_topic_timer, root: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def include_private_topic_timer?
|
||||||
|
scope.user
|
||||||
|
end
|
||||||
|
|
||||||
|
def private_topic_timer
|
||||||
|
timer = object.topic.private_topic_timer(scope.user)
|
||||||
|
TopicTimerSerializer.new(timer, root: false)
|
||||||
|
end
|
||||||
|
|
||||||
def tags
|
def tags
|
||||||
object.topic.tags.map(&:name)
|
object.topic.tags.map(&:name)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1555,12 +1555,14 @@ en:
|
||||||
deleted: "The topic has been deleted"
|
deleted: "The topic has been deleted"
|
||||||
|
|
||||||
topic_status_update:
|
topic_status_update:
|
||||||
title: "Set Topic Timer"
|
title: "Topic Timer"
|
||||||
save: "Set Timer"
|
save: "Set Timer"
|
||||||
num_of_hours: "Number of hours:"
|
num_of_hours: "Number of hours:"
|
||||||
remove: "Remove Timer"
|
remove: "Remove Timer"
|
||||||
publish_to: "Publish To:"
|
publish_to: "Publish To:"
|
||||||
when: "When:"
|
when: "When:"
|
||||||
|
public_timer_types: Topic Timers
|
||||||
|
private_timer_types: User Topic Timers
|
||||||
auto_update_input:
|
auto_update_input:
|
||||||
none: ""
|
none: ""
|
||||||
later_today: "Later today"
|
later_today: "Later today"
|
||||||
|
|
|
@ -1167,6 +1167,22 @@ describe Topic do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#private_topic_timer' do
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
let(:topic_timer) do
|
||||||
|
Fabricate(:topic_timer,
|
||||||
|
public_type: false,
|
||||||
|
user: user,
|
||||||
|
status_type: TopicTimer.private_types[:reminder]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return the right record' do
|
||||||
|
expect(topic_timer.topic.private_topic_timer(user)).to eq(topic_timer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#set_or_create_timer' do
|
describe '#set_or_create_timer' do
|
||||||
let(:topic) { Fabricate.build(:topic) }
|
let(:topic) { Fabricate.build(:topic) }
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue