Ability to add non-member users as watchers (#5159).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@8592 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
c22f60271f
commit
1b1c510ff9
|
@ -37,13 +37,28 @@ class WatchersController < ApplicationController
|
|||
end
|
||||
|
||||
def new
|
||||
@watcher = Watcher.new(params[:watcher])
|
||||
@watcher.watchable = @watched
|
||||
@watcher.save if request.post?
|
||||
respond_to do |format|
|
||||
format.js do
|
||||
render :update do |page|
|
||||
page.replace_html 'ajax-modal', :partial => 'watchers/new', :locals => {:watched => @watched}
|
||||
page << "showModal('ajax-modal', '400px');"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
if params[:watcher].is_a?(Hash) && request.post?
|
||||
user_ids = params[:watcher][:user_ids] || [params[:watcher][:user_id]]
|
||||
user_ids.each do |user_id|
|
||||
Watcher.create(:watchable => @watched, :user_id => user_id)
|
||||
end
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html { redirect_to :back }
|
||||
format.js do
|
||||
render :update do |page|
|
||||
page.replace_html 'ajax-modal', :partial => 'watchers/new', :locals => {:watched => @watched}
|
||||
page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched}
|
||||
end
|
||||
end
|
||||
|
@ -64,6 +79,11 @@ class WatchersController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def autocomplete_for_user
|
||||
@users = User.active.like(params[:q]).find(:all, :limit => 100) - @watched.watcher_users
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
private
|
||||
def find_project
|
||||
klass = Object.const_get(params[:object_type].camelcase)
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
</div>
|
||||
|
||||
<div id="ajax-indicator" style="display:none;"><span><%= l(:label_loading) %></span></div>
|
||||
<div id="ajax-modal" style="display:none;"></div>
|
||||
|
||||
<div id="footer">
|
||||
<div class="bgl"><div class="bgr">
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<h3 class="title"><%= l(:permission_add_issue_watchers) %></h3>
|
||||
|
||||
<% form_remote_tag :url => {:controller => 'watchers',
|
||||
:action => 'create',
|
||||
:object_type => watched.class.name.underscore,
|
||||
:object_id => watched},
|
||||
:method => :post,
|
||||
:html => {:id => 'new-watcher-form'} do %>
|
||||
|
||||
<p><%= label_tag 'user_search', l(:label_user_search) %><%= text_field_tag 'user_search', nil %></p>
|
||||
<%= observe_field(:user_search,
|
||||
:frequency => 0.5,
|
||||
:update => :users_for_watcher,
|
||||
:method => :get,
|
||||
:url => {
|
||||
:controller => 'watchers',
|
||||
:action => 'autocomplete_for_user',
|
||||
:object_type => watched.class.name.underscore,
|
||||
:object_id => watched},
|
||||
:with => 'q') %>
|
||||
|
||||
<div id="users_for_watcher">
|
||||
<%= principals_check_box_tags 'watcher[user_ids][]', watched.addable_watcher_users %>
|
||||
</div>
|
||||
|
||||
<p class="buttons">
|
||||
<%= submit_tag l(:button_add), :name => nil, :onclick => "hideModal(this);" %>
|
||||
<%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
|
||||
</p>
|
||||
<% end %>
|
|
@ -1,26 +1,14 @@
|
|||
<% if User.current.allowed_to?(:add_issue_watchers, @project) %>
|
||||
<div class="contextual">
|
||||
<%= link_to_remote l(:button_add),
|
||||
:url => {:controller => 'watchers',
|
||||
:action => 'new',
|
||||
:object_type => watched.class.name.underscore,
|
||||
:object_id => watched} if User.current.allowed_to?(:add_issue_watchers, @project) %>
|
||||
:object_id => watched},
|
||||
:method => 'get' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<h3><%= l(:label_issue_watchers) %> (<%= watched.watcher_users.size %>)</h3>
|
||||
|
||||
<% unless @watcher.nil? %>
|
||||
<% remote_form_for(:watcher, @watcher,
|
||||
:url => {:controller => 'watchers',
|
||||
:action => 'new',
|
||||
:object_type => watched.class.name.underscore,
|
||||
:object_id => watched},
|
||||
:method => :post,
|
||||
:html => {:id => 'new-watcher-form'}) do |f| %>
|
||||
<p><%= f.select :user_id, (watched.addable_watcher_users.collect {|m| [m.name, m.id]}), :prompt => "--- #{l(:actionview_instancetag_blank_option)} ---" %>
|
||||
|
||||
<%= submit_tag l(:button_add) %>
|
||||
<%= toggle_link l(:button_cancel), 'new-watcher-form'%></p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= watchers_list(watched) %>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<%= principals_check_box_tags 'watcher[user_ids][]', @users %>
|
|
@ -128,13 +128,17 @@ ActionController::Routing::Routes.draw do |map|
|
|||
:action => 'destroy', :conditions => {:method => :delete}
|
||||
|
||||
map.connect 'watchers/new', :controller=> 'watchers', :action => 'new',
|
||||
:conditions => {:method => [:get, :post]}
|
||||
:conditions => {:method => :get}
|
||||
map.connect 'watchers', :controller=> 'watchers', :action => 'create',
|
||||
:conditions => {:method => :post}
|
||||
map.connect 'watchers/destroy', :controller=> 'watchers', :action => 'destroy',
|
||||
:conditions => {:method => :post}
|
||||
map.connect 'watchers/watch', :controller=> 'watchers', :action => 'watch',
|
||||
:conditions => {:method => :post}
|
||||
map.connect 'watchers/unwatch', :controller=> 'watchers', :action => 'unwatch',
|
||||
:conditions => {:method => :post}
|
||||
map.connect 'watchers/autocomplete_for_user', :controller=> 'watchers', :action => 'autocomplete_for_user',
|
||||
:conditions => {:method => :get}
|
||||
|
||||
# TODO: port to be part of the resources route(s)
|
||||
map.with_options :conditions => {:method => :get} do |project_views|
|
||||
|
|
|
@ -495,6 +495,9 @@ div#tab-content-members fieldset legend, div#tab-content-memberships fieldset le
|
|||
div#tab-content-members fieldset label, div#tab-content-memberships fieldset label, div#tab-content-users fieldset label { display: block; }
|
||||
div#tab-content-members fieldset div, div#tab-content-users fieldset div { max-height: 400px; overflow:auto; }
|
||||
|
||||
#users_for_watcher {height: 200px; overflow:auto;}
|
||||
#users_for_watcher label {display: block;}
|
||||
|
||||
table.members td.group { padding-left: 20px; background: url(../images/group.png) no-repeat 0% 50%; }
|
||||
|
||||
input#principal_search, input#user_search {width:100%}
|
||||
|
|
|
@ -67,16 +67,36 @@ class WatchersControllerTest < ActionController::TestCase
|
|||
assert !Issue.find(1).watched_by?(User.find(3))
|
||||
end
|
||||
|
||||
def test_new_watcher
|
||||
def test_new
|
||||
@request.session[:user_id] = 2
|
||||
xhr :get, :new, :object_type => 'issue', :object_id => '2'
|
||||
assert_response :success
|
||||
assert_select_rjs :replace_html, 'ajax-modal'
|
||||
end
|
||||
|
||||
def test_create
|
||||
@request.session[:user_id] = 2
|
||||
assert_difference('Watcher.count') do
|
||||
xhr :post, :new, :object_type => 'issue', :object_id => '2', :watcher => {:user_id => '4'}
|
||||
xhr :post, :create, :object_type => 'issue', :object_id => '2', :watcher => {:user_id => '4'}
|
||||
assert_response :success
|
||||
assert_select_rjs :replace_html, 'watchers'
|
||||
assert_select_rjs :replace_html, 'ajax-modal'
|
||||
end
|
||||
assert Issue.find(2).watched_by?(User.find(4))
|
||||
end
|
||||
|
||||
def test_create_multiple
|
||||
@request.session[:user_id] = 2
|
||||
assert_difference('Watcher.count', 2) do
|
||||
xhr :post, :create, :object_type => 'issue', :object_id => '2', :watcher => {:user_ids => ['4', '7']}
|
||||
assert_response :success
|
||||
assert_select_rjs :replace_html, 'watchers'
|
||||
assert_select_rjs :replace_html, 'ajax-modal'
|
||||
end
|
||||
assert Issue.find(2).watched_by?(User.find(4))
|
||||
assert Issue.find(2).watched_by?(User.find(7))
|
||||
end
|
||||
|
||||
def test_remove_watcher
|
||||
@request.session[:user_id] = 2
|
||||
assert_difference('Watcher.count', -1) do
|
||||
|
|
|
@ -19,16 +19,22 @@ require File.expand_path('../../../test_helper', __FILE__)
|
|||
|
||||
class RoutingWatchersTest < ActionController::IntegrationTest
|
||||
def test_watchers
|
||||
["get", "post"].each do |method|
|
||||
assert_routing(
|
||||
{ :method => method, :path => "/watchers/new" },
|
||||
{ :method => 'get', :path => "/watchers/new" },
|
||||
{ :controller => 'watchers', :action => 'new' }
|
||||
)
|
||||
end
|
||||
assert_routing(
|
||||
{ :method => 'post', :path => "/watchers" },
|
||||
{ :controller => 'watchers', :action => 'create' }
|
||||
)
|
||||
assert_routing(
|
||||
{ :method => 'post', :path => "/watchers/destroy" },
|
||||
{ :controller => 'watchers', :action => 'destroy' }
|
||||
)
|
||||
assert_routing(
|
||||
{ :method => 'get', :path => "/watchers/autocomplete_for_user" },
|
||||
{ :controller => 'watchers', :action => 'autocomplete_for_user' }
|
||||
)
|
||||
assert_routing(
|
||||
{ :method => 'post', :path => "/watchers/watch" },
|
||||
{ :controller => 'watchers', :action => 'watch' }
|
||||
|
|
Loading…
Reference in New Issue