diff options
-rw-r--r-- | app/assets/stylesheets/sections/profile.scss | 13 | ||||
-rw-r--r-- | app/controllers/notifications_controller.rb | 14 | ||||
-rw-r--r-- | app/models/notification.rb | 21 | ||||
-rw-r--r-- | app/models/project.rb | 1 | ||||
-rw-r--r-- | app/models/users_project.rb | 18 | ||||
-rw-r--r-- | app/services/notification_service.rb | 40 | ||||
-rw-r--r-- | app/views/notifications/show.html.haml | 83 | ||||
-rw-r--r-- | app/views/notifications/update.js.haml | 5 | ||||
-rw-r--r-- | db/schema.rb | 15 | ||||
-rw-r--r-- | spec/models/project_spec.rb | 1 | ||||
-rw-r--r-- | spec/models/users_project_spec.rb | 13 |
11 files changed, 148 insertions, 76 deletions
diff --git a/app/assets/stylesheets/sections/profile.scss b/app/assets/stylesheets/sections/profile.scss index 607daf7a97e..c34cd23a9c9 100644 --- a/app/assets/stylesheets/sections/profile.scss +++ b/app/assets/stylesheets/sections/profile.scss @@ -20,3 +20,16 @@ border: 1px solid #ddd; } } + +.save-status-fixed { + position: fixed; + left: 20px; + bottom: 50px; +} + +.update-notifications { + margin-bottom: 0; + label { + margin-bottom: 0; + } +} diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index e44e0aa845e..4aa3172912f 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -3,11 +3,19 @@ class NotificationsController < ApplicationController def show @notification = current_user.notification - @projects = current_user.authorized_projects + @users_projects = current_user.users_projects end def update - current_user.notification_level = params[:notification_level] - @saved = current_user.save + type = params[:notification_type] + + @saved = if type == 'global' + current_user.notification_level = params[:notification_level] + current_user.save + else + users_project = current_user.users_projects.find(params[:notification_id]) + users_project.notification_level = params[:notification_level] + users_project.save + end end end diff --git a/app/models/notification.rb b/app/models/notification.rb index bfd1e2cff56..ff6a18d6a51 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -5,26 +5,35 @@ class Notification N_DISABLED = 0 N_PARTICIPATING = 1 N_WATCH = 2 + N_GLOBAL = 3 - attr_accessor :user + attr_accessor :target def self.notification_levels [N_DISABLED, N_PARTICIPATING, N_WATCH] end - def initialize(user) - @user = user + def self.project_notification_levels + [N_DISABLED, N_PARTICIPATING, N_WATCH, N_GLOBAL] + end + + def initialize(target) + @target = target end def disabled? - user.notification_level == N_DISABLED + target.notification_level == N_DISABLED end def participating? - user.notification_level == N_PARTICIPATING + target.notification_level == N_PARTICIPATING end def watch? - user.notification_level == N_WATCH + target.notification_level == N_WATCH + end + + def global? + target.notification_level == N_GLOBAL end end diff --git a/app/models/project.rb b/app/models/project.rb index 0263ffefdf0..53b318da66f 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -19,6 +19,7 @@ # issues_tracker :string(255) default("gitlab"), not null # issues_tracker_id :string(255) # snippets_enabled :boolean default(TRUE), not null +# last_activity_at :datetime # require "grit" diff --git a/app/models/users_project.rb b/app/models/users_project.rb index c32edf38025..935ecede42c 100644 --- a/app/models/users_project.rb +++ b/app/models/users_project.rb @@ -2,12 +2,13 @@ # # Table name: users_projects # -# id :integer not null, primary key -# user_id :integer not null -# project_id :integer not null -# created_at :datetime not null -# updated_at :datetime not null -# project_access :integer default(0), not null +# id :integer not null, primary key +# user_id :integer not null +# project_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# project_access :integer default(0), not null +# notification_level :integer default(3), not null # class UsersProject < ActiveRecord::Base @@ -29,6 +30,7 @@ class UsersProject < ActiveRecord::Base validates :user_id, uniqueness: { scope: [:project_id], message: "already exists in project" } validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true validates :project, presence: true + validates :notification_level, inclusion: { in: Notification.project_notification_levels }, presence: true delegate :name, :username, :email, to: :user, prefix: true @@ -134,4 +136,8 @@ class UsersProject < ActiveRecord::Base def skip_git? !!@skip_git end + + def notification + @notification ||= Notification.new(self) + end end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index f8779fd5c2d..4b3c982c189 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -80,7 +80,7 @@ class NotificationService # * project team members with notification level higher then Participating # def merge_mr(merge_request) - recipients = reject_muted_users([merge_request.author, merge_request.assignee]) + recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.project) recipients = recipients.concat(project_watchers(merge_request.project)).uniq recipients.each do |recipient| @@ -122,7 +122,7 @@ class NotificationService recipients = recipients.concat(project_watchers(note.project)).compact.uniq # Reject mutes users - recipients = reject_muted_users(recipients) + recipients = reject_muted_users(recipients, note.project) # Reject author recipients.delete(note.author) @@ -147,19 +147,41 @@ class NotificationService # Get project users with WATCH notification level def project_watchers(project) - project.users.where(notification_level: Notification::N_WATCH) + + # Get project notification settings since it has higher priority + user_ids = project.users_projects.where(notification_level: Notification::N_WATCH).pluck(:user_id) + project_watchers = User.where(id: user_ids) + + # next collect users who use global settings with watch state + user_ids = project.users_projects.where(notification_level: Notification::N_GLOBAL).pluck(:user_id) + project_watchers += User.where(id: user_ids, notification_level: Notification::N_WATCH) + + project_watchers.uniq end # Remove users with disabled notifications from array # Also remove duplications and nil recipients - def reject_muted_users(users) - users.compact.uniq.reject do |user| - user.notification.disabled? + def reject_muted_users(users, project = nil) + users = users.compact.uniq + + users.reject do |user| + next user.notification.disabled? unless project + + tm = project.users_projects.find_by_user_id(user.id) + + # reject users who globally disabled notification and has no membership + next user.notification.disabled? unless tm + + # reject users who disabled notification in project + next true if tm.notification.disabled? + + # reject users who have N_GLOBAL in project and disabled in global settings + tm.notification.global? && user.notification.disabled? end end def new_resource_email(target, method) - recipients = reject_muted_users([target.assignee]) + recipients = reject_muted_users([target.assignee], target.project) recipients = recipients.concat(project_watchers(target.project)).uniq recipients.delete(target.author) @@ -169,7 +191,7 @@ class NotificationService end def close_resource_email(target, current_user, method) - recipients = reject_muted_users([target.author, target.assignee]) + recipients = reject_muted_users([target.author, target.assignee], target.project) recipients = recipients.concat(project_watchers(target.project)).uniq recipients.delete(current_user) @@ -185,7 +207,7 @@ class NotificationService recipients = recipients.concat(project_watchers(target.project)) # reject users with disabled notifications - recipients = reject_muted_users(recipients) + recipients = reject_muted_users(recipients, target.project) # Reject me from recipients if I reassign an item recipients.delete(current_user) diff --git a/app/views/notifications/show.html.haml b/app/views/notifications/show.html.haml index d8ab93b8d1f..38e492f2d1b 100644 --- a/app/views/notifications/show.html.haml +++ b/app/views/notifications/show.html.haml @@ -13,56 +13,65 @@ – You will receive all notifications from projects in which you participate %hr -= form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do - %ul.well-list +.row + .span4 + %h5 Global + .span7 + = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do + = hidden_field_tag :notification_type, 'global' + + = label_tag do + = radio_button_tag :notification_level, Notification::N_DISABLED, @notification.disabled?, class: 'trigger-submit' + %span Disabled + + = label_tag do + = radio_button_tag :notification_level, Notification::N_PARTICIPATING, @notification.participating?, class: 'trigger-submit' + %span Participating + + = label_tag do + = radio_button_tag :notification_level, Notification::N_WATCH, @notification.watch?, class: 'trigger-submit' + %span Watch + +%hr += link_to '#', class: 'js-toggle-visibility-link' do + %h6.btn.btn-tiny + %i.icon-chevron-down + %span Per project notifications settings + +%ul.well-list.js-toggle-visibility-container.hide + - @users_projects.each do |users_project| + - notification = Notification.new(users_project) %li .row .span4 - %h5 Global + %span + = link_to_project(users_project.project) .span7 - = label_tag do - = radio_button_tag :notification_level, Notification::N_DISABLED, @notification.disabled? - %span Disabled - - = label_tag do - = radio_button_tag :notification_level, Notification::N_PARTICIPATING, @notification.participating? - %span Participating - - = label_tag do - = radio_button_tag :notification_level, Notification::N_WATCH, @notification.watch? - %span Watch + = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do + = hidden_field_tag :notification_type, 'project', id: dom_id(users_project, 'notification_type') + = hidden_field_tag :notification_id, users_project.id, id: dom_id(users_project, 'notification_id') + = label_tag do + = radio_button_tag :notification_level, Notification::N_GLOBAL, notification.global?, id: dom_id(users_project, 'notification_level'), class: 'trigger-submit' + %span Use global settings - = link_to '#', class: 'js-toggle-visibility-link' do - %h6.btn.btn-tiny - %i.icon-chevron-down - %span Per project notifications settings - %ul.well-list.js-toggle-visibility-container.hide - - @projects.each do |project| - %li - .row - .span4 - %span - = project.name_with_namespace - .span7 = label_tag do - = radio_button_tag :"notification_level[#{project.id}]", Notification::N_DISABLED, @notification.disabled?, disabled: true + = radio_button_tag :notification_level, Notification::N_DISABLED, notification.disabled?, id: dom_id(users_project, 'notification_level'), class: 'trigger-submit' %span Disabled = label_tag do - = radio_button_tag :"notification_level[#{project.id}]", Notification::N_PARTICIPATING, @notification.participating?, disabled: true + = radio_button_tag :notification_level, Notification::N_PARTICIPATING, notification.participating?, id: dom_id(users_project, 'notification_level'), class: 'trigger-submit' %span Participating = label_tag do - = radio_button_tag :"notification_level[#{project.id}]", Notification::N_WATCH, @notification.watch?, disabled: true + = radio_button_tag :notification_level, Notification::N_WATCH, notification.watch?, id: dom_id(users_project, 'notification_level'), class: 'trigger-submit' %span Watch - .form-actions - = submit_tag 'Save', class: 'btn btn-save' - %span.update-success.cgreen.hide - %i.icon-ok - Saved - %span.update-failed.cred.hide - %i.icon-remove - Failed +.save-status-fixed + %span.update-success.cgreen.hide + %i.icon-ok + Saved + %span.update-failed.cred.hide + %i.icon-remove + Failed diff --git a/app/views/notifications/update.js.haml b/app/views/notifications/update.js.haml index 4468004a5c2..88e74d50671 100644 --- a/app/views/notifications/update.js.haml +++ b/app/views/notifications/update.js.haml @@ -1,7 +1,6 @@ - if @saved :plain - $('.update-notifications .update-success').showAndHide(); + $('.save-status-fixed .update-success').showAndHide(); - else :plain - $('.update-notifications .update-failed').showAndHide(); - + $('.save-status-fixed .update-failed').showAndHide(); diff --git a/db/schema.rb b/db/schema.rb index 3c8b9eaee43..0f7827a736e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130325173941) do +ActiveRecord::Schema.define(:version => 20130404164628) do create_table "events", :force => true do |t| t.string "target_type" @@ -156,9 +156,11 @@ ActiveRecord::Schema.define(:version => 20130325173941) do t.string "issues_tracker", :default => "gitlab", :null => false t.string "issues_tracker_id" t.boolean "snippets_enabled", :default => true, :null => false + t.datetime "last_activity_at" end add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" + add_index "projects", ["last_activity_at"], :name => "index_projects_on_last_activity_at" add_index "projects", ["namespace_id"], :name => "index_projects_on_namespace_id" create_table "protected_branches", :force => true do |t| @@ -281,11 +283,12 @@ ActiveRecord::Schema.define(:version => 20130325173941) do add_index "users", ["username"], :name => "index_users_on_username" create_table "users_projects", :force => true do |t| - t.integer "user_id", :null => false - t.integer "project_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.integer "project_access", :default => 0, :null => false + t.integer "user_id", :null => false + t.integer "project_id", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "project_access", :default => 0, :null => false + t.integer "notification_level", :default => 3, :null => false end add_index "users_projects", ["project_access"], :name => "index_users_projects_on_project_access" diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index cbc7f278c2a..3ecf69795e3 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -19,6 +19,7 @@ # issues_tracker :string(255) default("gitlab"), not null # issues_tracker_id :string(255) # snippets_enabled :boolean default(TRUE), not null +# last_activity_at :datetime # require 'spec_helper' diff --git a/spec/models/users_project_spec.rb b/spec/models/users_project_spec.rb index e8f5b647ce0..e289a592b03 100644 --- a/spec/models/users_project_spec.rb +++ b/spec/models/users_project_spec.rb @@ -2,12 +2,13 @@ # # Table name: users_projects # -# id :integer not null, primary key -# user_id :integer not null -# project_id :integer not null -# created_at :datetime not null -# updated_at :datetime not null -# project_access :integer default(0), not null +# id :integer not null, primary key +# user_id :integer not null +# project_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# project_access :integer default(0), not null +# notification_level :integer default(3), not null # require 'spec_helper' |