197 lines
8.1 KiB
Ruby
197 lines
8.1 KiB
Ruby
#
|
|
# 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
|
|
belongs_to :communication_channel
|
|
has_many :delayed_messages, :dependent => :destroy
|
|
|
|
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]
|
|
|
|
# This is for choosing a policy for another context, so:
|
|
# NotificationPolicy.for(notification) or
|
|
# communication_channel.notification_policies.for(notification)
|
|
scope :for, lambda { |context|
|
|
case context
|
|
when User
|
|
joins(:communication_channel).
|
|
where("communication_channels.user_id=? AND communication_channels.workflow_state<>'retired'", context)
|
|
when Notification
|
|
where(:notification_id => context)
|
|
else
|
|
all
|
|
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) }
|
|
|
|
def self.setup_for(user, params)
|
|
# 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
|
|
end
|
|
when :no_submission_comments_inbox
|
|
user.preferences[:no_submission_comments_inbox] = bool_val
|
|
end
|
|
end
|
|
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_cached.select { |n| (n.category && n.category.underscore.gsub(/\s/, '_')) == params[:category] }.map(&:id)
|
|
frequency = params[:frequency]
|
|
cc = user.communication_channels.find(params[:channel_id])
|
|
|
|
# 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.
|
|
NotificationPolicy.transaction do
|
|
notifications.each do |notification_id|
|
|
scope = user.notification_policies.
|
|
where(communication_channel_id: cc, notification_id: notification_id)
|
|
p = scope.first_or_initialize
|
|
# Set the frequency and save
|
|
p.frequency = frequency
|
|
p.save!
|
|
end
|
|
end # transaction
|
|
end #if..else
|
|
nil
|
|
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.preload(:notification).for(user)
|
|
end
|
|
|
|
# Updates notification policies for a given category in a given communication channel
|
|
def self.find_or_update_for_category(communication_channel, category, frequency = nil)
|
|
notifs = Notification.where("category = ?", category)
|
|
raise ActiveRecord::RecordNotFound unless notifs.exists?
|
|
notifs.map do |notif|
|
|
NotificationPolicy.find_or_update_for(communication_channel, notif.name, frequency)
|
|
end
|
|
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
|
|
|
|
# frequencies is an optional hash; key is notification_name (underscore)
|
|
def self.find_all_for(communication_channel, frequencies = {})
|
|
frequencies = Hash[frequencies.map { |name, frequency| [BroadcastPolicy.notification_finder.by_name(name.titleize), frequency] }]
|
|
communication_channel.shard.activate do
|
|
policies = communication_channel.notification_policies.to_a
|
|
Notification.all_cached.each do |notification|
|
|
policy = policies.find { |p| p.notification_id == notification.id }
|
|
if policy
|
|
if frequencies[notification]
|
|
policy.frequency = frequencies[policy.notification]
|
|
policy.save! if policy.changed?
|
|
end
|
|
next
|
|
end
|
|
np = nil
|
|
NotificationPolicy.transaction(requires_new: true) do
|
|
begin
|
|
np = communication_channel.notification_policies.build(notification: notification)
|
|
np.frequency = if frequencies[notification]
|
|
frequencies[notification]
|
|
elsif 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
|
|
end
|
|
np ||= communication_channel.notification_policies.where(notification_id: notification).first
|
|
policies << np
|
|
end
|
|
policies
|
|
end
|
|
end
|
|
end
|