Browse Source

Allow addition of watchers via bulk edit context menu (#5754).

git-svn-id: http://svn.redmine.org/redmine/trunk@15311 e93f8b46-1217-0410-a6f0-8f06a7374b81
tags/3.3.0
Jean-Philippe Lang 8 years ago
parent
commit
5adc1ddde9

+ 1
- 0
app/controllers/context_menus_controller.rb View File

@@ -32,6 +32,7 @@ class ContextMenusController < ApplicationController
@can = {:edit => User.current.allowed_to?(:edit_issues, @projects),
:log_time => (@project && User.current.allowed_to?(:log_time, @project)),
:copy => User.current.allowed_to?(:copy_issues, @projects) && Issue.allowed_target_projects.any?,
:add_watchers => User.current.allowed_to?(:add_issue_watchers, @projects),
:delete => User.current.allowed_to?(:delete_issues, @projects)
}
if @project

+ 32
- 21
app/controllers/watchers_controller.rb View File

@@ -42,7 +42,9 @@ class WatchersController < ApplicationController
end
users = User.active.visible.where(:id => user_ids.flatten.compact.uniq)
users.each do |user|
Watcher.create(:watchable => @watched, :user => user)
@watchables.each do |watchable|
Watcher.create(:watchable => watchable, :user => user)
end
end
respond_to do |format|
format.html { redirect_to_referer_or {render :text => 'Watcher added.', :layout => true}}
@@ -62,7 +64,10 @@ class WatchersController < ApplicationController
end

def destroy
@watched.set_watcher(User.find(params[:user_id]), false)
user = User.find(params[:user_id])
@watchables.each do |watchable|
watchable.set_watcher(user, false)
end
respond_to do |format|
format.html { redirect_to :back }
format.js
@@ -81,30 +86,21 @@ class WatchersController < ApplicationController

def find_project
if params[:object_type] && params[:object_id]
klass = Object.const_get(params[:object_type].camelcase)
return false unless klass.respond_to?('watched_by')
@watched = klass.find(params[:object_id])
@project = @watched.project
@watchables = find_objets_from_params
@projects = @watchables.map(&:project).uniq
if @projects.size == 1
@project = @projects.first
end
elsif params[:project_id]
@project = Project.visible.find_by_param(params[:project_id])
end
rescue
render_404
end

def find_watchables
klass = Object.const_get(params[:object_type].camelcase) rescue nil
if klass && klass.respond_to?('watched_by')
@watchables = klass.where(:id => Array.wrap(params[:object_id])).to_a
raise Unauthorized if @watchables.any? {|w|
if w.respond_to?(:visible?)
!w.visible?
elsif w.respond_to?(:project) && w.project
!w.project.visible?
end
}
@watchables = find_objets_from_params
unless @watchables.present?
render_404
end
render_404 unless @watchables.present?
end

def set_watcher(watchables, user, watching)
@@ -125,9 +121,24 @@ class WatchersController < ApplicationController
scope = User.all.limit(100)
end
users = scope.active.visible.sorted.like(params[:q]).to_a
if @watched
users -= @watched.watcher_users
if @watchables
users -= @watchables.map(&:watcher_users).flatten
end
users
end

def find_objets_from_params
klass = Object.const_get(params[:object_type].camelcase) rescue nil
return unless klass && klass.respond_to?('watched_by')

objects = klass.where(:id => Array.wrap(params[:object_id])).to_a
raise Unauthorized if objects.any? do |w|
if w.respond_to?(:visible?)
!w.visible?
elsif w.respond_to?(:project) && w.project
!w.project.visible?
end
end
objects
end
end

+ 12
- 0
app/views/context_menus/issues.html.erb View File

@@ -117,6 +117,18 @@
</li>
<% end %>

<% if @can[:add_watchers] %>
<li class="folder">
<a href="#" class="submenu"><%= l(:label_issue_watchers) %></a>
<ul>
<li><%= context_menu_link l(:button_add),
new_watchers_path(:object_type => 'issue', :object_id => @issue_ids),
:remote => true,
:class => 'icon-add' %></li>
</ul>
</li>
<% end %>

<% if User.current.logged? %>
<li><%= watcher_link(@issues, User.current) %></li>
<% end %>

+ 11
- 7
app/views/watchers/_new.html.erb View File

@@ -1,19 +1,23 @@
<h3 class="title"><%= l(:permission_add_issue_watchers) %></h3>

<%= form_tag({:controller => 'watchers',
:action => (watched ? 'create' : 'append'),
:object_type => (watched && watched.class.name.underscore),
:object_id => watched,
:project_id => @project},
<%= form_tag(watchables.present? ? watchers_path : watchers_append_path,
:remote => true,
:method => :post,
:id => 'new-watcher-form') do %>

<% if watchables.present? %>
<%= hidden_field_tag 'object_type', watchables.first.class.name.underscore %>
<% watchables.each do |watchable| %>
<%= hidden_field_tag 'object_id[]', watchable.id %>
<% end %>
<% end %>
<%= hidden_field_tag 'project_id', @project.id if @project %>

<p><%= label_tag 'user_search', l(:label_user_search) %><%= text_field_tag 'user_search', nil %></p>
<%= javascript_tag "observeSearchfield('user_search', 'users_for_watcher', '#{ escape_javascript url_for(:controller => 'watchers',
:action => 'autocomplete_for_user',
:object_type => (watched && watched.class.name.underscore),
:object_id => watched,
:object_type => (watchables.present? ? watchables.first.class.name.underscore : nil),
:object_id => (watchables.present? && watchables.size == 1 ? watchables.first.id : nil),
:project_id => @project) }')" %>

