mirror of
https://github.com/meineerde/redmine.git
synced 2025-12-20 07:21:12 +00:00
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
This commit is contained in:
parent
c8c694840d
commit
5adc1ddde9
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 %>
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -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 %>
|
||||
|
||||
@ -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,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');
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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…
x
Reference in New Issue
Block a user