Skip to content
This repository has been archived by the owner on May 27, 2022. It is now read-only.

Commit

Permalink
DEV: adds support for bannered until (discourse#13417)
Browse files Browse the repository at this point in the history
ATM it only implements server side of it, as my need is for automation purposes. However it should probably be added in the UI too as it's unexpected to have pinned_until and no bannered_until.
  • Loading branch information
jjaffeux authored Jun 24, 2021
1 parent 0e4b8c5 commit 2654a66
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 9 deletions.
2 changes: 2 additions & 0 deletions app/controllers/topics_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,8 @@ def status
guardian.ensure_can_moderate!(@topic)
end

params[:until] === '' ? params[:until] = nil : params[:until]

@topic.update_status(status, enabled, current_user, until: params[:until])

render json: success_json.merge!(
Expand Down
18 changes: 18 additions & 0 deletions app/jobs/regular/remove_banner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

module Jobs

class RemoveBanner < ::Jobs::Base

def execute(args)
topic_id = args[:topic_id]

return unless topic_id.present?

topic = Topic.find_by(id: topic_id)
topic.remove_banner!(Discourse.system_user) if topic.present?
end

end

end
2 changes: 1 addition & 1 deletion app/jobs/regular/unpin_topic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class UnpinTopic < ::Jobs::Base
def execute(args)
topic_id = args[:topic_id]

raise Discourse::InvalidParameters.new(:topic_id) unless topic_id.present?
return unless topic_id.present?

topic = Topic.find_by(id: topic_id)
topic.update_pinned(false) if topic.present?
Expand Down
35 changes: 27 additions & 8 deletions app/models/topic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1093,7 +1093,15 @@ def participants_summary(options = {})
@participants_summary ||= TopicParticipantsSummary.new(self, options).summary
end

def make_banner!(user)
def make_banner!(user, bannered_until = nil)
if bannered_until
bannered_until = begin
Time.parse(bannered_until)
rescue ArgumentError
raise Discourse::InvalidParameters.new(:bannered_until)
end
end

# only one banner at the same time
previous_banner = Topic.where(archetype: Archetype.banner).first
previous_banner.remove_banner!(user) if previous_banner.present?
Expand All @@ -1102,18 +1110,25 @@ def make_banner!(user)
.update_all(dismissed_banner_key: nil)

self.archetype = Archetype.banner
self.bannered_until = bannered_until
self.add_small_action(user, "banner.enabled")
self.save

MessageBus.publish('/site/banner', banner)

Jobs.cancel_scheduled_job(:remove_banner, topic_id: self.id)
Jobs.enqueue_at(bannered_until, :remove_banner, topic_id: self.id) if bannered_until
end

def remove_banner!(user)
self.archetype = Archetype.default
self.bannered_until = nil
self.add_small_action(user, "banner.disabled")
self.save

MessageBus.publish('/site/banner', nil)

Jobs.cancel_scheduled_job(:remove_banner, topic_id: self.id)
end

def banner
Expand Down Expand Up @@ -1199,12 +1214,13 @@ def re_pin_for(user)
TopicUser.change(user.id, id, cleared_pinned_at: nil)
end

def update_pinned(status, global = false, pinned_until = "")
pinned_until ||= ''

pinned_until = begin
Time.parse(pinned_until)
rescue ArgumentError
def update_pinned(status, global = false, pinned_until = nil)
if pinned_until
pinned_until = begin
Time.parse(pinned_until)
rescue ArgumentError
raise Discourse::InvalidParameters.new(:pinned_until)
end
end

update_columns(
Expand Down Expand Up @@ -1233,7 +1249,10 @@ def muted?(user)

def self.ensure_consistency!
# unpin topics that might have been missed
Topic.where("pinned_until < now()").update_all(pinned_at: nil, pinned_globally: false, pinned_until: nil)
Topic.where('pinned_until < ?', Time.now).update_all(pinned_at: nil, pinned_globally: false, pinned_until: nil)
Topic.where('bannered_until < ?', Time.now).find_each do |topic|
topic.remove_banner!(Discourse.system_user)
end
end

def inherit_auto_close_from_category(timer_type: :close)
Expand Down
9 changes: 9 additions & 0 deletions db/migrate/20210621103509_add_bannered_until.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class AddBanneredUntil < ActiveRecord::Migration[6.1]
def change
add_column :topics, :bannered_until, :datetime, null: true

add_index :topics, :bannered_until, where: 'bannered_until IS NOT NULL'
end
end
11 changes: 11 additions & 0 deletions db/migrate/20210624080131_add_partial_index_pinned_until.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class AddPartialIndexPinnedUntil < ActiveRecord::Migration[6.1]
disable_ddl_transaction!

def change
add_index :topics, :pinned_until,
where: 'pinned_until IS NOT NULL',
algorithm: :concurrently
end
end
51 changes: 51 additions & 0 deletions spec/jobs/remove_banner_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

require 'rails_helper'

describe Jobs::RemoveBanner do
fab!(:topic) { Fabricate(:topic) }
fab!(:user) { topic.user }

context 'topic is not bannered until' do
it 'doesn’t enqueue a future job to remove it' do
expect do
topic.make_banner!(user)
end.to change { Jobs::RemoveBanner.jobs.size }.by(0)
end
end

context 'topic is bannered until' do
context 'bannered_until is a valid date' do
it 'enqueues a future job to remove it' do
bannered_until = 5.days.from_now

expect(topic.archetype).to eq(Archetype.default)

expect do
topic.make_banner!(user, bannered_until.to_s)
end.to change { Jobs::RemoveBanner.jobs.size }.by(1)

topic.reload
expect(topic.archetype).to eq(Archetype.banner)

job = Jobs::RemoveBanner.jobs[0]
expect(Time.at(job['at'])).to be_within_one_minute_of(bannered_until)
expect(job['args'][0]['topic_id']).to eq(topic.id)

job['class'].constantize.new.perform(*job['args'])
topic.reload
expect(topic.archetype).to eq(Archetype.default)
end
end

context 'bannered_until is an invalid date' do
it 'doesn’t enqueue a future job to remove it' do
expect do
expect do
topic.make_banner!(user, 'xxx')
end.to raise_error(Discourse::InvalidParameters)
end.to change { Jobs::RemoveBanner.jobs.size }.by(0)
end
end
end
end
18 changes: 18 additions & 0 deletions spec/models/topic_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,24 @@ def set_state!(group, user, state)

end

context "bannered_until date" do

it 'sets bannered_until to be caught by ensure_consistency' do
bannered_until = 5.days.from_now
topic.make_banner!(user, bannered_until.to_s)

freeze_time 6.days.from_now do
expect(topic.archetype).to eq(Archetype.banner)

Topic.ensure_consistency!
topic.reload

expect(topic.archetype).to eq(Archetype.default)
end
end

end

end

context 'last_poster info' do
Expand Down

0 comments on commit 2654a66

Please sign in to comment.