DEV: Replace 'processed' column on notifications with new table (#11864)
This commit is contained in:
parent
60f10e9067
commit
809274fe0d
|
@ -25,9 +25,8 @@ class DoNotDisturbController < ApplicationController
|
||||||
def destroy
|
def destroy
|
||||||
current_user.active_do_not_disturb_timings.destroy_all
|
current_user.active_do_not_disturb_timings.destroy_all
|
||||||
current_user.publish_do_not_disturb(ends_at: nil)
|
current_user.publish_do_not_disturb(ends_at: nil)
|
||||||
current_user.notifications.unprocessed.each do |notification|
|
current_user.shelved_notifications.each(&:process)
|
||||||
NotificationEmailer.process_notification(notification, no_delay: true)
|
current_user.shelved_notifications.destroy_all
|
||||||
end
|
|
||||||
render json: success_json
|
render json: success_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,22 +6,17 @@ module Jobs
|
||||||
|
|
||||||
def execute(args)
|
def execute(args)
|
||||||
sql = <<~SQL
|
sql = <<~SQL
|
||||||
SELECT n.id FROM notifications AS n
|
SELECT sn.id FROM shelved_notifications as sn
|
||||||
INNER JOIN do_not_disturb_timings AS dndt ON n.user_id = dndt.user_id
|
INNER JOIN notifications AS notification ON sn.notification_id = notification.id
|
||||||
WHERE n.processed = false
|
INNER JOIN do_not_disturb_timings AS dndt ON notification.user_id = dndt.user_id
|
||||||
AND dndt.ends_at <= :now
|
AND dndt.ends_at <= :now
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
now = Time.zone.now
|
now = Time.zone.now
|
||||||
notification_ids = DB.query_single(sql, now: now)
|
shelved_notification_ids = DB.query_single(sql, now: now)
|
||||||
|
shelved_notifications = ShelvedNotification.where(id: shelved_notification_ids)
|
||||||
Notification.where(id: notification_ids).each do |notification|
|
shelved_notifications.each(&:process)
|
||||||
begin
|
shelved_notifications.destroy_all
|
||||||
NotificationEmailer.process_notification(notification, no_delay: true)
|
|
||||||
rescue
|
|
||||||
Rails.logger.warn("Failed to process notification with ID #{notification.id}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
DB.exec("DELETE FROM do_not_disturb_timings WHERE ends_at < :now", now: now)
|
DB.exec("DELETE FROM do_not_disturb_timings WHERE ends_at < :now", now: now)
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,13 +4,14 @@ class Notification < ActiveRecord::Base
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :topic
|
belongs_to :topic
|
||||||
|
|
||||||
|
has_one :shelved_notification
|
||||||
|
|
||||||
MEMBERSHIP_REQUEST_CONSOLIDATION_WINDOW_HOURS = 24
|
MEMBERSHIP_REQUEST_CONSOLIDATION_WINDOW_HOURS = 24
|
||||||
|
|
||||||
validates_presence_of :data
|
validates_presence_of :data
|
||||||
validates_presence_of :notification_type
|
validates_presence_of :notification_type
|
||||||
|
|
||||||
scope :unread, lambda { where(read: false) }
|
scope :unread, lambda { where(read: false) }
|
||||||
scope :unprocessed, lambda { where(processed: false) }
|
|
||||||
scope :recent, lambda { |n = nil| n ||= 10; order('notifications.created_at desc').limit(n) }
|
scope :recent, lambda { |n = nil| n ||= 10; order('notifications.created_at desc').limit(n) }
|
||||||
scope :visible , lambda { joins('LEFT JOIN topics ON notifications.topic_id = topics.id')
|
scope :visible , lambda { joins('LEFT JOIN topics ON notifications.topic_id = topics.id')
|
||||||
.where('topics.id IS NULL OR topics.deleted_at IS NULL') }
|
.where('topics.id IS NULL OR topics.deleted_at IS NULL') }
|
||||||
|
@ -283,10 +284,11 @@ class Notification < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_email
|
def send_email
|
||||||
if skip_send_email
|
return if skip_send_email
|
||||||
return update(processed: true)
|
|
||||||
end
|
user.do_not_disturb? ?
|
||||||
NotificationEmailer.process_notification(self) unless user.do_not_disturb?
|
ShelvedNotification.create(notification_id: self.id) :
|
||||||
|
NotificationEmailer.process_notification(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ShelvedNotification < ActiveRecord::Base
|
||||||
|
belongs_to :notification
|
||||||
|
|
||||||
|
def process
|
||||||
|
NotificationEmailer.process_notification(notification, no_delay: true)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1391,6 +1391,10 @@ class User < ActiveRecord::Base
|
||||||
active_do_not_disturb_timings.maximum(:ends_at)
|
active_do_not_disturb_timings.maximum(:ends_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def shelved_notifications
|
||||||
|
ShelvedNotification.joins(:notification).where("notifications.user_id = ?", self.id)
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def badge_grant
|
def badge_grant
|
||||||
|
|
|
@ -125,7 +125,6 @@ class NotificationEmailer
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.process_notification(notification, no_delay: false)
|
def self.process_notification(notification, no_delay: false)
|
||||||
notification.update(processed: true)
|
|
||||||
return if @disabled
|
return if @disabled
|
||||||
|
|
||||||
email_user = EmailUser.new(notification, no_delay: no_delay)
|
email_user = EmailUser.new(notification, no_delay: no_delay)
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AddProcessedToNotifications < ActiveRecord::Migration[6.0]
|
class AddProcessedToNotifications < ActiveRecord::Migration[6.0]
|
||||||
def up
|
def change
|
||||||
add_column :notifications, :processed, :boolean, default: false
|
|
||||||
execute "UPDATE notifications SET processed = true"
|
|
||||||
change_column_null(:notifications, :processed, false)
|
|
||||||
add_index :notifications, [:processed], unique: false
|
|
||||||
end
|
|
||||||
|
|
||||||
def down
|
|
||||||
remove_column :notifications, :processed
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
class CreateShelvedNotifications < ActiveRecord::Migration[6.0]
|
||||||
|
def change
|
||||||
|
create_table :shelved_notifications do |t|
|
||||||
|
t.integer :notification_id, null: false
|
||||||
|
end
|
||||||
|
add_index :shelved_notifications, [:notification_id]
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,6 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
class UndoAddProcessedToNotifications < ActiveRecord::Migration[6.0]
|
||||||
|
def up
|
||||||
|
execute "ALTER TABLE notifications DROP COLUMN IF EXISTS processed"
|
||||||
|
end
|
||||||
|
end
|
|
@ -17,21 +17,21 @@ describe Jobs::ProcessShelvedNotifications do
|
||||||
expect(DoNotDisturbTiming.find_by(id: past.id)).to eq(nil)
|
expect(DoNotDisturbTiming.find_by(id: past.id)).to eq(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not process unprocessed notifications when the user is in DND" do
|
it "does not process shelved_notifications when the user is in DND" do
|
||||||
user.do_not_disturb_timings.create(starts_at: 2.days.ago, ends_at: 2.days.from_now)
|
user.do_not_disturb_timings.create(starts_at: 2.days.ago, ends_at: 2.days.from_now)
|
||||||
notification = Notification.create(read: false, user_id: user.id, topic_id: 2, post_number: 1, data: '{}', notification_type: 1)
|
notification = Notification.create(read: false, user_id: user.id, topic_id: 2, post_number: 1, data: '{}', notification_type: 1)
|
||||||
expect(notification.reload.processed).to eq(false)
|
expect(notification.shelved_notification).to be_present
|
||||||
subject.execute({})
|
subject.execute({})
|
||||||
expect(notification.reload.processed).to eq(false)
|
expect(notification.shelved_notification).to be_present
|
||||||
end
|
end
|
||||||
|
|
||||||
it "processes unprocessed notifications when the user leaves DND" do
|
it "processes and destroys shelved_notifications when the user leaves DND" do
|
||||||
user.do_not_disturb_timings.create(starts_at: 2.days.ago, ends_at: 2.days.from_now)
|
user.do_not_disturb_timings.create(starts_at: 2.days.ago, ends_at: 2.days.from_now)
|
||||||
notification = Notification.create(read: false, user_id: user.id, topic_id: 2, post_number: 1, data: '{}', notification_type: 1)
|
notification = Notification.create(read: false, user_id: user.id, topic_id: 2, post_number: 1, data: '{}', notification_type: 1)
|
||||||
user.do_not_disturb_timings.last.update(ends_at: 1.days.ago)
|
user.do_not_disturb_timings.last.update(ends_at: 1.days.ago)
|
||||||
|
|
||||||
expect(notification.reload.processed).to eq(false)
|
expect(notification.shelved_notification).to be_present
|
||||||
subject.execute({})
|
subject.execute({})
|
||||||
expect(notification.reload.processed).to eq(true)
|
expect { notification.shelved_notification.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -495,7 +495,6 @@ describe Notification do
|
||||||
expect { notification.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
expect { notification.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
|
|
||||||
notification = Notification.last
|
notification = Notification.last
|
||||||
expect(notification.processed).to eq(true)
|
|
||||||
expect(notification.notification_type).to eq(Notification.types[:membership_request_consolidated])
|
expect(notification.notification_type).to eq(Notification.types[:membership_request_consolidated])
|
||||||
|
|
||||||
data = notification.data_hash
|
data = notification.data_hash
|
||||||
|
@ -516,7 +515,7 @@ describe Notification do
|
||||||
|
|
||||||
notification = Notification.last
|
notification = Notification.last
|
||||||
expect(notification.notification_type).to eq(Notification.types[:membership_request_consolidated])
|
expect(notification.notification_type).to eq(Notification.types[:membership_request_consolidated])
|
||||||
expect(notification.processed).to eq(false)
|
expect(notification.shelved_notification).to be_present
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -543,18 +542,18 @@ describe Notification do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "processed" do
|
describe "do not disturb" do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
it "is false after creation when the user is in do not disturb" do
|
it "creates a shelved_notification record when created while user is in DND" do
|
||||||
user.do_not_disturb_timings.create(starts_at: Time.now, ends_at: 3.days.from_now)
|
user.do_not_disturb_timings.create(starts_at: Time.now, ends_at: 3.days.from_now)
|
||||||
notification = Notification.create(read: false, user_id: user.id, topic_id: 2, post_number: 1, data: '{}', notification_type: 1)
|
notification = Notification.create(read: false, user_id: user.id, topic_id: 2, post_number: 1, data: '{}', notification_type: 1)
|
||||||
expect(notification.processed).to be(false)
|
expect(notification.shelved_notification).to be_present
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is true after creation when the user isn't in do not disturb" do
|
it "doesn't create a shelved_notification record when created while user is isn't DND" do
|
||||||
notification = Notification.create(read: false, user_id: user.id, topic_id: 2, post_number: 1, data: '{}', notification_type: 1)
|
notification = Notification.create(read: false, user_id: user.id, topic_id: 2, post_number: 1, data: '{}', notification_type: 1)
|
||||||
expect(notification.processed).to be(true)
|
expect(notification.shelved_notification).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,13 +44,14 @@ describe DoNotDisturbController do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#destroy" do
|
describe "#destroy" do
|
||||||
it "process notifications that came in during DND" do
|
it "process shelved notifications that came in during DND" do
|
||||||
user.do_not_disturb_timings.create(starts_at: 2.days.ago, ends_at: 2.days.from_now)
|
user.do_not_disturb_timings.create(starts_at: 2.days.ago, ends_at: 2.days.from_now)
|
||||||
notification = Notification.create(read: false, user_id: user.id, topic_id: 2, post_number: 1, data: '{}', notification_type: 1)
|
notification = Notification.create(read: false, user_id: user.id, topic_id: 2, post_number: 1, data: '{}', notification_type: 1)
|
||||||
|
|
||||||
expect(notification.processed).to eq(false)
|
expect(notification.shelved_notification).to be_present
|
||||||
delete "/do-not-disturb.json"
|
delete "/do-not-disturb.json"
|
||||||
expect(notification.reload.processed).to eq(true)
|
expect { notification.shelved_notification.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
|
expect(user.do_not_disturb?).to eq(false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue