canvas-lms/app/models/notification_policy.rb

193 lines
7.6 KiB
Ruby
Raw Normal View History

2011-02-01 09:57:29 +08:00
#
# Copyright (C) 2011 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/>.
#
class NotificationPolicy < ActiveRecord::Base
include NotificationPreloader
2011-02-01 09:57:29 +08:00
belongs_to :communication_channel
has_many :delayed_messages
attr_accessible :notification, :communication_channel, :frequency, :notification_id, :communication_channel_id
validates_presence_of :communication_channel_id, :frequency
validates_inclusion_of :frequency, in: [Notification::FREQ_IMMEDIATELY,
Notification::FREQ_DAILY,
Notification::FREQ_WEEKLY,
Notification::FREQ_NEVER]
2011-02-01 09:57:29 +08:00
# This is for choosing a policy for another context, so:
# NotificationPolicy.for(notification) or
2011-02-01 09:57:29 +08:00
# communication_channel.notification_policies.for(notification)
scope :for, lambda { |context|
2011-02-01 09:57:29 +08:00
case context
when User
joins(:communication_channel).
where("communication_channels.user_id=? AND communication_channels.workflow_state<>'retired'", context)
2011-02-01 09:57:29 +08:00
when Notification
where(:notification_id => context)
2011-02-01 09:57:29 +08:00
else
scoped
2011-02-01 09:57:29 +08:00
end
}
# TODO: the scope name should be self-explanatory... change this to
# by_frequency or something This is for choosing a policy by frequency
scope :by, lambda { |freq| where(:frequency => Array(freq).map(&:to_s)) }
scope :in_state, lambda { |state| where(:workflow_state => state.to_s) }
2011-02-01 09:57:29 +08:00
def self.spam_blocked_by(user)
NotificationPolicy.where(:communication_channel_id => user.communication_channels.pluck(:id)).delete_all
2011-02-01 09:57:29 +08:00
cc = user.communication_channel
cc.confirm
Notification.all.each do |notification|
if notification.category == "Message"
NotificationPolicy.create(:notification => notification, :communication_channel => cc, :frequency => 'immediately')
2011-02-01 09:57:29 +08:00
else
NotificationPolicy.create(:notification => notification, :communication_channel => cc, :frequency => 'never')
2011-02-01 09:57:29 +08:00
end
end
true
rescue => e
puts e.to_s
false
end
2011-02-01 09:57:29 +08:00
def self.setup_for(user, params)
Update NotificationPolicy setting for all notifications in category. Refs #8066, refs #9643. Fix notification problem where making a 'category' frequency change did not change the settings for all the notification events in the category. Changed notification check box text per product's request. Added new unit-test spec for updating multiple notification settings for the same shared category. Testing notes: ============== Multiple Notifications in the same category should be updated when the category displayed is changed. For instance, "Due Date" has two notifications in that category. One is "Assignment Due Date Changed" and the other is "Assignment Created". There are two different ways to verify this. One is more technical but easier to verify. The other is all UI driven but more complicated. Technical Approach ------------------ * Find all notification IDs in the category "Due Date": id_list = Notification.find_all_by_category('Due Date').map(&:id) * Find the CommunicationChannel for a given email address: channel = CommunicationChannel.find_by_path_and_path_type('jimbo@instructure.com', 'email') * Find the NotificationPolicy entries for the category and channel: channel.notification_policies.scoped(:conditions => {:notification_id => id_list}).all * Make a change to "/profile/communication" settings for "Due Date". * Re-run the last query for listing the 2 NotificationPolicy entries. They should both be updated to have the new frequency. Non-Technical Approach ---------------------- * Make a change to trigger each event in the "Due Date" group. (listed above in Testing Notes). * Verify that changing "Due Date" to a setting like "Daily" and triggering the event that the notification is done as "Daily". * Change the category frequency to something like "ASAP" and trigger the two events in the category and verify that both are respected as "Immediate/ASAP". Change-Id: I9e0473c92206b2ec43ba1c1a6a0ec4c62cdae115 Reviewed-on: https://gerrit.instructure.com/12562 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com>
2012-07-28 05:23:17 +08:00
# Check for user preference settings first. Some communication related options are available on the page.
# Handle those if given.
user_prefs = params[:user]
# If have user preference settings and this is a root account, check further to see if settings can be changed
if user_prefs && params[:root_account]
user_prefs.each_pair do |key, value|
bool_val = (value == 'true')
# save the preference as a symbol (convert from string)
case key.to_sym
when :send_scores_in_emails
# Only set if a root account and the root account allows the setting.
if params[:root_account].settings[:allow_sending_scores_in_emails] != false
user.preferences[:send_scores_in_emails] = bool_val
2011-02-01 09:57:29 +08:00
end
Update NotificationPolicy setting for all notifications in category. Refs #8066, refs #9643. Fix notification problem where making a 'category' frequency change did not change the settings for all the notification events in the category. Changed notification check box text per product's request. Added new unit-test spec for updating multiple notification settings for the same shared category. Testing notes: ============== Multiple Notifications in the same category should be updated when the category displayed is changed. For instance, "Due Date" has two notifications in that category. One is "Assignment Due Date Changed" and the other is "Assignment Created". There are two different ways to verify this. One is more technical but easier to verify. The other is all UI driven but more complicated. Technical Approach ------------------ * Find all notification IDs in the category "Due Date": id_list = Notification.find_all_by_category('Due Date').map(&:id) * Find the CommunicationChannel for a given email address: channel = CommunicationChannel.find_by_path_and_path_type('jimbo@instructure.com', 'email') * Find the NotificationPolicy entries for the category and channel: channel.notification_policies.scoped(:conditions => {:notification_id => id_list}).all * Make a change to "/profile/communication" settings for "Due Date". * Re-run the last query for listing the 2 NotificationPolicy entries. They should both be updated to have the new frequency. Non-Technical Approach ---------------------- * Make a change to trigger each event in the "Due Date" group. (listed above in Testing Notes). * Verify that changing "Due Date" to a setting like "Daily" and triggering the event that the notification is done as "Daily". * Change the category frequency to something like "ASAP" and trigger the two events in the category and verify that both are respected as "Immediate/ASAP". Change-Id: I9e0473c92206b2ec43ba1c1a6a0ec4c62cdae115 Reviewed-on: https://gerrit.instructure.com/12562 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com>
2012-07-28 05:23:17 +08:00
when :no_submission_comments_inbox
user.preferences[:no_submission_comments_inbox] = bool_val
2011-02-01 09:57:29 +08:00
end
end
Update NotificationPolicy setting for all notifications in category. Refs #8066, refs #9643. Fix notification problem where making a 'category' frequency change did not change the settings for all the notification events in the category. Changed notification check box text per product's request. Added new unit-test spec for updating multiple notification settings for the same shared category. Testing notes: ============== Multiple Notifications in the same category should be updated when the category displayed is changed. For instance, "Due Date" has two notifications in that category. One is "Assignment Due Date Changed" and the other is "Assignment Created". There are two different ways to verify this. One is more technical but easier to verify. The other is all UI driven but more complicated. Technical Approach ------------------ * Find all notification IDs in the category "Due Date": id_list = Notification.find_all_by_category('Due Date').map(&:id) * Find the CommunicationChannel for a given email address: channel = CommunicationChannel.find_by_path_and_path_type('jimbo@instructure.com', 'email') * Find the NotificationPolicy entries for the category and channel: channel.notification_policies.scoped(:conditions => {:notification_id => id_list}).all * Make a change to "/profile/communication" settings for "Due Date". * Re-run the last query for listing the 2 NotificationPolicy entries. They should both be updated to have the new frequency. Non-Technical Approach ---------------------- * Make a change to trigger each event in the "Due Date" group. (listed above in Testing Notes). * Verify that changing "Due Date" to a setting like "Daily" and triggering the event that the notification is done as "Daily". * Change the category frequency to something like "ASAP" and trigger the two events in the category and verify that both are respected as "Immediate/ASAP". Change-Id: I9e0473c92206b2ec43ba1c1a6a0ec4c62cdae115 Reviewed-on: https://gerrit.instructure.com/12562 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com>
2012-07-28 05:23:17 +08:00
user.save!
else
# User preference change not being made. Make a notification policy change.
# Using the category name, fetch all Notifications for the category. Will set the desired value on them.
notifications = Notification.all.select { |n| (n.category && n.category.underscore.gsub(/\s/, '_')) == params[:category] }.map(&:id)
frequency = params[:frequency]
Update NotificationPolicy setting for all notifications in category. Refs #8066, refs #9643. Fix notification problem where making a 'category' frequency change did not change the settings for all the notification events in the category. Changed notification check box text per product's request. Added new unit-test spec for updating multiple notification settings for the same shared category. Testing notes: ============== Multiple Notifications in the same category should be updated when the category displayed is changed. For instance, "Due Date" has two notifications in that category. One is "Assignment Due Date Changed" and the other is "Assignment Created". There are two different ways to verify this. One is more technical but easier to verify. The other is all UI driven but more complicated. Technical Approach ------------------ * Find all notification IDs in the category "Due Date": id_list = Notification.find_all_by_category('Due Date').map(&:id) * Find the CommunicationChannel for a given email address: channel = CommunicationChannel.find_by_path_and_path_type('jimbo@instructure.com', 'email') * Find the NotificationPolicy entries for the category and channel: channel.notification_policies.scoped(:conditions => {:notification_id => id_list}).all * Make a change to "/profile/communication" settings for "Due Date". * Re-run the last query for listing the 2 NotificationPolicy entries. They should both be updated to have the new frequency. Non-Technical Approach ---------------------- * Make a change to trigger each event in the "Due Date" group. (listed above in Testing Notes). * Verify that changing "Due Date" to a setting like "Daily" and triggering the event that the notification is done as "Daily". * Change the category frequency to something like "ASAP" and trigger the two events in the category and verify that both are respected as "Immediate/ASAP". Change-Id: I9e0473c92206b2ec43ba1c1a6a0ec4c62cdae115 Reviewed-on: https://gerrit.instructure.com/12562 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com>
2012-07-28 05:23:17 +08:00
# Find any existing NotificationPolicies for the category and the channel. If frequency is 'never', delete the
# entry. If other than that, create or update the entry.
Update NotificationPolicy setting for all notifications in category. Refs #8066, refs #9643. Fix notification problem where making a 'category' frequency change did not change the settings for all the notification events in the category. Changed notification check box text per product's request. Added new unit-test spec for updating multiple notification settings for the same shared category. Testing notes: ============== Multiple Notifications in the same category should be updated when the category displayed is changed. For instance, "Due Date" has two notifications in that category. One is "Assignment Due Date Changed" and the other is "Assignment Created". There are two different ways to verify this. One is more technical but easier to verify. The other is all UI driven but more complicated. Technical Approach ------------------ * Find all notification IDs in the category "Due Date": id_list = Notification.find_all_by_category('Due Date').map(&:id) * Find the CommunicationChannel for a given email address: channel = CommunicationChannel.find_by_path_and_path_type('jimbo@instructure.com', 'email') * Find the NotificationPolicy entries for the category and channel: channel.notification_policies.scoped(:conditions => {:notification_id => id_list}).all * Make a change to "/profile/communication" settings for "Due Date". * Re-run the last query for listing the 2 NotificationPolicy entries. They should both be updated to have the new frequency. Non-Technical Approach ---------------------- * Make a change to trigger each event in the "Due Date" group. (listed above in Testing Notes). * Verify that changing "Due Date" to a setting like "Daily" and triggering the event that the notification is done as "Daily". * Change the category frequency to something like "ASAP" and trigger the two events in the category and verify that both are respected as "Immediate/ASAP". Change-Id: I9e0473c92206b2ec43ba1c1a6a0ec4c62cdae115 Reviewed-on: https://gerrit.instructure.com/12562 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com>
2012-07-28 05:23:17 +08:00
NotificationPolicy.transaction do
notifications.each do |notification_id|
scope = user.notification_policies.
where(communication_channel_id: params[:channel_id], notification_id: notification_id)
p = scope.first_or_initialize
# Set the frequency and save
p.frequency = frequency
p.save!
Update NotificationPolicy setting for all notifications in category. Refs #8066, refs #9643. Fix notification problem where making a 'category' frequency change did not change the settings for all the notification events in the category. Changed notification check box text per product's request. Added new unit-test spec for updating multiple notification settings for the same shared category. Testing notes: ============== Multiple Notifications in the same category should be updated when the category displayed is changed. For instance, "Due Date" has two notifications in that category. One is "Assignment Due Date Changed" and the other is "Assignment Created". There are two different ways to verify this. One is more technical but easier to verify. The other is all UI driven but more complicated. Technical Approach ------------------ * Find all notification IDs in the category "Due Date": id_list = Notification.find_all_by_category('Due Date').map(&:id) * Find the CommunicationChannel for a given email address: channel = CommunicationChannel.find_by_path_and_path_type('jimbo@instructure.com', 'email') * Find the NotificationPolicy entries for the category and channel: channel.notification_policies.scoped(:conditions => {:notification_id => id_list}).all * Make a change to "/profile/communication" settings for "Due Date". * Re-run the last query for listing the 2 NotificationPolicy entries. They should both be updated to have the new frequency. Non-Technical Approach ---------------------- * Make a change to trigger each event in the "Due Date" group. (listed above in Testing Notes). * Verify that changing "Due Date" to a setting like "Daily" and triggering the event that the notification is done as "Daily". * Change the category frequency to something like "ASAP" and trigger the two events in the category and verify that both are respected as "Immediate/ASAP". Change-Id: I9e0473c92206b2ec43ba1c1a6a0ec4c62cdae115 Reviewed-on: https://gerrit.instructure.com/12562 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Jon Jensen <jon@instructure.com>
2012-07-28 05:23:17 +08:00
end
end # transaction
end #if..else
nil
2011-02-01 09:57:29 +08:00
end
# Fetch the user's NotificationPolicies but whenever a category is not
# represented, create a NotificationPolicy on the primary
# CommunicationChannel with a default frequency set.
# Returns the full list of policies for the user
#
# ===== Arguments
# * <tt>user</tt> - The User instance to load the values for.
# * <tt>full_category_list</tt> - An array of Notification models that
# represent the unique list of categories that should be displayed for the
# user.
#
# ===== Returns
# A list of NotificationPolicy entries for the user. May include newly
# created entries if defaults were needed.
def self.setup_with_default_policies(user, full_category_list)
if user.communication_channel
user.communication_channel.user = user
find_all_for(user.communication_channel)
end
# Load and return user's policies after defaults may or may not have been set.
# TODO: Don't load policies for retired channels
NotificationPolicy.includes(:notification).for(user)
end
# Finds the current policy for a given communication channel, or creates it (with default)
# and/or updates it
def self.find_or_update_for(communication_channel, notification_name, frequency = nil)
notification_name = notification_name.titleize
notification = BroadcastPolicy.notification_finder.by_name(notification_name)
raise ActiveRecord::RecordNotFound unless notification
communication_channel.shard.activate do
unique_constraint_retry do
np = communication_channel.notification_policies.where(notification_id: notification).first
if !np
np = communication_channel.notification_policies.build(notification: notification)
frequency ||= begin
if communication_channel == communication_channel.user.communication_channel
notification.default_frequency(communication_channel.user)
else
'never'
end
end
end
if frequency
np.frequency = frequency
np.save!
end
np
end
end
end
def self.find_all_for(communication_channel)
communication_channel.shard.activate do
policies = communication_channel.notification_policies.all
Notification.all.each do |notification|
next if policies.find { |p| p.notification_id == notification.id }
NotificationPolicy.transaction(requires_new: true) do
np = nil
begin
np = communication_channel.notification_policies.build(notification: notification)
np.frequency = if communication_channel == communication_channel.user.communication_channel
notification.default_frequency(communication_channel.user)
else
'never'
end
np.save!
rescue ActiveRecord::RecordNotUnique
np = nil
raise ActiveRecord::Rollback
end
np ||= communication_channel.notification_policies.where(notification_id: notification).first
policies << np
end
end
policies
end
end
2011-02-01 09:57:29 +08:00
end