<div id="users_for_watcher">

+ 5
- 2
app/views/watchers/create.js.erb View File

@@ -1,2 +1,5 @@
$('#ajax-modal').html('<%= escape_javascript(render(:partial => 'watchers/new', :locals => {:watched => @watched, :users => @users})) %>');
$('#watchers').html('<%= escape_javascript(render(:partial => 'watchers/watchers', :locals => {:watched => @watched})) %>');
$('#ajax-modal').html('<%= escape_javascript(render(:partial => 'watchers/new', :locals => {:watchables => @watchables, :users => @users})) %>');

<% if @watchables.size == 1 %>
$('#watchers').html('<%= escape_javascript(render(:partial => 'watchers/watchers', :locals => {:watched => @watchables.first})) %>');
<% end %>

+ 3
- 1
app/views/watchers/destroy.js.erb View File

@@ -1 +1,3 @@
$('#watchers').html('<%= escape_javascript(render(:partial => 'watchers/watchers', :locals => {:watched => @watched})) %>');
<% if @watchables.size == 1 %>
$('#watchers').html('<%= escape_javascript(render(:partial => 'watchers/watchers', :locals => {:watched => @watchables.first})) %>');
<% end %>

+ 1
- 1
app/views/watchers/new.js.erb View File

@@ -1,3 +1,3 @@
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'watchers/new', :locals => {:watched => @watched, :users => @users}) %>');
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'watchers/new', :locals => {:watchables => @watchables, :users => @users}) %>');
showModal('ajax-modal', '400px');
$('#ajax-modal').addClass('new-watcher');

+ 1
- 1
config/routes.rb View File

@@ -91,7 +91,7 @@ Rails.application.routes.draw do

post 'watchers/watch', :to => 'watchers#watch', :as => 'watch'
delete 'watchers/watch', :to => 'watchers#unwatch'
get 'watchers/new', :to => 'watchers#new'
get 'watchers/new', :to => 'watchers#new', :as => 'new_watchers'
post 'watchers', :to => 'watchers#create'
post 'watchers/append', :to => 'watchers#append'
delete 'watchers', :to => 'watchers#destroy'

+ 1
- 1
public/javascripts/context_menu.js View File

@@ -67,7 +67,7 @@ function contextMenuClick(event) {
// click is outside the rows
if (target.is('a') && (target.hasClass('disabled') || target.hasClass('submenu'))) {
event.preventDefault();
} else if (target.is('.toggle-selection')) {
} else if (target.is('.toggle-selection') || target.is('.ui-dialog *') || $('#ajax-modal').is(':visible')) {
// nop
} else {
contextMenuUnselectAll();

+ 23
- 1
test/functional/watchers_controller_test.rb View File

@@ -133,6 +133,13 @@ class WatchersControllerTest < ActionController::TestCase
assert_match /ajax-modal/, response.body
end

def test_new_with_multiple_objects
@request.session[:user_id] = 2
xhr :get, :new, :object_type => 'issue', :object_id => ['1', '2']
assert_response :success
assert_match /ajax-modal/, response.body
end

def test_new_for_new_record_with_project_id
@request.session[:user_id] = 2
xhr :get, :new, :project_id => 1
@@ -161,7 +168,7 @@ class WatchersControllerTest < ActionController::TestCase
assert Issue.find(2).watched_by?(User.find(4))
end

def test_create_multiple
def test_create_with_mutiple_users
@request.session[:user_id] = 2
assert_difference('Watcher.count', 2) do
xhr :post, :create, :object_type => 'issue', :object_id => '2',
@@ -174,6 +181,21 @@ class WatchersControllerTest < ActionController::TestCase
assert Issue.find(2).watched_by?(User.find(7))
end

def test_create_with_mutiple_objects
@request.session[:user_id] = 2
assert_difference('Watcher.count', 4) do
xhr :post, :create, :object_type => 'issue', :object_id => ['1', '2'],
:watcher => {:user_ids => ['4', '7']}
assert_response :success
assert_match /watchers/, response.body
assert_match /ajax-modal/, response.body
end
assert Issue.find(1).watched_by?(User.find(4))
assert Issue.find(2).watched_by?(User.find(4))
assert Issue.find(1).watched_by?(User.find(7))
assert Issue.find(2).watched_by?(User.find(7))
end

def test_autocomplete_on_watchable_creation
@request.session[:user_id] = 2
xhr :get, :autocomplete_for_user, :q => 'mi', :project_id => 'ecookbook'

Loading…
Cancel
Save