##// END OF EJS Templates
Count users with a single query on group list (#16905)....
Jean-Philippe Lang -
r12874:8aeab43247f9
parent child
Show More
@@ -1,141 +1,150
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2014 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class GroupsController < ApplicationController
19 19 layout 'admin'
20 20
21 21 before_filter :require_admin
22 22 before_filter :find_group, :except => [:index, :new, :create]
23 23 accept_api_auth :index, :show, :create, :update, :destroy, :add_users, :remove_user
24 24
25 25 helper :custom_fields
26 26
27 27 def index
28 28 @groups = Group.sorted.all
29
30 29 respond_to do |format|
31 format.html
30 format.html {
31 @user_count_by_group_id = user_count_by_group_id
32 }
32 33 format.api
33 34 end
34 35 end
35 36
36 37 def show
37 38 respond_to do |format|
38 39 format.html
39 40 format.api
40 41 end
41 42 end
42 43
43 44 def new
44 45 @group = Group.new
45 46 end
46 47
47 48 def create
48 49 @group = Group.new
49 50 @group.safe_attributes = params[:group]
50 51
51 52 respond_to do |format|
52 53 if @group.save
53 54 format.html {
54 55 flash[:notice] = l(:notice_successful_create)
55 56 redirect_to(params[:continue] ? new_group_path : groups_path)
56 57 }
57 58 format.api { render :action => 'show', :status => :created, :location => group_url(@group) }
58 59 else
59 60 format.html { render :action => "new" }
60 61 format.api { render_validation_errors(@group) }
61 62 end
62 63 end
63 64 end
64 65
65 66 def edit
66 67 end
67 68
68 69 def update
69 70 @group.safe_attributes = params[:group]
70 71
71 72 respond_to do |format|
72 73 if @group.save
73 74 flash[:notice] = l(:notice_successful_update)
74 75 format.html { redirect_to(groups_path) }
75 76 format.api { render_api_ok }
76 77 else
77 78 format.html { render :action => "edit" }
78 79 format.api { render_validation_errors(@group) }
79 80 end
80 81 end
81 82 end
82 83
83 84 def destroy
84 85 @group.destroy
85 86
86 87 respond_to do |format|
87 88 format.html { redirect_to(groups_path) }
88 89 format.api { render_api_ok }
89 90 end
90 91 end
91 92
92 93 def add_users
93 94 @users = User.where(:id => (params[:user_id] || params[:user_ids])).all
94 95 @group.users << @users if request.post?
95 96 respond_to do |format|
96 97 format.html { redirect_to edit_group_path(@group, :tab => 'users') }
97 98 format.js
98 99 format.api { render_api_ok }
99 100 end
100 101 end
101 102
102 103 def remove_user
103 104 @group.users.delete(User.find(params[:user_id])) if request.delete?
104 105 respond_to do |format|
105 106 format.html { redirect_to edit_group_path(@group, :tab => 'users') }
106 107 format.js
107 108 format.api { render_api_ok }
108 109 end
109 110 end
110 111
111 112 def autocomplete_for_user
112 113 respond_to do |format|
113 114 format.js
114 115 end
115 116 end
116 117
117 118 def edit_membership
118 119 @membership = Member.edit_membership(params[:membership_id], params[:membership], @group)
119 120 @membership.save if request.post?
120 121 respond_to do |format|
121 122 format.html { redirect_to edit_group_path(@group, :tab => 'memberships') }
122 123 format.js
123 124 end
124 125 end
125 126
126 127 def destroy_membership
127 128 Member.find(params[:membership_id]).destroy if request.post?
128 129 respond_to do |format|
129 130 format.html { redirect_to edit_group_path(@group, :tab => 'memberships') }
130 131 format.js
131 132 end
132 133 end
133 134
134 135 private
135 136
136 137 def find_group
137 138 @group = Group.find(params[:id])
138 139 rescue ActiveRecord::RecordNotFound
139 140 render_404
140 141 end
142
143 def user_count_by_group_id
144 h = User.joins(:groups).group('group_id').count
145 h.keys.each do |key|
146 h[key.to_i] = h.delete(key)
147 end
148 h
149 end
141 150 end
@@ -1,26 +1,25
1 1 <div class="contextual">
2 2 <%= link_to l(:label_group_new), new_group_path, :class => 'icon icon-add' %>
3 3 </div>
4 4
5 5 <%= title l(:label_group_plural) %>
6
7 6 <% if @groups.any? %>
8 7 <table class="list groups">
9 8 <thead><tr>
10 9 <th><%=l(:label_group)%></th>
11 10 <th><%=l(:label_user_plural)%></th>
12 11 <th></th>
13 12 </tr></thead>
14 13 <tbody>
15 14 <% @groups.each do |group| %>
16 <tr class="<%= cycle 'odd', 'even' %>">
15 <tr id="group-<%= group.id %>" class="<%= cycle 'odd', 'even' %>">
17 16 <td class="name"><%= link_to h(group), edit_group_path(group) %></td>
18 <td><%= group.users.size %></td>
17 <td class="user_count"><%= @user_count_by_group_id[group.id] || 0 %></td>
19 18 <td class="buttons"><%= delete_link group %></td>
20 19 </tr>
21 20 <% end %>
22 21 </tbody>
23 22 </table>
24 23 <% else %>
25 24 <p class="nodata"><%= l(:label_no_data) %></p>
26 25 <% end %>
@@ -1,202 +1,208
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2014 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class GroupsControllerTest < ActionController::TestCase
21 21 fixtures :projects, :users, :members, :member_roles, :roles, :groups_users
22 22
23 23 def setup
24 24 @request.session[:user_id] = 1
25 25 end
26 26
27 27 def test_index
28 28 get :index
29 29 assert_response :success
30 30 assert_template 'index'
31 31 end
32 32
33 def test_index_should_show_user_count
34 get :index
35 assert_response :success
36 assert_select 'tr#group-11 td.user_count', :text => '1'
37 end
38
33 39 def test_show
34 40 get :show, :id => 10
35 41 assert_response :success
36 42 assert_template 'show'
37 43 end
38 44
39 45 def test_show_invalid_should_return_404
40 46 get :show, :id => 99
41 47 assert_response 404
42 48 end
43 49
44 50 def test_new
45 51 get :new
46 52 assert_response :success
47 53 assert_template 'new'
48 54 assert_select 'input[name=?]', 'group[name]'
49 55 end
50 56
51 57 def test_create
52 58 assert_difference 'Group.count' do
53 59 post :create, :group => {:name => 'New group'}
54 60 end
55 61 assert_redirected_to '/groups'
56 62 group = Group.order('id DESC').first
57 63 assert_equal 'New group', group.name
58 64 assert_equal [], group.users
59 65 end
60 66
61 67 def test_create_and_continue
62 68 assert_difference 'Group.count' do
63 69 post :create, :group => {:name => 'New group'}, :continue => 'Create and continue'
64 70 end
65 71 assert_redirected_to '/groups/new'
66 72 group = Group.order('id DESC').first
67 73 assert_equal 'New group', group.name
68 74 end
69 75
70 76 def test_create_with_failure
71 77 assert_no_difference 'Group.count' do
72 78 post :create, :group => {:name => ''}
73 79 end
74 80 assert_response :success
75 81 assert_template 'new'
76 82 end
77 83
78 84 def test_edit
79 85 get :edit, :id => 10
80 86 assert_response :success
81 87 assert_template 'edit'
82 88
83 89 assert_select 'div#tab-content-users'
84 90 assert_select 'div#tab-content-memberships' do
85 91 assert_select 'a', :text => 'Private child of eCookbook'
86 92 end
87 93 end
88 94
89 95 def test_update
90 96 new_name = 'New name'
91 97 put :update, :id => 10, :group => {:name => new_name}
92 98 assert_redirected_to '/groups'
93 99 group = Group.find(10)
94 100 assert_equal new_name, group.name
95 101 end
96 102
97 103 def test_update_with_failure
98 104 put :update, :id => 10, :group => {:name => ''}
99 105 assert_response :success
100 106 assert_template 'edit'
101 107 end
102 108
103 109 def test_destroy
104 110 assert_difference 'Group.count', -1 do
105 111 post :destroy, :id => 10
106 112 end
107 113 assert_redirected_to '/groups'
108 114 end
109 115
110 116 def test_add_users
111 117 assert_difference 'Group.find(10).users.count', 2 do
112 118 post :add_users, :id => 10, :user_ids => ['2', '3']
113 119 end
114 120 end
115 121
116 122 def test_xhr_add_users
117 123 assert_difference 'Group.find(10).users.count', 2 do
118 124 xhr :post, :add_users, :id => 10, :user_ids => ['2', '3']
119 125 assert_response :success
120 126 assert_template 'add_users'
121 127 assert_equal 'text/javascript', response.content_type
122 128 end
123 129 assert_match /John Smith/, response.body
124 130 end
125 131
126 132 def test_remove_user
127 133 assert_difference 'Group.find(10).users.count', -1 do
128 134 delete :remove_user, :id => 10, :user_id => '8'
129 135 end
130 136 end
131 137
132 138 def test_xhr_remove_user
133 139 assert_difference 'Group.find(10).users.count', -1 do
134 140 xhr :delete, :remove_user, :id => 10, :user_id => '8'
135 141 assert_response :success
136 142 assert_template 'remove_user'
137 143 assert_equal 'text/javascript', response.content_type
138 144 end
139 145 end
140 146
141 147 def test_new_membership
142 148 assert_difference 'Group.find(10).members.count' do
143 149 post :edit_membership, :id => 10, :membership => { :project_id => 2, :role_ids => ['1', '2']}
144 150 end
145 151 end
146 152
147 153 def test_xhr_new_membership
148 154 assert_difference 'Group.find(10).members.count' do
149 155 xhr :post, :edit_membership, :id => 10, :membership => { :project_id => 2, :role_ids => ['1', '2']}
150 156 assert_response :success
151 157 assert_template 'edit_membership'
152 158 assert_equal 'text/javascript', response.content_type
153 159 end
154 160 assert_match /OnlineStore/, response.body
155 161 end
156 162
157 163 def test_xhr_new_membership_with_failure
158 164 assert_no_difference 'Group.find(10).members.count' do
159 165 xhr :post, :edit_membership, :id => 10, :membership => { :project_id => 999, :role_ids => ['1', '2']}
160 166 assert_response :success
161 167 assert_template 'edit_membership'
162 168 assert_equal 'text/javascript', response.content_type
163 169 end
164 170 assert_match /alert/, response.body, "Alert message not sent"
165 171 end
166 172
167 173 def test_edit_membership
168 174 assert_no_difference 'Group.find(10).members.count' do
169 175 post :edit_membership, :id => 10, :membership_id => 6, :membership => { :role_ids => ['1', '3']}
170 176 end
171 177 end
172 178
173 179 def test_xhr_edit_membership
174 180 assert_no_difference 'Group.find(10).members.count' do
175 181 xhr :post, :edit_membership, :id => 10, :membership_id => 6, :membership => { :role_ids => ['1', '3']}
176 182 assert_response :success
177 183 assert_template 'edit_membership'
178 184 assert_equal 'text/javascript', response.content_type
179 185 end
180 186 end
181 187
182 188 def test_destroy_membership
183 189 assert_difference 'Group.find(10).members.count', -1 do
184 190 post :destroy_membership, :id => 10, :membership_id => 6
185 191 end
186 192 end
187 193
188 194 def test_xhr_destroy_membership
189 195 assert_difference 'Group.find(10).members.count', -1 do
190 196 xhr :post, :destroy_membership, :id => 10, :membership_id => 6
191 197 assert_response :success
192 198 assert_template 'destroy_membership'
193 199 assert_equal 'text/javascript', response.content_type
194 200 end
195 201 end
196 202
197 203 def test_autocomplete_for_user
198 204 get :autocomplete_for_user, :id => 10, :q => 'smi', :format => 'js'
199 205 assert_response :success
200 206 assert_include 'John Smith', response.body
201 207 end
202 208 end
General Comments 0
You need to be logged in to leave comments. Login now