##// END OF EJS Templates
Ability to add non-member watchers on issue creation (#5159)....
Jean-Philippe Lang -
r9134:fae5250e5250
parent child
Show More
@@ -407,6 +407,7 private
407
407
408 @priorities = IssuePriority.active
408 @priorities = IssuePriority.active
409 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
409 @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
410 @available_watchers = (@issue.project.users.sort + @issue.watcher_users).uniq
410 end
411 end
411
412
412 def check_for_default_issue_status
413 def check_for_default_issue_status
@@ -64,6 +64,23 class WatchersController < ApplicationController
64 render :text => 'Watcher added.', :layout => true
64 render :text => 'Watcher added.', :layout => true
65 end
65 end
66
66
67 def append
68 if params[:watcher].is_a?(Hash)
69 user_ids = params[:watcher][:user_ids] || [params[:watcher][:user_id]]
70 users = User.active.find_all_by_id(user_ids)
71 respond_to do |format|
72 format.js do
73 render :update do |page|
74 users.each do |user|
75 page.select("#issue_watcher_user_ids_#{user.id}").each(&:hide)
76 end
77 page.insert_html :bottom, 'watchers_inputs', :text => watchers_checkboxes(nil, users, true)
78 end
79 end
80 end
81 end
82 end
83
67 def destroy
84 def destroy
68 @watched.set_watcher(User.find(params[:user_id]), false) if request.post?
85 @watched.set_watcher(User.find(params[:user_id]), false) if request.post?
69 respond_to do |format|
86 respond_to do |format|
@@ -77,16 +94,23 class WatchersController < ApplicationController
77 end
94 end
78
95
79 def autocomplete_for_user
96 def autocomplete_for_user
80 @users = User.active.like(params[:q]).find(:all, :limit => 100) - @watched.watcher_users
97 @users = User.active.like(params[:q]).find(:all, :limit => 100)
98 if @watched
99 @user -= @watched.watcher_users
100 end
81 render :layout => false
101 render :layout => false
82 end
102 end
83
103
84 private
104 private
85 def find_project
105 def find_project
106 if params[:object_type] && params[:object_id]
86 klass = Object.const_get(params[:object_type].camelcase)
107 klass = Object.const_get(params[:object_type].camelcase)
87 return false unless klass.respond_to?('watched_by')
108 return false unless klass.respond_to?('watched_by')
88 @watched = klass.find(params[:object_id])
109 @watched = klass.find(params[:object_id])
89 @project = @watched.project
110 @project = @watched.project
111 elsif params[:project_id]
112 @project = Project.visible.find(params[:project_id])
113 end
90 rescue
114 rescue
91 render_404
115 render_404
92 end
116 end
@@ -63,4 +63,12 module WatchersHelper
63 end
63 end
64 (lis.empty? ? "" : "<ul>#{ lis.join("\n") }</ul>").html_safe
64 (lis.empty? ? "" : "<ul>#{ lis.join("\n") }</ul>").html_safe
65 end
65 end
66
67 def watchers_checkboxes(object, users, checked=nil)
68 users.map do |user|
69 c = checked.nil? ? object.watched_by?(user) : checked
70 tag = check_box_tag 'issue[watcher_user_ids][]', user.id, c, :id => nil
71 content_tag 'label', "#{tag} #{h(user)}", :id => "issue_watcher_user_ids_#{user.id}", :class => "floating"
72 end.join
73 end
66 end
74 end
@@ -14,6 +14,5
14 <%= link_to_function(image_tag('delete.png'), 'removeFileField(this)', :title => (l(:button_delete))) %>
14 <%= link_to_function(image_tag('delete.png'), 'removeFileField(this)', :title => (l(:button_delete))) %>
15 </span>
15 </span>
16 </span>
16 </span>
17 <small><%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;' %>
17 <span class="add_attachment"><%= link_to l(:label_add_another_file), '#', :onclick => 'addFileField(); return false;', :class => 'add_attachment' %>
18 (<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
18 (<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)</span>
19 </small>
@@ -22,9 +22,14
22
22
23 <% if @issue.safe_attribute? 'watcher_user_ids' -%>
23 <% if @issue.safe_attribute? 'watcher_user_ids' -%>
24 <p id="watchers_form"><label><%= l(:label_issue_watchers) %></label>
24 <p id="watchers_form"><label><%= l(:label_issue_watchers) %></label>
25 <% @issue.project.users.sort.each do |user| -%>
25 <span id="watchers_inputs">
26 <label class="floating"><%= check_box_tag 'issue[watcher_user_ids][]', user.id, @issue.watched_by?(user), :id => nil %> <%=h user %></label>
26 <%= watchers_checkboxes(@issue, @available_watchers) %>
27 <% end -%>
27 </span>
28 <span class="search_for_watchers">
29 <%= link_to_remote l(:label_search_for_watchers),
30 :url => {:controller => 'watchers', :action => 'new', :project_id => @issue.project},
31 :method => 'get' %>
32 </span>
28 </p>
33 </p>
29 <% end %>
34 <% end %>
30 </div>
35 </div>
@@ -1,7 +1,7
1 <h3 class="title"><%= l(:permission_add_issue_watchers) %></h3>
1 <h3 class="title"><%= l(:permission_add_issue_watchers) %></h3>
2
2
3 <% form_remote_tag :url => {:controller => 'watchers',
3 <% form_remote_tag :url => {:controller => 'watchers',
4 :action => 'create',
4 :action => (watched ? 'create' : 'append'),
5 :object_type => watched.class.name.underscore,
5 :object_type => watched.class.name.underscore,
6 :object_id => watched},
6 :object_id => watched},
7 :method => :post,
7 :method => :post,
@@ -22,7 +22,7
22 :with => 'q') %>
22 :with => 'q') %>
23
23
24 <div id="users_for_watcher">
24 <div id="users_for_watcher">
25 <%= principals_check_box_tags 'watcher[user_ids][]', watched.addable_watcher_users %>
25 <%= principals_check_box_tags 'watcher[user_ids][]', (watched ? watched.addable_watcher_users : User.active.all(:limit => 100)) %>
26 </div>
26 </div>
27
27
28 <p class="buttons">
28 <p class="buttons">
@@ -844,6 +844,7 en:
844 label_copy_attachments: Copy attachments
844 label_copy_attachments: Copy attachments
845 label_item_position: "%{position} of %{count}"
845 label_item_position: "%{position} of %{count}"
846 label_completed_versions: Completed versions
846 label_completed_versions: Completed versions
847 label_search_for_watchers: Search for watchers to add
847
848
848 button_login: Login
849 button_login: Login
849 button_submit: Submit
850 button_submit: Submit
@@ -124,6 +124,8 ActionController::Routing::Routes.draw do |map|
124 :conditions => {:method => :get}
124 :conditions => {:method => :get}
125 map.connect 'watchers', :controller=> 'watchers', :action => 'create',
125 map.connect 'watchers', :controller=> 'watchers', :action => 'create',
126 :conditions => {:method => :post}
126 :conditions => {:method => :post}
127 map.connect 'watchers/append', :controller=> 'watchers', :action => 'append',
128 :conditions => {:method => :post}
127 map.connect 'watchers/destroy', :controller=> 'watchers', :action => 'destroy',
129 map.connect 'watchers/destroy', :controller=> 'watchers', :action => 'destroy',
128 :conditions => {:method => :post}
130 :conditions => {:method => :post}
129 map.connect 'watchers/watch', :controller=> 'watchers', :action => 'watch',
131 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
265 #watchers a.delete:hover {opacity: 1;}
265 #watchers a.delete:hover {opacity: 1;}
266 #watchers img.gravatar {margin: 0 4px 2px 0;}
266 #watchers img.gravatar {margin: 0 4px 2px 0;}
267
267
268 span#watchers_inputs {overflow:auto; display:block;}
269 span.search_for_watchers {display:block;}
270 span.search_for_watchers, span.add_attachment {font-size:80%; line-height:2.5em;}
271 span.search_for_watchers a, span.add_attachment a {padding-left:16px; background: url(../images/bullet_add.png) no-repeat 0 50%; }
272
273
268 .highlight { background-color: #FCFD8D;}
274 .highlight { background-color: #FCFD8D;}
269 .highlight.token-1 { background-color: #faa;}
275 .highlight.token-1 { background-color: #faa;}
270 .highlight.token-2 { background-color: #afa;}
276 .highlight.token-2 { background-color: #afa;}
@@ -1680,6 +1680,21 class IssuesControllerTest < ActionController::TestCase
1680 :value => 'Value for field 2'}
1680 :value => 'Value for field 2'}
1681 end
1681 end
1682
1682
1683 def test_post_create_with_failure_should_preserve_watchers
1684 assert !User.find(8).member_of?(Project.find(1))
1685
1686 @request.session[:user_id] = 2
1687 post :create, :project_id => 1,
1688 :issue => {:tracker_id => 1,
1689 :watcher_user_ids => ['3', '8']}
1690 assert_response :success
1691 assert_template 'new'
1692
1693 assert_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]', :value => '2', :checked => nil}
1694 assert_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]', :value => '3', :checked => 'checked'}
1695 assert_tag 'input', :attributes => {:name => 'issue[watcher_user_ids][]', :value => '8', :checked => 'checked'}
1696 end
1697
1683 def test_post_create_should_ignore_non_safe_attributes
1698 def test_post_create_should_ignore_non_safe_attributes
1684 @request.session[:user_id] = 2
1699 @request.session[:user_id] = 2
1685 assert_nothing_raised do
1700 assert_nothing_raised do
@@ -68,6 +68,13 class WatchersControllerTest < ActionController::TestCase
68 assert_select_rjs :replace_html, 'ajax-modal'
68 assert_select_rjs :replace_html, 'ajax-modal'
69 end
69 end
70
70
71 def test_new_for_new_record
72 @request.session[:user_id] = 2
73 xhr :get, :new, :project_id => 1
74 assert_response :success
75 assert_select_rjs :replace_html, 'ajax-modal'
76 end
77
71 def test_create
78 def test_create
72 @request.session[:user_id] = 2
79 @request.session[:user_id] = 2
73 assert_difference('Watcher.count') do
80 assert_difference('Watcher.count') do
@@ -91,6 +98,18 class WatchersControllerTest < ActionController::TestCase
91 assert Issue.find(2).watched_by?(User.find(7))
98 assert Issue.find(2).watched_by?(User.find(7))
92 end
99 end
93
100
101 def test_append
102 @request.session[:user_id] = 2
103 assert_no_difference 'Watcher.count' do
104 xhr :post, :append, :watcher => {:user_ids => ['4', '7']}
105 assert_response :success
106 assert_select_rjs :insert_html, 'watchers_inputs' do
107 assert_select 'input[name=?][value=4]', 'issue[watcher_user_ids][]'
108 assert_select 'input[name=?][value=7]', 'issue[watcher_user_ids][]'
109 end
110 end
111 end
112
94 def test_remove_watcher
113 def test_remove_watcher
95 @request.session[:user_id] = 2
114 @request.session[:user_id] = 2
96 assert_difference('Watcher.count', -1) do
115 assert_difference('Watcher.count', -1) do
@@ -24,6 +24,10 class RoutingWatchersTest < ActionController::IntegrationTest
24 { :controller => 'watchers', :action => 'new' }
24 { :controller => 'watchers', :action => 'new' }
25 )
25 )
26 assert_routing(
26 assert_routing(
27 { :method => 'post', :path => "/watchers/append" },
28 { :controller => 'watchers', :action => 'append' }
29 )
30 assert_routing(
27 { :method => 'post', :path => "/watchers" },
31 { :method => 'post', :path => "/watchers" },
28 { :controller => 'watchers', :action => 'create' }
32 { :controller => 'watchers', :action => 'create' }
29 )
33 )
General Comments 0
You need to be logged in to leave comments. Login now