normalize user_id out of notification_policies

fixes #6585, #7096

by normalizing, it's impossible to not maintain a column that isn't
there (yes, triple negative is intended in that sentence), thus
preventing sending notifications to the wrong user after a merge
or any other bugs that would have missing maintaining the
denormalization.

test plan:
 * test notifications in general
 * merge two active users together - their notification preferences
   should survive the merge

Change-Id: I239d810c5499b94550b65128cac71c42cedd11ba
Reviewed-on: https://gerrit.instructure.com/8013
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
This commit is contained in:
Cody Cutrer 2012-01-11 14:22:50 -07:00
parent 9096efcf94
commit bc48b1ef34
20 changed files with 78 additions and 95 deletions

View File

@ -25,15 +25,14 @@ class FacebookController < ApplicationController
def notification_preferences
@cc = @user.communication_channels.find_by_path_type('facebook')
if @cc
@old_policies = @user.notification_policies.for_channel(@cc)
@old_policies = @cc.notification_policies
@policies = []
params[:types].each do |type, frequency|
notifications = Notification.find_all_by_category(type)
notifications.each do |notification|
pref = @user.notification_policies.new
pref = @cc.notification_policies.new
pref.notification_id = notification.id
pref.frequency = frequency
pref.communication_channel_id = @cc.id
@policies << pref unless frequency == 'never'
end
end
@ -44,7 +43,7 @@ class FacebookController < ApplicationController
end
# TODO: i18n... see notification.rb
@notification_categories = Notification.dashboard_categories.reject{|c| c.category == "Summaries"}
@policies = @user.notification_policies.for_channel(@cc)
@policies = @cc.notification_policies
redirect_to facebook_settings_url
end
@ -74,7 +73,7 @@ class FacebookController < ApplicationController
def settings
@notification_categories = Notification.dashboard_categories
@cc = @user && @user.communication_channels.find_by_path_type('facebook')
@policies = @user && @user.notification_policies.for_channel(@cc)
@policies = @cc.try(:notification_policies)
respond_to do |format|
format.html { render :action => 'settings', :layout => 'facebook' }
end

View File

@ -105,28 +105,31 @@ class ProfileController < ApplicationController
@channels = @user.communication_channels.unretired
@current_user.used_feature(:cc_prefs)
@notification_categories = Notification.dashboard_categories(@user)
@policies = @user.notification_policies
@policies = NotificationPolicy.for(@user).scoped(:include => [:communication_channel, :notification]).to_a
@context = UserProfile.new(@user)
@active_tab = "communication-preferences"
# build placeholder notification policies for categories the user does not have policies for already
# Note that currently a NotificationPolicy might not have a Notification attached to it.
# See the relevant spec in profile_controller_spec.rb for more details.
user_categories = @user.notification_policies.map {|np| np.notification.try(:category) }
user_categories = @policies.map {|np| np.notification.try(:category) }
@notification_categories.each do |category|
# category is actually a Notification
next if user_categories.include?(category.category)
policy = @user.notification_policies.build
policy = @user.communication_channel.notification_policies.build
policy.notification = category
policy.frequency = category.default_frequency
policy.communication_channel = @user.communication_channel
policy.save!
@policies << policy
end
has_facebook_installed = !@current_user.user_services.for_service('facebook').empty?
@policies = @policies.select{|p| (p.communication_channel && p.communication_channel.path_type != 'facebook') || has_facebook_installed }
has_twitter_installed = !@current_user.user_services.for_service('twitter').empty?
@email_channels = @channels.select{|c| c.path_type == "email"}
@sms_channels = @channels.select{|c| c.path_type == 'sms'}
@other_channels = @channels.select{|c| c.path_type != "email"}
@other_channels.reject! { |c| c.path_type == 'facebook' } unless has_facebook_installed
@other_channels.reject! { |c| c.path_type == 'twitter' } unless has_twitter_installed
end
def profile_pics

View File

@ -203,7 +203,7 @@ class CommunicationChannel < ActiveRecord::Base
policy_matches_frequency = {}
policy_for_channel = {}
can_notify = {}
user.notification_policies.select{|p| p.notification_id == notification.id}.each do |policy|
NotificationPolicy.for(user).for(notification).each do |policy|
policy_matches_frequency[policy.communication_channel_id] = true if policy.frequency == frequency
policy_for_channel[policy.communication_channel_id] = true
can_notify[policy.communication_channel_id] = false if policy.frequency == 'never'

