##// END OF EJS Templates
Fixed that project settings should show locked members (#22034)....
Jean-Philippe Lang -
r15734:514d9bad9efd
parent child
Show More
@@ -1,129 +1,129
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class MembersController < ApplicationController
18 class MembersController < ApplicationController
19 model_object Member
19 model_object Member
20 before_action :find_model_object, :except => [:index, :new, :create, :autocomplete]
20 before_action :find_model_object, :except => [:index, :new, :create, :autocomplete]
21 before_action :find_project_from_association, :except => [:index, :new, :create, :autocomplete]
21 before_action :find_project_from_association, :except => [:index, :new, :create, :autocomplete]
22 before_action :find_project_by_project_id, :only => [:index, :new, :create, :autocomplete]
22 before_action :find_project_by_project_id, :only => [:index, :new, :create, :autocomplete]
23 before_action :authorize
23 before_action :authorize
24 accept_api_auth :index, :show, :create, :update, :destroy
24 accept_api_auth :index, :show, :create, :update, :destroy
25
25
26 require_sudo_mode :create, :update, :destroy
26 require_sudo_mode :create, :update, :destroy
27
27
28 def index
28 def index
29 scope = @project.memberships.active
29 scope = @project.memberships
30 @offset, @limit = api_offset_and_limit
30 @offset, @limit = api_offset_and_limit
31 @member_count = scope.count
31 @member_count = scope.count
32 @member_pages = Paginator.new @member_count, @limit, params['page']
32 @member_pages = Paginator.new @member_count, @limit, params['page']
33 @offset ||= @member_pages.offset
33 @offset ||= @member_pages.offset
34 @members = scope.order(:id).limit(@limit).offset(@offset).to_a
34 @members = scope.order(:id).limit(@limit).offset(@offset).to_a
35
35
36 respond_to do |format|
36 respond_to do |format|
37 format.html { head 406 }
37 format.html { head 406 }
38 format.api
38 format.api
39 end
39 end
40 end
40 end
41
41
42 def show
42 def show
43 respond_to do |format|
43 respond_to do |format|
44 format.html { head 406 }
44 format.html { head 406 }
45 format.api
45 format.api
46 end
46 end
47 end
47 end
48
48
49 def new
49 def new
50 @member = Member.new
50 @member = Member.new
51 end
51 end
52
52
53 def create
53 def create
54 members = []
54 members = []
55 if params[:membership]
55 if params[:membership]
56 user_ids = Array.wrap(params[:membership][:user_id] || params[:membership][:user_ids])
56 user_ids = Array.wrap(params[:membership][:user_id] || params[:membership][:user_ids])
57 user_ids << nil if user_ids.empty?
57 user_ids << nil if user_ids.empty?
58 user_ids.each do |user_id|
58 user_ids.each do |user_id|
59 member = Member.new(:project => @project, :user_id => user_id)
59 member = Member.new(:project => @project, :user_id => user_id)
60 member.set_editable_role_ids(params[:membership][:role_ids])
60 member.set_editable_role_ids(params[:membership][:role_ids])
61 members << member
61 members << member
62 end
62 end
63 @project.members << members
63 @project.members << members
64 end
64 end
65
65
66 respond_to do |format|
66 respond_to do |format|
67 format.html { redirect_to_settings_in_projects }
67 format.html { redirect_to_settings_in_projects }
68 format.js {
68 format.js {
69 @members = members
69 @members = members
70 @member = Member.new
70 @member = Member.new
71 }
71 }
72 format.api {
72 format.api {
73 @member = members.first
73 @member = members.first
74 if @member.valid?
74 if @member.valid?
75 render :action => 'show', :status => :created, :location => membership_url(@member)
75 render :action => 'show', :status => :created, :location => membership_url(@member)
76 else
76 else
77 render_validation_errors(@member)
77 render_validation_errors(@member)
78 end
78 end
79 }
79 }
80 end
80 end
81 end
81 end
82
82
83 def update
83 def update
84 if params[:membership]
84 if params[:membership]
85 @member.set_editable_role_ids(params[:membership][:role_ids])
85 @member.set_editable_role_ids(params[:membership][:role_ids])
86 end
86 end
87 saved = @member.save
87 saved = @member.save
88 respond_to do |format|
88 respond_to do |format|
89 format.html { redirect_to_settings_in_projects }
89 format.html { redirect_to_settings_in_projects }
90 format.js
90 format.js
91 format.api {
91 format.api {
92 if saved
92 if saved
93 render_api_ok
93 render_api_ok
94 else
94 else
95 render_validation_errors(@member)
95 render_validation_errors(@member)
96 end
96 end
97 }
97 }
98 end
98 end
99 end
99 end
100
100
101 def destroy
101 def destroy
102 if @member.deletable?
102 if @member.deletable?
103 @member.destroy
103 @member.destroy
104 end
104 end
105 respond_to do |format|
105 respond_to do |format|
106 format.html { redirect_to_settings_in_projects }
106 format.html { redirect_to_settings_in_projects }
107 format.js
107 format.js
108 format.api {
108 format.api {
109 if @member.destroyed?
109 if @member.destroyed?
110 render_api_ok
110 render_api_ok
111 else
111 else
112 head :unprocessable_entity
112 head :unprocessable_entity
113 end
113 end
114 }
114 }
115 end
115 end
116 end
116 end
117
117
118 def autocomplete
118 def autocomplete
119 respond_to do |format|
119 respond_to do |format|
120 format.js
120 format.js
121 end
121 end
122 end
122 end
123
123
124 private
124 private
125
125
126 def redirect_to_settings_in_projects
126 def redirect_to_settings_in_projects
127 redirect_to settings_project_path(@project, :tab => 'members')
127 redirect_to settings_project_path(@project, :tab => 'members')
128 end
128 end
129 end
129 end
@@ -1,62 +1,62
1 <% roles = Role.find_all_givable
1 <% roles = Role.find_all_givable
2 members = @project.memberships.active.sorted.to_a %>
2 members = @project.memberships.sorted.to_a %>
3
3
4 <p><%= link_to l(:label_member_new), new_project_membership_path(@project), :remote => true, :class => "icon icon-add" %></p>
4 <p><%= link_to l(:label_member_new), new_project_membership_path(@project), :remote => true, :class => "icon icon-add" %></p>
5
5
6 <% if members.any? %>
6 <% if members.any? %>
7 <table class="list members">
7 <table class="list members">
8 <thead>
8 <thead>
9 <tr>
9 <tr>
10 <th><%= l(:label_user) %> / <%= l(:label_group) %></th>
10 <th><%= l(:label_user) %> / <%= l(:label_group) %></th>
11 <th><%= l(:label_role_plural) %></th>
11 <th><%= l(:label_role_plural) %></th>
12 <th style="width:15%"></th>
12 <th style="width:15%"></th>
13 <%= call_hook(:view_projects_settings_members_table_header, :project => @project) %>
13 <%= call_hook(:view_projects_settings_members_table_header, :project => @project) %>
14 </tr>
14 </tr>
15 </thead>
15 </thead>
16 <tbody>
16 <tbody>
17 <% members.each do |member| %>
17 <% members.each do |member| %>
18 <% next if member.new_record? %>
18 <% next if member.new_record? %>
19 <tr id="member-<%= member.id %>" class="<%= cycle 'odd', 'even' %> member">
19 <tr id="member-<%= member.id %>" class="<%= cycle 'odd', 'even' %> member">
20 <td class="name icon icon-<%= member.principal.class.name.downcase %>"><%= link_to_user member.principal %></td>
20 <td class="name icon icon-<%= member.principal.class.name.downcase %>"><%= link_to_user member.principal %></td>
21 <td class="roles">
21 <td class="roles">
22 <span id="member-<%= member.id %>-roles"><%= member.roles.sort.collect(&:to_s).join(', ') %></span>
22 <span id="member-<%= member.id %>-roles"><%= member.roles.sort.collect(&:to_s).join(', ') %></span>
23 <%= form_for(member,
23 <%= form_for(member,
24 {:as => :membership, :remote => true,
24 {:as => :membership, :remote => true,
25 :url => membership_path(member),
25 :url => membership_path(member),
26 :method => :put,
26 :method => :put,
27 :html => { :id => "member-#{member.id}-roles-form", :class => 'hol' }}
27 :html => { :id => "member-#{member.id}-roles-form", :class => 'hol' }}
28 ) do |f| %>
28 ) do |f| %>
29 <p>
29 <p>
30 <% roles.each do |role| %>
30 <% roles.each do |role| %>
31 <label>
31 <label>
32 <%= check_box_tag('membership[role_ids][]',
32 <%= check_box_tag('membership[role_ids][]',
33 role.id, member.roles.include?(role),
33 role.id, member.roles.include?(role),
34 :id => nil,
34 :id => nil,
35 :disabled => !member.role_editable?(role)) %> <%= role %>
35 :disabled => !member.role_editable?(role)) %> <%= role %>
36 </label><br />
36 </label><br />
37 <% end %>
37 <% end %>
38 </p>
38 </p>
39 <%= hidden_field_tag 'membership[role_ids][]', '', :id => nil %>
39 <%= hidden_field_tag 'membership[role_ids][]', '', :id => nil %>
40 <p>
40 <p>
41 <%= submit_tag l(:button_save), :class => "small" %>
41 <%= submit_tag l(:button_save), :class => "small" %>
42 <%= link_to_function(l(:button_cancel),
42 <%= link_to_function(l(:button_cancel),
43 "$('#member-#{member.id}-roles').show(); $('#member-#{member.id}-roles-form').hide(); return false;") %>
43 "$('#member-#{member.id}-roles').show(); $('#member-#{member.id}-roles-form').hide(); return false;") %>
44 </p>
44 </p>
45 <% end %>
45 <% end %>
46 </td>
46 </td>
47 <td class="buttons">
47 <td class="buttons">
48 <%= link_to_function l(:button_edit),
48 <%= link_to_function l(:button_edit),
49 "$('#member-#{member.id}-roles').hide(); $('#member-#{member.id}-roles-form').show(); return false;",
49 "$('#member-#{member.id}-roles').hide(); $('#member-#{member.id}-roles-form').show(); return false;",
50 :class => 'icon icon-edit' %>
50 :class => 'icon icon-edit' %>
51 <%= delete_link membership_path(member),
51 <%= delete_link membership_path(member),
52 :remote => true,
52 :remote => true,
53 :data => (!User.current.admin? && member.include?(User.current) ? {:confirm => l(:text_own_membership_delete_confirmation)} : {}) if member.deletable? %>
53 :data => (!User.current.admin? && member.include?(User.current) ? {:confirm => l(:text_own_membership_delete_confirmation)} : {}) if member.deletable? %>
54 </td>
54 </td>
55 <%= call_hook(:view_projects_settings_members_table_row, { :project => @project, :member => member}) %>
55 <%= call_hook(:view_projects_settings_members_table_row, { :project => @project, :member => member}) %>
56 </tr>
56 </tr>
57 <% end; reset_cycle %>
57 <% end; reset_cycle %>
58 </tbody>
58 </tbody>
59 </table>
59 </table>
60 <% else %>
60 <% else %>
61 <p class="nodata"><%= l(:label_no_data) %></p>
61 <p class="nodata"><%= l(:label_no_data) %></p>
62 <% end %>
62 <% end %>
@@ -1,197 +1,215
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class MembersControllerTest < Redmine::ControllerTest
20 class MembersControllerTest < Redmine::ControllerTest
21 fixtures :projects, :members, :member_roles, :roles, :users
21 fixtures :projects, :members, :member_roles, :roles, :users
22
22
23 def setup
23 def setup
24 User.current = nil
24 User.current = nil
25 @request.session[:user_id] = 2
25 @request.session[:user_id] = 2
26 end
26 end
27
27
28 def test_new
28 def test_new
29 get :new, :project_id => 1
29 get :new, :project_id => 1
30 assert_response :success
30 assert_response :success
31 end
31 end
32
32
33 def test_new_should_propose_managed_roles_only
33 def test_new_should_propose_managed_roles_only
34 role = Role.find(1)
34 role = Role.find(1)
35 role.update! :all_roles_managed => false
35 role.update! :all_roles_managed => false
36 role.managed_roles = Role.where(:id => [2, 3]).to_a
36 role.managed_roles = Role.where(:id => [2, 3]).to_a
37
37
38 get :new, :project_id => 1
38 get :new, :project_id => 1
39 assert_response :success
39 assert_response :success
40 assert_select 'div.roles-selection' do
40 assert_select 'div.roles-selection' do
41 assert_select 'label', :text => 'Manager', :count => 0
41 assert_select 'label', :text => 'Manager', :count => 0
42 assert_select 'label', :text => 'Developer'
42 assert_select 'label', :text => 'Developer'
43 assert_select 'label', :text => 'Reporter'
43 assert_select 'label', :text => 'Reporter'
44 end
44 end
45 end
45 end
46
46
47 def test_xhr_new
47 def test_xhr_new
48 xhr :get, :new, :project_id => 1
48 xhr :get, :new, :project_id => 1
49 assert_response :success
49 assert_response :success
50 assert_equal 'text/javascript', response.content_type
50 assert_equal 'text/javascript', response.content_type
51 end
51 end
52
52
53 def test_create
53 def test_create
54 assert_difference 'Member.count' do
54 assert_difference 'Member.count' do
55 post :create, :project_id => 1, :membership => {:role_ids => [1], :user_id => 7}
55 post :create, :project_id => 1, :membership => {:role_ids => [1], :user_id => 7}
56 end
56 end
57 assert_redirected_to '/projects/ecookbook/settings/members'
57 assert_redirected_to '/projects/ecookbook/settings/members'
58 assert User.find(7).member_of?(Project.find(1))
58 assert User.find(7).member_of?(Project.find(1))
59 end
59 end
60
60
61 def test_create_multiple
61 def test_create_multiple
62 assert_difference 'Member.count', 3 do
62 assert_difference 'Member.count', 3 do
63 post :create, :project_id => 1, :membership => {:role_ids => [1], :user_ids => [7, 8, 9]}
63 post :create, :project_id => 1, :membership => {:role_ids => [1], :user_ids => [7, 8, 9]}
64 end
64 end
65 assert_redirected_to '/projects/ecookbook/settings/members'
65 assert_redirected_to '/projects/ecookbook/settings/members'
66 assert User.find(7).member_of?(Project.find(1))
66 assert User.find(7).member_of?(Project.find(1))
67 end
67 end
68
68
69 def test_create_should_ignore_unmanaged_roles
69 def test_create_should_ignore_unmanaged_roles
70 role = Role.find(1)
70 role = Role.find(1)
71 role.update! :all_roles_managed => false
71 role.update! :all_roles_managed => false
72 role.managed_roles = Role.where(:id => [2, 3]).to_a
72 role.managed_roles = Role.where(:id => [2, 3]).to_a
73
73
74 assert_difference 'Member.count' do
74 assert_difference 'Member.count' do
75 post :create, :project_id => 1, :membership => {:role_ids => [1, 2], :user_id => 7}
75 post :create, :project_id => 1, :membership => {:role_ids => [1, 2], :user_id => 7}
76 end
76 end
77 member = Member.order(:id => :desc).first
77 member = Member.order(:id => :desc).first
78 assert_equal [2], member.role_ids
78 assert_equal [2], member.role_ids
79 end
79 end
80
80
81 def test_create_should_be_allowed_for_admin_without_role
81 def test_create_should_be_allowed_for_admin_without_role
82 User.find(1).members.delete_all
82 User.find(1).members.delete_all
83 @request.session[:user_id] = 1
83 @request.session[:user_id] = 1
84
84
85 assert_difference 'Member.count' do
85 assert_difference 'Member.count' do
86 post :create, :project_id => 1, :membership => {:role_ids => [1, 2], :user_id => 7}
86 post :create, :project_id => 1, :membership => {:role_ids => [1, 2], :user_id => 7}
87 end
87 end
88 member = Member.order(:id => :desc).first
88 member = Member.order(:id => :desc).first
89 assert_equal [1, 2], member.role_ids
89 assert_equal [1, 2], member.role_ids
90 end
90 end
91
91
92 def test_xhr_create
92 def test_xhr_create
93 assert_difference 'Member.count', 3 do
93 assert_difference 'Member.count', 3 do
94 xhr :post, :create, :project_id => 1, :membership => {:role_ids => [1], :user_ids => [7, 8, 9]}
94 xhr :post, :create, :project_id => 1, :membership => {:role_ids => [1], :user_ids => [7, 8, 9]}
95 assert_response :success
95 assert_response :success
96 assert_equal 'text/javascript', response.content_type
96 assert_equal 'text/javascript', response.content_type
97 end
97 end
98 assert User.find(7).member_of?(Project.find(1))
98 assert User.find(7).member_of?(Project.find(1))
99 assert User.find(8).member_of?(Project.find(1))
99 assert User.find(8).member_of?(Project.find(1))
100 assert User.find(9).member_of?(Project.find(1))
100 assert User.find(9).member_of?(Project.find(1))
101 assert_include 'tab-content-members', response.body
101 assert_include 'tab-content-members', response.body
102 end
102 end
103
103
104 def test_xhr_create_with_failure
104 def test_xhr_create_with_failure
105 assert_no_difference 'Member.count' do
105 assert_no_difference 'Member.count' do
106 xhr :post, :create, :project_id => 1, :membership => {:role_ids => [], :user_ids => [7, 8, 9]}
106 xhr :post, :create, :project_id => 1, :membership => {:role_ids => [], :user_ids => [7, 8, 9]}
107 assert_response :success
107 assert_response :success
108 assert_equal 'text/javascript', response.content_type
108 assert_equal 'text/javascript', response.content_type
109 end
109 end
110 assert_match /alert/, response.body, "Alert message not sent"
110 assert_match /alert/, response.body, "Alert message not sent"
111 end
111 end
112
112
113 def test_update
113 def test_update
114 assert_no_difference 'Member.count' do
114 assert_no_difference 'Member.count' do
115 put :update, :id => 2, :membership => {:role_ids => [1], :user_id => 3}
115 put :update, :id => 2, :membership => {:role_ids => [1], :user_id => 3}
116 end
116 end
117 assert_redirected_to '/projects/ecookbook/settings/members'
117 assert_redirected_to '/projects/ecookbook/settings/members'
118 end
118 end
119
119
120 def test_update_locked_member_should_be_allowed
121 User.find(3).lock!
122
123 put :update, :id => 2, :membership => {:role_ids => [1]}
124 assert_response 302
125 member = Member.find(2)
126 assert member.user.locked?
127 assert_equal [1], member.role_ids
128 end
129
120 def test_update_should_not_add_unmanaged_roles
130 def test_update_should_not_add_unmanaged_roles
121 role = Role.find(1)
131 role = Role.find(1)
122 role.update! :all_roles_managed => false
132 role.update! :all_roles_managed => false
123 role.managed_roles = Role.where(:id => [2, 3]).to_a
133 role.managed_roles = Role.where(:id => [2, 3]).to_a
124 member = Member.create!(:user => User.find(9), :role_ids => [3], :project_id => 1)
134 member = Member.create!(:user => User.find(9), :role_ids => [3], :project_id => 1)
125
135
126 put :update, :id => member.id, :membership => {:role_ids => [1, 2, 3]}
136 put :update, :id => member.id, :membership => {:role_ids => [1, 2, 3]}
127 assert_equal [2, 3], member.reload.role_ids.sort
137 assert_equal [2, 3], member.reload.role_ids.sort
128 end
138 end
129
139
130 def test_update_should_not_remove_unmanaged_roles
140 def test_update_should_not_remove_unmanaged_roles
131 role = Role.find(1)
141 role = Role.find(1)
132 role.update! :all_roles_managed => false
142 role.update! :all_roles_managed => false
133 role.managed_roles = Role.where(:id => [2, 3]).to_a
143 role.managed_roles = Role.where(:id => [2, 3]).to_a
134 member = Member.create!(:user => User.find(9), :role_ids => [1, 3], :project_id => 1)
144 member = Member.create!(:user => User.find(9), :role_ids => [1, 3], :project_id => 1)
135
145
136 put :update, :id => member.id, :membership => {:role_ids => [2]}
146 put :update, :id => member.id, :membership => {:role_ids => [2]}
137 assert_equal [1, 2], member.reload.role_ids.sort
147 assert_equal [1, 2], member.reload.role_ids.sort
138 end
148 end
139
149
140 def test_xhr_update
150 def test_xhr_update
141 assert_no_difference 'Member.count' do
151 assert_no_difference 'Member.count' do
142 xhr :put, :update, :id => 2, :membership => {:role_ids => [1], :user_id => 3}
152 xhr :put, :update, :id => 2, :membership => {:role_ids => [1], :user_id => 3}
143 assert_response :success
153 assert_response :success
144 assert_equal 'text/javascript', response.content_type
154 assert_equal 'text/javascript', response.content_type
145 end
155 end
146 member = Member.find(2)
156 member = Member.find(2)
147 assert_equal [1], member.role_ids
157 assert_equal [1], member.role_ids
148 assert_equal 3, member.user_id
158 assert_equal 3, member.user_id
149 assert_include 'tab-content-members', response.body
159 assert_include 'tab-content-members', response.body
150 end
160 end
151
161
152 def test_destroy
162 def test_destroy
153 assert_difference 'Member.count', -1 do
163 assert_difference 'Member.count', -1 do
154 delete :destroy, :id => 2
164 delete :destroy, :id => 2
155 end
165 end
156 assert_redirected_to '/projects/ecookbook/settings/members'
166 assert_redirected_to '/projects/ecookbook/settings/members'
157 assert !User.find(3).member_of?(Project.find(1))
167 assert !User.find(3).member_of?(Project.find(1))
158 end
168 end
159
169
170 def test_destroy_locked_member_should_be_allowed
171 assert User.find(3).lock!
172
173 assert_difference 'Member.count', -1 do
174 delete :destroy, :id => 2
175 end
176 end
177
160 def test_destroy_should_fail_with_unmanaged_roles
178 def test_destroy_should_fail_with_unmanaged_roles
161 role = Role.find(1)
179 role = Role.find(1)
162 role.update! :all_roles_managed => false
180 role.update! :all_roles_managed => false
163 role.managed_roles = Role.where(:id => [2, 3]).to_a
181 role.managed_roles = Role.where(:id => [2, 3]).to_a
164 member = Member.create!(:user => User.find(9), :role_ids => [1, 3], :project_id => 1)
182 member = Member.create!(:user => User.find(9), :role_ids => [1, 3], :project_id => 1)
165
183
166 assert_no_difference 'Member.count' do
184 assert_no_difference 'Member.count' do
167 delete :destroy, :id => member.id
185 delete :destroy, :id => member.id
168 end
186 end
169 end
187 end
170
188
171 def test_destroy_should_succeed_with_managed_roles_only
189 def test_destroy_should_succeed_with_managed_roles_only
172 role = Role.find(1)
190 role = Role.find(1)
173 role.update! :all_roles_managed => false
191 role.update! :all_roles_managed => false
174 role.managed_roles = Role.where(:id => [2, 3]).to_a
192 role.managed_roles = Role.where(:id => [2, 3]).to_a
175 member = Member.create!(:user => User.find(9), :role_ids => [3], :project_id => 1)
193 member = Member.create!(:user => User.find(9), :role_ids => [3], :project_id => 1)
176
194
177 assert_difference 'Member.count', -1 do
195 assert_difference 'Member.count', -1 do
178 delete :destroy, :id => member.id
196 delete :destroy, :id => member.id
179 end
197 end
180 end
198 end
181
199
182 def test_xhr_destroy
200 def test_xhr_destroy
183 assert_difference 'Member.count', -1 do
201 assert_difference 'Member.count', -1 do
184 xhr :delete, :destroy, :id => 2
202 xhr :delete, :destroy, :id => 2
185 assert_response :success
203 assert_response :success
186 assert_equal 'text/javascript', response.content_type
204 assert_equal 'text/javascript', response.content_type
187 end
205 end
188 assert_nil Member.find_by_id(2)
206 assert_nil Member.find_by_id(2)
189 assert_include 'tab-content-members', response.body
207 assert_include 'tab-content-members', response.body
190 end
208 end
191
209
192 def test_autocomplete
210 def test_autocomplete
193 xhr :get, :autocomplete, :project_id => 1, :q => 'mis', :format => 'js'
211 xhr :get, :autocomplete, :project_id => 1, :q => 'mis', :format => 'js'
194 assert_response :success
212 assert_response :success
195 assert_include 'User Misc', response.body
213 assert_include 'User Misc', response.body
196 end
214 end
197 end
215 end
@@ -1,755 +1,767
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class ProjectsControllerTest < Redmine::ControllerTest
20 class ProjectsControllerTest < Redmine::ControllerTest
21 fixtures :projects, :versions, :users, :email_addresses, :roles, :members,
21 fixtures :projects, :versions, :users, :email_addresses, :roles, :members,
22 :member_roles, :issues, :journals, :journal_details,
22 :member_roles, :issues, :journals, :journal_details,
23 :trackers, :projects_trackers, :issue_statuses,
23 :trackers, :projects_trackers, :issue_statuses,
24 :enabled_modules, :enumerations, :boards, :messages,
24 :enabled_modules, :enumerations, :boards, :messages,
25 :attachments, :custom_fields, :custom_values, :time_entries,
25 :attachments, :custom_fields, :custom_values, :time_entries,
26 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
26 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
27
27
28 def setup
28 def setup
29 @request.session[:user_id] = nil
29 @request.session[:user_id] = nil
30 Setting.default_language = 'en'
30 Setting.default_language = 'en'
31 end
31 end
32
32
33 def test_index_by_anonymous_should_not_show_private_projects
33 def test_index_by_anonymous_should_not_show_private_projects
34 get :index
34 get :index
35 assert_response :success
35 assert_response :success
36
36
37 assert_select 'ul' do
37 assert_select 'ul' do
38 assert_select 'li' do
38 assert_select 'li' do
39 assert_select 'a', :text => 'eCookbook'
39 assert_select 'a', :text => 'eCookbook'
40 assert_select 'ul' do
40 assert_select 'ul' do
41 assert_select 'a', :text => 'Child of private child'
41 assert_select 'a', :text => 'Child of private child'
42 end
42 end
43 end
43 end
44 end
44 end
45 assert_select 'a', :text => /Private child of eCookbook/, :count => 0
45 assert_select 'a', :text => /Private child of eCookbook/, :count => 0
46 end
46 end
47
47
48 def test_index_atom
48 def test_index_atom
49 get :index, :format => 'atom'
49 get :index, :format => 'atom'
50 assert_response :success
50 assert_response :success
51 assert_select 'feed>title', :text => 'Redmine: Latest projects'
51 assert_select 'feed>title', :text => 'Redmine: Latest projects'
52 assert_select 'feed>entry', :count => Project.visible(User.current).count
52 assert_select 'feed>entry', :count => Project.visible(User.current).count
53 end
53 end
54
54
55 def test_index_js
55 def test_index_js
56 xhr :get, :index, :format => 'js', :q => 'coo'
56 xhr :get, :index, :format => 'js', :q => 'coo'
57 assert_response :success
57 assert_response :success
58 assert_equal 'text/javascript', response.content_type
58 assert_equal 'text/javascript', response.content_type
59 end
59 end
60
60
61 test "#index by non-admin user with view_time_entries permission should show overall spent time link" do
61 test "#index by non-admin user with view_time_entries permission should show overall spent time link" do
62 @request.session[:user_id] = 3
62 @request.session[:user_id] = 3
63 get :index
63 get :index
64 assert_select 'a[href=?]', '/time_entries'
64 assert_select 'a[href=?]', '/time_entries'
65 end
65 end
66
66
67 test "#index by non-admin user without view_time_entries permission should not show overall spent time link" do
67 test "#index by non-admin user without view_time_entries permission should not show overall spent time link" do
68 Role.find(2).remove_permission! :view_time_entries
68 Role.find(2).remove_permission! :view_time_entries
69 Role.non_member.remove_permission! :view_time_entries
69 Role.non_member.remove_permission! :view_time_entries
70 Role.anonymous.remove_permission! :view_time_entries
70 Role.anonymous.remove_permission! :view_time_entries
71 @request.session[:user_id] = 3
71 @request.session[:user_id] = 3
72
72
73 get :index
73 get :index
74 assert_select 'a[href=?]', '/time_entries', 0
74 assert_select 'a[href=?]', '/time_entries', 0
75 end
75 end
76
76
77 test "#index by non-admin user with permission should show add project link" do
77 test "#index by non-admin user with permission should show add project link" do
78 Role.find(1).add_permission! :add_project
78 Role.find(1).add_permission! :add_project
79 @request.session[:user_id] = 2
79 @request.session[:user_id] = 2
80
80
81 get :index
81 get :index
82 assert_select 'a[href=?]', '/projects/new'
82 assert_select 'a[href=?]', '/projects/new'
83 end
83 end
84
84
85 test "#new by admin user should accept get" do
85 test "#new by admin user should accept get" do
86 @request.session[:user_id] = 1
86 @request.session[:user_id] = 1
87
87
88 get :new
88 get :new
89 assert_response :success
89 assert_response :success
90 assert_select 'input[name=?]', 'project[name]'
90 assert_select 'input[name=?]', 'project[name]'
91 assert_select 'select[name=?]', 'project[parent_id]'
91 assert_select 'select[name=?]', 'project[parent_id]'
92 end
92 end
93
93
94 test "#new by non-admin user with add_project permission should accept get" do
94 test "#new by non-admin user with add_project permission should accept get" do
95 Role.non_member.add_permission! :add_project
95 Role.non_member.add_permission! :add_project
96 @request.session[:user_id] = 9
96 @request.session[:user_id] = 9
97
97
98 get :new
98 get :new
99 assert_response :success
99 assert_response :success
100 assert_select 'input[name=?]', 'project[name]'
100 assert_select 'input[name=?]', 'project[name]'
101 assert_select 'select[name=?]', 'project[parent_id]', 0
101 assert_select 'select[name=?]', 'project[parent_id]', 0
102 end
102 end
103
103
104 test "#new by non-admin user with add_subprojects permission should accept get" do
104 test "#new by non-admin user with add_subprojects permission should accept get" do
105 Role.find(1).remove_permission! :add_project
105 Role.find(1).remove_permission! :add_project
106 Role.find(1).add_permission! :add_subprojects
106 Role.find(1).add_permission! :add_subprojects
107 @request.session[:user_id] = 2
107 @request.session[:user_id] = 2
108
108
109 get :new, :parent_id => 'ecookbook'
109 get :new, :parent_id => 'ecookbook'
110 assert_response :success
110 assert_response :success
111
111
112 assert_select 'select[name=?]', 'project[parent_id]' do
112 assert_select 'select[name=?]', 'project[parent_id]' do
113 # parent project selected
113 # parent project selected
114 assert_select 'option[value="1"][selected=selected]'
114 assert_select 'option[value="1"][selected=selected]'
115 # no empty value
115 # no empty value
116 assert_select 'option[value=""]', 0
116 assert_select 'option[value=""]', 0
117 end
117 end
118 end
118 end
119
119
120 def test_new_by_non_admin_should_display_modules_if_default_role_is_allowed_to_select_modules
120 def test_new_by_non_admin_should_display_modules_if_default_role_is_allowed_to_select_modules
121 Role.non_member.add_permission!(:add_project)
121 Role.non_member.add_permission!(:add_project)
122 default_role = Role.generate!(:permissions => [:view_issues])
122 default_role = Role.generate!(:permissions => [:view_issues])
123 user = User.generate!
123 user = User.generate!
124 @request.session[:user_id] = user.id
124 @request.session[:user_id] = user.id
125
125
126 with_settings :new_project_user_role_id => default_role.id.to_s do
126 with_settings :new_project_user_role_id => default_role.id.to_s do
127 get :new
127 get :new
128 assert_select 'input[name=?]', 'project[enabled_module_names][]', 0
128 assert_select 'input[name=?]', 'project[enabled_module_names][]', 0
129
129
130 default_role.add_permission!(:select_project_modules)
130 default_role.add_permission!(:select_project_modules)
131 get :new
131 get :new
132 assert_select 'input[name=?]', 'project[enabled_module_names][]'
132 assert_select 'input[name=?]', 'project[enabled_module_names][]'
133 end
133 end
134 end
134 end
135
135
136 def test_new_should_not_display_invalid_search_link
136 def test_new_should_not_display_invalid_search_link
137 @request.session[:user_id] = 1
137 @request.session[:user_id] = 1
138
138
139 get :new
139 get :new
140 assert_response :success
140 assert_response :success
141 assert_select '#quick-search form[action=?]', '/search'
141 assert_select '#quick-search form[action=?]', '/search'
142 assert_select '#quick-search a[href=?]', '/search'
142 assert_select '#quick-search a[href=?]', '/search'
143 end
143 end
144
144
145 test "#create by admin user should create a new project" do
145 test "#create by admin user should create a new project" do
146 @request.session[:user_id] = 1
146 @request.session[:user_id] = 1
147
147
148 post :create,
148 post :create,
149 :project => {
149 :project => {
150 :name => "blog",
150 :name => "blog",
151 :description => "weblog",
151 :description => "weblog",
152 :homepage => 'http://weblog',
152 :homepage => 'http://weblog',
153 :identifier => "blog",
153 :identifier => "blog",
154 :is_public => 1,
154 :is_public => 1,
155 :custom_field_values => { '3' => 'Beta' },
155 :custom_field_values => { '3' => 'Beta' },
156 :tracker_ids => ['1', '3'],
156 :tracker_ids => ['1', '3'],
157 # an issue custom field that is not for all project
157 # an issue custom field that is not for all project
158 :issue_custom_field_ids => ['9'],
158 :issue_custom_field_ids => ['9'],
159 :enabled_module_names => ['issue_tracking', 'news', 'repository']
159 :enabled_module_names => ['issue_tracking', 'news', 'repository']
160 }
160 }
161 assert_redirected_to '/projects/blog/settings'
161 assert_redirected_to '/projects/blog/settings'
162
162
163 project = Project.find_by_name('blog')
163 project = Project.find_by_name('blog')
164 assert_kind_of Project, project
164 assert_kind_of Project, project
165 assert project.active?
165 assert project.active?
166 assert_equal 'weblog', project.description
166 assert_equal 'weblog', project.description
167 assert_equal 'http://weblog', project.homepage
167 assert_equal 'http://weblog', project.homepage
168 assert_equal true, project.is_public?
168 assert_equal true, project.is_public?
169 assert_nil project.parent
169 assert_nil project.parent
170 assert_equal 'Beta', project.custom_value_for(3).value
170 assert_equal 'Beta', project.custom_value_for(3).value
171 assert_equal [1, 3], project.trackers.map(&:id).sort
171 assert_equal [1, 3], project.trackers.map(&:id).sort
172 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
172 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
173 assert project.issue_custom_fields.include?(IssueCustomField.find(9))
173 assert project.issue_custom_fields.include?(IssueCustomField.find(9))
174 end
174 end
175
175
176 test "#create by admin user should create a new subproject" do
176 test "#create by admin user should create a new subproject" do
177 @request.session[:user_id] = 1
177 @request.session[:user_id] = 1
178
178
179 assert_difference 'Project.count' do
179 assert_difference 'Project.count' do
180 post :create, :project => { :name => "blog",
180 post :create, :project => { :name => "blog",
181 :description => "weblog",
181 :description => "weblog",
182 :identifier => "blog",
182 :identifier => "blog",
183 :is_public => 1,
183 :is_public => 1,
184 :custom_field_values => { '3' => 'Beta' },
184 :custom_field_values => { '3' => 'Beta' },
185 :parent_id => 1
185 :parent_id => 1
186 }
186 }
187 assert_redirected_to '/projects/blog/settings'
187 assert_redirected_to '/projects/blog/settings'
188 end
188 end
189
189
190 project = Project.find_by_name('blog')
190 project = Project.find_by_name('blog')
191 assert_kind_of Project, project
191 assert_kind_of Project, project
192 assert_equal Project.find(1), project.parent
192 assert_equal Project.find(1), project.parent
193 end
193 end
194
194
195 test "#create by admin user should continue" do
195 test "#create by admin user should continue" do
196 @request.session[:user_id] = 1
196 @request.session[:user_id] = 1
197
197
198 assert_difference 'Project.count' do
198 assert_difference 'Project.count' do
199 post :create, :project => {:name => "blog", :identifier => "blog"}, :continue => 'Create and continue'
199 post :create, :project => {:name => "blog", :identifier => "blog"}, :continue => 'Create and continue'
200 end
200 end
201 assert_redirected_to '/projects/new'
201 assert_redirected_to '/projects/new'
202 end
202 end
203
203
204 test "#create by non-admin user with add_project permission should create a new project" do
204 test "#create by non-admin user with add_project permission should create a new project" do
205 Role.non_member.add_permission! :add_project
205 Role.non_member.add_permission! :add_project
206 @request.session[:user_id] = 9
206 @request.session[:user_id] = 9
207
207
208 post :create, :project => { :name => "blog",
208 post :create, :project => { :name => "blog",
209 :description => "weblog",
209 :description => "weblog",
210 :identifier => "blog",
210 :identifier => "blog",
211 :is_public => 1,
211 :is_public => 1,
212 :custom_field_values => { '3' => 'Beta' },
212 :custom_field_values => { '3' => 'Beta' },
213 :tracker_ids => ['1', '3'],
213 :tracker_ids => ['1', '3'],
214 :enabled_module_names => ['issue_tracking', 'news', 'repository']
214 :enabled_module_names => ['issue_tracking', 'news', 'repository']
215 }
215 }
216
216
217 assert_redirected_to '/projects/blog/settings'
217 assert_redirected_to '/projects/blog/settings'
218
218
219 project = Project.find_by_name('blog')
219 project = Project.find_by_name('blog')
220 assert_kind_of Project, project
220 assert_kind_of Project, project
221 assert_equal 'weblog', project.description
221 assert_equal 'weblog', project.description
222 assert_equal true, project.is_public?
222 assert_equal true, project.is_public?
223 assert_equal [1, 3], project.trackers.map(&:id).sort
223 assert_equal [1, 3], project.trackers.map(&:id).sort
224 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
224 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
225
225
226 # User should be added as a project member
226 # User should be added as a project member
227 assert User.find(9).member_of?(project)
227 assert User.find(9).member_of?(project)
228 assert_equal 1, project.members.size
228 assert_equal 1, project.members.size
229 end
229 end
230
230
231 test "#create by non-admin user with add_project permission should fail with parent_id" do
231 test "#create by non-admin user with add_project permission should fail with parent_id" do
232 Role.non_member.add_permission! :add_project
232 Role.non_member.add_permission! :add_project
233 User.find(9).update! :language => 'en'
233 User.find(9).update! :language => 'en'
234 @request.session[:user_id] = 9
234 @request.session[:user_id] = 9
235
235
236 assert_no_difference 'Project.count' do
236 assert_no_difference 'Project.count' do
237 post :create, :project => { :name => "blog",
237 post :create, :project => { :name => "blog",
238 :description => "weblog",
238 :description => "weblog",
239 :identifier => "blog",
239 :identifier => "blog",
240 :is_public => 1,
240 :is_public => 1,
241 :custom_field_values => { '3' => 'Beta' },
241 :custom_field_values => { '3' => 'Beta' },
242 :parent_id => 1
242 :parent_id => 1
243 }
243 }
244 end
244 end
245 assert_response :success
245 assert_response :success
246 assert_select_error /Subproject of is invalid/
246 assert_select_error /Subproject of is invalid/
247 end
247 end
248
248
249 test "#create by non-admin user with add_subprojects permission should create a project with a parent_id" do
249 test "#create by non-admin user with add_subprojects permission should create a project with a parent_id" do
250 Role.find(1).remove_permission! :add_project
250 Role.find(1).remove_permission! :add_project
251 Role.find(1).add_permission! :add_subprojects
251 Role.find(1).add_permission! :add_subprojects
252 @request.session[:user_id] = 2
252 @request.session[:user_id] = 2
253
253
254 post :create, :project => { :name => "blog",
254 post :create, :project => { :name => "blog",
255 :description => "weblog",
255 :description => "weblog",
256 :identifier => "blog",
256 :identifier => "blog",
257 :is_public => 1,
257 :is_public => 1,
258 :custom_field_values => { '3' => 'Beta' },
258 :custom_field_values => { '3' => 'Beta' },
259 :parent_id => 1
259 :parent_id => 1
260 }
260 }
261 assert_redirected_to '/projects/blog/settings'
261 assert_redirected_to '/projects/blog/settings'
262 project = Project.find_by_name('blog')
262 project = Project.find_by_name('blog')
263 assert_equal 1, project.parent_id
263 assert_equal 1, project.parent_id
264 end
264 end
265
265
266 test "#create by non-admin user with add_subprojects permission should fail without parent_id" do
266 test "#create by non-admin user with add_subprojects permission should fail without parent_id" do
267 Role.find(1).remove_permission! :add_project
267 Role.find(1).remove_permission! :add_project
268 Role.find(1).add_permission! :add_subprojects
268 Role.find(1).add_permission! :add_subprojects
269 @request.session[:user_id] = 2
269 @request.session[:user_id] = 2
270
270
271 assert_no_difference 'Project.count' do
271 assert_no_difference 'Project.count' do
272 post :create, :project => { :name => "blog",
272 post :create, :project => { :name => "blog",
273 :description => "weblog",
273 :description => "weblog",
274 :identifier => "blog",
274 :identifier => "blog",
275 :is_public => 1,
275 :is_public => 1,
276 :custom_field_values => { '3' => 'Beta' }
276 :custom_field_values => { '3' => 'Beta' }
277 }
277 }
278 end
278 end
279 assert_response :success
279 assert_response :success
280 assert_select_error /Subproject of is invalid/
280 assert_select_error /Subproject of is invalid/
281 end
281 end
282
282
283 test "#create by non-admin user with add_subprojects permission should fail with unauthorized parent_id" do
283 test "#create by non-admin user with add_subprojects permission should fail with unauthorized parent_id" do
284 Role.find(1).remove_permission! :add_project
284 Role.find(1).remove_permission! :add_project
285 Role.find(1).add_permission! :add_subprojects
285 Role.find(1).add_permission! :add_subprojects
286 @request.session[:user_id] = 2
286 @request.session[:user_id] = 2
287
287
288 assert !User.find(2).member_of?(Project.find(6))
288 assert !User.find(2).member_of?(Project.find(6))
289 assert_no_difference 'Project.count' do
289 assert_no_difference 'Project.count' do
290 post :create, :project => { :name => "blog",
290 post :create, :project => { :name => "blog",
291 :description => "weblog",
291 :description => "weblog",
292 :identifier => "blog",
292 :identifier => "blog",
293 :is_public => 1,
293 :is_public => 1,
294 :custom_field_values => { '3' => 'Beta' },
294 :custom_field_values => { '3' => 'Beta' },
295 :parent_id => 6
295 :parent_id => 6
296 }
296 }
297 end
297 end
298 assert_response :success
298 assert_response :success
299 assert_select_error /Subproject of is invalid/
299 assert_select_error /Subproject of is invalid/
300 end
300 end
301
301
302 def test_create_by_non_admin_should_accept_modules_if_default_role_is_allowed_to_select_modules
302 def test_create_by_non_admin_should_accept_modules_if_default_role_is_allowed_to_select_modules
303 Role.non_member.add_permission!(:add_project)
303 Role.non_member.add_permission!(:add_project)
304 default_role = Role.generate!(:permissions => [:view_issues, :add_project])
304 default_role = Role.generate!(:permissions => [:view_issues, :add_project])
305 user = User.generate!
305 user = User.generate!
306 @request.session[:user_id] = user.id
306 @request.session[:user_id] = user.id
307
307
308 with_settings :new_project_user_role_id => default_role.id.to_s, :default_projects_modules => %w(news files) do
308 with_settings :new_project_user_role_id => default_role.id.to_s, :default_projects_modules => %w(news files) do
309 project = new_record(Project) do
309 project = new_record(Project) do
310 post :create, :project => {
310 post :create, :project => {
311 :name => "blog1",
311 :name => "blog1",
312 :identifier => "blog1",
312 :identifier => "blog1",
313 :enabled_module_names => ["issue_tracking", "repository"]
313 :enabled_module_names => ["issue_tracking", "repository"]
314 }
314 }
315 end
315 end
316 assert_equal %w(files news), project.enabled_module_names.sort
316 assert_equal %w(files news), project.enabled_module_names.sort
317
317
318 default_role.add_permission!(:select_project_modules)
318 default_role.add_permission!(:select_project_modules)
319 project = new_record(Project) do
319 project = new_record(Project) do
320 post :create, :project => {
320 post :create, :project => {
321 :name => "blog2",
321 :name => "blog2",
322 :identifier => "blog2",
322 :identifier => "blog2",
323 :enabled_module_names => ["issue_tracking", "repository"]
323 :enabled_module_names => ["issue_tracking", "repository"]
324 }
324 }
325 end
325 end
326 assert_equal %w(issue_tracking repository), project.enabled_module_names.sort
326 assert_equal %w(issue_tracking repository), project.enabled_module_names.sort
327 end
327 end
328 end
328 end
329
329
330 def test_create_subproject_with_inherit_members_should_inherit_members
330 def test_create_subproject_with_inherit_members_should_inherit_members
331 Role.find_by_name('Manager').add_permission! :add_subprojects
331 Role.find_by_name('Manager').add_permission! :add_subprojects
332 parent = Project.find(1)
332 parent = Project.find(1)
333 @request.session[:user_id] = 2
333 @request.session[:user_id] = 2
334
334
335 assert_difference 'Project.count' do
335 assert_difference 'Project.count' do
336 post :create, :project => {
336 post :create, :project => {
337 :name => 'inherited', :identifier => 'inherited', :parent_id => parent.id, :inherit_members => '1'
337 :name => 'inherited', :identifier => 'inherited', :parent_id => parent.id, :inherit_members => '1'
338 }
338 }
339 assert_response 302
339 assert_response 302
340 end
340 end
341
341
342 project = Project.order('id desc').first
342 project = Project.order('id desc').first
343 assert_equal 'inherited', project.name
343 assert_equal 'inherited', project.name
344 assert_equal parent, project.parent
344 assert_equal parent, project.parent
345 assert project.memberships.count > 0
345 assert project.memberships.count > 0
346 assert_equal parent.memberships.count, project.memberships.count
346 assert_equal parent.memberships.count, project.memberships.count
347 end
347 end
348
348
349 def test_create_should_preserve_modules_on_validation_failure
349 def test_create_should_preserve_modules_on_validation_failure
350 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
350 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
351 @request.session[:user_id] = 1
351 @request.session[:user_id] = 1
352 assert_no_difference 'Project.count' do
352 assert_no_difference 'Project.count' do
353 post :create, :project => {
353 post :create, :project => {
354 :name => "blog",
354 :name => "blog",
355 :identifier => "",
355 :identifier => "",
356 :enabled_module_names => %w(issue_tracking news)
356 :enabled_module_names => %w(issue_tracking news)
357 }
357 }
358 end
358 end
359 assert_response :success
359 assert_response :success
360 %w(issue_tracking news).each do |mod|
360 %w(issue_tracking news).each do |mod|
361 assert_select 'input[name=?][value=?][checked=checked]', 'project[enabled_module_names][]', mod
361 assert_select 'input[name=?][value=?][checked=checked]', 'project[enabled_module_names][]', mod
362 end
362 end
363 assert_select 'input[name=?][checked=checked]', 'project[enabled_module_names][]', :count => 2
363 assert_select 'input[name=?][checked=checked]', 'project[enabled_module_names][]', :count => 2
364 end
364 end
365 end
365 end
366
366
367 def test_show_by_id
367 def test_show_by_id
368 get :show, :id => 1
368 get :show, :id => 1
369 assert_response :success
369 assert_response :success
370 assert_select '#header h1', :text => "eCookbook"
370 assert_select '#header h1', :text => "eCookbook"
371 end
371 end
372
372
373 def test_show_by_identifier
373 def test_show_by_identifier
374 get :show, :id => 'ecookbook'
374 get :show, :id => 'ecookbook'
375 assert_response :success
375 assert_response :success
376 assert_select '#header h1', :text => "eCookbook"
376 assert_select '#header h1', :text => "eCookbook"
377 end
377 end
378
378
379 def test_show_should_not_display_empty_sidebar
379 def test_show_should_not_display_empty_sidebar
380 p = Project.find(1)
380 p = Project.find(1)
381 p.enabled_module_names = []
381 p.enabled_module_names = []
382 p.save!
382 p.save!
383
383
384 get :show, :id => 'ecookbook'
384 get :show, :id => 'ecookbook'
385 assert_response :success
385 assert_response :success
386 assert_select '#main.nosidebar'
386 assert_select '#main.nosidebar'
387 end
387 end
388
388
389 def test_show_should_display_visible_custom_fields
389 def test_show_should_display_visible_custom_fields
390 ProjectCustomField.find_by_name('Development status').update_attribute :visible, true
390 ProjectCustomField.find_by_name('Development status').update_attribute :visible, true
391 get :show, :id => 'ecookbook'
391 get :show, :id => 'ecookbook'
392 assert_response :success
392 assert_response :success
393
393
394 assert_select 'li', :text => /Development status/
394 assert_select 'li', :text => /Development status/
395 end
395 end
396
396
397 def test_show_should_not_display_hidden_custom_fields
397 def test_show_should_not_display_hidden_custom_fields
398 ProjectCustomField.find_by_name('Development status').update_attribute :visible, false
398 ProjectCustomField.find_by_name('Development status').update_attribute :visible, false
399 get :show, :id => 'ecookbook'
399 get :show, :id => 'ecookbook'
400 assert_response :success
400 assert_response :success
401
401
402 assert_select 'li', :text => /Development status/, :count => 0
402 assert_select 'li', :text => /Development status/, :count => 0
403 end
403 end
404
404
405 def test_show_should_not_display_blank_custom_fields_with_multiple_values
405 def test_show_should_not_display_blank_custom_fields_with_multiple_values
406 f1 = ProjectCustomField.generate! :field_format => 'list', :possible_values => %w(Foo Bar), :multiple => true
406 f1 = ProjectCustomField.generate! :field_format => 'list', :possible_values => %w(Foo Bar), :multiple => true
407 f2 = ProjectCustomField.generate! :field_format => 'list', :possible_values => %w(Baz Qux), :multiple => true
407 f2 = ProjectCustomField.generate! :field_format => 'list', :possible_values => %w(Baz Qux), :multiple => true
408 project = Project.generate!(:custom_field_values => {f2.id.to_s => %w(Qux)})
408 project = Project.generate!(:custom_field_values => {f2.id.to_s => %w(Qux)})
409
409
410 get :show, :id => project.id
410 get :show, :id => project.id
411 assert_response :success
411 assert_response :success
412
412
413 assert_select 'li', :text => /#{f1.name}/, :count => 0
413 assert_select 'li', :text => /#{f1.name}/, :count => 0
414 assert_select 'li', :text => /#{f2.name}/
414 assert_select 'li', :text => /#{f2.name}/
415 end
415 end
416
416
417 def test_show_should_not_display_blank_text_custom_fields
417 def test_show_should_not_display_blank_text_custom_fields
418 f1 = ProjectCustomField.generate! :field_format => 'text'
418 f1 = ProjectCustomField.generate! :field_format => 'text'
419
419
420 get :show, :id => 1
420 get :show, :id => 1
421 assert_response :success
421 assert_response :success
422
422
423 assert_select 'li', :text => /#{f1.name}/, :count => 0
423 assert_select 'li', :text => /#{f1.name}/, :count => 0
424 end
424 end
425
425
426 def test_show_should_not_fail_when_custom_values_are_nil
426 def test_show_should_not_fail_when_custom_values_are_nil
427 project = Project.find_by_identifier('ecookbook')
427 project = Project.find_by_identifier('ecookbook')
428 project.custom_values.first.update_attribute(:value, nil)
428 project.custom_values.first.update_attribute(:value, nil)
429 get :show, :id => 'ecookbook'
429 get :show, :id => 'ecookbook'
430 assert_response :success
430 assert_response :success
431 end
431 end
432
432
433 def show_archived_project_should_be_denied
433 def show_archived_project_should_be_denied
434 project = Project.find_by_identifier('ecookbook')
434 project = Project.find_by_identifier('ecookbook')
435 project.archive!
435 project.archive!
436
436
437 get :show, :id => 'ecookbook'
437 get :show, :id => 'ecookbook'
438 assert_response 403
438 assert_response 403
439 assert_select 'p', :text => /archived/
439 assert_select 'p', :text => /archived/
440 assert_not_include project.name, response.body
440 assert_not_include project.name, response.body
441 end
441 end
442
442
443 def test_show_should_not_show_private_subprojects_that_are_not_visible
443 def test_show_should_not_show_private_subprojects_that_are_not_visible
444 get :show, :id => 'ecookbook'
444 get :show, :id => 'ecookbook'
445 assert_response :success
445 assert_response :success
446 assert_select 'a', :text => /Private child/, :count => 0
446 assert_select 'a', :text => /Private child/, :count => 0
447 end
447 end
448
448
449 def test_show_should_show_private_subprojects_that_are_visible
449 def test_show_should_show_private_subprojects_that_are_visible
450 @request.session[:user_id] = 2 # manager who is a member of the private subproject
450 @request.session[:user_id] = 2 # manager who is a member of the private subproject
451 get :show, :id => 'ecookbook'
451 get :show, :id => 'ecookbook'
452 assert_response :success
452 assert_response :success
453 assert_select 'a', :text => /Private child/
453 assert_select 'a', :text => /Private child/
454 end
454 end
455
455
456 def test_settings
456 def test_settings
457 @request.session[:user_id] = 2 # manager
457 @request.session[:user_id] = 2 # manager
458 get :settings, :id => 1
458 get :settings, :id => 1
459 assert_response :success
459 assert_response :success
460
460
461 assert_select 'input[name=?]', 'project[name]'
461 assert_select 'input[name=?]', 'project[name]'
462 end
462 end
463
463
464 def test_settings_of_subproject
464 def test_settings_of_subproject
465 @request.session[:user_id] = 2
465 @request.session[:user_id] = 2
466 get :settings, :id => 'private-child'
466 get :settings, :id => 'private-child'
467 assert_response :success
467 assert_response :success
468
468
469 assert_select 'input[type=checkbox][name=?]', 'project[inherit_members]'
469 assert_select 'input[type=checkbox][name=?]', 'project[inherit_members]'
470 end
470 end
471
471
472 def test_settings_should_be_denied_for_member_on_closed_project
472 def test_settings_should_be_denied_for_member_on_closed_project
473 Project.find(1).close
473 Project.find(1).close
474 @request.session[:user_id] = 2 # manager
474 @request.session[:user_id] = 2 # manager
475
475
476 get :settings, :id => 1
476 get :settings, :id => 1
477 assert_response 403
477 assert_response 403
478 end
478 end
479
479
480 def test_settings_should_be_denied_for_anonymous_on_closed_project
480 def test_settings_should_be_denied_for_anonymous_on_closed_project
481 Project.find(1).close
481 Project.find(1).close
482
482
483 get :settings, :id => 1
483 get :settings, :id => 1
484 assert_response 302
484 assert_response 302
485 end
485 end
486
486
487 def test_setting_with_wiki_module_and_no_wiki
487 def test_setting_with_wiki_module_and_no_wiki
488 Project.find(1).wiki.destroy
488 Project.find(1).wiki.destroy
489 Role.find(1).add_permission! :manage_wiki
489 Role.find(1).add_permission! :manage_wiki
490 @request.session[:user_id] = 2
490 @request.session[:user_id] = 2
491
491
492 get :settings, :id => 1
492 get :settings, :id => 1
493 assert_response :success
493 assert_response :success
494
494
495 assert_select 'form[action=?]', '/projects/ecookbook/wiki' do
495 assert_select 'form[action=?]', '/projects/ecookbook/wiki' do
496 assert_select 'input[name=?]', 'wiki[start_page]'
496 assert_select 'input[name=?]', 'wiki[start_page]'
497 end
497 end
498 end
498 end
499
499
500 def test_settings_should_accept_version_status_filter
500 def test_settings_should_accept_version_status_filter
501 @request.session[:user_id] = 2
501 @request.session[:user_id] = 2
502
502
503 get :settings, :id => 'ecookbook', :tab => 'versions', :version_status => 'locked'
503 get :settings, :id => 'ecookbook', :tab => 'versions', :version_status => 'locked'
504 assert_response :success
504 assert_response :success
505
505
506 assert_select 'select[name=version_status]' do
506 assert_select 'select[name=version_status]' do
507 assert_select 'option[value=locked][selected=selected]'
507 assert_select 'option[value=locked][selected=selected]'
508 end
508 end
509 assert_select 'table.versions tbody' do
509 assert_select 'table.versions tbody' do
510 assert_select 'tr', 1
510 assert_select 'tr', 1
511 assert_select 'td.name', :text => '1.0'
511 assert_select 'td.name', :text => '1.0'
512 end
512 end
513 assert_select 'a#tab-versions[href=?]', '/projects/ecookbook/settings/versions?version_status=locked'
513 assert_select 'a#tab-versions[href=?]', '/projects/ecookbook/settings/versions?version_status=locked'
514 end
514 end
515
515
516 def test_settings_should_accept_version_name_filter
516 def test_settings_should_accept_version_name_filter
517 @request.session[:user_id] = 2
517 @request.session[:user_id] = 2
518
518
519 get :settings, :id => 'ecookbook', :tab => 'versions', :version_status => '', :version_name => '.1'
519 get :settings, :id => 'ecookbook', :tab => 'versions', :version_status => '', :version_name => '.1'
520 assert_response :success
520 assert_response :success
521
521
522 assert_select 'input[name=version_name][value=?]', '.1'
522 assert_select 'input[name=version_name][value=?]', '.1'
523 assert_select 'table.versions tbody' do
523 assert_select 'table.versions tbody' do
524 assert_select 'tr', 1
524 assert_select 'tr', 1
525 assert_select 'td.name', :text => '0.1'
525 assert_select 'td.name', :text => '0.1'
526 end
526 end
527 assert_select 'a#tab-versions[href=?]', '/projects/ecookbook/settings/versions?version_name=.1&version_status='
527 assert_select 'a#tab-versions[href=?]', '/projects/ecookbook/settings/versions?version_name=.1&version_status='
528 end
528 end
529
529
530 def test_settings_should_show_locked_members
531 user = User.generate!
532 member = User.add_to_project(user, Project.find(1))
533 user.lock!
534 assert user.reload.locked?
535 @request.session[:user_id] = 2
536
537 get :settings, :id => 'ecookbook', :tab => 'members'
538 assert_response :success
539 assert_select "tr#member-#{member.id}"
540 end
541
530 def test_update
542 def test_update
531 @request.session[:user_id] = 2 # manager
543 @request.session[:user_id] = 2 # manager
532 post :update, :id => 1, :project => {:name => 'Test changed name',
544 post :update, :id => 1, :project => {:name => 'Test changed name',
533 :issue_custom_field_ids => ['']}
545 :issue_custom_field_ids => ['']}
534 assert_redirected_to '/projects/ecookbook/settings'
546 assert_redirected_to '/projects/ecookbook/settings'
535 project = Project.find(1)
547 project = Project.find(1)
536 assert_equal 'Test changed name', project.name
548 assert_equal 'Test changed name', project.name
537 end
549 end
538
550
539 def test_update_with_failure
551 def test_update_with_failure
540 @request.session[:user_id] = 2 # manager
552 @request.session[:user_id] = 2 # manager
541 post :update, :id => 1, :project => {:name => ''}
553 post :update, :id => 1, :project => {:name => ''}
542 assert_response :success
554 assert_response :success
543 assert_select_error /name cannot be blank/i
555 assert_select_error /name cannot be blank/i
544 end
556 end
545
557
546 def test_update_should_be_denied_for_member_on_closed_project
558 def test_update_should_be_denied_for_member_on_closed_project
547 Project.find(1).close
559 Project.find(1).close
548 @request.session[:user_id] = 2 # manager
560 @request.session[:user_id] = 2 # manager
549
561
550 post :update, :id => 1, :project => {:name => 'Closed'}
562 post :update, :id => 1, :project => {:name => 'Closed'}
551 assert_response 403
563 assert_response 403
552 assert_equal 'eCookbook', Project.find(1).name
564 assert_equal 'eCookbook', Project.find(1).name
553 end
565 end
554
566
555 def test_update_should_be_denied_for_anonymous_on_closed_project
567 def test_update_should_be_denied_for_anonymous_on_closed_project
556 Project.find(1).close
568 Project.find(1).close
557
569
558 post :update, :id => 1, :project => {:name => 'Closed'}
570 post :update, :id => 1, :project => {:name => 'Closed'}
559 assert_response 302
571 assert_response 302
560 assert_equal 'eCookbook', Project.find(1).name
572 assert_equal 'eCookbook', Project.find(1).name
561 end
573 end
562
574
563 def test_update_child_project_without_parent_permission_should_not_show_validation_error
575 def test_update_child_project_without_parent_permission_should_not_show_validation_error
564 child = Project.generate_with_parent!
576 child = Project.generate_with_parent!
565 user = User.generate!
577 user = User.generate!
566 User.add_to_project(user, child, Role.generate!(:permissions => [:edit_project]))
578 User.add_to_project(user, child, Role.generate!(:permissions => [:edit_project]))
567 @request.session[:user_id] = user.id
579 @request.session[:user_id] = user.id
568
580
569 post :update, :id => child.id, :project => {:name => 'Updated'}
581 post :update, :id => child.id, :project => {:name => 'Updated'}
570 assert_response 302
582 assert_response 302
571 assert_match /Successful update/, flash[:notice]
583 assert_match /Successful update/, flash[:notice]
572 end
584 end
573
585
574 def test_modules
586 def test_modules
575 @request.session[:user_id] = 2
587 @request.session[:user_id] = 2
576 Project.find(1).enabled_module_names = ['issue_tracking', 'news']
588 Project.find(1).enabled_module_names = ['issue_tracking', 'news']
577
589
578 post :modules, :id => 1, :enabled_module_names => ['issue_tracking', 'repository', 'documents']
590 post :modules, :id => 1, :enabled_module_names => ['issue_tracking', 'repository', 'documents']
579 assert_redirected_to '/projects/ecookbook/settings/modules'
591 assert_redirected_to '/projects/ecookbook/settings/modules'
580 assert_equal ['documents', 'issue_tracking', 'repository'], Project.find(1).enabled_module_names.sort
592 assert_equal ['documents', 'issue_tracking', 'repository'], Project.find(1).enabled_module_names.sort
581 end
593 end
582
594
583 def test_destroy_leaf_project_without_confirmation_should_show_confirmation
595 def test_destroy_leaf_project_without_confirmation_should_show_confirmation
584 @request.session[:user_id] = 1 # admin
596 @request.session[:user_id] = 1 # admin
585
597
586 assert_no_difference 'Project.count' do
598 assert_no_difference 'Project.count' do
587 delete :destroy, :id => 2
599 delete :destroy, :id => 2
588 assert_response :success
600 assert_response :success
589 end
601 end
590 assert_select '.warning', :text => /Are you sure you want to delete this project/
602 assert_select '.warning', :text => /Are you sure you want to delete this project/
591 end
603 end
592
604
593 def test_destroy_without_confirmation_should_show_confirmation_with_subprojects
605 def test_destroy_without_confirmation_should_show_confirmation_with_subprojects
594 @request.session[:user_id] = 1 # admin
606 @request.session[:user_id] = 1 # admin
595
607
596 assert_no_difference 'Project.count' do
608 assert_no_difference 'Project.count' do
597 delete :destroy, :id => 1
609 delete :destroy, :id => 1
598 assert_response :success
610 assert_response :success
599 end
611 end
600 assert_select 'strong',
612 assert_select 'strong',
601 :text => ['Private child of eCookbook',
613 :text => ['Private child of eCookbook',
602 'Child of private child, eCookbook Subproject 1',
614 'Child of private child, eCookbook Subproject 1',
603 'eCookbook Subproject 2'].join(', ')
615 'eCookbook Subproject 2'].join(', ')
604 end
616 end
605
617
606 def test_destroy_with_confirmation_should_destroy_the_project_and_subprojects
618 def test_destroy_with_confirmation_should_destroy_the_project_and_subprojects
607 @request.session[:user_id] = 1 # admin
619 @request.session[:user_id] = 1 # admin
608
620
609 assert_difference 'Project.count', -5 do
621 assert_difference 'Project.count', -5 do
610 delete :destroy, :id => 1, :confirm => 1
622 delete :destroy, :id => 1, :confirm => 1
611 assert_redirected_to '/admin/projects'
623 assert_redirected_to '/admin/projects'
612 end
624 end
613 assert_nil Project.find_by_id(1)
625 assert_nil Project.find_by_id(1)
614 end
626 end
615
627
616 def test_archive
628 def test_archive
617 @request.session[:user_id] = 1 # admin
629 @request.session[:user_id] = 1 # admin
618 post :archive, :id => 1
630 post :archive, :id => 1
619 assert_redirected_to '/admin/projects'
631 assert_redirected_to '/admin/projects'
620 assert !Project.find(1).active?
632 assert !Project.find(1).active?
621 end
633 end
622
634
623 def test_archive_with_failure
635 def test_archive_with_failure
624 @request.session[:user_id] = 1
636 @request.session[:user_id] = 1
625 Project.any_instance.stubs(:archive).returns(false)
637 Project.any_instance.stubs(:archive).returns(false)
626 post :archive, :id => 1
638 post :archive, :id => 1
627 assert_redirected_to '/admin/projects'
639 assert_redirected_to '/admin/projects'
628 assert_match /project cannot be archived/i, flash[:error]
640 assert_match /project cannot be archived/i, flash[:error]
629 end
641 end
630
642
631 def test_unarchive
643 def test_unarchive
632 @request.session[:user_id] = 1 # admin
644 @request.session[:user_id] = 1 # admin
633 Project.find(1).archive
645 Project.find(1).archive
634 post :unarchive, :id => 1
646 post :unarchive, :id => 1
635 assert_redirected_to '/admin/projects'
647 assert_redirected_to '/admin/projects'
636 assert Project.find(1).active?
648 assert Project.find(1).active?
637 end
649 end
638
650
639 def test_close
651 def test_close
640 @request.session[:user_id] = 2
652 @request.session[:user_id] = 2
641 post :close, :id => 1
653 post :close, :id => 1
642 assert_redirected_to '/projects/ecookbook'
654 assert_redirected_to '/projects/ecookbook'
643 assert_equal Project::STATUS_CLOSED, Project.find(1).status
655 assert_equal Project::STATUS_CLOSED, Project.find(1).status
644 end
656 end
645
657
646 def test_reopen
658 def test_reopen
647 Project.find(1).close
659 Project.find(1).close
648 @request.session[:user_id] = 2
660 @request.session[:user_id] = 2
649 post :reopen, :id => 1
661 post :reopen, :id => 1
650 assert_redirected_to '/projects/ecookbook'
662 assert_redirected_to '/projects/ecookbook'
651 assert Project.find(1).active?
663 assert Project.find(1).active?
652 end
664 end
653
665
654 def test_project_breadcrumbs_should_be_limited_to_3_ancestors
666 def test_project_breadcrumbs_should_be_limited_to_3_ancestors
655 CustomField.delete_all
667 CustomField.delete_all
656 parent = nil
668 parent = nil
657 6.times do |i|
669 6.times do |i|
658 p = Project.generate_with_parent!(parent)
670 p = Project.generate_with_parent!(parent)
659 get :show, :id => p
671 get :show, :id => p
660 assert_select '#header h1' do
672 assert_select '#header h1' do
661 assert_select 'a', :count => [i, 3].min
673 assert_select 'a', :count => [i, 3].min
662 end
674 end
663
675
664 parent = p
676 parent = p
665 end
677 end
666 end
678 end
667
679
668 def test_get_copy
680 def test_get_copy
669 @request.session[:user_id] = 1 # admin
681 @request.session[:user_id] = 1 # admin
670 orig = Project.find(1)
682 orig = Project.find(1)
671
683
672 get :copy, :id => orig.id
684 get :copy, :id => orig.id
673 assert_response :success
685 assert_response :success
674
686
675 assert_select 'textarea[name=?]', 'project[description]', :text => orig.description
687 assert_select 'textarea[name=?]', 'project[description]', :text => orig.description
676 assert_select 'input[name=?][value=?]', 'project[enabled_module_names][]', 'issue_tracking', 1
688 assert_select 'input[name=?][value=?]', 'project[enabled_module_names][]', 'issue_tracking', 1
677 end
689 end
678
690
679 def test_get_copy_with_invalid_source_should_respond_with_404
691 def test_get_copy_with_invalid_source_should_respond_with_404
680 @request.session[:user_id] = 1
692 @request.session[:user_id] = 1
681 get :copy, :id => 99
693 get :copy, :id => 99
682 assert_response 404
694 assert_response 404
683 end
695 end
684
696
685 def test_get_copy_should_preselect_custom_fields
697 def test_get_copy_should_preselect_custom_fields
686 field1 = IssueCustomField.generate!(:is_for_all => false)
698 field1 = IssueCustomField.generate!(:is_for_all => false)
687 field2 = IssueCustomField.generate!(:is_for_all => false)
699 field2 = IssueCustomField.generate!(:is_for_all => false)
688 source = Project.generate!(:issue_custom_fields => [field1])
700 source = Project.generate!(:issue_custom_fields => [field1])
689 @request.session[:user_id] = 1
701 @request.session[:user_id] = 1
690
702
691 get :copy, :id => source.id
703 get :copy, :id => source.id
692 assert_response :success
704 assert_response :success
693 assert_select 'fieldset#project_issue_custom_fields' do
705 assert_select 'fieldset#project_issue_custom_fields' do
694 assert_select 'input[type=checkbox][value=?][checked=checked]', field1.id.to_s
706 assert_select 'input[type=checkbox][value=?][checked=checked]', field1.id.to_s
695 assert_select 'input[type=checkbox][value=?]:not([checked])', field2.id.to_s
707 assert_select 'input[type=checkbox][value=?]:not([checked])', field2.id.to_s
696 end
708 end
697 end
709 end
698
710
699 def test_post_copy_should_copy_requested_items
711 def test_post_copy_should_copy_requested_items
700 @request.session[:user_id] = 1 # admin
712 @request.session[:user_id] = 1 # admin
701 CustomField.delete_all
713 CustomField.delete_all
702
714
703 assert_difference 'Project.count' do
715 assert_difference 'Project.count' do
704 post :copy, :id => 1,
716 post :copy, :id => 1,
705 :project => {
717 :project => {
706 :name => 'Copy',
718 :name => 'Copy',
707 :identifier => 'unique-copy',
719 :identifier => 'unique-copy',
708 :tracker_ids => ['1', '2', '3', ''],
720 :tracker_ids => ['1', '2', '3', ''],
709 :enabled_module_names => %w(issue_tracking time_tracking)
721 :enabled_module_names => %w(issue_tracking time_tracking)
710 },
722 },
711 :only => %w(issues versions)
723 :only => %w(issues versions)
712 end
724 end
713 project = Project.find('unique-copy')
725 project = Project.find('unique-copy')
714 source = Project.find(1)
726 source = Project.find(1)
715 assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort
727 assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort
716
728
717 assert_equal source.versions.count, project.versions.count, "All versions were not copied"
729 assert_equal source.versions.count, project.versions.count, "All versions were not copied"
718 assert_equal source.issues.count, project.issues.count, "All issues were not copied"
730 assert_equal source.issues.count, project.issues.count, "All issues were not copied"
719 assert_equal 0, project.members.count
731 assert_equal 0, project.members.count
720 end
732 end
721
733
722 def test_post_copy_should_redirect_to_settings_when_successful
734 def test_post_copy_should_redirect_to_settings_when_successful
723 @request.session[:user_id] = 1 # admin
735 @request.session[:user_id] = 1 # admin
724 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => 'unique-copy'}
736 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => 'unique-copy'}
725 assert_response :redirect
737 assert_response :redirect
726 assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'unique-copy'
738 assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'unique-copy'
727 end
739 end
728
740
729 def test_post_copy_with_failure
741 def test_post_copy_with_failure
730 @request.session[:user_id] = 1
742 @request.session[:user_id] = 1
731 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => ''}
743 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => ''}
732 assert_response :success
744 assert_response :success
733 assert_select_error /Identifier cannot be blank/
745 assert_select_error /Identifier cannot be blank/
734 end
746 end
735
747
736 def test_jump_should_redirect_to_active_tab
748 def test_jump_should_redirect_to_active_tab
737 get :show, :id => 1, :jump => 'issues'
749 get :show, :id => 1, :jump => 'issues'
738 assert_redirected_to '/projects/ecookbook/issues'
750 assert_redirected_to '/projects/ecookbook/issues'
739 end
751 end
740
752
741 def test_jump_should_not_redirect_to_inactive_tab
753 def test_jump_should_not_redirect_to_inactive_tab
742 get :show, :id => 3, :jump => 'documents'
754 get :show, :id => 3, :jump => 'documents'
743 assert_response :success
755 assert_response :success
744 end
756 end
745
757
746 def test_jump_should_not_redirect_to_unknown_tab
758 def test_jump_should_not_redirect_to_unknown_tab
747 get :show, :id => 3, :jump => 'foobar'
759 get :show, :id => 3, :jump => 'foobar'
748 assert_response :success
760 assert_response :success
749 end
761 end
750
762
751 def test_body_should_have_project_css_class
763 def test_body_should_have_project_css_class
752 get :show, :id => 1
764 get :show, :id => 1
753 assert_select 'body.project-ecookbook'
765 assert_select 'body.project-ecookbook'
754 end
766 end
755 end
767 end
@@ -1,158 +1,164
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class Redmine::ApiTest::MembershipsTest < Redmine::ApiTest::Base
20 class Redmine::ApiTest::MembershipsTest < Redmine::ApiTest::Base
21 fixtures :projects, :users, :roles, :members, :member_roles
21 fixtures :projects, :users, :roles, :members, :member_roles
22
22
23 test "GET /projects/:project_id/memberships.xml should return memberships" do
23 test "GET /projects/:project_id/memberships.xml should return memberships" do
24 get '/projects/1/memberships.xml', {}, credentials('jsmith')
24 get '/projects/1/memberships.xml', {}, credentials('jsmith')
25
25
26 assert_response :success
26 assert_response :success
27 assert_equal 'application/xml', @response.content_type
27 assert_equal 'application/xml', @response.content_type
28 assert_select 'memberships[type=array] membership id', :text => '2' do
28 assert_select 'memberships[type=array] membership id', :text => '2' do
29 assert_select '~ user[id="3"][name="Dave Lopper"]'
29 assert_select '~ user[id="3"][name="Dave Lopper"]'
30 assert_select '~ roles role[id="2"][name=Developer]'
30 assert_select '~ roles role[id="2"][name=Developer]'
31 end
31 end
32 end
32 end
33
33
34 test "GET /projects/:project_id/memberships.json should return memberships" do
34 test "GET /projects/:project_id/memberships.json should return memberships" do
35 get '/projects/1/memberships.json', {}, credentials('jsmith')
35 get '/projects/1/memberships.json', {}, credentials('jsmith')
36
36
37 assert_response :success
37 assert_response :success
38 assert_equal 'application/json', @response.content_type
38 assert_equal 'application/json', @response.content_type
39 json = ActiveSupport::JSON.decode(response.body)
39 json = ActiveSupport::JSON.decode(response.body)
40 assert_equal({
40 assert_equal 3, json["total_count"]
41 "memberships" =>
41 assert_equal 25, json["limit"]
42 [{"id"=>1,
42 assert_equal 0, json["offset"]
43 "project" => {"name"=>"eCookbook", "id"=>1},
43 assert_include({
44 "roles" => [{"name"=>"Manager", "id"=>1}],
44 "id"=>1,
45 "user" => {"name"=>"John Smith", "id"=>2}},
45 "project" => {"name"=>"eCookbook", "id"=>1},
46 {"id"=>2,
46 "roles" => [{"name"=>"Manager", "id"=>1}],
47 "project" => {"name"=>"eCookbook", "id"=>1},
47 "user" => {"name"=>"John Smith", "id"=>2}
48 "roles" => [{"name"=>"Developer", "id"=>2}],
48 },
49 "user" => {"name"=>"Dave Lopper", "id"=>3}}],
49 json["memberships"]
50 "limit" => 25,
50 )
51 "total_count" => 2,
52 "offset" => 0},
53 json)
54 end
51 end
55
52
56 test "GET /projects/:project_id/memberships.xml should succeed for closed project" do
53 test "GET /projects/:project_id/memberships.xml should succeed for closed project" do
57 project = Project.find(1)
54 project = Project.find(1)
58 project.close
55 project.close
59 assert !project.reload.active?
56 assert !project.reload.active?
60 get '/projects/1/memberships.json', {}, credentials('jsmith')
57 get '/projects/1/memberships.json', {}, credentials('jsmith')
61 assert_response :success
58 assert_response :success
62 end
59 end
63
60
61 test "GET /projects/:project_id/memberships.xml should include locked users" do
62 assert User.find(3).lock!
63 get '/projects/ecookbook/memberships.xml', {}, credentials('jsmith')
64 assert_response :success
65 assert_select 'memberships[type=array] membership id', :text => '2' do
66 assert_select '~ user[id="3"][name="Dave Lopper"]'
67 end
68 end
69
64 test "POST /projects/:project_id/memberships.xml should create the membership" do
70 test "POST /projects/:project_id/memberships.xml should create the membership" do
65 assert_difference 'Member.count' do
71 assert_difference 'Member.count' do
66 post '/projects/1/memberships.xml', {:membership => {:user_id => 7, :role_ids => [2,3]}}, credentials('jsmith')
72 post '/projects/1/memberships.xml', {:membership => {:user_id => 7, :role_ids => [2,3]}}, credentials('jsmith')
67
73
68 assert_response :created
74 assert_response :created
69 end
75 end
70 end
76 end
71
77
72 test "POST /projects/:project_id/memberships.xml should create the group membership" do
78 test "POST /projects/:project_id/memberships.xml should create the group membership" do
73 group = Group.find(11)
79 group = Group.find(11)
74
80
75 assert_difference 'Member.count', 1 + group.users.count do
81 assert_difference 'Member.count', 1 + group.users.count do
76 post '/projects/1/memberships.xml', {:membership => {:user_id => 11, :role_ids => [2,3]}}, credentials('jsmith')
82 post '/projects/1/memberships.xml', {:membership => {:user_id => 11, :role_ids => [2,3]}}, credentials('jsmith')
77
83
78 assert_response :created
84 assert_response :created
79 end
85 end
80 end
86 end
81
87
82 test "POST /projects/:project_id/memberships.xml with invalid parameters should return errors" do
88 test "POST /projects/:project_id/memberships.xml with invalid parameters should return errors" do
83 assert_no_difference 'Member.count' do
89 assert_no_difference 'Member.count' do
84 post '/projects/1/memberships.xml', {:membership => {:role_ids => [2,3]}}, credentials('jsmith')
90 post '/projects/1/memberships.xml', {:membership => {:role_ids => [2,3]}}, credentials('jsmith')
85
91
86 assert_response :unprocessable_entity
92 assert_response :unprocessable_entity
87 assert_equal 'application/xml', @response.content_type
93 assert_equal 'application/xml', @response.content_type
88 assert_select 'errors error', :text => "Principal cannot be blank"
94 assert_select 'errors error', :text => "Principal cannot be blank"
89 end
95 end
90 end
96 end
91
97
92 test "GET /memberships/:id.xml should return the membership" do
98 test "GET /memberships/:id.xml should return the membership" do
93 get '/memberships/2.xml', {}, credentials('jsmith')
99 get '/memberships/2.xml', {}, credentials('jsmith')
94
100
95 assert_response :success
101 assert_response :success
96 assert_equal 'application/xml', @response.content_type
102 assert_equal 'application/xml', @response.content_type
97 assert_select 'membership id', :text => '2' do
103 assert_select 'membership id', :text => '2' do
98 assert_select '~ user[id="3"][name="Dave Lopper"]'
104 assert_select '~ user[id="3"][name="Dave Lopper"]'
99 assert_select '~ roles role[id="2"][name=Developer]'
105 assert_select '~ roles role[id="2"][name=Developer]'
100 end
106 end
101 end
107 end
102
108
103 test "GET /memberships/:id.json should return the membership" do
109 test "GET /memberships/:id.json should return the membership" do
104 get '/memberships/2.json', {}, credentials('jsmith')
110 get '/memberships/2.json', {}, credentials('jsmith')
105
111
106 assert_response :success
112 assert_response :success
107 assert_equal 'application/json', @response.content_type
113 assert_equal 'application/json', @response.content_type
108 json = ActiveSupport::JSON.decode(response.body)
114 json = ActiveSupport::JSON.decode(response.body)
109 assert_equal(
115 assert_equal(
110 {"membership" => {
116 {"membership" => {
111 "id" => 2,
117 "id" => 2,
112 "project" => {"name"=>"eCookbook", "id"=>1},
118 "project" => {"name"=>"eCookbook", "id"=>1},
113 "roles" => [{"name"=>"Developer", "id"=>2}],
119 "roles" => [{"name"=>"Developer", "id"=>2}],
114 "user" => {"name"=>"Dave Lopper", "id"=>3}}
120 "user" => {"name"=>"Dave Lopper", "id"=>3}}
115 },
121 },
116 json)
122 json)
117 end
123 end
118
124
119 test "PUT /memberships/:id.xml should update the membership" do
125 test "PUT /memberships/:id.xml should update the membership" do
120 assert_not_equal [1,2], Member.find(2).role_ids.sort
126 assert_not_equal [1,2], Member.find(2).role_ids.sort
121 assert_no_difference 'Member.count' do
127 assert_no_difference 'Member.count' do
122 put '/memberships/2.xml', {:membership => {:user_id => 3, :role_ids => [1,2]}}, credentials('jsmith')
128 put '/memberships/2.xml', {:membership => {:user_id => 3, :role_ids => [1,2]}}, credentials('jsmith')
123
129
124 assert_response :ok
130 assert_response :ok
125 assert_equal '', @response.body
131 assert_equal '', @response.body
126 end
132 end
127 member = Member.find(2)
133 member = Member.find(2)
128 assert_equal [1,2], member.role_ids.sort
134 assert_equal [1,2], member.role_ids.sort
129 end
135 end
130
136
131 test "PUT /memberships/:id.xml with invalid parameters should return errors" do
137 test "PUT /memberships/:id.xml with invalid parameters should return errors" do
132 put '/memberships/2.xml', {:membership => {:user_id => 3, :role_ids => [99]}}, credentials('jsmith')
138 put '/memberships/2.xml', {:membership => {:user_id => 3, :role_ids => [99]}}, credentials('jsmith')
133
139
134 assert_response :unprocessable_entity
140 assert_response :unprocessable_entity
135 assert_equal 'application/xml', @response.content_type
141 assert_equal 'application/xml', @response.content_type
136 assert_select 'errors error', :text => "Role cannot be empty"
142 assert_select 'errors error', :text => "Role cannot be empty"
137 end
143 end
138
144
139 test "DELETE /memberships/:id.xml should destroy the membership" do
145 test "DELETE /memberships/:id.xml should destroy the membership" do
140 assert_difference 'Member.count', -1 do
146 assert_difference 'Member.count', -1 do
141 delete '/memberships/2.xml', {}, credentials('jsmith')
147 delete '/memberships/2.xml', {}, credentials('jsmith')
142
148
143 assert_response :ok
149 assert_response :ok
144 assert_equal '', @response.body
150 assert_equal '', @response.body
145 end
151 end
146 assert_nil Member.find_by_id(2)
152 assert_nil Member.find_by_id(2)
147 end
153 end
148
154
149 test "DELETE /memberships/:id.xml should respond with 422 on failure" do
155 test "DELETE /memberships/:id.xml should respond with 422 on failure" do
150 assert_no_difference 'Member.count' do
156 assert_no_difference 'Member.count' do
151 # A membership with an inherited role cannot be deleted
157 # A membership with an inherited role cannot be deleted
152 Member.find(2).member_roles.first.update_attribute :inherited_from, 99
158 Member.find(2).member_roles.first.update_attribute :inherited_from, 99
153 delete '/memberships/2.xml', {}, credentials('jsmith')
159 delete '/memberships/2.xml', {}, credentials('jsmith')
154
160
155 assert_response :unprocessable_entity
161 assert_response :unprocessable_entity
156 end
162 end
157 end
163 end
158 end
164 end
General Comments 0
You need to be logged in to leave comments. Login now