331 lines
14 KiB
Ruby
331 lines
14 KiB
Ruby
#
|
|
# Copyright (C) 2011 - present Instructure, Inc.
|
|
#
|
|
# This file is part of Canvas.
|
|
#
|
|
# Canvas is free software: you can redistribute it and/or modify it under
|
|
# the terms of the GNU Affero General Public License as published by the Free
|
|
# Software Foundation, version 3 of the License.
|
|
#
|
|
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License along
|
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
|
|
require File.expand_path(File.dirname(__FILE__) + '/../sharding_spec_helper')
|
|
|
|
describe NotificationPolicy do
|
|
it "should create a new instance given valid attributes" do
|
|
notification_policy_model
|
|
end
|
|
|
|
context "channels" do
|
|
before(:once) do
|
|
@course = factory_with_protected_attributes(Course, :name => "test course", :workflow_state => "available")
|
|
@student = factory_with_protected_attributes(User, :name => "student", :workflow_state => "registered")
|
|
e = @course.enroll_student(@student)
|
|
e.accept!
|
|
Notification.all.each{|n| n.destroy }
|
|
Notification.reset_cache!
|
|
@notif = Notification.create!(:name => "Assignment Created", :subject => "Test", :category => 'TestNever')
|
|
end
|
|
|
|
it "should cause message dispatch to specified channel on triggered policies" do
|
|
@default_cc = @student.communication_channels.create(:path => "default@example.com")
|
|
@default_cc.confirm!
|
|
@cc = @student.communication_channels.create(:path => "secondary@example.com")
|
|
@cc.confirm!
|
|
@policy = NotificationPolicy.create(:notification => @notif, :communication_channel => @cc, :frequency => "immediately")
|
|
@assignment = @course.assignments.create!(:title => "test assignment")
|
|
expect(@assignment.messages_sent).to be_include("Assignment Created")
|
|
m = @assignment.messages_sent["Assignment Created"].find{|m| m.to == "default@example.com"}
|
|
expect(m).to be_nil
|
|
m = @assignment.messages_sent["Assignment Created"].find{|m| m.to == "secondary@example.com"}
|
|
expect(m).not_to be_nil
|
|
end
|
|
|
|
it "should prevent message dispatches if set to 'never' on triggered policies" do
|
|
@cc = @student.communication_channels.create(:path => "secondary@example.com")
|
|
@cc.confirm!
|
|
@policy = NotificationPolicy.create(:notification => @notif, :communication_channel => @cc, :frequency => "never")
|
|
@assignment = @course.assignments.create!(:title => "test assignment")
|
|
m = @assignment.messages_sent["Assignment Created"].find{|m| m.to == "default@example.com"}
|
|
expect(m).to be_nil
|
|
m = @assignment.messages_sent["Assignment Created"].find{|m| m.to == "secondary@example.com"}
|
|
expect(m).to be_nil
|
|
end
|
|
|
|
it "should prevent message dispatches if no policy setting exists" do
|
|
@cc = @student.communication_channels.create(:path => "secondary@example.com")
|
|
@cc.confirm!
|
|
NotificationPolicy.where(:notification_id => @notif, :communication_channel_id => @cc).delete_all
|
|
@assignment = @course.assignments.create!(:title => "test assignment")
|
|
m = @assignment.messages_sent["Assignment Created"].find{|m| m.to == "default@example.com"}
|
|
expect(m).to be_nil
|
|
m = @assignment.messages_sent["Assignment Created"].find{|m| m.to == "secondary@example.com"}
|
|
expect(m).to be_nil
|
|
end
|
|
end
|
|
|
|
it "should pass 'data' to the message" do
|
|
Notification.create! :name => "Hello",
|
|
:subject => "Hello",
|
|
:category => "TestImmediately"
|
|
allow_any_instance_of(Message).to receive(:get_template).and_return("here's a free <%= data.favorite_soda %>")
|
|
class DataTest < ActiveRecord::Base
|
|
self.table_name = :courses
|
|
|
|
has_a_broadcast_policy
|
|
set_broadcast_policy do
|
|
dispatch :hello
|
|
to {
|
|
u = User.create
|
|
u.communication_channels.build(
|
|
:path => 'blarg@example.com',
|
|
:path_type => 'email'
|
|
) { |cc| cc.workflow_state = 'active' }
|
|
u.save!
|
|
u.register
|
|
u
|
|
}
|
|
whenever { true }
|
|
data { {:favorite_soda => 'mtn dew'} }
|
|
end
|
|
def root_account
|
|
Account.default
|
|
end
|
|
end
|
|
dt = DataTest.new(account_id: Account.default.id,
|
|
root_account_id: Account.default.id,
|
|
enrollment_term_id: Account.default.default_enrollment_term.id,
|
|
workflow_state: 'created')
|
|
dt.save!
|
|
msg = dt.messages_sent["Hello"].find { |m| m.to == "blarg@example.com" }
|
|
expect(msg).not_to be_nil
|
|
expect(msg.body).to include "mtn dew"
|
|
end
|
|
|
|
context "named scopes" do
|
|
it "should have a named scope for users" do
|
|
user_with_pseudonym(:active_all => 1)
|
|
notification_policy_model(:communication_channel => @cc)
|
|
expect(NotificationPolicy.for(@user)).to eq [@notification_policy]
|
|
end
|
|
|
|
it "should have a named scope for notifications" do
|
|
notification_model
|
|
notification_policy_model(:notification => @notification)
|
|
expect(NotificationPolicy.for(@notification)).to eq [@notification_policy]
|
|
end
|
|
|
|
it "should not slow down from other kinds of input on the *for* named scope" do
|
|
notification_policy_model
|
|
expect(NotificationPolicy.for(:anything_else)).to eq NotificationPolicy.all
|
|
end
|
|
|
|
context "by" do
|
|
before :once do
|
|
user_with_pseudonym(:active_all => 1)
|
|
@n1 = notification_policy_model(:frequency => 'immediately', :communication_channel => @cc, notification: notification_model(name: 'N1'))
|
|
@n2 = notification_policy_model(:frequency => 'daily', :communication_channel => @cc, notification: notification_model(name: 'N2'))
|
|
@n3 = notification_policy_model(:frequency => 'weekly', :communication_channel => @cc, notification: notification_model(name: 'N3'))
|
|
@n4 = notification_policy_model(:frequency => 'never', :communication_channel => @cc, notification: notification_model(name: 'N4'))
|
|
end
|
|
|
|
it "should have a scope to differentiate by frequency" do
|
|
expect(NotificationPolicy.by(:immediately)).to eq [@n1]
|
|
expect(NotificationPolicy.by(:daily)).to eq [@n2]
|
|
expect(NotificationPolicy.by(:weekly)).to eq [@n3]
|
|
expect(NotificationPolicy.by(:never)).to eq [@n4]
|
|
end
|
|
|
|
it "should be able to differentiate by several frequencies at once" do
|
|
expect(NotificationPolicy.by([:immediately, :daily])).to be_include(@n1)
|
|
expect(NotificationPolicy.by([:immediately, :daily])).to be_include(@n2)
|
|
end
|
|
|
|
it "should be able to combine an array of frequencies with a for scope" do
|
|
expect(NotificationPolicy.for(@user).by([:daily, :weekly])).to be_include(@n2)
|
|
expect(NotificationPolicy.for(@user).by([:daily, :weekly])).to be_include(@n3)
|
|
expect(NotificationPolicy.for(@user).by([:daily, :weekly])).not_to be_include(@n1)
|
|
end
|
|
end
|
|
|
|
it "should find all daily and weekly policies for the user, communication_channel, and notification" do
|
|
user_model
|
|
communication_channel_model
|
|
notification_model
|
|
|
|
NotificationPolicy.delete_all
|
|
|
|
trifecta_opts = {
|
|
:communication_channel => @communication_channel,
|
|
:notification => @notification
|
|
}
|
|
|
|
n1 = notification_policy_model
|
|
|
|
policies = NotificationPolicy.for(@notification).for(@user).for(@communication_channel).by([:daily, :weekly])
|
|
expect(policies).to eq []
|
|
|
|
n1.update_attribute(:frequency, 'never')
|
|
policies = NotificationPolicy.for(@notification).for(@user).for(@communication_channel).by([:daily, :weekly])
|
|
expect(policies).to eq []
|
|
|
|
n1.update_attribute(:frequency, 'daily')
|
|
policies = NotificationPolicy.for(@notification).for(@user).for(@communication_channel).by([:daily, :weekly])
|
|
expect(policies).to eq [n1]
|
|
|
|
n1.update_attribute(:frequency, 'weekly')
|
|
policies = NotificationPolicy.for(@notification).for(@user).for(@communication_channel).by([:daily, :weekly])
|
|
expect(policies).to eq [n1]
|
|
end
|
|
|
|
end
|
|
|
|
describe "setup_for" do
|
|
it "should not fail when params does not include a user, and the account doesn't allow scores in e-mails" do
|
|
user_model
|
|
communication_channel_model
|
|
notify1 = notification_model(:name => 'Setting 1', :category => 'MultiCategory')
|
|
params = { :channel_id => @communication_channel.id }
|
|
params[:root_account] = Account.default
|
|
params[:root_account].settings[:allow_sending_scores_in_emails] = false
|
|
NotificationPolicy.setup_for(@user, params)
|
|
end
|
|
|
|
it "should set all notification entries within the same category" do
|
|
user_model
|
|
communication_channel_model
|
|
notify1 = notification_model(:name => 'Setting 1', :category => 'MultiCategory')
|
|
notify2 = notification_model(:name => 'Setting 2', :category => 'MultiCategory')
|
|
|
|
NotificationPolicy.delete_all
|
|
|
|
trifecta_opts = {
|
|
:communication_channel => @communication_channel,
|
|
:frequency => Notification::FREQ_NEVER
|
|
}
|
|
n1 = notification_policy_model(trifecta_opts.merge(:notification => notify1) )
|
|
n2 = notification_policy_model(trifecta_opts.merge(:notification => notify2) )
|
|
params = {:category => 'multi_category', :channel_id => @communication_channel.id, :frequency => Notification::FREQ_IMMEDIATELY}
|
|
NotificationPolicy.setup_for(@user, params)
|
|
n1.reload; n2.reload
|
|
expect(n1.frequency).to eq Notification::FREQ_IMMEDIATELY
|
|
expect(n2.frequency).to eq Notification::FREQ_IMMEDIATELY
|
|
end
|
|
|
|
it "does not modify another user's preferences" do
|
|
notification_model
|
|
hax0r = user_with_communication_channel
|
|
user_with_communication_channel
|
|
expect {
|
|
NotificationPolicy.setup_for(hax0r, :channel_id => @cc.id, :frequency => Notification::FREQ_IMMEDIATELY, :category => 'test_immediately')
|
|
}.to raise_error(ActiveRecord::RecordNotFound)
|
|
expect(@user.notification_policies.any?).to eq false
|
|
end
|
|
|
|
context "sharding" do
|
|
specs_require_sharding
|
|
|
|
it "should create records on the correct shard" do
|
|
user_with_pseudonym(active_all: true)
|
|
NotificationPolicy.delete_all
|
|
notification_model
|
|
@shard1.activate do
|
|
expect(@user.notification_policies.scope.exists?).to be_falsey
|
|
NotificationPolicy.setup_for(@user, channel_id: @cc.id, frequency: Notification::FREQ_IMMEDIATELY, category: 'test_immediately')
|
|
expect(@user.notification_policies.scope.exists?).to be_truthy
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "setup_with_default_policies" do
|
|
before :once do
|
|
@user = User.create!
|
|
@communication_channel = @user.communication_channels.create!(path: 'email@example.com')
|
|
@announcement = notification_model(:name => 'Setting 1', :category => 'Announcement')
|
|
end
|
|
|
|
before :each do
|
|
allow(Notification).to receive(:all).and_return([@notification])
|
|
end
|
|
|
|
it "should create default NotificationPolicy entries if missing" do
|
|
# Ensure no existing policies
|
|
NotificationPolicy.delete_all
|
|
|
|
policies = NotificationPolicy.setup_with_default_policies(@user, [@announcement])
|
|
expect(policies.length).to eq 1
|
|
expect(policies.first.frequency).to eq @announcement.default_frequency
|
|
end
|
|
|
|
it "should not overwrite an existing setting with a default" do
|
|
# Create an existing policy entry
|
|
NotificationPolicy.delete_all
|
|
n1 = notification_policy_model({:communication_channel => @communication_channel,
|
|
:notification => @announcement,
|
|
:frequency => Notification::FREQ_NEVER})
|
|
|
|
expect(@announcement.default_frequency).not_to eq Notification::FREQ_NEVER # verify that it differs from the default
|
|
policies = NotificationPolicy.setup_with_default_policies(@user, [@announcement])
|
|
expect(policies.length).to eq 1
|
|
expect(policies.first.frequency).to eq Notification::FREQ_NEVER
|
|
end
|
|
|
|
it "should not set defaults on secondary communication channel" do
|
|
NotificationPolicy.delete_all
|
|
# Setup the second channel (higher position)
|
|
primary_channel = @user.communication_channel
|
|
secondary_channel = communication_channel_model(:path => 'secondary@example.com')
|
|
# start out with 0 on primary and secondary
|
|
expect(primary_channel.notification_policies.count).to eq 0
|
|
expect(secondary_channel.notification_policies.count).to eq 0
|
|
# Load data
|
|
NotificationPolicy.setup_with_default_policies(@user, [@announcement])
|
|
# Primary should have 1 created and secondary should be left alone.
|
|
expect(primary_channel.notification_policies.count).to eq 1
|
|
expect(secondary_channel.notification_policies.count).to eq 0
|
|
end
|
|
|
|
it "should not pull defaults from non-default channels" do
|
|
NotificationPolicy.delete_all
|
|
# Setup the second channel (higher position)
|
|
primary_channel = @user.communication_channel
|
|
secondary_channel = communication_channel_model(:path => 'secondary@example.com')
|
|
secondary_channel.notification_policies.create!(:notification => @notification, :frequency => Notification::FREQ_NEVER)
|
|
NotificationPolicy.setup_with_default_policies(@user, [@announcement])
|
|
# Primary should have 1 created and secondary should be left alone.
|
|
expect(primary_channel.reload.notification_policies.count).to eq 1
|
|
expect(secondary_channel.reload.notification_policies.count).to eq 1
|
|
end
|
|
|
|
it "should not error if no channel exists" do
|
|
NotificationPolicy.delete_all
|
|
CommunicationChannel.delete_all
|
|
expect { NotificationPolicy.setup_with_default_policies(@user, [@announcement])}.not_to raise_error
|
|
end
|
|
|
|
context "across shards" do
|
|
specs_require_sharding
|
|
|
|
it "should find user categories accross shards" do
|
|
@shard1.activate {
|
|
@shard_user = user_model
|
|
@channel = communication_channel_model(:user => @shard_user)
|
|
NotificationPolicy.delete_all
|
|
@policy = @channel.notification_policies.create!(:notification => @notification, :frequency => Notification::FREQ_NEVER)
|
|
NotificationPolicy.setup_with_default_policies(@shard_user, [@announcement])
|
|
expect(@policy.reload.frequency).to eq Notification::FREQ_NEVER
|
|
}
|
|
end
|
|
end
|
|
end
|
|
end
|