mirror of
https://github.com/discourse/discourse.git
synced 2026-08-08 17:53:55 +08:00
Since we have been using the upcoming change system
more heavily, we noticed that notifications for available changes
(i.e. changes that have been added at promotion status - 1 OR
changes that recently reached promotion status - 1) are crowding
the admin's notifications a lot.
To address this, we already allowed admins to opt out of these
in 0c46a2e805 . However, we also
want to reduce the cadence of these notifications for admins who do want
to opt out completely.
This commit changes upcoming change available notifications to be
collected & sent in a weekly job, rather than in the job that runs
every 20 minutes & logs added/status changed events.
This weekly job will also handle consolidating existing unread upcoming
change available notifications, and making sure that we do not send
N new notifications per change when an admin has no existing unread
notification.
Upcoming change promoted notifications will still happen "instantly"
239 lines
7.3 KiB
Ruby
Vendored
239 lines
7.3 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
RSpec.describe UpcomingChanges::Action::TrackStatusChanges do
|
|
let(:enable_upload_debug_mode_status) { :experimental }
|
|
let(:show_user_menu_avatars_status) { :beta }
|
|
|
|
before do
|
|
mock_upcoming_change_metadata(
|
|
{
|
|
enable_upload_debug_mode: {
|
|
impact: "other,developers",
|
|
status: enable_upload_debug_mode_status,
|
|
impact_type: "other",
|
|
impact_role: "developers",
|
|
},
|
|
show_user_menu_avatars: {
|
|
impact: "feature,all_members",
|
|
status: show_user_menu_avatars_status,
|
|
impact_type: "feature",
|
|
impact_role: "all_members",
|
|
},
|
|
},
|
|
)
|
|
end
|
|
|
|
def scoped_events
|
|
UpcomingChangeEvent.where(
|
|
upcoming_change_name: %i[enable_upload_debug_mode show_user_menu_avatars],
|
|
)
|
|
end
|
|
|
|
fab!(:admin_1, :admin)
|
|
fab!(:admin_2, :admin)
|
|
let(:added_changes) { [] }
|
|
let(:removed_changes) { [] }
|
|
|
|
describe ".call" do
|
|
subject(:result) do
|
|
described_class.call(all_admins: [admin_1, admin_2], added_changes:, removed_changes:)
|
|
end
|
|
|
|
before do
|
|
scoped_events.where(event_type: :status_changed).delete_all
|
|
scoped_events.where(event_type: :added).delete_all
|
|
UpcomingChangeEvent.create!(
|
|
event_type: :added,
|
|
upcoming_change_name: :enable_upload_debug_mode,
|
|
)
|
|
UpcomingChangeEvent.create!(event_type: :added, upcoming_change_name: :show_user_menu_avatars)
|
|
end
|
|
|
|
context "when there are no previous status changes" do
|
|
it "creates a status_changed event for the current status" do
|
|
expect { result }.to change { scoped_events.where(event_type: :status_changed).count }.by(2)
|
|
end
|
|
|
|
it "sets previous_value to nil in the event data" do
|
|
result
|
|
event =
|
|
scoped_events.find_by(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :enable_upload_debug_mode,
|
|
)
|
|
expect(event.event_data["previous_value"]).to be_nil
|
|
end
|
|
|
|
it "sets new_value to the current status in the event data" do
|
|
result
|
|
event =
|
|
scoped_events.find_by(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :enable_upload_debug_mode,
|
|
)
|
|
expect(event.event_data["new_value"]).to eq("experimental")
|
|
end
|
|
|
|
it "returns N/A as previous_value in the result" do
|
|
expect(result[:enable_upload_debug_mode]).to eq(
|
|
{ previous_value: "N/A", new_value: :experimental },
|
|
)
|
|
end
|
|
end
|
|
|
|
it "clears the latest new feature created_at cache" do
|
|
Discourse.redis.set("latest_new_feature_created_at", Time.zone.now.iso8601)
|
|
result
|
|
expect(Discourse.redis.get("latest_new_feature_created_at")).to be_nil
|
|
end
|
|
|
|
context "when there are added changes in the same run" do
|
|
let(:added_changes) { [:enable_upload_debug_mode] }
|
|
|
|
before do
|
|
scoped_events.where(event_type: :added).delete_all
|
|
UpcomingChangeEvent.create!(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :enable_upload_debug_mode,
|
|
event_data: {
|
|
"previous_value" => nil,
|
|
"new_value" => "alpha",
|
|
},
|
|
)
|
|
UpcomingChangeEvent.create!(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :show_user_menu_avatars,
|
|
event_data: {
|
|
"previous_value" => nil,
|
|
"new_value" => "beta",
|
|
},
|
|
)
|
|
end
|
|
|
|
it "does not create additional status change events for added changes" do
|
|
expect { result }.not_to change {
|
|
scoped_events.where(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :enable_upload_debug_mode,
|
|
).count
|
|
}
|
|
end
|
|
end
|
|
|
|
context "when there are removed changes in the same run" do
|
|
let(:removed_changes) { [:old_removed_change] }
|
|
|
|
before do
|
|
UpcomingChangeEvent.create!(event_type: :added, upcoming_change_name: :old_removed_change)
|
|
UpcomingChangeEvent.create!(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :old_removed_change,
|
|
event_data: {
|
|
"previous_value" => nil,
|
|
"new_value" => "beta",
|
|
},
|
|
)
|
|
UpcomingChangeEvent.create!(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :enable_upload_debug_mode,
|
|
event_data: {
|
|
"previous_value" => nil,
|
|
"new_value" => "experimental",
|
|
},
|
|
)
|
|
UpcomingChangeEvent.create!(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :show_user_menu_avatars,
|
|
event_data: {
|
|
"previous_value" => nil,
|
|
"new_value" => "beta",
|
|
},
|
|
)
|
|
end
|
|
|
|
it "does not create a status change event for removed changes" do
|
|
expect { result }.not_to change {
|
|
UpcomingChangeEvent.where(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :old_removed_change,
|
|
).count
|
|
}
|
|
end
|
|
end
|
|
|
|
context "when the status has changed from a previous value" do
|
|
let(:show_user_menu_avatars_status) { :stable }
|
|
|
|
before do
|
|
UpcomingChangeEvent.create!(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :show_user_menu_avatars,
|
|
event_data: {
|
|
"previous_value" => nil,
|
|
"new_value" => "beta",
|
|
},
|
|
)
|
|
UpcomingChangeEvent.create!(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :enable_upload_debug_mode,
|
|
event_data: {
|
|
"previous_value" => nil,
|
|
"new_value" => "experimental",
|
|
},
|
|
)
|
|
end
|
|
|
|
it "creates a status_changed event with correct data" do
|
|
expect { result }.to change {
|
|
scoped_events.where(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :show_user_menu_avatars,
|
|
).count
|
|
}.by(1)
|
|
end
|
|
|
|
it "records the previous and new status values" do
|
|
result
|
|
expect(
|
|
scoped_events
|
|
.where(event_type: :status_changed, upcoming_change_name: :show_user_menu_avatars)
|
|
.order(:created_at)
|
|
.last,
|
|
).to have_attributes(event_data: { "previous_value" => "beta", "new_value" => "stable" })
|
|
end
|
|
|
|
it "returns the status change in the result" do
|
|
expect(result[:show_user_menu_avatars]).to eq(
|
|
{ previous_value: "beta", new_value: :stable },
|
|
)
|
|
end
|
|
end
|
|
|
|
context "when status has not changed" do
|
|
let(:show_user_menu_avatars_status) { :beta }
|
|
|
|
before do
|
|
UpcomingChangeEvent.create!(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :show_user_menu_avatars,
|
|
event_data: {
|
|
"previous_value" => nil,
|
|
"new_value" => "beta",
|
|
},
|
|
)
|
|
UpcomingChangeEvent.create!(
|
|
event_type: :status_changed,
|
|
upcoming_change_name: :enable_upload_debug_mode,
|
|
event_data: {
|
|
"previous_value" => nil,
|
|
"new_value" => "experimental",
|
|
},
|
|
)
|
|
end
|
|
|
|
it "does not create a new status_changed event" do
|
|
expect { result }.not_to change { scoped_events.where(event_type: :status_changed).count }
|
|
end
|
|
end
|
|
end
|
|
end
|