diff --git a/lib/notification.rb b/lib/notification.rb index 2caa0da..1793940 100644 --- a/lib/notification.rb +++ b/lib/notification.rb @@ -1,139 +1,139 @@ require 'singleton' class Notification include Singleton # Send out a notification about bulk record operations. def notify_record_bulk(user, domain, ops) ActiveSupport::Notifications.instrument( 'webdns.record.bulk', user: user, domain: domain, ops: ops) end # Send out a notification about notable record changes. def notify_record(user, record, context) ActiveSupport::Notifications.instrument( 'webdns.record', user: user, context: context, object: record) end # Send out a notification about notable domain changes. def notify_domain(user, domain, context) ActiveSupport::Notifications.instrument( 'webdns.domain', user: user, context: context, object: domain) end # Subscribe to domain/record notifications. def hook hook_record hook_record_bulk hook_domain end private def hook_record ActiveSupport::Notifications .subscribe 'webdns.record' do |_name, _started, _finished, _unique_id, data| handle_record(data) end end def hook_record_bulk ActiveSupport::Notifications .subscribe 'webdns.record.bulk' do |_name, _started, _finished, _unique_id, data| handle_record_bulk(data) end end def hook_domain ActiveSupport::Notifications .subscribe 'webdns.domain' do |_name, _started, _finished, _unique_id, data| handle_domain(data) end end def handle_record(data) record, context, user = data.values_at(:object, :context, :user) domain = record.domain changes = filter_changes(record) return if changes.empty? && context == :update - others = domain.group.users.where.not(id: user.id).pluck(:email) + others = domain.group.users.pluck(:email) return if others.empty? admin_action = !user.groups.exists?(domain.group_id) NotificationMailer.notify_record( record: record, context: context, user: user, admin: admin_action, others: others, changes: changes ).deliver end def handle_record_bulk(data) ops, domain, user = data.values_at(:ops, :domain, :user) operations = [] operations += ops[:deletes].map { |rec| [:destroy, rec, nil] } operations += ops[:changes].map { |rec| [:update, rec, filter_changes(rec)] } operations += ops[:additions].map { |rec| [:create, rec, nil] } - others = domain.group.users.where.not(id: user.id).pluck(:email) + others = domain.group.users.pluck(:email) return if others.empty? admin_action = !user.groups.exists?(domain.group_id) NotificationMailer.notify_record_bulk( user: user, admin: admin_action, others: others, domain: domain, operations: operations, ).deliver end def handle_domain(data) domain, context, user = data.values_at(:object, :context, :user) changes = filter_changes(domain) return if changes.empty? && context == :update - others = domain.group.users.where.not(id: user.id).pluck(:email) + others = domain.group.users.pluck(:email) return if others.empty? admin_action = !user.groups.exists?(domain.group_id) NotificationMailer.notify_domain( domain: domain, context: context, user: user, admin: admin_action, others: others, changes: changes ).deliver end private def filter_changes(record) changes = record.previous_changes # Nobody is interested in those changes.delete('updated_at') changes.delete('created_at') changes end end diff --git a/test/mailers/notification_mailer_test.rb b/test/mailers/notification_mailer_test.rb index 4d3bb4c..5805c3c 100644 --- a/test/mailers/notification_mailer_test.rb +++ b/test/mailers/notification_mailer_test.rb @@ -1,175 +1,175 @@ require 'test_helper' class NotificationMailerTest < ActionMailer::TestCase class DomainNotificationMailerTest < ActionMailer::TestCase def setup @notification = Notification.instance @group = create(:group_with_users) @domain = create(:domain, group: @group) @record = build(:a, name: 'a', domain: @domain) end test 'domain add' do @record.save! @notification.notify_domain(@group.users.first, @domain, :create) assert_not ActionMailer::Base.deliveries.empty? mail = ActionMailer::Base.deliveries.last - assert_equal [@group.users.last.email], mail.to + assert_equal mail.to, @group.users.pluck(:email) assert_includes mail.subject, 'Created' assert_includes mail.body.to_s, "Domain: #{@domain.name}" assert_includes mail.body.to_s, "By: #{@group.users.first.email}" end test 'domain edit' do @record.save! @domain.type = 'SLAVE' @domain.master = '1.2.3.4' @domain.save! @notification.notify_domain(@group.users.first, @domain, :update) assert_not ActionMailer::Base.deliveries.empty? mail = ActionMailer::Base.deliveries.last - assert_equal [@group.users.last.email], mail.to + assert_equal mail.to, @group.users.pluck(:email) assert_includes mail.subject, 'Modified' assert_includes mail.body.to_s, "Domain: #{@domain.name}" assert_includes mail.body.to_s, "By: #{@group.users.first.email}" assert_includes mail.body.to_s, 'type from NATIVE' assert_includes mail.body.to_s, 'type to SLAVE' assert_includes mail.body.to_s, 'master from (empty)' assert_includes mail.body.to_s, 'master to 1.2.3.4' end test 'domain destroy' do @record.save! @domain.destroy! @notification.notify_domain(@group.users.first, @domain, :destroy) assert_not ActionMailer::Base.deliveries.empty? mail = ActionMailer::Base.deliveries.last - assert_equal [@group.users.last.email], mail.to + assert_equal mail.to, @group.users.pluck(:email) assert_includes mail.subject, 'Deleted' assert_includes mail.body.to_s, "Domain: #{@domain.name}" assert_includes mail.body.to_s, "By: #{@group.users.first.email}" end end class DomainNotificationMailerTest < ActionMailer::TestCase test 'record add' do @record.save! @notification.notify_record(@group.users.first, @record, :create) assert_not ActionMailer::Base.deliveries.empty? mail = ActionMailer::Base.deliveries.last - assert_equal [@group.users.last.email], mail.to + assert_equal mail.to, @group.users.pluck(:email) assert_includes mail.subject, 'Created' assert_includes mail.body.to_s, "Record: #{@record.name}" assert_includes mail.body.to_s, "Domain: #{@domain.name}" assert_includes mail.body.to_s, "State: #{@record.to_dns}" assert_includes mail.body.to_s, "By: #{@group.users.first.email}" end test 'record edit' do @record.save! prev_content = @record.content @record.content = '1.1.1.1' @record.save! @notification.notify_record(@group.users.first, @record, :update) assert_not ActionMailer::Base.deliveries.empty? mail = ActionMailer::Base.deliveries.last - assert_equal [@group.users.last.email], mail.to + assert_equal mail.to.sort, @group.users.pluck(:email) assert_includes mail.subject, 'Modified' assert_includes mail.body.to_s, "Record: #{@record.name}" assert_includes mail.body.to_s, "Domain: #{@domain.name}" assert_includes mail.body.to_s, "State: #{@record.to_dns}" assert_includes mail.body.to_s, "By: #{@group.users.first.email}" assert_includes mail.body.to_s, "content from #{prev_content}" assert_includes mail.body.to_s, 'content to 1.1.1.1' end test 'soa edit' do @record = @domain.soa prev_content = @record.content @record.nx = 10 @record.save! @notification.notify_record(@group.users.first, @record, :update) assert_not ActionMailer::Base.deliveries.empty? mail = ActionMailer::Base.deliveries.last - assert_equal [@group.users.last.email], mail.to + assert_equal mail.to, @group.users.pluck(:email) assert_includes mail.subject, 'Modified' assert_includes mail.body.to_s, "Record: #{@record.name}" assert_includes mail.body.to_s, "Domain: #{@domain.name}" assert_includes mail.body.to_s, "State: #{@record.to_dns}" assert_includes mail.body.to_s, "By: #{@group.users.first.email}" assert_includes mail.body.to_s, "content from #{prev_content}" assert_includes mail.body.to_s, "content to #{@record.content}" assert_includes mail.body.to_s, ' 10' end test 'record destroy' do @record.save! @record.destroy! @notification.notify_record(@group.users.first, @record, :destroy) assert_not ActionMailer::Base.deliveries.empty? mail = ActionMailer::Base.deliveries.last - assert_equal [@group.users.last.email], mail.to + assert_equal mail.to, @group.users.pluck(:email) assert_includes mail.subject, 'Deleted' assert_includes mail.body.to_s, "Record: #{@record.name}" assert_includes mail.body.to_s, "Domain: #{@domain.name}" assert_includes mail.body.to_s, "By: #{@group.users.first.email}" end test 'bulk operations' do a = create(:a, domain: @domain) aaaa = create(:aaaa, domain: @domain) new = build(:mx, domain: @domain) changes = {}.tap { |c| c[:deletes] = [a.id] c[:changes] = { aaaa.id => { content: '::42' }} c[:additions] = { 1 => new.as_bulky_json } } ops, err = @domain.bulk(changes) assert_empty err @notification.notify_record_bulk(@group.users.first, @domain, ops) assert_not ActionMailer::Base.deliveries.empty? mail = ActionMailer::Base.deliveries.last - assert_equal [@group.users.last.email], mail.to + assert_equal mail.to, @group.users.pluck(:email) assert_includes mail.subject, 'Bulk' assert_includes mail.body.to_s, "Domain: #{@domain.name}" assert_includes mail.body.to_s, "By: #{@group.users.first.email}" assert_includes mail.body.to_s, "Action: destroy" assert_includes mail.body.to_s, "Action: update" assert_includes mail.body.to_s, "Action: create" end end end