View File

@ -56,7 +56,6 @@ class Notification < ActiveRecord::Base
has_many :messages
has_many :notification_policies, :dependent => :destroy
has_many :users, :through => :notification_policies
before_save :infer_default_content
attr_accessible :name, :subject, :body, :sms_body, :main_link, :delay_for, :category
@ -96,15 +95,15 @@ class Notification < ActiveRecord::Base
asset = opts[:asset] || raise(ArgumentError, "Must provide an asset")
policies = user.notification_policies.select{|p| p.notification_id == self.id && p.communication_channel_id}
policies << NotificationPolicy.create(:notification => self, :user => user, :communication_channel => cc, :frequency => self.default_frequency) if policies.empty? && cc && cc.active?
policies = NotificationPolicy.for(user).for(self).to_a
policies << NotificationPolicy.create(:notification => self, :communication_channel => cc, :frequency => self.default_frequency) if policies.empty? && cc && cc.active?
policies = policies.select{|p| [:daily,:weekly].include?(p.frequency.to_sym) }
# If we pass in a fallback_channel, that means this message has been
# throttled, so it definitely needs to go to at least one communication
# channel with 'daily' as the frequency.
if !policies.any?{|p| p.frequency == 'daily'} && opts[:fallback_channel]
policies << NotificationPolicy.new(:user => user, :communication_channel => opts[:fallback_channel], :frequency => 'daily')
policies << NotificationPolicy.new(:communication_channel => opts[:fallback_channel], :frequency => 'daily')
end
return false if (!opts[:fallback_channel] && cc && !cc.active?) || policies.empty? || self.registration?
@ -162,7 +161,7 @@ class Notification < ActiveRecord::Base
end
end
recipients += User.find(:all, :conditions => {:id => recipient_ids}, :include => [:communication_channels, :notification_policies])
recipients += User.find(:all, :conditions => {:id => recipient_ids}, :include => { :communication_channels => :notification_policies})
# Cancel any that haven't been sent out for the same purpose
all_matching_messages = self.messages.for(asset).by_name(name).for_user(recipients).in_state([:created,:staged,:sending,:dashboard])

View File

