Ability to add non-member watchers on issue creation (#5159).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@9254 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
e2bb8721d9
commit
fae5250e52
|
@ -407,6 +407,7 @@ private
|
||||||
|
|
||||||
@priorities = IssuePriority.active
|
@priorities = IssuePriority.active
|
||||||
@allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
|
@allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
|
||||||
|
@available_watchers = (@issue.project.users.sort + @issue.watcher_users).uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_for_default_issue_status
|
def check_for_default_issue_status
|
||||||
|
|
|
@ -64,6 +64,23 @@ class WatchersController < ApplicationController
|
||||||
render :text => 'Watcher added.', :layout => true
|
render :text => 'Watcher added.', :layout => true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def append
|
||||||
|
if params[:watcher].is_a?(Hash)
|
||||||
|
user_ids = params[:watcher][:user_ids] || [params[:watcher][:user_id]]
|
||||||
|
users = User.active.find_all_by_id(user_ids)
|
||||||
|
respond_to do |format|
|
||||||
|
format.js do
|
||||||
|
render :update do |page|
|
||||||
|
users.each do |user|
|
||||||
|
page.select("#issue_watcher_user_ids_#{user.id}").each(&:hide)
|
||||||
|
end
|
||||||
|
page.insert_html :bottom, 'watchers_inputs', :text => watchers_checkboxes(nil, users, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@watched.set_watcher(User.find(params[:user_id]), false) if request.post?
|
@watched.set_watcher(User.find(params[:user_id]), false) if request.post?
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
|
@ -77,16 +94,23 @@ class WatchersController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def autocomplete_for_user
|
def autocomplete_for_user
|
||||||
@users = User.active.like(params[:q]).find(:all, :limit => 100) - @watched.watcher_users
|
@users = User.active.like(params[:q]).find(:all, :limit => 100)
|
||||||
|
if @watched
|
||||||
|
@user -= @watched.watcher_users
|
||||||
|
end
|
||||||
render :layout => false
|
render :layout => false
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def find_project
|
def find_project
|
||||||
klass = Object.const_get(params[:object_type].camelcase)
|
if params[:object_type] && params[:object_id]
|
||||||
return false unless klass.respond_to?('watched_by')
|
klass = Object.const_get(params[:object_type].camelcase)
|
||||||
@watched = klass.find(params[:object_id])
|
return false unless klass.respond_to?('watched_by')
|
||||||
@project = @watched.project
|
@watched = klass.find(params[:object_id])
|
||||||
|
@project = @watched.project
|
||||||
|
elsif params[:project_id]
|
||||||
|
@project = Project.visible.find(params[:project_id])
|
||||||
|
end
|
||||||
rescue
|
rescue
|
||||||
render_404
|
render_404
|
||||||
end
|
end
|
||||||
|
|
|
@ -63,4 +63,12 @@ module WatchersHelper
|
||||||
end
|
end
|
||||||
(lis.empty? ? "" : "<ul>#{ lis.join("\n") }</ul>").html_safe
|
(lis.empty? ? "" : "<ul>#{ lis.join("\n") }</ul>").html_safe
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def watchers_checkboxes(object, users, checked=nil)
|
||||||
|
users.map do |user|
|
||||||
|
c = checked.nil? ? object.watched_by?(user) : checked
|
||||||
|
tag = check_box_tag 'issue[watcher_user_ids][]', user.id, c, :id => nil
|
||||||
|
content_tag 'label', "#{tag} #{h(user)}", :id => "issue_watcher_user_ids_#{user.id}", :class => "floating"
|
||||||
|
end.join
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,6 +14,5 @@
|
||||||
<%= link_to_function(image_tag('delete.png'), 'removeFileField(this)', :title => (l(:button_delete))) %>
|
<%= link_to_function(image_tag('delete.png'), 'removeFileField(this)', :title => (l(:button_delete))) %>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<small><%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;' %>
|
<span class="add_attachment"><%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;', :class => 'add_attachment' %>
|
||||||
(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
|
(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)</span>
|
||||||
</small>
|
|
||||||
|
|
|
@ -22,10 +22,15 @@
|
||||||
|
|
||||||
<% if @issue.safe_attribute? 'watcher_user_ids' -%>
|
<% if @issue.safe_attribute? 'watcher_user_ids' -%>
|
||||||
<p id="watchers_form"><label><%= l(:label_issue_watchers) %></label>
|
<p id="watchers_form"><label><%= l(:label_issue_watchers) %></label>
|
||||||
<% @issue.project.users.sort.each do |user| -%>
|
<span id="watchers_inputs">
|
||||||
<label class="floating"><%= check_box_tag 'issue[watcher_user_ids][]', user.id, @issue.watched_by?(user), :id => nil %> <%=h user %></label>
|
<%= watchers_checkboxes(@issue, @available_watchers) %>
|
||||||
<% end -%>
|
</span>
|
||||||
</p>
|
<span class="search_for_watchers">
|
||||||
|
<%= link_to_remote l(:label_search_for_watchers),
|
||||||
|
:url => {:controller => 'watchers', :action => 'new', :project_id => @issue.project},
|
||||||
|
:method => 'get' %>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<h3 class="title"><%= l(:permission_add_issue_watchers) %></h3>
|
<h3 class="title"><%= l(:permission_add_issue_watchers) %></h3>
|
||||||
|
|
||||||
<% form_remote_tag :url => {:controller => 'watchers',
|
<% form_remote_tag :url => {:controller => 'watchers',
|
||||||
:action => 'create',
|
:action => (watched ? 'create' : 'append'),
|
||||||
:object_type => watched.class.name.underscore,
|
:object_type => watched.class.name.underscore,
|
||||||
:object_id => watched},
|
:object_id => watched},
|
||||||
:method => :post,
|
:method => :post,
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
:with => 'q') %>
|
:with => 'q') %>
|
||||||
|
|
||||||
<div id="users_for_watcher">
|
<div id="users_for_watcher">
|
||||||
<%= principals_check_box_tags 'watcher[user_ids][]', watched.addable_watcher_users %>
|
<%= principals_check_box_tags 'watcher[user_ids][]', (watched ? watched.addable_watcher_users : User.active.all(:limit => 100)) %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="buttons">
|
<p class="buttons">
|
||||||
|
|
|
@ -844,6 +844,7 @@ en:
|
||||||
label_copy_attachments: Copy attachments
|
label_copy_attachments: Copy attachments
|
||||||
label_item_position: "%{position} of %{count}"
|
label_item_position: "%{position} of %{count}"
|
||||||
label_completed_versions: Completed versions
|
label_completed_versions: Completed versions
|
||||||
|
label_search_for_watchers: Search for watchers to add
|
||||||
|
|
||||||
button_login: Login
|
button_login: Login
|
||||||
button_submit: Submit
|
button_submit: Submit
|
||||||
|
|
|
@ -124,6 +124,8 @@ ActionController::Routing::Routes.draw do |map|
|
||||||
:conditions => {:method => :get}
|
:conditions => {:method => :get}
|
||||||
map.connect 'watchers', :controller=> 'watchers', :action => 'create',
|
map.connect 'watchers', :controller=> 'watchers', :action => 'create',
|
||||||
:conditions => {:method => :post}
|
:conditions => {:method => :post}
|
||||||
|
map.connect 'watchers/append', :controller=> 'watchers', :action => 'append',
|
||||||
|
:conditions => {:method => :post}
|
||||||
map.connect 'watchers/destroy', :controller=> 'watchers', :action => 'destroy',
|
map.connect 'watchers/destroy', :controller=> 'watchers', :action => 'destroy',
|
||||||
:conditions => {:method => :post}
|
:conditions => {:method => :post}
|
||||||
map.connect 'watchers/watch', :controller=> 'watchers', :action => 'watch',
|
map.connect 'watchers/watch', :controller=> 'watchers', :action => 'watch',
|
||||||
|
|
|
@ -265,6 +265,12 @@ div.projects h3 { background: url(../images/projects.png) no-repeat 0% 50%; padd
|
||||||
#watchers a.delete:hover {opacity: 1;}
|
#watchers a.delete:hover {opacity: 1;}
|
||||||
#watchers img.gravatar {margin: 0 4px 2px 0;}
|
#watchers img.gravatar {margin: 0 4px 2px 0;}
|
||||||
|
|
||||||
|
span#watchers_inputs {overflow:auto; display:block;}
|
||||||
|
span.search_for_watchers {display:block;}
|
||||||
|
span.search_for_watchers, span.add_attachment {font-size:80%; line-height:2.5em;}
|
||||||
|
span.search_for_watchers a, span.add_attachment a {padding-left:16px; background: url(../images/bullet_add.png) no-repeat 0 50%; }
|
||||||
|
|
||||||
|
|
||||||
.highlight { background-color: #FCFD8D;}
|
.highlight { background-color: #FCFD8D;}
|
||||||
.highlight.token-1 { background-color: #faa;}
|
.highlight.token-1 { background-color: #faa;}
|
||||||
.highlight.token-2 { background-color: #afa;}
|
.highlight.token-2 { background-color: #afa;}
|
||||||
|
|
|
@ -1680,6 +1680,21 @@ class IssuesControllerTest < ActionController::TestCase
|
||||||
:value => 'Value for field 2'}
|
:value => 'Value for field 2'}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_post_create_with_failure_should_preserve_watchers
|
||||||
|
assert !User.find(8).member_of?(Project.find(1))
|
||||||
|
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
post :create, :project_id => 1,
|
||||||
|
:issue => {:tracker_id => 1,
|
||||||
|
:watcher_user_ids => ['3', '8']}
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'new'
|
||||||
|
|
||||||
|
assert_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]', :value => '2', :checked => nil}
|
||||||
|
assert_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]', :value => '3', :checked => 'checked'}
|
||||||
|
assert_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]', :value => '8', :checked => 'checked'}
|
||||||
|
end
|
||||||
|
|
||||||
def test_post_create_should_ignore_non_safe_attributes
|
def test_post_create_should_ignore_non_safe_attributes
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
assert_nothing_raised do
|
assert_nothing_raised do
|
||||||
|
|
|
@ -68,6 +68,13 @@ class WatchersControllerTest < ActionController::TestCase
|
||||||
assert_select_rjs :replace_html, 'ajax-modal'
|
assert_select_rjs :replace_html, 'ajax-modal'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_new_for_new_record
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
xhr :get, :new, :project_id => 1
|
||||||
|
assert_response :success
|
||||||
|
assert_select_rjs :replace_html, 'ajax-modal'
|
||||||
|
end
|
||||||
|
|
||||||
def test_create
|
def test_create
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
assert_difference('Watcher.count') do
|
assert_difference('Watcher.count') do
|
||||||
|
@ -91,6 +98,18 @@ class WatchersControllerTest < ActionController::TestCase
|
||||||
assert Issue.find(2).watched_by?(User.find(7))
|
assert Issue.find(2).watched_by?(User.find(7))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_append
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
assert_no_difference 'Watcher.count' do
|
||||||
|
xhr :post, :append, :watcher => {:user_ids => ['4', '7']}
|
||||||
|
assert_response :success
|
||||||
|
assert_select_rjs :insert_html, 'watchers_inputs' do
|
||||||
|
assert_select 'input[name=?][value=4]', 'issue[watcher_user_ids][]'
|
||||||
|
assert_select 'input[name=?][value=7]', 'issue[watcher_user_ids][]'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_remove_watcher
|
def test_remove_watcher
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
assert_difference('Watcher.count', -1) do
|
assert_difference('Watcher.count', -1) do
|
||||||
|
|
|
@ -23,6 +23,10 @@ class RoutingWatchersTest < ActionController::IntegrationTest
|
||||||
{ :method => 'get', :path => "/watchers/new" },
|
{ :method => 'get', :path => "/watchers/new" },
|
||||||
{ :controller => 'watchers', :action => 'new' }
|
{ :controller => 'watchers', :action => 'new' }
|
||||||
)
|
)
|
||||||
|
assert_routing(
|
||||||
|
{ :method => 'post', :path => "/watchers/append" },
|
||||||
|
{ :controller => 'watchers', :action => 'append' }
|
||||||
|
)
|
||||||
assert_routing(
|
assert_routing(
|
||||||
{ :method => 'post', :path => "/watchers" },
|
{ :method => 'post', :path => "/watchers" },
|
||||||
{ :controller => 'watchers', :action => 'create' }
|
{ :controller => 'watchers', :action => 'create' }
|
||||||
|
|
Loading…
Reference in New Issue