diff --git a/app/models/concerns/notifiable.rb b/app/models/concerns/notifiable.rb deleted file mode 100644 index d7dcd97911d..00000000000 --- a/app/models/concerns/notifiable.rb +++ /dev/null @@ -1,15 +0,0 @@ -# == Notifiable concern -# -# Contains notification functionality -# -module Notifiable - extend ActiveSupport::Concern - - included do - validates :notification_level, inclusion: { in: Notification.project_notification_levels }, presence: true - end - - def notification - @notification ||= Notification.new(self) - end -end diff --git a/app/models/group.rb b/app/models/group.rb index b332601c59b..9a04ac70d35 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -27,6 +27,7 @@ class Group < Namespace has_many :users, through: :group_members has_many :project_group_links, dependent: :destroy has_many :shared_projects, through: :project_group_links, source: :project + has_many :notification_settings, dependent: :destroy, as: :source validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? } validate :visibility_level_allowed_by_projects diff --git a/app/models/member.rb b/app/models/member.rb index 177f37c3bbd..e665ba6fb75 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -19,7 +19,6 @@ class Member < ActiveRecord::Base include Sortable - include Notifiable include Gitlab::Access attr_accessor :raw_invite_token @@ -170,6 +169,10 @@ class Member < ActiveRecord::Base end end + def notification + @notification ||= user.notification_settings.find_by(source: source) + end + private def send_invite diff --git a/app/models/notification.rb b/app/models/notification.rb index 379f041969b..8a90b456cc2 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -30,30 +30,12 @@ class Notification end end + delegate :disabled?, :participating?, :watch?, :global?, :mention?, to: :target + def initialize(target) @target = target end - def disabled? - target.notification_level == N_DISABLED - end - - def participating? - target.notification_level == N_PARTICIPATING - end - - def watch? - target.notification_level == N_WATCH - end - - def global? - target.notification_level == N_GLOBAL - end - - def mention? - target.notification_level == N_MENTION - end - def level target.notification_level end diff --git a/app/models/project.rb b/app/models/project.rb index 2285063ab50..2f9621809b6 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -154,6 +154,7 @@ class Project < ActiveRecord::Base has_many :project_group_links, dependent: :destroy has_many :invited_groups, through: :project_group_links, source: :group has_many :todos, dependent: :destroy + has_many :notification_settings, dependent: :destroy, as: :source has_one :import_data, dependent: :destroy, class_name: "ProjectImportData" diff --git a/app/models/user.rb b/app/models/user.rb index 59493e6f90c..f556dc5903d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -193,6 +193,9 @@ class User < ActiveRecord::Base # Notification level # Note: When adding an option, it MUST go on the end of the array. + # + # TODO: Add '_prefix: :notification' to enum when update to Rails 5. https://github.com/rails/rails/pull/19813 + # Because user.notification_disabled? is much better than user.disabled? enum notification_level: [:disabled, :participating, :watch, :global, :mention] alias_attribute :private_token, :authentication_token diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index eff0d96f93d..9628843c230 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -253,8 +253,8 @@ class NotificationService def project_watchers(project) project_members = project_member_notification(project) - users_with_project_level_global = project_member_notification(project, Notification::N_GLOBAL) - users_with_group_level_global = group_member_notification(project, Notification::N_GLOBAL) + users_with_project_level_global = project_member_notification(project, :global) + users_with_group_level_global = group_member_notification(project, :global) users = users_with_global_level_watch([users_with_project_level_global, users_with_group_level_global].flatten.uniq) users_with_project_setting = select_project_member_setting(project, users_with_project_level_global, users) @@ -264,18 +264,16 @@ class NotificationService end def project_member_notification(project, notification_level=nil) - project_members = project.project_members - if notification_level - project_members.where(notification_level: notification_level).pluck(:user_id) + project.notification_settings.where(level: NotificationSetting.levels[notification_level]).pluck(:user_id) else - project_members.pluck(:user_id) + project.notification_settings.pluck(:user_id) end end def group_member_notification(project, notification_level) if project.group - project.group.group_members.where(notification_level: notification_level).pluck(:user_id) + project.group.notification_settings.where(level: NotificationSetting.levels[notification_level]).pluck(:user_id) else [] end @@ -284,13 +282,13 @@ class NotificationService def users_with_global_level_watch(ids) User.where( id: ids, - notification_level: Notification::N_WATCH + notification_level: NotificationSetting.levels[:watch] ).pluck(:id) end # Build a list of users based on project notifcation settings def select_project_member_setting(project, global_setting, users_global_level_watch) - users = project_member_notification(project, Notification::N_WATCH) + users = project_member_notification(project, :watch) # If project setting is global, add to watch list if global setting is watch global_setting.each do |user_id| @@ -304,7 +302,7 @@ class NotificationService # Build a list of users based on group notification settings def select_group_member_setting(project, project_members, global_setting, users_global_level_watch) - uids = group_member_notification(project, Notification::N_WATCH) + uids = group_member_notification(project, :watch) # Group setting is watch, add to users list if user is not project member users = [] @@ -351,20 +349,20 @@ class NotificationService users.reject do |user| next user.notification.send(method_name) unless project - member = project.project_members.find_by(user_id: user.id) + setting = user.notification_settings.find_by(source: project) - if !member && project.group - member = project.group.group_members.find_by(user_id: user.id) + if !setting && project.group + setting = user.notification_settings.find_by(source: group) end - # reject users who globally set mention notification and has no membership - next user.notification.send(method_name) unless member + # reject users who globally set mention notification and has no setting per project/group + next user.notification.send(method_name) unless setting # reject users who set mention notification in project - next true if member.notification.send(method_name) + next true if setting.send(method_name) - # reject users who have N_MENTION in project and disabled in global settings - member.notification.global? && user.notification.send(method_name) + # reject users who have mention level in project and disabled in global settings + setting.global? && user.notification.send(method_name) end end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 0f2aa3ae73c..c01851a8a24 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -89,11 +89,11 @@ describe NotificationService, services: true do note.project.group.add_user(@u_watcher, GroupMember::MASTER) note.project.save user_project = note.project.project_members.find_by_user_id(@u_watcher.id) - user_project.notification_level = Notification::N_PARTICIPATING + user_project.notification.level = :participating user_project.save group_member = note.project.group.group_members.find_by_user_id(@u_watcher.id) - group_member.notification_level = Notification::N_GLOBAL - group_member.save + group_member.notification.level = :global + group_member.notification.save ActionMailer::Base.deliveries.clear end @@ -215,7 +215,7 @@ describe NotificationService, services: true do end it do - @u_committer.update_attributes(notification_level: Notification::N_MENTION) + @u_committer.update_attributes(notification_level: :mention) notification.new_note(note) should_not_email(@u_committer) end @@ -246,7 +246,7 @@ describe NotificationService, services: true do end it do - issue.assignee.update_attributes(notification_level: Notification::N_MENTION) + issue.assignee.update_attributes(notification_level: :mention) notification.new_issue(issue, @u_disabled) should_not_email(issue.assignee) @@ -596,13 +596,13 @@ describe NotificationService, services: true do end def build_team(project) - @u_watcher = create(:user, notification_level: Notification::N_WATCH) - @u_participating = create(:user, notification_level: Notification::N_PARTICIPATING) - @u_participant_mentioned = create(:user, username: 'participant', notification_level: Notification::N_PARTICIPATING) - @u_disabled = create(:user, notification_level: Notification::N_DISABLED) - @u_mentioned = create(:user, username: 'mention', notification_level: Notification::N_MENTION) + @u_watcher = create(:user, notification_level: :watch) + @u_participating = create(:user, notification_level: :participating) + @u_participant_mentioned = create(:user, username: 'participant', notification_level: :participating) + @u_disabled = create(:user, notification_level: :disabled) + @u_mentioned = create(:user, username: 'mention', notification_level: :mention) @u_committer = create(:user, username: 'committer') - @u_not_mentioned = create(:user, username: 'regular', notification_level: Notification::N_PARTICIPATING) + @u_not_mentioned = create(:user, username: 'regular', notification_level: :participating) @u_outsider_mentioned = create(:user, username: 'outsider') project.team << [@u_watcher, :master] @@ -617,8 +617,8 @@ describe NotificationService, services: true do def add_users_with_subscription(project, issuable) @subscriber = create :user @unsubscriber = create :user - @subscribed_participant = create(:user, username: 'subscribed_participant', notification_level: Notification::N_PARTICIPATING) - @watcher_and_subscriber = create(:user, notification_level: Notification::N_WATCH) + @subscribed_participant = create(:user, username: 'subscribed_participant', notification_level: :participating) + @watcher_and_subscriber = create(:user, notification_level: :watch) project.team << [@subscribed_participant, :master] project.team << [@subscriber, :master]