@ -19,25 +19,23 @@
class NotificationPolicy < ActiveRecord::Base
belongs_to :notification
belongs_to :user
belongs_to :communication_channel
before_save :infer_frequency
attr_accessible :notification, :user, :communication_channel, :frequency, :notification_id, :user_id, :communication_channel_id
attr_accessible :notification, :communication_channel, :frequency, :notification_id, :communication_channel_id
validates_presence_of :communication_channel_id
# This is for choosing a policy for another context, so:
# user.notification_policies.for(notification) or
# user.notification_policies.for(communication_channel) or
# NotificationPolicy.for(notification) or
# communication_channel.notification_policies.for(notification)
named_scope :for, lambda { |context|
case context
when User
{ :conditions => ['notification_policies.user_id = ?', context.id] }
{ :joins => :communication_channel, :conditions => { 'communication_channels.user_id' => context.id } }
when Notification
{ :conditions => ['notification_policies.notification_id = ?', context.id] }
when CommunicationChannel
{ :conditions => ['notification_policies.communication_channel_id = ?', context.id] }
else
{}
end
@ -57,8 +55,7 @@ class NotificationPolicy < ActiveRecord::Base
named_scope :where, lambda { |where| { :include => [:communication_channel], :conditions => where } }
named_scope :in_state, lambda { |state| { :conditions => ["notification_policies.workflow_state = ?", state.to_s] } }
named_scope :for_channel, lambda { |channel| { :conditions => ['notification_policies.communication_channel_id = ?', channel.id] } }
def infer_frequency
self.frequency ||= "immediately"
end
@ -70,14 +67,14 @@ class NotificationPolicy < ActiveRecord::Base
end
def self.spam_blocked_by(user)
NotificationPolicy.delete_all({:user_id => user.id})
NotificationPolicy.delete_all({:communication_channel_id => user.communication_channels.map(&:id)})
cc = user.communication_channel
cc.confirm
Notification.all.each do |notification|
if notification.category == "Message"
NotificationPolicy.create(:notification => notification, :user => user, :communication_channel => cc, :frequency => 'immediately')
NotificationPolicy.create(:notification => notification, :communication_channel => cc, :frequency => 'immediately')
else
NotificationPolicy.create(:notification => notification, :user => user, :communication_channel => cc, :frequency => 'never')
NotificationPolicy.create(:notification => notification, :communication_channel => cc, :frequency => 'never')
end
end
true
@ -88,7 +85,7 @@ class NotificationPolicy < ActiveRecord::Base
def self.refresh_for(user)
categories = Notification.dashboard_categories
policies = user.notification_policies.to_a
policies = NotificationPolicy.for(user).to_a
params = {}
categories.each do |category|
ps = policies.select{|p| p.notification_id == category.id }
@ -107,7 +104,6 @@ class NotificationPolicy < ActiveRecord::Base
params[:user] && params[:user][:send_scores_in_emails] == '1'
params[:user].try(:delete, :send_scores_in_emails)
@user.update_attributes(params[:user])
@old_policies = @user.notification_policies
@channels = @user.communication_channels
categories = Notification.dashboard_categories
prefs_to_save = []
@ -134,22 +130,21 @@ class NotificationPolicy < ActiveRecord::Base
end
channels.uniq.each do |channel|
frequency = category_data["channel_#{channel.id}".to_sym] || 'never'
pref = @user.notification_policies.new
pref = channel.notification_policies.new
pref.notification_id = notification.id
pref.frequency = frequency
pref.communication_channel_id = channel.id
prefs_to_save << pref
end
end
end
end
NotificationPolicy.transaction do
NotificationPolicy.connection.execute("DELETE FROM notification_policies WHERE id IN (#{@old_policies.map(&:id).join(',')})") unless @old_policies.empty?
NotificationPolicy.transaction do
NotificationPolicy.delete_all({:communication_channel_id => user.communication_channels.map(&:id)})
prefs_to_save.each{|p| p.save! }
end
categories = Notification.dashboard_categories
@user.reload
@policies = @user.notification_policies.select{|p| categories.include?(p.notification)}
@policies = NotificationPolicy.for(@user).scoped(:conditions => { :notification_id => categories.map(&:id)})
@policies
end
end

View File

@ -77,10 +77,8 @@ class User < ActiveRecord::Base
has_many :active_folders_detailed, :class_name => 'Folder', :as => :context, :include => [:active_sub_folders, :active_file_attachments], :conditions => ['folders.workflow_state != ?', 'deleted'], :order => 'folders.name'
has_many :calendar_events, :as => 'context', :dependent => :destroy, :include => [:parent_event]
has_many :eportfolios, :dependent => :destroy
has_many :notifications, :through => :notification_policies
has_many :quiz_submissions, :dependent => :destroy
has_many :dashboard_messages, :class_name => 'Message', :conditions => {:to => "dashboard", :workflow_state => 'dashboard'}, :order => 'created_at DESC', :dependent => :destroy
has_many :notification_policies, :include => :communication_channel, :dependent => :destroy
has_many :collaborations, :order => 'created_at DESC'
has_many :user_services, :order => 'created_at', :dependent => :destroy
has_one :scribd_account, :as => :scribdable

View File

@ -11,7 +11,7 @@
<div style="clear: left; margin-bottom: 5px;"></div>
<% if @messages.blank? %>
<b><%= t :all_set, "You're all set up!" %></b>
<% if @user.notification_policies.any?{|p| p.communication_channel.path_type == 'facebook' } %>
<% if NotificationPolicy.for(@user).find(:first, :conditions => {'communication_channels.path_type' => 'facebook' }) %>
<%= t :no_messages_notice, "As things happen in the course you'll start seeing notifications show up here letting you know about things happening in your Canvas account." %>
<% else %>
<%= t :configure_notification_preferences_notice, "After you *configure your notification preferences* you should start to see notifications show up here letting you know about things happening in your Canvas account.", :wrapper => '<a href="#{Facebook.app_url}/settings">\1</a>' %>

View File

@ -1,17 +1,3 @@
<% list ||= []
if list.empty?
list << NotificationPolicy.new(:frequency => "never", :communication_channel => @user.communication_channel)
end
found = {}
list = list.select do |policy|
if !found[[policy.communication_channel_id, policy.frequency]]
true
else
false
end
end
list.compact!
%>
<tr>
<td colspan="7" class="notification_type">
<%= notification_preference.category_description %>

View File

@ -26,6 +26,7 @@ class ActiveRecord::Base
'enrollment_terms' => %w(sis_data sis_name),
'enrollments' => %w(invitation_email),
'groups' => %w(sis_name),
'notification_policies' => %w(user_id),
'pseudonyms' => %w(sis_update_data deleted_unique_id sis_source_id),
'role_overrides' => %w(context_code),
'users' => %w(type creation_unique_id creation_sis_batch_id creation_email sis_name),

View File

@ -0,0 +1,10 @@
class RemoveUserIdFromNotificationPolicy < ActiveRecord::Migration
def self.up
remove_column :notification_policies, :user_id
end
def self.down
add_column :notification_policies, :user_id, :integer, :limit => 8
NotificationPolicy.update_all('user_id=(SELECT user_id FROM communication_channels WHERE communication_channels.id=communication_channel_id)')
end
end

View File

@ -58,7 +58,7 @@ describe ProfileController do
user_model
user_session(@user)
cc = @user.communication_channels.create!(:path => 'user@example.com', :path_type => 'email') { |cc| cc.workflow_state = 'active' }
@user.notification_policies.create!(:notification => nil, :communication_channel => cc, :frequency => 'daily')
cc.notification_policies.create!(:notification => nil, :frequency => 'daily')
get 'communication'
response.should be_success

View File

@ -24,7 +24,6 @@ end
def notification_policy_valid_attributes
{
:notification_id => 1,
:user_id => 1,
:communication_channel_id => 1
}
end

View File

@ -37,9 +37,9 @@ describe CommunicationChannel do
c = communication_channel_model(:user_id => @user.id, :workflow_state => 'active', :path => "path3@example.com")
d = communication_channel_model(:user_id => @user.id, :path => "path4@example.com")
notification_model
notification_policy_model(:communication_channel_id => a.id, :notification_id => @notification.id, :user_id => @user.id )
notification_policy_model(:communication_channel_id => b.id, :notification_id => @notification.id, :user_id => @user.id )
notification_policy_model(:communication_channel_id => c.id, :notification_id => @notification.id, :user_id => @user.id )
notification_policy_model(:communication_channel_id => a.id, :notification_id => @notification.id )
notification_policy_model(:communication_channel_id => b.id, :notification_id => @notification.id )
notification_policy_model(:communication_channel_id => c.id, :notification_id => @notification.id )
@user.reload
channels = CommunicationChannel.find_all_for(@user, @notification)
channels.should include(a)
@ -53,8 +53,8 @@ describe CommunicationChannel do
a = communication_channel_model(:user_id => @user.id, :workflow_state => 'active')
d = communication_channel_model(:user_id => @user.id, :path => "path4@example.com")
notification_model
notification_policy_model(:communication_channel_id => a.id, :notification_id => @notification.id, :user_id => @user.id )
notification_policy_model(:communication_channel_id => d.id, :notification_id => @notification.id, :user_id => @user.id )
notification_policy_model(:communication_channel_id => a.id, :notification_id => @notification.id )
notification_policy_model(:communication_channel_id => d.id, :notification_id => @notification.id )
@user.reload
channels = CommunicationChannel.find_all_for(@user, @notification)
channels.should include(a)
@ -70,7 +70,7 @@ describe CommunicationChannel do
a.should
@n = Notification.create(:name => "New Notification")
@u.notification_policies.create(:communication_channel => a, :notification => @n)
a.notification_policies.create!(:notification => @n)
channels = CommunicationChannel.find_all_for(@u, @n)
channels.should eql([@u.communication_channel])
end
@ -106,7 +106,7 @@ describe CommunicationChannel do
channels.should include(a)
channels.should_not include(b)
@user.notification_policies.create!(:communication_channel => b, :notification => @n, :frequency => 'immediately')
b.notification_policies.create!(:notification => @n, :frequency => 'immediately')
channels = CommunicationChannel.find_all_for(@user, @n)
channels.should include(b)
channels.should_not include(a)
@ -117,7 +117,7 @@ describe CommunicationChannel do
a = @user.communication_channels.create(:path => "a@example.com")
a.confirm!
@n = Notification.create!(:name => "New notification")
@user.notification_policies.create!(:communication_channel => a, :notification => @n, :frequency => 'daily')
a.notification_policies.create!(:notification => @n, :frequency => 'daily')
channels = CommunicationChannel.find_all_for(@user, @n)
channels.should be_empty
end

View File

@ -42,7 +42,7 @@ describe NotificationPolicy do
@default_cc.confirm!
@cc = @student.communication_channels.create(:path => "secondary@example.com")
@cc.confirm!
@policy = NotificationPolicy.create(:user => @student, :notification => @notif, :communication_channel => @cc, :frequency => "immediately")
@policy = NotificationPolicy.create(:notification => @notif, :communication_channel => @cc, :frequency => "immediately")
@assignment.publish!
@assignment.messages_sent.should be_include("Assignment Graded")
m = @assignment.messages_sent["Assignment Graded"].find{|m| m.to == "default@example.com"}
@ -56,7 +56,7 @@ describe NotificationPolicy do
@assignment.unpublish!
@cc = @student.communication_channels.create(:path => "secondary@example.com")
@cc.confirm!
@policy = NotificationPolicy.create(:user => @student, :notification => @notif, :communication_channel => @cc, :frequency => "never")
@policy = NotificationPolicy.create(:notification => @notif, :communication_channel => @cc, :frequency => "never")
@assignment.previously_published = false
@assignment.save
@assignment.publish!
@ -68,23 +68,17 @@ describe NotificationPolicy do
context "named scopes" do
it "should have a named scope for users" do
user_model
notification_policy_model(:user_id => @user.id)
user_with_pseudonym(:active_all => 1)
notification_policy_model(:communication_channel_id => @cc.id)
NotificationPolicy.for(@user).should eql([@notification_policy])
end
it "should have a named scope for notifications" do
notification_model
notification_policy_model(:notification_id => @notification.id)
NotificationPolicy.for(@notification).should eql([@notification_policy])
end
it "should have a named scope for communication_channels" do
communication_channel_model
notification_policy_model(:communication_channel_id => @communication_channel.id)
NotificationPolicy.for(@communication_channel).should eql([@notification_policy])
end
it "should not slow down from other kinds of input on the *for* named scope" do
notification_policy_model
NotificationPolicy.for(:anything_else).should eql(NotificationPolicy.all)
@ -111,16 +105,16 @@ describe NotificationPolicy do
end
it "should be able to combine an array of frequencies with a for scope" do
user_model
user_with_pseudonym(:active_all => 1)
n1 = notification_policy_model(
:user_id => @user.id,
:communication_channel => @cc,
:frequency => 'daily'
)
n2 = notification_policy_model(
:user_id => @user.id,
:communication_channel => @cc,
:frequency => 'weekly'
)
n3 = notification_policy_model(:user_id => @user.id)
n3 = notification_policy_model(:communication_channel => @cc)
NotificationPolicy.for(@user).by([:daily, :weekly]).should be_include(n1)
NotificationPolicy.for(@user).by([:daily, :weekly]).should be_include(n2)
NotificationPolicy.for(@user).by([:daily, :weekly]).should_not be_include(n3)
@ -135,8 +129,7 @@ describe NotificationPolicy do
NotificationPolicy.delete_all
trifecta_opts = {
:user_id => @user.id,
:communication_channel_id => @communication_channel.id,
:communication_channel_id => @communication_channel.id,
:notification_id => @notification.id
}

View File

@ -228,7 +228,7 @@ describe Notification do
it "should not use notification policies for unconfirmed communication channels" do
notification_set
cc = communication_channel_model(:user_id => @user.id, :workflow_state => 'unconfirmed', :path => "nope")
notification_policy_model(:communication_channel_id => cc.id, :notification_id => @notification.id, :user_id => @user.id )
notification_policy_model(:communication_channel_id => cc.id, :notification_id => @notification.id)
messages = @notification.create_message(@assignment, @user)
messages.size.should == 2
messages.map(&:to).sort.should == ['dashboard', 'value for path']
@ -242,7 +242,9 @@ describe Notification do
@cc.confirm
notification_model
# Universal context
old_user = @user
assignment_model
@user = old_user
@valid_record_delayed_messages_opts = {
:user => @user,
:communication_channel => @cc,
@ -276,8 +278,7 @@ describe Notification do
NotificationPolicy.delete_all
@trifecta_opts = {
:user_id => @user.id,
:communication_channel_id => @communication_channel.id,
:communication_channel_id => @communication_channel.id,
:notification_id => @notification.id
}
end
@ -352,7 +353,6 @@ def notification_set(opts={})
communication_channel_model(:user_id => @user).confirm!
notification_policy_model(
:notification_id => @notification.id,
:user_id => @user.id,
:communication_channel_id => @communication_channel.id
)
@notification.reload

View File

@ -22,7 +22,7 @@ describe WikiPage do
it "should send page updated notifications" do
course_with_teacher(:active_all => true)
n = Notification.create(:name => "Updated Wiki Page", :category => "TestImmediately")
NotificationPolicy.create(:notification => n, :communication_channel => @user.communication_channel, :user => @user, :frequency => "immediately")
NotificationPolicy.create(:notification => n, :communication_channel => @user.communication_channel, :frequency => "immediately")
p = @course.wiki.wiki_pages.create(:title => "some page")
p.created_at = 3.days.ago
p.notify_of_update = true

View File

@ -104,9 +104,9 @@ describe "profile" do
daily_select.click
daily_select.find_element(:xpath, '..').should have_class('selected_pending')
#change notification setting for second notification
never_select = content_tbody.find_element(:css, 'tr:nth-child(3) > td:nth-child(5) > div')
never_select.click
never_select.find_element(:xpath, '..').should have_class('selected_pending')
weekly_select = content_tbody.find_element(:css, 'tr:nth-child(3) > td:nth-child(4) > div')
weekly_select.click
weekly_select.find_element(:xpath, '..').should have_class('selected_pending')
driver.find_element(:css, '#content .save_preferences_button').click
wait_for_ajax_requests
refresh_page
@ -118,7 +118,7 @@ describe "profile" do
# the daily
row.find_element(:css, 'td > span > select > option:checked').text.should == @user.email
else
# the never
# the weekly
row.find_element(:css, 'td > span > select > option:checked').text.should == second_email
end
end
@ -290,8 +290,8 @@ describe "profile" do
end
it "should show the correct defaults for the rest of the policies when at least one is set" do
@user.notification_policies.create!(:notification => @immediate, :communication_channel => @user.email_channel, :frequency => "immediately")
@user.notification_policies.create!(:notification => @daily, :communication_channel => @user.email_channel, :frequency => "immediately")
@user.email_channel.notification_policies.create!(:notification => @immediate, :frequency => "immediately")
@user.email_channel.notification_policies.create!(:notification => @daily, :frequency => "immediately")
get "/profile/communication"

View File

@ -26,7 +26,7 @@ describe "/profile/_notification_preference" do
assigns[:user] = @user
n = Notification.create!
cc = @user.communication_channels.create!(:path => 'user@example.com')
pref = @user.notification_policies.create!(:notification => n, :communication_channel => cc)
pref = cc.notification_policies.create!(:notification => n)
assigns[:notification_preference] = pref
assigns[:email_channels] = []
assigns[:other_channels] = []

View File

@ -28,7 +28,7 @@ describe "/profile/communication" do
assigns[:other_channels] = []
assigns[:sms_channels] = []
assigns[:notification_categories] = Notification.dashboard_categories
assigns[:policies] = @user.notification_policies
assigns[:policies] = NotificationPolicy.for(@user)
assigns[:user] = @user
render "profile/communication"
response.should_not be_nil

View File

@ -29,7 +29,7 @@ describe "/profile/profile" do
assigns[:other_channels] = []
assigns[:sms_channels] = []
assigns[:notification_categories] = Notification.dashboard_categories
assigns[:policies] = @user.notification_policies
assigns[:policies] = NotificationPolicy.for(@user)
assigns[:default_pseudonym] = @user.pseudonyms.create!(:unique_id => "unique@example.com", :password => "asdfaa", :password_confirmation => "asdfaa")
assigns[:pseudonyms] = @user.pseudonyms
assigns[:password_pseudonyms] = []
@ -46,7 +46,7 @@ describe "/profile/profile" do
assigns[:other_channels] = []
assigns[:sms_channels] = []
assigns[:notification_categories] = Notification.dashboard_categories
assigns[:policies] = @user.notification_policies
assigns[:policies] = NotificationPolicy.for(@user)
default_pseudonym = assigns[:default_pseudonym] = @user.pseudonyms.create!(:unique_id => "unique@example.com", :password => "asdfaa", :password_confirmation => "asdfaa")
sis_pseudonym = @user.pseudonyms.create!(:unique_id => 'sis_unique@example.com') { |p| p.sis_user_id = 'sis_id' }
assigns[:pseudonyms] = @user.pseudonyms