Skip to content
Snippets Groups Projects
Commit 25856a47 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets
Browse files

save each notification setting with ajax on change

parent 3c3baf8f
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -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;
}
}
Loading
Loading
@@ -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
Loading
Loading
@@ -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
Loading
Loading
@@ -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"
Loading
Loading
Loading
Loading
@@ -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
Loading
Loading
@@ -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
 
Loading
Loading
@@ -134,4 +136,8 @@ class UsersProject < ActiveRecord::Base
def skip_git?
!!@skip_git
end
def notification
@notification ||= Notification.new(self)
end
end
Loading
Loading
@@ -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|
Loading
Loading
@@ -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)
Loading
Loading
@@ -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)
 
Loading
Loading
@@ -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)
 
Loading
Loading
@@ -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)
Loading
Loading
Loading
Loading
@@ -13,56 +13,65 @@
&ndash; 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
- 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();
Loading
Loading
@@ -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"
Loading
Loading
@@ -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|
Loading
Loading
@@ -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"
Loading
Loading
Loading
Loading
@@ -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'
Loading
Loading
Loading
Loading
@@ -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'
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment