@@ -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) |
|
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 | |
86 | klass = Object.const_get(params[:object_type].camelcase) |
|
106 | if params[:object_type] && params[:object_id] | |
87 | return false unless klass.respond_to?('watched_by') |
|
107 | klass = Object.const_get(params[:object_type].camelcase) | |
88 | @watched = klass.find(params[:object_id]) |
|
108 | return false unless klass.respond_to?('watched_by') | |
89 | @project = @watched.project |
|
109 | @watched = klass.find(params[:object_id]) | |
|
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 |
<s |
|
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,10 +22,15 | |||||
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 | </p> |
|
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> | |||
|
33 | </p> | |||
29 | <% end %> |
|
34 | <% end %> | |
30 | </div> |
|
35 | </div> | |
31 |
|
36 |
@@ -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