|
1 | 1 | class AccountNotification < ActiveRecord::Base |
2 | 2 | attr_accessible :subject, :icon, :message, |
3 | | - :account, :user, :start_at, :end_at |
| 3 | + :account, :user, :start_at, :end_at, |
| 4 | + :required_account_service, :months_in_display_cycle |
4 | 5 |
|
5 | 6 | validates_presence_of :start_at, :end_at, :account_id |
6 | 7 | before_validation :infer_defaults |
7 | 8 | belongs_to :account, :touch => true |
8 | 9 | belongs_to :user |
9 | 10 | validates_length_of :message, :maximum => maximum_text_length, :allow_nil => false, :allow_blank => false |
10 | 11 | sanitize_field :message, Instructure::SanitizeField::SANITIZE |
11 | | - |
| 12 | + |
| 13 | + ACCOUNT_SERVICE_NOTIFICATION_FLAGS = %w[account_survey_notifications] |
| 14 | + validates_inclusion_of :required_account_service, in: ACCOUNT_SERVICE_NOTIFICATION_FLAGS, allow_nil: true |
| 15 | + |
| 16 | + validates_inclusion_of :months_in_display_cycle, in: 1..48, allow_nil: true |
| 17 | + |
12 | 18 | def infer_defaults |
13 | 19 | self.start_at ||= Time.now.utc |
14 | 20 | self.end_at ||= self.start_at + 2.weeks |
15 | 21 | self.end_at = [self.end_at, self.start_at].max |
16 | 22 | end |
17 | 23 |
|
18 | 24 | def self.for_user_and_account(user, account) |
19 | | - closed_ids = user.preferences[:closed_notifications] || [] |
20 | | - now = Time.now.utc |
21 | | - # Refreshes every 10 minutes at the longest |
22 | | - current = Rails.cache.fetch(['account_notifications2', account].cache_key, :expires_in => 10.minutes) do |
23 | | - Shard.partition_by_shard([Account.site_admin, account]) do |accounts| |
24 | | - AccountNotification.where("account_id IN (?) AND start_at <? AND end_at>?", accounts, now, now).order('start_at DESC').all |
25 | | - end |
26 | | - end |
| 25 | + current = self.for_account(account) |
27 | 26 |
|
28 | 27 | user.shard.activate do |
| 28 | + closed_ids = user.preferences[:closed_notifications] || [] |
29 | 29 | # If there are ids marked as 'closed' that are no longer |
30 | 30 | # applicable, they probably need to be cleared out. |
31 | 31 | current_ids = current.map(&:id) |
32 | 32 | if !(closed_ids - current_ids).empty? |
33 | 33 | closed_ids = user.preferences[:closed_notifications] &= current_ids |
34 | 34 | user.save! |
35 | 35 | end |
36 | | - current.reject { |announcement| closed_ids.include?(announcement.id) } |
| 36 | + current.reject! { |announcement| closed_ids.include?(announcement.id) } |
| 37 | + |
| 38 | + # filter out announcements that have a periodic cycle of display, |
| 39 | + # and the user isn't in the set of users to display it to this month (based |
| 40 | + # on user id) |
| 41 | + current.reject! do |announcement| |
| 42 | + if months_in_period = announcement.months_in_display_cycle |
| 43 | + !self.display_for_user?(user.id, months_in_period) |
| 44 | + end |
| 45 | + end |
37 | 46 | end |
| 47 | + |
| 48 | + current |
| 49 | + end |
| 50 | + |
| 51 | + def self.for_account(account) |
| 52 | + # Refreshes every 10 minutes at the longest |
| 53 | + Rails.cache.fetch(['account_notifications2', account].cache_key, :expires_in => 10.minutes) do |
| 54 | + now = Time.now.utc |
| 55 | + # we always check the given account for the flag, even if the announcement is from the site_admin account |
| 56 | + # this allows us to make a global announcement that is filtered to only accounts with this flag |
| 57 | + enabled_flags = ACCOUNT_SERVICE_NOTIFICATION_FLAGS & account.allowed_services_hash.keys.map(&:to_s) |
| 58 | + |
| 59 | + Shard.partition_by_shard([Account.site_admin, account]) do |accounts| |
| 60 | + AccountNotification.where("account_id IN (?) AND start_at <? AND end_at>?", accounts, now, now). |
| 61 | + where("required_account_service IS NULL OR required_account_service IN (?)", enabled_flags). |
| 62 | + order('start_at DESC').all |
| 63 | + end |
| 64 | + end |
| 65 | + end |
| 66 | + |
| 67 | + def self.default_months_in_display_cycle |
| 68 | + Setting.get_cached("account_notification_default_months_in_display_cycle", "9").to_i |
| 69 | + end |
| 70 | + |
| 71 | + # private |
| 72 | + def self.display_for_user?(user_id, months_in_period, current_time = Time.now.utc) |
| 73 | + # we just need a stable reference point, doesn't matter what it is, so |
| 74 | + # let's use unix epoch |
| 75 | + start_time = Time.at(0).utc |
| 76 | + months_since_start_time = (current_time.year - start_time.year) * 12 + (current_time.month - start_time.month) |
| 77 | + periods_since_start_time = months_since_start_time / months_in_period |
| 78 | + months_into_current_period = months_since_start_time % months_in_period |
| 79 | + mod_value = (Random.new(periods_since_start_time).rand(months_in_period) + months_into_current_period) % months_in_period |
| 80 | + user_id % months_in_period == mod_value |
38 | 81 | end |
39 | 82 | end |
0 commit comments