From 31b0e53015e38e51d9c02cca85c9279600b1bf85 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Mon, 28 Mar 2016 13:41:00 +0200 Subject: [PATCH 01/34] Introduce NotificationSetting model It will hold notification setting per group or per project. It will allow get rid of notification level stored in Member model Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- app/models/notification_setting.rb | 14 ++++++++++++++ ...20160328112808_create_notification_settings.rb | 12 ++++++++++++ db/schema.rb | 15 ++++++++++++--- spec/models/notification_setting_spec.rb | 15 +++++++++++++++ 4 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 app/models/notification_setting.rb create mode 100644 db/migrate/20160328112808_create_notification_settings.rb create mode 100644 spec/models/notification_setting_spec.rb diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb new file mode 100644 index 000000000000..0dce146b7a9e --- /dev/null +++ b/app/models/notification_setting.rb @@ -0,0 +1,14 @@ +class NotificationSetting < ActiveRecord::Base + belongs_to :user + belongs_to :source, polymorphic: true + + validates :user, presence: true + validates :source, presence: true + validates :level, presence: true + validates :user_id, uniqueness: { scope: [:source_type, :source_id], + message: "already exists in source", + allow_nil: true } + # Notification level + # Note: When adding an option, it MUST go on the end of the array. + enum level: [:disabled, :participating, :watch, :global, :mention] +end diff --git a/db/migrate/20160328112808_create_notification_settings.rb b/db/migrate/20160328112808_create_notification_settings.rb new file mode 100644 index 000000000000..88652821ac38 --- /dev/null +++ b/db/migrate/20160328112808_create_notification_settings.rb @@ -0,0 +1,12 @@ +class CreateNotificationSettings < ActiveRecord::Migration + def change + create_table :notification_settings do |t| + t.integer :user_id + t.integer :level + t.integer :source_id + t.string :source_type + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index dce2bfe62cab..a9a68e723ab2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160320204112) do +ActiveRecord::Schema.define(version: 20160328112808) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -417,9 +417,9 @@ t.string "state" t.integer "iid" t.integer "updated_by_id" - t.integer "moved_to_id" - t.boolean "confidential", default: false + t.boolean "confidential", default: false t.datetime "deleted_at" + t.integer "moved_to_id" end add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree @@ -638,6 +638,15 @@ add_index "notes", ["project_id"], name: "index_notes_on_project_id", using: :btree add_index "notes", ["updated_at"], name: "index_notes_on_updated_at", using: :btree + create_table "notification_settings", force: :cascade do |t| + t.integer "user_id" + t.integer "level" + t.integer "source_id" + t.string "source_type" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "oauth_access_grants", force: :cascade do |t| t.integer "resource_owner_id", null: false t.integer "application_id", null: false diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb new file mode 100644 index 000000000000..f9d668ed75b4 --- /dev/null +++ b/spec/models/notification_setting_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +RSpec.describe NotificationSetting, type: :model do + describe "Associations" do + it { is_expected.to belong_to(:user) } + end + + describe "Validation" do + subject { NotificationSetting.new } + + it { is_expected.to validate_presence_of(:user) } + it { is_expected.to validate_presence_of(:source) } + it { is_expected.to validate_presence_of(:level) } + end +end -- GitLab From 73c5a3410596165244bfa3d2f657c313ec1c558c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Mon, 28 Mar 2016 14:27:30 +0200 Subject: [PATCH 02/34] Migrate notification setting from members table Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- ...160328115649_migrate_new_notification_setting.rb | 13 +++++++++++++ ...20160328121138_add_notification_setting_index.rb | 6 ++++++ db/schema.rb | 5 ++++- 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20160328115649_migrate_new_notification_setting.rb create mode 100644 db/migrate/20160328121138_add_notification_setting_index.rb diff --git a/db/migrate/20160328115649_migrate_new_notification_setting.rb b/db/migrate/20160328115649_migrate_new_notification_setting.rb new file mode 100644 index 000000000000..331c35535f29 --- /dev/null +++ b/db/migrate/20160328115649_migrate_new_notification_setting.rb @@ -0,0 +1,13 @@ +# This migration will create one row of NotificationSetting for each Member row +# It can take long time on big instances. Its unclear yet if this migration can be done online. +# This comment should be updated by @dzaporozhets before 8.7 release. If not - please ask him to do so. +class MigrateNewNotificationSetting < ActiveRecord::Migration + def up + timestamp = Time.now + execute "INSERT INTO notification_settings ( user_id, source_id, source_type, level, created_at, updated_at ) SELECT user_id, source_id, source_type, notification_level, '#{timestamp}', '#{timestamp}' FROM members" + end + + def down + NotificationSetting.delete_all + end +end diff --git a/db/migrate/20160328121138_add_notification_setting_index.rb b/db/migrate/20160328121138_add_notification_setting_index.rb new file mode 100644 index 000000000000..8aebce0244d6 --- /dev/null +++ b/db/migrate/20160328121138_add_notification_setting_index.rb @@ -0,0 +1,6 @@ +class AddNotificationSettingIndex < ActiveRecord::Migration + def change + add_index :notification_settings, :user_id + add_index :notification_settings, [:source_id, :source_type] + end +end diff --git a/db/schema.rb b/db/schema.rb index a9a68e723ab2..29639abb6fcf 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160328112808) do +ActiveRecord::Schema.define(version: 20160328121138) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -647,6 +647,9 @@ t.datetime "updated_at", null: false end + add_index "notification_settings", ["source_id", "source_type"], name: "index_notification_settings_on_source_id_and_source_type", using: :btree + add_index "notification_settings", ["user_id"], name: "index_notification_settings_on_user_id", using: :btree + create_table "oauth_access_grants", force: :cascade do |t| t.integer "resource_owner_id", null: false t.integer "application_id", null: false -- GitLab From 359157c097993a9b917ca590e128e85cf358d95d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Mon, 28 Mar 2016 18:17:42 +0200 Subject: [PATCH 03/34] Introduce NotificationSetting to user interface * visiting project will create notification setting if missing * change notification setting per project even without membership * use notification settings instead of membership on profile page Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- app/assets/javascripts/project.js.coffee | 8 +- .../profiles/notifications_controller.rb | 14 ++-- app/controllers/projects_controller.rb | 17 ++++- app/helpers/notifications_helper.rb | 74 +++++++++++-------- app/models/notification.rb | 4 +- app/models/notification_setting.rb | 7 ++ app/models/user.rb | 7 +- .../notifications/_settings.html.haml | 18 ++--- .../profiles/notifications/show.html.haml | 30 ++++---- .../projects/buttons/_notifications.html.haml | 20 ++--- 10 files changed, 106 insertions(+), 93 deletions(-) diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee index 87d313ed67c2..f171442d05ad 100644 --- a/app/assets/javascripts/project.js.coffee +++ b/app/assets/javascripts/project.js.coffee @@ -37,15 +37,9 @@ class @Project $('.update-notification').on 'click', (e) -> e.preventDefault() notification_level = $(@).data 'notification-level' + label = $(@).data 'notification-title' $('#notification_level').val(notification_level) $('#notification-form').submit() - label = null - switch notification_level - when 0 then label = ' Disabled ' - when 1 then label = ' Participating ' - when 2 then label = ' Watching ' - when 3 then label = ' Global ' - when 4 then label = ' On Mention ' $('#notifications-button').empty().append("<i class='fa fa-bell'></i>" + label + "<i class='fa fa-angle-down'></i>") $(@).parents('ul').find('li.active').removeClass 'active' $(@).parent().addClass 'active' diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb index 1fd1d6882dfe..6ca7537300fe 100644 --- a/app/controllers/profiles/notifications_controller.rb +++ b/app/controllers/profiles/notifications_controller.rb @@ -2,8 +2,8 @@ class Profiles::NotificationsController < Profiles::ApplicationController def show @user = current_user @notification = current_user.notification - @project_members = current_user.project_members - @group_members = current_user.group_members + @group_notifications = current_user.notification_settings.for_groups + @project_notifications = current_user.notification_settings.for_projects end def update @@ -11,14 +11,10 @@ def update @saved = if type == 'global' current_user.update_attributes(user_params) - elsif type == 'group' - group_member = current_user.group_members.find(params[:notification_id]) - group_member.notification_level = params[:notification_level] - group_member.save else - project_member = current_user.project_members.find(params[:notification_id]) - project_member.notification_level = params[:notification_level] - project_member.save + notification_setting = current_user.notification_settings.find(params[:notification_id]) + notification_setting.level = params[:notification_level] + notification_setting.save end respond_to do |format| diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 928817ba811e..77122f59128b 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -98,14 +98,23 @@ def show respond_to do |format| format.html do + if current_user + @membership = @project.team.find_member(current_user.id) + + if @membership + @notification_setting = current_user.notification_settings.find_or_initialize_by(source: @project) + + unless @notification_setting.persisted? + @notification_setting.set_defaults + @notification_setting.save + end + end + end + if @project.repository_exists? if @project.empty_repo? render 'projects/empty' else - if current_user - @membership = @project.team.find_member(current_user.id) - end - render :show end else diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 499c655d2bf2..a0e91a63d2d4 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -1,48 +1,60 @@ module NotificationsHelper include IconsHelper - def notification_icon(notification) - if notification.disabled? - icon('volume-off', class: 'ns-mute') - elsif notification.participating? - icon('volume-down', class: 'ns-part') - elsif notification.watch? - icon('volume-up', class: 'ns-watch') - else - icon('circle-o', class: 'ns-default') + def notification_icon_class(level) + case level.to_sym + when :disabled + 'microphone-slash' + when :participating + 'volume-up' + when :watch + 'eye' + when :mention + 'at' + when :global + 'globe' end end - def notification_list_item(notification_level, user_membership) - case notification_level - when Notification::N_DISABLED - update_notification_link(Notification::N_DISABLED, user_membership, 'Disabled', 'microphone-slash') - when Notification::N_PARTICIPATING - update_notification_link(Notification::N_PARTICIPATING, user_membership, 'Participate', 'volume-up') - when Notification::N_WATCH - update_notification_link(Notification::N_WATCH, user_membership, 'Watch', 'eye') - when Notification::N_MENTION - update_notification_link(Notification::N_MENTION, user_membership, 'On mention', 'at') - when Notification::N_GLOBAL - update_notification_link(Notification::N_GLOBAL, user_membership, 'Global', 'globe') - else - # do nothing + def notification_icon(level) + icon("#{notification_icon_class(level)} fw") + end + + def notification_title(level) + case level.to_sym + when :disabled + 'Disabled' + when :participating + 'Participate' + when :watch + 'Watch' + when :mention + 'On mention' + when :global + 'Global' end end - def update_notification_link(notification_level, user_membership, title, icon) - content_tag(:li, class: active_level_for(user_membership, notification_level)) do - link_to '#', class: 'update-notification', data: { notification_level: notification_level } do - icon("#{icon} fw", text: title) + def notification_list_item(level, setting) + title = notification_title(level) + + data = { + notification_level: level, + notification_title: title + } + + content_tag(:li, class: active_level_for(setting, level)) do + link_to '#', class: 'update-notification', data: data do + icon("#{notification_icon_class(level)} fw", text: title) end end end - def notification_label(user_membership) - Notification.new(user_membership).to_s + def notification_label(setting) + notification_title(setting.level) end - def active_level_for(user_membership, level) - 'active' if user_membership.notification_level == level + def active_level_for(setting, level) + 'active' if setting.level == level end end diff --git a/app/models/notification.rb b/app/models/notification.rb index 171b8df45c2f..379f041969b3 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -57,7 +57,7 @@ def mention? def level target.notification_level end - + def to_s case level when N_DISABLED @@ -71,7 +71,7 @@ def to_s when N_GLOBAL 'Global' else - # do nothing + # do nothing end end end diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb index 0dce146b7a9e..287862a01bc7 100644 --- a/app/models/notification_setting.rb +++ b/app/models/notification_setting.rb @@ -11,4 +11,11 @@ class NotificationSetting < ActiveRecord::Base # Notification level # Note: When adding an option, it MUST go on the end of the array. enum level: [:disabled, :participating, :watch, :global, :mention] + + scope :for_groups, -> { where(source_type: 'Namespace') } + scope :for_projects, -> { where(source_type: 'Project') } + + def set_defaults + self.level = :global + end end diff --git a/app/models/user.rb b/app/models/user.rb index 128ddc2a694e..59493e6f90c7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -143,6 +143,7 @@ class User < ActiveRecord::Base has_many :spam_logs, dependent: :destroy has_many :builds, dependent: :nullify, class_name: 'Ci::Build' has_many :todos, dependent: :destroy + has_many :notification_settings, dependent: :destroy # # Validations @@ -157,7 +158,7 @@ class User < ActiveRecord::Base presence: true, uniqueness: { case_sensitive: false } - validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true + validates :notification_level, presence: true validate :namespace_uniq, if: ->(user) { user.username_changed? } validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? } validate :unique_email, if: ->(user) { user.email_changed? } @@ -190,6 +191,10 @@ class User < ActiveRecord::Base # Note: When adding an option, it MUST go on the end of the array. enum project_view: [:readme, :activity, :files] + # Notification level + # Note: When adding an option, it MUST go on the end of the array. + enum notification_level: [:disabled, :participating, :watch, :global, :mention] + alias_attribute :private_token, :authentication_token delegate :path, to: :namespace, allow_nil: true, prefix: true diff --git a/app/views/profiles/notifications/_settings.html.haml b/app/views/profiles/notifications/_settings.html.haml index d0d044136f6f..c32de0b9925a 100644 --- a/app/views/profiles/notifications/_settings.html.haml +++ b/app/views/profiles/notifications/_settings.html.haml @@ -1,17 +1,17 @@ %li.notification-list-item %span.notification.fa.fa-holder.append-right-5 - - if notification.global? - = notification_icon(@notification) + - if setting.global? + = notification_icon(current_user.notification_level) - else - = notification_icon(notification) + = notification_icon(setting.level) %span.str-truncated - - if membership.kind_of? GroupMember - = link_to membership.group.name, membership.group + - if setting.source.kind_of? Project + = link_to_project(setting.source) - else - = link_to_project(membership.project) + = link_to setting.source.name, group_path(setting.source) .pull-right = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do - = hidden_field_tag :notification_type, type, id: dom_id(membership, 'notification_type') - = hidden_field_tag :notification_id, membership.id, id: dom_id(membership, 'notification_id') - = select_tag :notification_level, options_for_select(Notification.options_with_labels, notification.level), class: 'form-control trigger-submit' + = hidden_field_tag :notification_id, setting.id + = hidden_field_tag :notification_level, setting.level + = select_tag :notification_level, options_for_select(User.notification_levels.keys, setting.level), class: 'form-control trigger-submit' diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml index de80abd7f4da..f6900f61b2d0 100644 --- a/app/views/profiles/notifications/show.html.haml +++ b/app/views/profiles/notifications/show.html.haml @@ -26,29 +26,29 @@ .form-group = f.label :notification_level, class: 'label-light' .radio - = f.label :notification_level, value: Notification::N_DISABLED do - = f.radio_button :notification_level, Notification::N_DISABLED + = f.label :notification_level, value: :disabled do + = f.radio_button :notification_level, :disabled .level-title Disabled %p You will not get any notifications via email .radio - = f.label :notification_level, value: Notification::N_MENTION do - = f.radio_button :notification_level, Notification::N_MENTION + = f.label :notification_level, value: :mention do + = f.radio_button :notification_level, :mention .level-title On Mention %p You will receive notifications only for comments in which you were @mentioned .radio - = f.label :notification_level, value: Notification::N_PARTICIPATING do - = f.radio_button :notification_level, Notification::N_PARTICIPATING + = f.label :notification_level, value: :participating do + = f.radio_button :notification_level, :participating .level-title Participating %p You will only receive notifications from related resources (e.g. from your commits or assigned issues) .radio - = f.label :notification_level, value: Notification::N_WATCH do - = f.radio_button :notification_level, Notification::N_WATCH + = f.label :notification_level, value: :watch do + = f.radio_button :notification_level, :watch .level-title Watch %p You will receive notifications for any activity @@ -57,18 +57,16 @@ = f.submit 'Update settings', class: "btn btn-create" %hr %h5 - Groups (#{@group_members.count}) + Groups (#{@group_notifications.count}) %div %ul.bordered-list - - @group_members.each do |group_member| - - notification = Notification.new(group_member) - = render 'settings', type: 'group', membership: group_member, notification: notification + - @group_notifications.each do |setting| + = render 'settings', setting: setting %h5 - Projects (#{@project_members.count}) + Projects (#{@project_notifications.count}) %p.account-well To specify the notification level per project of a group you belong to, you need to be a member of the project itself, not only its group. .append-bottom-default %ul.bordered-list - - @project_members.each do |project_member| - - notification = Notification.new(project_member) - = render 'settings', type: 'project', membership: project_member, notification: notification + - @project_notifications.each do |setting| + = render 'settings', setting: setting diff --git a/app/views/projects/buttons/_notifications.html.haml b/app/views/projects/buttons/_notifications.html.haml index a3786c35a1f9..4b8a10f08197 100644 --- a/app/views/projects/buttons/_notifications.html.haml +++ b/app/views/projects/buttons/_notifications.html.haml @@ -1,20 +1,12 @@ -- case @membership -- when ProjectMember +- if @notification_setting = form_tag profile_notifications_path, method: :put, remote: true, class: 'inline', id: 'notification-form' do - = hidden_field_tag :notification_type, 'project' - = hidden_field_tag :notification_id, @membership.id - = hidden_field_tag :notification_level + = hidden_field_tag :notification_id, @notification_setting.id + = hidden_field_tag :notification_level, @notification_setting.level %span.dropdown %a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"} = icon('bell') - = notification_label(@membership) + = notification_title(@notification_setting.level) = icon('angle-down') %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown - - Notification.project_notification_levels.each do |level| - = notification_list_item(level, @membership) - -- when GroupMember - .btn.disabled.notifications-btn.has-tooltip{title: "To change the notification level, you need to be a member of the project itself, not only its group."} - = icon('bell') - = notification_label(@membership) - = icon('angle-down') + - NotificationSetting.levels.each do |level| + = notification_list_item(level.first, @notification_setting) -- GitLab From 7ea1bcab45697556d4ffd79ab680872ed823d4a3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Mon, 28 Mar 2016 18:25:57 +0200 Subject: [PATCH 04/34] Create notification setting when membership created Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- app/models/member.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/models/member.rb b/app/models/member.rb index ca08007b7eb9..177f37c3bbdc 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -56,6 +56,7 @@ class Member < ActiveRecord::Base before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? } after_create :send_invite, if: :invite? + after_create :create_notification_setting, unless: :invite? after_create :post_create_hook, unless: :invite? after_update :post_update_hook, unless: :invite? after_destroy :post_destroy_hook, unless: :invite? @@ -160,6 +161,15 @@ def resend_invite send_invite end + def create_notification_setting + notification_setting = user.notification_settings.find_or_initialize_by(source: source) + + unless notification_setting.persisted? + notification_setting.set_defaults + notification_setting.save + end + end + private def send_invite -- GitLab From b8f38437900cdddac9d19d5c48a2a8e5bb037f41 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Mon, 28 Mar 2016 20:31:36 +0200 Subject: [PATCH 05/34] Update NotificationService to use NotificationSettings instead of membership Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- app/models/concerns/notifiable.rb | 15 ---------- app/models/group.rb | 1 + app/models/member.rb | 5 +++- app/models/notification.rb | 22 ++------------ app/models/project.rb | 1 + app/models/user.rb | 3 ++ app/services/notification_service.rb | 34 ++++++++++------------ spec/services/notification_service_spec.rb | 26 ++++++++--------- 8 files changed, 40 insertions(+), 67 deletions(-) delete mode 100644 app/models/concerns/notifiable.rb diff --git a/app/models/concerns/notifiable.rb b/app/models/concerns/notifiable.rb deleted file mode 100644 index d7dcd97911dd..000000000000 --- 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 b332601c59b7..9a04ac70d350 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 177f37c3bbdc..e665ba6fb756 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 @@ def create_notification_setting 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 379f041969b3..8a90b456cc26 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -30,30 +30,12 @@ def project_notification_levels 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 2285063ab507..2f9621809b62 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -154,6 +154,7 @@ def update_forks_visibility_level 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 59493e6f90c7..f556dc5903d8 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 eff0d96f93dd..9628843c230f 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -253,8 +253,8 @@ def issue_moved(issue, new_issue, current_user) 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 @@ def project_watchers(project) 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 @@ def group_member_notification(project, notification_level) 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 @@ def select_project_member_setting(project, global_setting, users_global_level_wa # 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 @@ def reject_users(users, method_name, project = nil) 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 0f2aa3ae73cc..c01851a8a24f 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -89,11 +89,11 @@ 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 @@ 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 @@ 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 @@ 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 @@ def build_team(project) 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] -- GitLab From 4ca73f56cb59b86f25b55ff02800571fb82c742f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Mon, 28 Mar 2016 23:22:28 +0200 Subject: [PATCH 06/34] Small refactoring and cleanup of notification logic Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- app/helpers/notifications_helper.rb | 12 +----- app/models/member.rb | 2 + app/models/members/group_member.rb | 1 - app/models/members/project_member.rb | 1 - app/models/notification.rb | 46 ---------------------- spec/models/notification_setting_spec.rb | 1 + spec/services/notification_service_spec.rb | 9 ++--- 7 files changed, 8 insertions(+), 64 deletions(-) diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index a0e91a63d2d4..8816cc5d1649 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -22,16 +22,12 @@ def notification_icon(level) def notification_title(level) case level.to_sym - when :disabled - 'Disabled' when :participating 'Participate' - when :watch - 'Watch' when :mention 'On mention' - when :global - 'Global' + else + level.to_s.titlecase end end @@ -50,10 +46,6 @@ def notification_list_item(level, setting) end end - def notification_label(setting) - notification_title(setting.level) - end - def active_level_for(setting, level) 'active' if setting.level == level end diff --git a/app/models/member.rb b/app/models/member.rb index e665ba6fb756..799f28c3fdf3 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -62,6 +62,8 @@ class Member < ActiveRecord::Base delegate :name, :username, :email, to: :user, prefix: true + default_value_for :notification_level, NotificationSetting.levels[:global] + class << self def find_by_invite_token(invite_token) invite_token = Devise.token_generator.digest(self, :invite_token, invite_token) diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb index 65d2ea00570d..9fb474a1a93d 100644 --- a/app/models/members/group_member.rb +++ b/app/models/members/group_member.rb @@ -24,7 +24,6 @@ class GroupMember < Member # Make sure group member points only to group as it source default_value_for :source_type, SOURCE_TYPE - default_value_for :notification_level, Notification::N_GLOBAL validates_format_of :source_type, with: /\ANamespace\z/ default_scope { where(source_type: SOURCE_TYPE) } diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 560d1690e143..07ddb02ae9dd 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -27,7 +27,6 @@ class ProjectMember < Member # Make sure project member points only to project as it source default_value_for :source_type, SOURCE_TYPE - default_value_for :notification_level, Notification::N_GLOBAL validates_format_of :source_type, with: /\AProject\z/ default_scope { where(source_type: SOURCE_TYPE) } diff --git a/app/models/notification.rb b/app/models/notification.rb index 8a90b456cc26..3805bde88b0d 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -1,35 +1,6 @@ class Notification - # - # Notification levels - # - N_DISABLED = 0 - N_PARTICIPATING = 1 - N_WATCH = 2 - N_GLOBAL = 3 - N_MENTION = 4 - attr_accessor :target - class << self - def notification_levels - [N_DISABLED, N_MENTION, N_PARTICIPATING, N_WATCH] - end - - def options_with_labels - { - disabled: N_DISABLED, - participating: N_PARTICIPATING, - watch: N_WATCH, - mention: N_MENTION, - global: N_GLOBAL - } - end - - def project_notification_levels - [N_DISABLED, N_MENTION, N_PARTICIPATING, N_WATCH, N_GLOBAL] - end - end - delegate :disabled?, :participating?, :watch?, :global?, :mention?, to: :target def initialize(target) @@ -39,21 +10,4 @@ def initialize(target) def level target.notification_level end - - def to_s - case level - when N_DISABLED - 'Disabled' - when N_PARTICIPATING - 'Participating' - when N_WATCH - 'Watching' - when N_MENTION - 'On mention' - when N_GLOBAL - 'Global' - else - # do nothing - end - end end diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb index f9d668ed75b4..f31b2a3cd6f2 100644 --- a/spec/models/notification_setting_spec.rb +++ b/spec/models/notification_setting_spec.rb @@ -3,6 +3,7 @@ RSpec.describe NotificationSetting, type: :model do describe "Associations" do it { is_expected.to belong_to(:user) } + it { is_expected.to belong_to(:source) } end describe "Validation" do diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index c01851a8a24f..c4d52584a4b7 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -88,12 +88,9 @@ note.project.namespace_id = group.id 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 = :participating - user_project.save - group_member = note.project.group.group_members.find_by_user_id(@u_watcher.id) - group_member.notification.level = :global - group_member.notification.save + + @u_watcher.notification_settings.find_by(source: note.project).participating! + @u_watcher.notification_settings.find_by(source: note.project.group).global! ActionMailer::Base.deliveries.clear end -- GitLab From 855b2820c16c6e569d5c38b7def8ead18c86cecd Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Mon, 28 Mar 2016 23:39:49 +0200 Subject: [PATCH 07/34] Improve db migrations for notification settings Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- ...60328112808_create_notification_settings.rb | 7 +++---- ...8115649_migrate_new_notification_setting.rb | 2 +- db/schema.rb | 18 +++++++++--------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/db/migrate/20160328112808_create_notification_settings.rb b/db/migrate/20160328112808_create_notification_settings.rb index 88652821ac38..4755da8b8066 100644 --- a/db/migrate/20160328112808_create_notification_settings.rb +++ b/db/migrate/20160328112808_create_notification_settings.rb @@ -1,10 +1,9 @@ class CreateNotificationSettings < ActiveRecord::Migration def change create_table :notification_settings do |t| - t.integer :user_id - t.integer :level - t.integer :source_id - t.string :source_type + t.references :user, null: false + t.references :source, polymorphic: true, null: false + t.integer :level, default: 0, null: false t.timestamps null: false end diff --git a/db/migrate/20160328115649_migrate_new_notification_setting.rb b/db/migrate/20160328115649_migrate_new_notification_setting.rb index 331c35535f29..aff866b5f46f 100644 --- a/db/migrate/20160328115649_migrate_new_notification_setting.rb +++ b/db/migrate/20160328115649_migrate_new_notification_setting.rb @@ -4,7 +4,7 @@ class MigrateNewNotificationSetting < ActiveRecord::Migration def up timestamp = Time.now - execute "INSERT INTO notification_settings ( user_id, source_id, source_type, level, created_at, updated_at ) SELECT user_id, source_id, source_type, notification_level, '#{timestamp}', '#{timestamp}' FROM members" + execute "INSERT INTO notification_settings ( user_id, source_id, source_type, level, created_at, updated_at ) SELECT user_id, source_id, source_type, notification_level, '#{timestamp}', '#{timestamp}' FROM members WHERE user_id IS NOT NULL" end def down diff --git a/db/schema.rb b/db/schema.rb index 29639abb6fcf..e946ecd3f2b3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -639,12 +639,12 @@ add_index "notes", ["updated_at"], name: "index_notes_on_updated_at", using: :btree create_table "notification_settings", force: :cascade do |t| - t.integer "user_id" - t.integer "level" - t.integer "source_id" - t.string "source_type" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.integer "user_id", null: false + t.integer "source_id", null: false + t.string "source_type", null: false + t.integer "level", default: 0, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "notification_settings", ["source_id", "source_type"], name: "index_notification_settings_on_source_id_and_source_type", using: :btree @@ -798,9 +798,9 @@ t.string "type" t.string "title" t.integer "project_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "active", null: false + t.datetime "created_at" + t.datetime "updated_at" + t.boolean "active", default: false, null: false t.text "properties" t.boolean "template", default: false t.boolean "push_events", default: true -- GitLab From 08b3d7f6ef23b7a8a83c7e71e2d04f6416e73406 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Tue, 29 Mar 2016 13:08:30 +0200 Subject: [PATCH 08/34] Refactor notification helper and fix notification service Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- app/helpers/notifications_helper.rb | 12 +++----- app/services/notification_service.rb | 2 +- spec/helpers/notifications_helper_spec.rb | 37 ++++++----------------- 3 files changed, 14 insertions(+), 37 deletions(-) diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 8816cc5d1649..54ab9179efc0 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -16,8 +16,8 @@ def notification_icon_class(level) end end - def notification_icon(level) - icon("#{notification_icon_class(level)} fw") + def notification_icon(level, text = nil) + icon("#{notification_icon_class(level)} fw", text: text) end def notification_title(level) @@ -39,14 +39,10 @@ def notification_list_item(level, setting) notification_title: title } - content_tag(:li, class: active_level_for(setting, level)) do + content_tag(:li, class: ('active' if setting.level == level)) do link_to '#', class: 'update-notification', data: data do - icon("#{notification_icon_class(level)} fw", text: title) + notification_icon(level, title) end end end - - def active_level_for(setting, level) - 'active' if setting.level == level - end end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 9628843c230f..23f211dfcd2a 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -352,7 +352,7 @@ def reject_users(users, method_name, project = nil) setting = user.notification_settings.find_by(source: project) if !setting && project.group - setting = user.notification_settings.find_by(source: group) + setting = user.notification_settings.find_by(source: project.group) end # reject users who globally set mention notification and has no setting per project/group diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb index f1aba4cfdf3a..9d5f009ebe1a 100644 --- a/spec/helpers/notifications_helper_spec.rb +++ b/spec/helpers/notifications_helper_spec.rb @@ -2,34 +2,15 @@ describe NotificationsHelper do describe 'notification_icon' do - let(:notification) { double(disabled?: false, participating?: false, watch?: false) } - - context "disabled notification" do - before { allow(notification).to receive(:disabled?).and_return(true) } - - it "has a red icon" do - expect(notification_icon(notification)).to match('class="fa fa-volume-off ns-mute"') - end - end - - context "participating notification" do - before { allow(notification).to receive(:participating?).and_return(true) } - - it "has a blue icon" do - expect(notification_icon(notification)).to match('class="fa fa-volume-down ns-part"') - end - end - - context "watched notification" do - before { allow(notification).to receive(:watch?).and_return(true) } - - it "has a green icon" do - expect(notification_icon(notification)).to match('class="fa fa-volume-up ns-watch"') - end - end + it { expect(notification_icon(:disabled)).to match('class="fa fa-microphone-slash fa-fw"') } + it { expect(notification_icon(:participating)).to match('class="fa fa-volume-up fa-fw"') } + it { expect(notification_icon(:mention)).to match('class="fa fa-at fa-fw"') } + it { expect(notification_icon(:global)).to match('class="fa fa-globe fa-fw"') } + it { expect(notification_icon(:watch)).to match('class="fa fa-eye fa-fw"') } + end - it "has a blue icon" do - expect(notification_icon(notification)).to match('class="fa fa-circle-o ns-default"') - end + describe 'notification_title' do + it { expect(notification_title(:watch)).to match('Watch') } + it { expect(notification_title(:mention)).to match('On mention') } end end -- GitLab From 86418c475be1b2a37e89682bc87055b7372bbcfb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Tue, 29 Mar 2016 13:37:43 +0200 Subject: [PATCH 09/34] Remove useless Notification model Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- app/models/member.rb | 4 ++-- app/models/notification.rb | 13 ------------- app/models/user.rb | 4 ---- app/services/notification_service.rb | 24 +++++++++++++++--------- 4 files changed, 17 insertions(+), 28 deletions(-) delete mode 100644 app/models/notification.rb diff --git a/app/models/member.rb b/app/models/member.rb index 799f28c3fdf3..cbcc54c02506 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -171,8 +171,8 @@ def create_notification_setting end end - def notification - @notification ||= user.notification_settings.find_by(source: source) + def notification_setting + @notification_setting ||= user.notification_settings.find_by(source: source) end private diff --git a/app/models/notification.rb b/app/models/notification.rb deleted file mode 100644 index 3805bde88b0d..000000000000 --- a/app/models/notification.rb +++ /dev/null @@ -1,13 +0,0 @@ -class Notification - attr_accessor :target - - delegate :disabled?, :participating?, :watch?, :global?, :mention?, to: :target - - def initialize(target) - @target = target - end - - def level - target.notification_level - end -end diff --git a/app/models/user.rb b/app/models/user.rb index f556dc5903d8..af6b86bfa703 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -357,10 +357,6 @@ def to_reference(_from_project = nil) "#{self.class.reference_prefix}#{username}" end - def notification - @notification ||= Notification.new(self) - end - def generate_password if self.force_random_password self.password = self.password_confirmation = Devise.friendly_token.first(8) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 23f211dfcd2a..0928dda349ef 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -329,25 +329,31 @@ def add_project_watchers(recipients, project) # Remove users with disabled notifications from array # Also remove duplications and nil recipients def reject_muted_users(users, project = nil) - reject_users(users, :disabled?, project) + reject_users(users, :disabled, project) end # Remove users with notification level 'Mentioned' def reject_mention_users(users, project = nil) - reject_users(users, :mention?, project) + reject_users(users, :mention, project) end - # Reject users which method_name from notification object returns true. + # Reject users which has certain notification level # # Example: - # reject_users(users, :watch?, project) + # reject_users(users, :watch, project) # - def reject_users(users, method_name, project = nil) + def reject_users(users, level, project = nil) + level = level.to_s + + unless NotificationSetting.levels.keys.include?(level) + raise 'Invalid notification level' + end + users = users.to_a.compact.uniq users = users.reject(&:blocked?) users.reject do |user| - next user.notification.send(method_name) unless project + next user.notification_level == level unless project setting = user.notification_settings.find_by(source: project) @@ -356,13 +362,13 @@ def reject_users(users, method_name, project = nil) end # reject users who globally set mention notification and has no setting per project/group - next user.notification.send(method_name) unless setting + next user.notification_level == level unless setting # reject users who set mention notification in project - next true if setting.send(method_name) + next true if setting.level == level # reject users who have mention level in project and disabled in global settings - setting.global? && user.notification.send(method_name) + setting.global? && user.notification_level == level end end -- GitLab From 630c86a7a36cee36ed6b9c93644a6cb51e2b3b23 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Tue, 29 Mar 2016 13:42:48 +0200 Subject: [PATCH 10/34] Add spec for user_id uniq in NotificationSetting model Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- spec/models/notification_setting_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb index f31b2a3cd6f2..295081e9da16 100644 --- a/spec/models/notification_setting_spec.rb +++ b/spec/models/notification_setting_spec.rb @@ -7,10 +7,11 @@ end describe "Validation" do - subject { NotificationSetting.new } + subject { NotificationSetting.new(source_id: 1, source_type: 'Project') } it { is_expected.to validate_presence_of(:user) } it { is_expected.to validate_presence_of(:source) } it { is_expected.to validate_presence_of(:level) } + it { is_expected.to validate_uniqueness_of(:user_id).scoped_to([:source_id, :source_type]).with_message(/already exists in source/) } end end -- GitLab From 71e7b398431506c8bac2e8e6014b0f3891a41f95 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Tue, 29 Mar 2016 13:52:42 +0200 Subject: [PATCH 11/34] Refactor creating notification setting with defaults Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- app/controllers/projects_controller.rb | 7 +------ app/models/member.rb | 7 +------ app/models/notification_setting.rb | 11 +++++++++++ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 77122f59128b..e2dc6309d263 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -102,12 +102,7 @@ def show @membership = @project.team.find_member(current_user.id) if @membership - @notification_setting = current_user.notification_settings.find_or_initialize_by(source: @project) - - unless @notification_setting.persisted? - @notification_setting.set_defaults - @notification_setting.save - end + @notification_setting = current_user.notification_settings.find_or_create_for(@project) end end diff --git a/app/models/member.rb b/app/models/member.rb index cbcc54c02506..747d0f16d8d9 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -163,12 +163,7 @@ def resend_invite end def create_notification_setting - notification_setting = user.notification_settings.find_or_initialize_by(source: source) - - unless notification_setting.persisted? - notification_setting.set_defaults - notification_setting.save - end + user.notification_setting.find_or_create_for(source) end def notification_setting diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb index 287862a01bc7..13a8995b036c 100644 --- a/app/models/notification_setting.rb +++ b/app/models/notification_setting.rb @@ -15,6 +15,17 @@ class NotificationSetting < ActiveRecord::Base scope :for_groups, -> { where(source_type: 'Namespace') } scope :for_projects, -> { where(source_type: 'Project') } + def self.find_or_create_for(source) + setting = find_or_initialize_by(source: source) + + unless setting.persisted? + setting.set_defaults + setting.save + end + + setting + end + def set_defaults self.level = :global end -- GitLab From f8f68d6b8c5b5d85b4798257ae3ae4bf4ec8fadc Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Tue, 29 Mar 2016 14:03:23 +0200 Subject: [PATCH 12/34] Fix few bugs related to recent notifications refactoring Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- app/controllers/profiles/notifications_controller.rb | 1 - app/models/member.rb | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb index 6ca7537300fe..0cca5d1e3307 100644 --- a/app/controllers/profiles/notifications_controller.rb +++ b/app/controllers/profiles/notifications_controller.rb @@ -1,7 +1,6 @@ class Profiles::NotificationsController < Profiles::ApplicationController def show @user = current_user - @notification = current_user.notification @group_notifications = current_user.notification_settings.for_groups @project_notifications = current_user.notification_settings.for_projects end diff --git a/app/models/member.rb b/app/models/member.rb index 747d0f16d8d9..7d5af1d5c8af 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -163,7 +163,7 @@ def resend_invite end def create_notification_setting - user.notification_setting.find_or_create_for(source) + user.notification_settings.find_or_create_for(source) end def notification_setting -- GitLab From 5583197e091e8f75ad9c99a1bbc46e6a0b7279d4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Tue, 29 Mar 2016 17:42:38 +0200 Subject: [PATCH 13/34] Create NotificationSettings object only when user change value in dropdown Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- app/assets/javascripts/project.js.coffee | 9 +++++++- .../notification_settings_controller.rb | 22 +++++++++++++++++++ app/controllers/projects_controller.rb | 3 ++- .../projects/buttons/_notifications.html.haml | 5 ++--- config/routes.rb | 1 + 5 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 app/controllers/projects/notification_settings_controller.rb diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee index f171442d05ad..07be85a32a5c 100644 --- a/app/assets/javascripts/project.js.coffee +++ b/app/assets/javascripts/project.js.coffee @@ -38,12 +38,19 @@ class @Project e.preventDefault() notification_level = $(@).data 'notification-level' label = $(@).data 'notification-title' - $('#notification_level').val(notification_level) + $('#notification_setting_level').val(notification_level) $('#notification-form').submit() $('#notifications-button').empty().append("<i class='fa fa-bell'></i>" + label + "<i class='fa fa-angle-down'></i>") $(@).parents('ul').find('li.active').removeClass 'active' $(@).parent().addClass 'active' + $('#notification-form').on 'ajax:success', (e, data) -> + if data.saved + new Flash("Notification settings saved", "notice") + else + new Flash("Failed to save new settings", "alert") + + @projectSelectDropdown() projectSelectDropdown: -> diff --git a/app/controllers/projects/notification_settings_controller.rb b/app/controllers/projects/notification_settings_controller.rb new file mode 100644 index 000000000000..3ecf63d107f0 --- /dev/null +++ b/app/controllers/projects/notification_settings_controller.rb @@ -0,0 +1,22 @@ +class Projects::NotificationSettingsController < Projects::ApplicationController + def create + notification_setting = project.notification_settings.new(notification_setting_params) + notification_setting.user = current_user + saved = notification_setting.save + + render json: { saved: saved } + end + + def update + notification_setting = project.notification_settings.where(user_id: current_user).find(params[:id]) + saved = notification_setting.update_attributes(notification_setting_params) + + render json: { saved: saved } + end + + private + + def notification_setting_params + params.require(:notification_setting).permit(:level) + end +end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index e2dc6309d263..ec5318f2d2cf 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -102,7 +102,8 @@ def show @membership = @project.team.find_member(current_user.id) if @membership - @notification_setting = current_user.notification_settings.find_or_create_for(@project) + @notification_setting = current_user.notification_settings.find_or_initialize_by(source: @project) + @notification_setting.set_defaults unless @notification_setting.persisted? end end diff --git a/app/views/projects/buttons/_notifications.html.haml b/app/views/projects/buttons/_notifications.html.haml index 4b8a10f08197..2b9d8f2ac816 100644 --- a/app/views/projects/buttons/_notifications.html.haml +++ b/app/views/projects/buttons/_notifications.html.haml @@ -1,7 +1,6 @@ - if @notification_setting - = form_tag profile_notifications_path, method: :put, remote: true, class: 'inline', id: 'notification-form' do - = hidden_field_tag :notification_id, @notification_setting.id - = hidden_field_tag :notification_level, @notification_setting.level + = form_for [@project.namespace.becomes(Namespace), @project, @notification_setting], remote: true, html: { class: 'inline', id: 'notification-form' } do |f| + = f.hidden_field :level %span.dropdown %a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"} = icon('bell') diff --git a/config/routes.rb b/config/routes.rb index 6bf22fb44567..c665cefbb57d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -606,6 +606,7 @@ resources :forks, only: [:index, :new, :create] resource :import, only: [:new, :create, :show] + resources :notification_settings, only: [:create, :update] resources :refs, only: [] do collection do -- GitLab From 729fe42bff474535c9eebb0b73974a79756372b8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Tue, 29 Mar 2016 17:56:12 +0200 Subject: [PATCH 14/34] Improve project notification settings explanation Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- app/views/profiles/notifications/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml index f6900f61b2d0..e9c8ae285447 100644 --- a/app/views/profiles/notifications/show.html.haml +++ b/app/views/profiles/notifications/show.html.haml @@ -65,7 +65,7 @@ %h5 Projects (#{@project_notifications.count}) %p.account-well - To specify the notification level per project of a group you belong to, you need to be a member of the project itself, not only its group. + To specify the notification level per project of a group you belong to, you need to visit project page and change notification level there. .append-bottom-default %ul.bordered-list - @project_notifications.each do |setting| -- GitLab From 26631f9981a826ebe4aeba726e9be2b813d2c5c5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Tue, 29 Mar 2016 18:59:03 +0200 Subject: [PATCH 15/34] Change how notification settings in profile are rendered and updated Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- app/assets/javascripts/profile.js.coffee | 7 +- .../notification_settings_controller.rb | 14 ++++ .../profiles/notifications_controller.rb | 28 ++------ .../notifications/_group_settings.html.haml | 13 ++++ .../notifications/_project_settings.html.haml | 13 ++++ .../notifications/_settings.html.haml | 17 ----- .../profiles/notifications/show.html.haml | 72 ++++++++++--------- .../profiles/notifications/update.js.haml | 6 -- config/routes.rb | 1 + 9 files changed, 89 insertions(+), 82 deletions(-) create mode 100644 app/controllers/groups/notification_settings_controller.rb create mode 100644 app/views/profiles/notifications/_group_settings.html.haml create mode 100644 app/views/profiles/notifications/_project_settings.html.haml delete mode 100644 app/views/profiles/notifications/_settings.html.haml delete mode 100644 app/views/profiles/notifications/update.js.haml diff --git a/app/assets/javascripts/profile.js.coffee b/app/assets/javascripts/profile.js.coffee index ae87c6c4e40b..f4a2562885df 100644 --- a/app/assets/javascripts/profile.js.coffee +++ b/app/assets/javascripts/profile.js.coffee @@ -18,8 +18,11 @@ class @Profile $(this).find('.btn-save').enable() $(this).find('.loading-gif').hide() - $('.update-notifications').on 'ajax:complete', -> - $(this).find('.btn-save').enable() + $('.update-notifications').on 'ajax:success', (e, data) -> + if data.saved + new Flash("Notification settings saved", "notice") + else + new Flash("Failed to save new settings", "alert") @bindEvents() diff --git a/app/controllers/groups/notification_settings_controller.rb b/app/controllers/groups/notification_settings_controller.rb new file mode 100644 index 000000000000..78e43c83abab --- /dev/null +++ b/app/controllers/groups/notification_settings_controller.rb @@ -0,0 +1,14 @@ +class Groups::NotificationSettingsController < Groups::ApplicationController + def update + notification_setting = group.notification_settings.where(user_id: current_user).find(params[:id]) + saved = notification_setting.update_attributes(notification_setting_params) + + render json: { saved: saved } + end + + private + + def notification_setting_params + params.require(:notification_setting).permit(:level) + end +end diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb index 0cca5d1e3307..18ee55c839a6 100644 --- a/app/controllers/profiles/notifications_controller.rb +++ b/app/controllers/profiles/notifications_controller.rb @@ -6,29 +6,13 @@ def show end def update - type = params[:notification_type] - - @saved = if type == 'global' - current_user.update_attributes(user_params) - else - notification_setting = current_user.notification_settings.find(params[:notification_id]) - notification_setting.level = params[:notification_level] - notification_setting.save - end - - respond_to do |format| - format.html do - if @saved - flash[:notice] = "Notification settings saved" - else - flash[:alert] = "Failed to save new settings" - end - - redirect_back_or_default(default: profile_notifications_path) - end - - format.js + if current_user.update_attributes(user_params) + flash[:notice] = "Notification settings saved" + else + flash[:alert] = "Failed to save new settings" end + + redirect_back_or_default(default: profile_notifications_path) end def user_params diff --git a/app/views/profiles/notifications/_group_settings.html.haml b/app/views/profiles/notifications/_group_settings.html.haml new file mode 100644 index 000000000000..89ae7ffda2bb --- /dev/null +++ b/app/views/profiles/notifications/_group_settings.html.haml @@ -0,0 +1,13 @@ +%li.notification-list-item + %span.notification.fa.fa-holder.append-right-5 + - if setting.global? + = notification_icon(current_user.notification_level) + - else + = notification_icon(setting.level) + + %span.str-truncated + = link_to group.name, group_path(group) + + .pull-right + = form_for [group, setting], remote: true, html: { class: 'update-notifications' } do |f| + = f.select :level, NotificationSetting.levels.keys, {}, class: 'form-control trigger-submit' diff --git a/app/views/profiles/notifications/_project_settings.html.haml b/app/views/profiles/notifications/_project_settings.html.haml new file mode 100644 index 000000000000..17c097154da6 --- /dev/null +++ b/app/views/profiles/notifications/_project_settings.html.haml @@ -0,0 +1,13 @@ +%li.notification-list-item + %span.notification.fa.fa-holder.append-right-5 + - if setting.global? + = notification_icon(current_user.notification_level) + - else + = notification_icon(setting.level) + + %span.str-truncated + = link_to_project(project) + + .pull-right + = form_for [project.namespace.becomes(Namespace), project, setting], remote: true, html: { class: 'update-notifications' } do |f| + = f.select :level, NotificationSetting.levels.keys, {}, class: 'form-control trigger-submit' diff --git a/app/views/profiles/notifications/_settings.html.haml b/app/views/profiles/notifications/_settings.html.haml deleted file mode 100644 index c32de0b9925a..000000000000 --- a/app/views/profiles/notifications/_settings.html.haml +++ /dev/null @@ -1,17 +0,0 @@ -%li.notification-list-item - %span.notification.fa.fa-holder.append-right-5 - - if setting.global? - = notification_icon(current_user.notification_level) - - else - = notification_icon(setting.level) - - %span.str-truncated - - if setting.source.kind_of? Project - = link_to_project(setting.source) - - else - = link_to setting.source.name, group_path(setting.source) - .pull-right - = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do - = hidden_field_tag :notification_id, setting.id - = hidden_field_tag :notification_level, setting.level - = select_tag :notification_level, options_for_select(User.notification_levels.keys, setting.level), class: 'form-control trigger-submit' diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml index e9c8ae285447..a2a505c082b7 100644 --- a/app/views/profiles/notifications/show.html.haml +++ b/app/views/profiles/notifications/show.html.haml @@ -1,8 +1,8 @@ - page_title "Notifications" - header_title page_title, profile_notifications_path -= form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications prepend-top-default' } do |f| - -if @user.errors.any? +%div + - if @user.errors.any? %div.alert.alert-danger %ul - @user.errors.full_messages.each do |msg| @@ -20,48 +20,50 @@ .col-lg-9 %h5 Global notification settings - .form-group - = f.label :notification_email, class: "label-light" - = f.select :notification_email, @user.all_emails, { include_blank: false }, class: "select2" - .form-group - = f.label :notification_level, class: 'label-light' - .radio - = f.label :notification_level, value: :disabled do - = f.radio_button :notification_level, :disabled - .level-title - Disabled - %p You will not get any notifications via email - .radio - = f.label :notification_level, value: :mention do - = f.radio_button :notification_level, :mention - .level-title - On Mention - %p You will receive notifications only for comments in which you were @mentioned + = form_for @user, url: profile_notifications_path, method: :put, html: { class: 'update-notifications prepend-top-default' } do |f| + .form-group + = f.label :notification_email, class: "label-light" + = f.select :notification_email, @user.all_emails, { include_blank: false }, class: "select2" + .form-group + = f.label :notification_level, class: 'label-light' + .radio + = f.label :notification_level, value: :disabled do + = f.radio_button :notification_level, :disabled + .level-title + Disabled + %p You will not get any notifications via email - .radio - = f.label :notification_level, value: :participating do - = f.radio_button :notification_level, :participating - .level-title - Participating - %p You will only receive notifications from related resources (e.g. from your commits or assigned issues) + .radio + = f.label :notification_level, value: :mention do + = f.radio_button :notification_level, :mention + .level-title + On Mention + %p You will receive notifications only for comments in which you were @mentioned - .radio - = f.label :notification_level, value: :watch do - = f.radio_button :notification_level, :watch - .level-title - Watch - %p You will receive notifications for any activity + .radio + = f.label :notification_level, value: :participating do + = f.radio_button :notification_level, :participating + .level-title + Participating + %p You will only receive notifications from related resources (e.g. from your commits or assigned issues) - .prepend-top-default - = f.submit 'Update settings', class: "btn btn-create" + .radio + = f.label :notification_level, value: :watch do + = f.radio_button :notification_level, :watch + .level-title + Watch + %p You will receive notifications for any activity + + .prepend-top-default + = f.submit 'Update settings', class: "btn btn-create" %hr %h5 Groups (#{@group_notifications.count}) %div %ul.bordered-list - @group_notifications.each do |setting| - = render 'settings', setting: setting + = render 'group_settings', setting: setting, group: setting.source %h5 Projects (#{@project_notifications.count}) %p.account-well @@ -69,4 +71,4 @@ .append-bottom-default %ul.bordered-list - @project_notifications.each do |setting| - = render 'settings', setting: setting + = render 'project_settings', setting: setting, project: setting.source diff --git a/app/views/profiles/notifications/update.js.haml b/app/views/profiles/notifications/update.js.haml deleted file mode 100644 index 84c6ab25599e..000000000000 --- a/app/views/profiles/notifications/update.js.haml +++ /dev/null @@ -1,6 +0,0 @@ -- if @saved - :plain - new Flash("Notification settings saved", "notice") -- else - :plain - new Flash("Failed to save new settings", "alert") diff --git a/config/routes.rb b/config/routes.rb index c665cefbb57d..7f03fbf6af91 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -406,6 +406,7 @@ resource :avatar, only: [:destroy] resources :milestones, constraints: { id: /[^\/]+/ }, only: [:index, :show, :update, :new, :create] + resources :notification_settings, only: [:update] end end -- GitLab From 949431fa02da18257c8b7c7a24c03faa04c02c5e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Tue, 29 Mar 2016 22:19:00 +0200 Subject: [PATCH 16/34] Update API to use notification_level from notification_setting Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- lib/api/entities.rb | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index f686c568bee3..f414c1f98855 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -255,14 +255,19 @@ class Namespace < Grape::Entity expose :id, :path, :kind end - class ProjectAccess < Grape::Entity + class Member < Grape::Entity expose :access_level - expose :notification_level + expose :notification_level do |member, options| + if member.notification_setting + NotificationSetting.levels[member.notification_setting.level] + end + end end - class GroupAccess < Grape::Entity - expose :access_level - expose :notification_level + class ProjectAccess < Member + end + + class GroupAccess < Member end class ProjectService < Grape::Entity -- GitLab From 49f9873ce2a88fb38f23f7eb09471e8b58aebe1d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Tue, 29 Mar 2016 22:20:59 +0200 Subject: [PATCH 17/34] Add changelog item Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 2cd06d90257d..88edf1e8484a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ v 8.7.0 (unreleased) - Implement 'Groups View' as an option for dashboard preferences !3379 (Elias W.) - Implement 'TODOs View' as an option for dashboard preferences !3379 (Elias W.) - Gracefully handle notes on deleted commits in merge requests (Stan Hu) + - Decouple membership and notifications v 8.6.2 (unreleased) - Comments on confidential issues don't show up in activity feed to non-members -- GitLab From 065faac3a390f29b57db5261e9eab4efa076554c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Wed, 30 Mar 2016 10:32:19 +0200 Subject: [PATCH 18/34] Test changing notification settings per project fron notificaitons page Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- features/profile/notifications.feature | 6 ++++++ features/steps/profile/notifications.rb | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/features/profile/notifications.feature b/features/profile/notifications.feature index 55997d44dec2..ef8743932f51 100644 --- a/features/profile/notifications.feature +++ b/features/profile/notifications.feature @@ -7,3 +7,9 @@ Feature: Profile Notifications Scenario: I visit notifications tab When I visit profile notifications page Then I should see global notifications settings + + @javascript + Scenario: I edit Project Notifications + Given I visit profile notifications page + When I select Mention setting from dropdown + Then I should see Notification saved message diff --git a/features/steps/profile/notifications.rb b/features/steps/profile/notifications.rb index 447ea6d9d10f..a96f35ada51e 100644 --- a/features/steps/profile/notifications.rb +++ b/features/steps/profile/notifications.rb @@ -9,4 +9,14 @@ class Spinach::Features::ProfileNotifications < Spinach::FeatureSteps step 'I should see global notifications settings' do expect(page).to have_content "Notifications" end + + step 'I select Mention setting from dropdown' do + select 'mention', from: 'notification_setting_level' + end + + step 'I should see Notification saved message' do + page.within '.flash-container' do + expect(page).to have_content 'Notification settings saved' + end + end end -- GitLab From 1a293a43847b30d4357116f830a1b22d370c4a6f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> Date: Wed, 30 Mar 2016 10:38:03 +0200 Subject: [PATCH 19/34] Update migration comment Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> --- .../20160328115649_migrate_new_notification_setting.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/db/migrate/20160328115649_migrate_new_notification_setting.rb b/db/migrate/20160328115649_migrate_new_notification_setting.rb index aff866b5f46f..6a68890f5b15 100644 --- a/db/migrate/20160328115649_migrate_new_notification_setting.rb +++ b/db/migrate/20160328115649_migrate_new_notification_setting.rb @@ -1,6 +1,10 @@ # This migration will create one row of NotificationSetting for each Member row -# It can take long time on big instances. Its unclear yet if this migration can be done online. -# This comment should be updated by @dzaporozhets before 8.7 release. If not - please ask him to do so. +# It can take long time on big instances. +# +# This migration can be done online but with following effects: +# - during migration some users will receive notifications based on their global settings (project/group settings will be ignored) +# - its possible to get duplicate records for notification settings since we don't create uniq index yet +# class MigrateNewNotificationSetting < ActiveRecord::Migration def up timestamp = Time.now -- GitLab From d11288be9580633baa3b21b4c70a5fc01e53d094 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Fri, 8 Apr 2016 16:49:01 -0300 Subject: [PATCH 20/34] Use query instead of model on migrations --- db/migrate/20160328115649_migrate_new_notification_setting.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20160328115649_migrate_new_notification_setting.rb b/db/migrate/20160328115649_migrate_new_notification_setting.rb index 6a68890f5b15..0a110869027a 100644 --- a/db/migrate/20160328115649_migrate_new_notification_setting.rb +++ b/db/migrate/20160328115649_migrate_new_notification_setting.rb @@ -12,6 +12,6 @@ def up end def down - NotificationSetting.delete_all + execute "DELETE FROM notification_settings" end end -- GitLab From 127119f2c4db9038a7f34d1cc73ae1ed19cf0b8d Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Fri, 8 Apr 2016 16:59:06 -0300 Subject: [PATCH 21/34] Simplify query to retrieve NotificationSetting on controllers --- app/controllers/groups/notification_settings_controller.rb | 2 +- app/controllers/projects/notification_settings_controller.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/groups/notification_settings_controller.rb b/app/controllers/groups/notification_settings_controller.rb index 78e43c83abab..20405a051906 100644 --- a/app/controllers/groups/notification_settings_controller.rb +++ b/app/controllers/groups/notification_settings_controller.rb @@ -1,6 +1,6 @@ class Groups::NotificationSettingsController < Groups::ApplicationController def update - notification_setting = group.notification_settings.where(user_id: current_user).find(params[:id]) + notification_setting = group.notification_settings.find_by(user_id: current_user) saved = notification_setting.update_attributes(notification_setting_params) render json: { saved: saved } diff --git a/app/controllers/projects/notification_settings_controller.rb b/app/controllers/projects/notification_settings_controller.rb index 3ecf63d107f0..da9034380afe 100644 --- a/app/controllers/projects/notification_settings_controller.rb +++ b/app/controllers/projects/notification_settings_controller.rb @@ -8,7 +8,7 @@ def create end def update - notification_setting = project.notification_settings.where(user_id: current_user).find(params[:id]) + notification_setting = project.notification_settings.find_by(user_id: current_user) saved = notification_setting.update_attributes(notification_setting_params) render json: { saved: saved } -- GitLab From 069724cef5873b83720004772d1e874030cc9fff Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Fri, 8 Apr 2016 17:11:13 -0300 Subject: [PATCH 22/34] Use singular resource for NotificationSetting Since a user cannot have multiple NotificationSettings records for one group/project we can use singular resource. --- config/routes.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index fade07c05005..552385110dd2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -406,7 +406,7 @@ resource :avatar, only: [:destroy] resources :milestones, constraints: { id: /[^\/]+/ }, only: [:index, :show, :update, :new, :create] - resources :notification_settings, only: [:update] + resource :notification_setting, only: [:update] end end @@ -608,7 +608,7 @@ resources :forks, only: [:index, :new, :create] resource :import, only: [:new, :create, :show] - resources :notification_settings, only: [:create, :update] + resource :notification_setting, only: [:create, :update] resources :refs, only: [] do collection do -- GitLab From ee497599cc69b126cc2e4a929f1799d3d3eb989d Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Fri, 8 Apr 2016 17:24:27 -0300 Subject: [PATCH 23/34] Use default_value_for to set default NotificationSetting#level --- app/controllers/projects_controller.rb | 1 - app/models/notification_setting.rb | 14 ++++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 41a4c41cf805..39f436f6f4e4 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -106,7 +106,6 @@ def show if @membership @notification_setting = current_user.notification_settings.find_or_initialize_by(source: @project) - @notification_setting.set_defaults unless @notification_setting.persisted? end end diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb index 13a8995b036c..d89194b5a128 100644 --- a/app/models/notification_setting.rb +++ b/app/models/notification_setting.rb @@ -1,4 +1,10 @@ class NotificationSetting < ActiveRecord::Base + # Notification level + # Note: When adding an option, it MUST go on the end of the array. + enum level: [:disabled, :participating, :watch, :global, :mention] + + default_value_for :level, NotificationSetting.levels[:global] + belongs_to :user belongs_to :source, polymorphic: true @@ -8,9 +14,6 @@ class NotificationSetting < ActiveRecord::Base validates :user_id, uniqueness: { scope: [:source_type, :source_id], message: "already exists in source", allow_nil: true } - # Notification level - # Note: When adding an option, it MUST go on the end of the array. - enum level: [:disabled, :participating, :watch, :global, :mention] scope :for_groups, -> { where(source_type: 'Namespace') } scope :for_projects, -> { where(source_type: 'Project') } @@ -19,14 +22,9 @@ def self.find_or_create_for(source) setting = find_or_initialize_by(source: source) unless setting.persisted? - setting.set_defaults setting.save end setting end - - def set_defaults - self.level = :global - end end -- GitLab From 635b65d1206293d0b92322df18d458447ee73d5a Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Fri, 8 Apr 2016 17:35:21 -0300 Subject: [PATCH 24/34] Add method to return the user notification setting for a group, or a project --- app/controllers/projects_controller.rb | 2 +- app/models/user.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 39f436f6f4e4..3768efe142aa 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -105,7 +105,7 @@ def show @membership = @project.team.find_member(current_user.id) if @membership - @notification_setting = current_user.notification_settings.find_or_initialize_by(source: @project) + @notification_setting = current_user.notification_settings_for(@project) end end diff --git a/app/models/user.rb b/app/models/user.rb index f68379fd0504..031315debd75 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -831,6 +831,10 @@ def ci_authorized_runners end end + def notification_settings_for(source) + notification_settings.find_or_initialize_by(source: source) + end + private def projects_union -- GitLab From e3d4ebdd543f17d91e5c67be2f30bb97c687b448 Mon Sep 17 00:00:00 2001 From: Yorick Peterse <yorickpeterse@gmail.com> Date: Thu, 7 Apr 2016 16:40:51 +0200 Subject: [PATCH 25/34] Update gitlab-shell to 2.7.2 --- GITLAB_SHELL_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index 24ba9a38de68..37c2961c2430 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -2.7.0 +2.7.2 -- GitLab From 47c8b7f3037c3e464e34d6f978a27e591f09e687 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Fri, 8 Apr 2016 17:44:55 -0300 Subject: [PATCH 26/34] Fix CHANGELOG --- CHANGELOG | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c072cada732c..eae6cb907003 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -25,10 +25,6 @@ v 8.7.0 (unreleased) - Implement 'TODOs View' as an option for dashboard preferences !3379 (Elias W.) - Gracefully handle notes on deleted commits in merge requests (Stan Hu) - Decouple membership and notifications - -v 8.6.2 (unreleased) - - Comments on confidential issues don't show up in activity feed to non-members - - Fix NoMethodError when visiting CI root path at `/ci` - Fix creation of merge requests for orphaned branches (Stan Hu) - Fall back to `In-Reply-To` and `References` headers when sub-addressing is not available (David Padilla) - Remove "Congratulations!" tweet button on newly-created project. (Connor Shea) -- GitLab From 99067a505ca62dc069189118d7d4c4e91de83917 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Fri, 8 Apr 2016 18:06:36 -0300 Subject: [PATCH 27/34] Fix schema.rb --- db/schema.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index 4c7673511fbf..a66274dc5a1b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160331133914) do +ActiveRecord::Schema.define(version: 20160331223143) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -799,9 +799,9 @@ t.string "type" t.string "title" t.integer "project_id" - t.datetime "created_at" - t.datetime "updated_at" - t.boolean "active", default: false, null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "active", null: false t.text "properties" t.boolean "template", default: false t.boolean "push_events", default: true -- GitLab From 73fdd4b83d76998fef9770dbeaf05981d4500b8c Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Mon, 11 Apr 2016 10:23:40 -0300 Subject: [PATCH 28/34] Use Hash instead of Array on NotificationSetting#level enum --- app/models/notification_setting.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb index d89194b5a128..5001738f411f 100644 --- a/app/models/notification_setting.rb +++ b/app/models/notification_setting.rb @@ -1,7 +1,5 @@ class NotificationSetting < ActiveRecord::Base - # Notification level - # Note: When adding an option, it MUST go on the end of the array. - enum level: [:disabled, :participating, :watch, :global, :mention] + enum level: { disabled: 0, participating: 1, watch: 2, global: 3, mention: 4 } default_value_for :level, NotificationSetting.levels[:global] -- GitLab From 93a10f17e0c84074580eaf1b101af2a0fffd19ed Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Mon, 11 Apr 2016 18:23:12 -0300 Subject: [PATCH 29/34] Reuse `User#notification_settings_for` when it's possible --- app/controllers/groups/notification_settings_controller.rb | 2 +- .../projects/notification_settings_controller.rb | 7 +++---- app/models/member.rb | 2 +- app/services/notification_service.rb | 4 ++-- spec/services/notification_service_spec.rb | 4 ++-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/controllers/groups/notification_settings_controller.rb b/app/controllers/groups/notification_settings_controller.rb index 20405a051906..1b46f26a3781 100644 --- a/app/controllers/groups/notification_settings_controller.rb +++ b/app/controllers/groups/notification_settings_controller.rb @@ -1,6 +1,6 @@ class Groups::NotificationSettingsController < Groups::ApplicationController def update - notification_setting = group.notification_settings.find_by(user_id: current_user) + notification_setting = current_user.notification_settings_for(group) saved = notification_setting.update_attributes(notification_setting_params) render json: { saved: saved } diff --git a/app/controllers/projects/notification_settings_controller.rb b/app/controllers/projects/notification_settings_controller.rb index da9034380afe..90d294a46246 100644 --- a/app/controllers/projects/notification_settings_controller.rb +++ b/app/controllers/projects/notification_settings_controller.rb @@ -1,14 +1,13 @@ class Projects::NotificationSettingsController < Projects::ApplicationController def create - notification_setting = project.notification_settings.new(notification_setting_params) - notification_setting.user = current_user - saved = notification_setting.save + notification_setting = current_user.notification_settings_for(project) + saved = notification_setting.update_attributes(notification_setting_params) render json: { saved: saved } end def update - notification_setting = project.notification_settings.find_by(user_id: current_user) + notification_setting = current_user.notification_settings_for(project) saved = notification_setting.update_attributes(notification_setting_params) render json: { saved: saved } diff --git a/app/models/member.rb b/app/models/member.rb index 7d5af1d5c8af..60efafef2117 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -167,7 +167,7 @@ def create_notification_setting end def notification_setting - @notification_setting ||= user.notification_settings.find_by(source: source) + @notification_setting ||= user.notification_settings_for(source) end private diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 0928dda349ef..42ec1ac9e1a1 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -355,10 +355,10 @@ def reject_users(users, level, project = nil) users.reject do |user| next user.notification_level == level unless project - setting = user.notification_settings.find_by(source: project) + setting = user.notification_settings_for(project) if !setting && project.group - setting = user.notification_settings.find_by(source: project.group) + setting = user.notification_settings_for(project.group) end # reject users who globally set mention notification and has no setting per project/group diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index c4d52584a4b7..d7c72dc08118 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -89,8 +89,8 @@ note.project.group.add_user(@u_watcher, GroupMember::MASTER) note.project.save - @u_watcher.notification_settings.find_by(source: note.project).participating! - @u_watcher.notification_settings.find_by(source: note.project.group).global! + @u_watcher.notification_settings_for(note.project).participating! + @u_watcher.notification_settings_for(note.project.group).global! ActionMailer::Base.deliveries.clear end -- GitLab From bee28e1785ad7844bd518c19106beee7d8a4c560 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Mon, 11 Apr 2016 18:57:18 -0300 Subject: [PATCH 30/34] Requires user to be signed in when changing notification settings --- .../notification_settings_controller.rb | 2 ++ .../notification_settings_controller.rb | 2 ++ .../notification_settings_controller_spec.rb | 17 ++++++++++ .../notification_settings_controller_spec.rb | 31 +++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 spec/controllers/groups/notification_settings_controller_spec.rb create mode 100644 spec/controllers/projects/notification_settings_controller_spec.rb diff --git a/app/controllers/groups/notification_settings_controller.rb b/app/controllers/groups/notification_settings_controller.rb index 1b46f26a3781..de13b16ccf21 100644 --- a/app/controllers/groups/notification_settings_controller.rb +++ b/app/controllers/groups/notification_settings_controller.rb @@ -1,4 +1,6 @@ class Groups::NotificationSettingsController < Groups::ApplicationController + before_action :authenticate_user! + def update notification_setting = current_user.notification_settings_for(group) saved = notification_setting.update_attributes(notification_setting_params) diff --git a/app/controllers/projects/notification_settings_controller.rb b/app/controllers/projects/notification_settings_controller.rb index 90d294a46246..e536725c5b11 100644 --- a/app/controllers/projects/notification_settings_controller.rb +++ b/app/controllers/projects/notification_settings_controller.rb @@ -1,4 +1,6 @@ class Projects::NotificationSettingsController < Projects::ApplicationController + before_action :authenticate_user! + def create notification_setting = current_user.notification_settings_for(project) saved = notification_setting.update_attributes(notification_setting_params) diff --git a/spec/controllers/groups/notification_settings_controller_spec.rb b/spec/controllers/groups/notification_settings_controller_spec.rb new file mode 100644 index 000000000000..3572535d61c1 --- /dev/null +++ b/spec/controllers/groups/notification_settings_controller_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe Groups::NotificationSettingsController do + let(:group) { create(:group) } + + describe '#update' do + context 'when not authorized' do + it 'redirects to sign in page' do + put :update, + group_id: group.to_param, + notification_setting: { level: NotificationSetting.levels[:participating] } + + expect(response).to redirect_to(new_user_session_path) + end + end + end +end diff --git a/spec/controllers/projects/notification_settings_controller_spec.rb b/spec/controllers/projects/notification_settings_controller_spec.rb new file mode 100644 index 000000000000..7e32a75b8125 --- /dev/null +++ b/spec/controllers/projects/notification_settings_controller_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe Projects::NotificationSettingsController do + let(:project) { create(:empty_project) } + + describe '#create' do + context 'when not authorized' do + it 'redirects to sign in page' do + post :create, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + notification_setting: { level: NotificationSetting.levels[:participating] } + + expect(response).to redirect_to(new_user_session_path) + end + end + end + + describe '#update' do + context 'when not authorized' do + it 'redirects to sign in page' do + put :update, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + notification_setting: { level: NotificationSetting.levels[:participating] } + + expect(response).to redirect_to(new_user_session_path) + end + end + end +end -- GitLab From fe58c1f13cc0758bbbd8f85b8794b458b3a72b55 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Mon, 11 Apr 2016 19:29:31 -0300 Subject: [PATCH 31/34] Fix partial for update project notifications --- app/views/projects/buttons/_notifications.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/buttons/_notifications.html.haml b/app/views/projects/buttons/_notifications.html.haml index 2b9d8f2ac816..49f541399f24 100644 --- a/app/views/projects/buttons/_notifications.html.haml +++ b/app/views/projects/buttons/_notifications.html.haml @@ -1,5 +1,5 @@ - if @notification_setting - = form_for [@project.namespace.becomes(Namespace), @project, @notification_setting], remote: true, html: { class: 'inline', id: 'notification-form' } do |f| + = form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), remote: true, html: { class: 'inline', id: 'notification-form' } do |f| = f.hidden_field :level %span.dropdown %a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"} -- GitLab From ef22b76b732c2bf4ce52b8a73570ac2921f9caa4 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Mon, 11 Apr 2016 19:33:26 -0300 Subject: [PATCH 32/34] Simplify Projects::NotificationSettingsController --- .../projects/notification_settings_controller.rb | 7 ------- app/views/projects/buttons/_notifications.html.haml | 2 +- config/routes.rb | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/app/controllers/projects/notification_settings_controller.rb b/app/controllers/projects/notification_settings_controller.rb index e536725c5b11..7d81cc03c73f 100644 --- a/app/controllers/projects/notification_settings_controller.rb +++ b/app/controllers/projects/notification_settings_controller.rb @@ -1,13 +1,6 @@ class Projects::NotificationSettingsController < Projects::ApplicationController before_action :authenticate_user! - def create - notification_setting = current_user.notification_settings_for(project) - saved = notification_setting.update_attributes(notification_setting_params) - - render json: { saved: saved } - end - def update notification_setting = current_user.notification_settings_for(project) saved = notification_setting.update_attributes(notification_setting_params) diff --git a/app/views/projects/buttons/_notifications.html.haml b/app/views/projects/buttons/_notifications.html.haml index 49f541399f24..c1e3e5b73a2c 100644 --- a/app/views/projects/buttons/_notifications.html.haml +++ b/app/views/projects/buttons/_notifications.html.haml @@ -1,5 +1,5 @@ - if @notification_setting - = form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), remote: true, html: { class: 'inline', id: 'notification-form' } do |f| + = form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), method: :patch, remote: true, html: { class: 'inline', id: 'notification-form' } do |f| = f.hidden_field :level %span.dropdown %a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"} diff --git a/config/routes.rb b/config/routes.rb index 552385110dd2..48601b7567b0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -608,7 +608,7 @@ resources :forks, only: [:index, :new, :create] resource :import, only: [:new, :create, :show] - resource :notification_setting, only: [:create, :update] + resource :notification_setting, only: [:update] resources :refs, only: [] do collection do -- GitLab From aabb466e5b35477b39cc57642083df361cd5d112 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Mon, 11 Apr 2016 19:54:13 -0300 Subject: [PATCH 33/34] Improve specs for group/project notification controller --- .../notification_settings_controller_spec.rb | 17 +++++++- .../notification_settings_controller_spec.rb | 39 ++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/spec/controllers/groups/notification_settings_controller_spec.rb b/spec/controllers/groups/notification_settings_controller_spec.rb index 3572535d61c1..0786e45515a5 100644 --- a/spec/controllers/groups/notification_settings_controller_spec.rb +++ b/spec/controllers/groups/notification_settings_controller_spec.rb @@ -2,16 +2,31 @@ describe Groups::NotificationSettingsController do let(:group) { create(:group) } + let(:user) { create(:user) } describe '#update' do context 'when not authorized' do it 'redirects to sign in page' do put :update, group_id: group.to_param, - notification_setting: { level: NotificationSetting.levels[:participating] } + notification_setting: { level: :participating } expect(response).to redirect_to(new_user_session_path) end end + + context 'when authorized' do + before do + sign_in(user) + end + + it 'returns success' do + put :update, + group_id: group.to_param, + notification_setting: { level: :participating } + + expect(response.status).to eq 200 + end + end end end diff --git a/spec/controllers/projects/notification_settings_controller_spec.rb b/spec/controllers/projects/notification_settings_controller_spec.rb index 7e32a75b8125..385877a26df6 100644 --- a/spec/controllers/projects/notification_settings_controller_spec.rb +++ b/spec/controllers/projects/notification_settings_controller_spec.rb @@ -2,6 +2,11 @@ describe Projects::NotificationSettingsController do let(:project) { create(:empty_project) } + let(:user) { create(:user) } + + before do + project.team << [user, :developer] + end describe '#create' do context 'when not authorized' do @@ -9,11 +14,26 @@ post :create, namespace_id: project.namespace.to_param, project_id: project.to_param, - notification_setting: { level: NotificationSetting.levels[:participating] } + notification_setting: { level: :participating } expect(response).to redirect_to(new_user_session_path) end end + + context 'when authorized' do + before do + sign_in(user) + end + + it 'returns success' do + post :create, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + notification_setting: { level: :participating } + + expect(response.status).to eq 200 + end + end end describe '#update' do @@ -22,10 +42,25 @@ put :update, namespace_id: project.namespace.to_param, project_id: project.to_param, - notification_setting: { level: NotificationSetting.levels[:participating] } + notification_setting: { level: :participating } expect(response).to redirect_to(new_user_session_path) end end + + context 'when authorized' do + before do + sign_in(user) + end + + it 'returns success' do + put :update, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + notification_setting: { level: :participating } + + expect(response.status).to eq 200 + end + end end end -- GitLab From 61a62e00e3b08e6ed962b029564e3a2446e169fd Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre <dbalexandre@gmail.com> Date: Tue, 12 Apr 2016 12:57:39 -0300 Subject: [PATCH 34/34] Fix specs for Projects::NotificationSettingsController --- .../notification_settings_controller_spec.rb | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/spec/controllers/projects/notification_settings_controller_spec.rb b/spec/controllers/projects/notification_settings_controller_spec.rb index 385877a26df6..4908b5456487 100644 --- a/spec/controllers/projects/notification_settings_controller_spec.rb +++ b/spec/controllers/projects/notification_settings_controller_spec.rb @@ -8,34 +8,6 @@ project.team << [user, :developer] end - describe '#create' do - context 'when not authorized' do - it 'redirects to sign in page' do - post :create, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - notification_setting: { level: :participating } - - expect(response).to redirect_to(new_user_session_path) - end - end - - context 'when authorized' do - before do - sign_in(user) - end - - it 'returns success' do - post :create, - namespace_id: project.namespace.to_param, - project_id: project.to_param, - notification_setting: { level: :participating } - - expect(response.status).to eq 200 - end - end - end - describe '#update' do context 'when not authorized' do it 'redirects to sign in page' do -- GitLab