##// END OF EJS Templates
Adds a 'Add subprojects' permission....
Jean-Philippe Lang -
r3124:62c83bdd2e1b
parent child
Show More
@@ -73,7 +73,7 class ProjectsController < ApplicationController
73 73 @project.enabled_module_names = Setting.default_projects_modules
74 74 else
75 75 @project.enabled_module_names = params[:enabled_modules]
76 if @project.save
76 if validate_parent_id && @project.save
77 77 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
78 78 # Add current user as a project member if he is not admin
79 79 unless User.current.admin?
@@ -104,7 +104,7 class ProjectsController < ApplicationController
104 104 else
105 105 @project = Project.new(params[:project])
106 106 @project.enabled_module_names = params[:enabled_modules]
107 if @project.copy(@source_project, :only => params[:only])
107 if validate_parent_id && @project.copy(@source_project, :only => params[:only])
108 108 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
109 109 flash[:notice] = l(:notice_successful_create)
110 110 redirect_to :controller => 'admin', :action => 'projects'
@@ -156,7 +156,7 class ProjectsController < ApplicationController
156 156 def edit
157 157 if request.post?
158 158 @project.attributes = params[:project]
159 if @project.save
159 if validate_parent_id && @project.save
160 160 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
161 161 flash[:notice] = l(:notice_successful_update)
162 162 redirect_to :action => 'settings', :id => @project
@@ -395,4 +395,19 private
395 395 @selected_tracker_ids = (default_trackers || selectable_trackers).collect {|t| t.id.to_s }
396 396 end
397 397 end
398
399 # Validates parent_id param according to user's permissions
400 # TODO: move it to Project model in a validation that depends on User.current
401 def validate_parent_id
402 return true if User.current.admin?
403 parent_id = params[:project] && params[:project][:parent_id]
404 if parent_id || @project.new_record?
405 parent = parent_id.blank? ? nil : Project.find_by_id(parent_id.to_i)
406 unless @project.allowed_parents.include?(parent)
407 @project.errors.add :parent_id, :invalid
408 return false
409 end
410 end
411 true
412 end
398 413 end
@@ -36,7 +36,16 module ProjectsHelper
36 36 end
37 37
38 38 def parent_project_select_tag(project)
39 options = '<option></option>' + project_tree_options_for_select(project.allowed_parents, :selected => project.parent)
39 selected = project.parent
40 # retrieve the requested parent project
41 parent_id = (params[:project] && params[:project][:parent_id]) || params[:parent_id]
42 if parent_id
43 selected = (parent_id.blank? ? nil : Project.find(parent_id))
44 end
45
46 options = ''
47 options << "<option value=''></option>" if project.allowed_parents.include?(nil)
48 options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected)
40 49 content_tag('select', options, :name => 'project[parent_id]')
41 50 end
42 51
@@ -246,7 +246,11 class Project < ActiveRecord::Base
246 246 # by the current user
247 247 def allowed_parents
248 248 return @allowed_parents if @allowed_parents
249 @allowed_parents = (Project.find(:all, :conditions => Project.allowed_to_condition(User.current, :add_project, :member => true)) - self_and_descendants)
249 @allowed_parents = Project.find(:all, :conditions => Project.allowed_to_condition(User.current, :add_subprojects))
250 @allowed_parents = @allowed_parents - self_and_descendants
251 if User.current.allowed_to?(:add_project, nil, :global => true)
252 @allowed_parents << nil
253 end
250 254 unless parent.nil? || @allowed_parents.empty? || @allowed_parents.include?(parent)
251 255 @allowed_parents << parent
252 256 end
@@ -4,7 +4,7
4 4 <!--[form:project]-->
5 5 <p><%= f.text_field :name, :required => true %><br /><em><%= l(:text_caracters_maximum, 30) %></em></p>
6 6
7 <% unless @project.allowed_parents.empty? %>
7 <% unless @project.allowed_parents.compact.empty? %>
8 8 <p><label><%= l(:field_parent) %></label><%= parent_project_select_tag(@project) %></p>
9 9 <% end %>
10 10
@@ -1,3 +1,9
1 <div class="contextual">
2 <% if User.current.allowed_to?(:add_subprojects, @project) %>
3 <%= link_to l(:label_subproject_new), {:controller => 'projects', :action => 'add', :parent_id => @project}, :class => 'icon icon-add' %>
4 <% end %>
5 </div>
6
1 7 <h2><%=l(:label_overview)%></h2>
2 8
3 9 <div class="splitcontentleft">
@@ -867,3 +867,5 bg:
867 867 button_show: Show
868 868 text_line_separated: Multiple values allowed (one line for each value).
869 869 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
870 permission_add_subprojects: Create subprojects
871 label_subproject_new: New subproject
@@ -891,3 +891,5 bs:
891 891 button_show: Show
892 892 text_line_separated: Multiple values allowed (one line for each value).
893 893 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
894 permission_add_subprojects: Create subprojects
895 label_subproject_new: New subproject
@@ -870,3 +870,5 ca:
870 870 button_show: Show
871 871 text_line_separated: Multiple values allowed (one line for each value).
872 872 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
873 permission_add_subprojects: Create subprojects
874 label_subproject_new: New subproject
@@ -873,3 +873,5 cs:
873 873 button_show: Show
874 874 text_line_separated: Multiple values allowed (one line for each value).
875 875 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
876 permission_add_subprojects: Create subprojects
877 label_subproject_new: New subproject
@@ -893,3 +893,5 da:
893 893 button_show: Show
894 894 text_line_separated: Multiple values allowed (one line for each value).
895 895 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
896 permission_add_subprojects: Create subprojects
897 label_subproject_new: New subproject
@@ -893,3 +893,5 de:
893 893 label_missing_api_access_key: Missing an API access key
894 894 label_missing_feeds_access_key: Missing a RSS access key
895 895 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
896 permission_add_subprojects: Create subprojects
897 label_subproject_new: New subproject
@@ -873,3 +873,5 el:
873 873 button_show: Show
874 874 text_line_separated: Multiple values allowed (one line for each value).
875 875 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
876 permission_add_subprojects: Create subprojects
877 label_subproject_new: New subproject
@@ -328,6 +328,7 en:
328 328 setting_rest_api_enabled: Enable REST web service
329 329
330 330 permission_add_project: Create project
331 permission_add_subprojects: Create subprojects
331 332 permission_edit_project: Edit project
332 333 permission_select_project_modules: Select project modules
333 334 permission_manage_members: Manage members
@@ -463,6 +464,7 en:
463 464 label_auth_source_new: New authentication mode
464 465 label_auth_source_plural: Authentication modes
465 466 label_subproject_plural: Subprojects
467 label_subproject_new: New subproject
466 468 label_and_its_subprojects: "{{value}} and its subprojects"
467 469 label_min_max_length: Min - Max length
468 470 label_list: List
@@ -917,3 +917,5 es:
917 917 button_show: Mostrar
918 918 text_line_separated: MΓΊltiples valores permitidos (un valor en cada lΓ­nea).
919 919 setting_mail_handler_body_delimiters: Truncar correos tras una de estas lΓ­neas
920 permission_add_subprojects: Create subprojects
921 label_subproject_new: New subproject
@@ -903,3 +903,5 fi:
903 903 button_show: Show
904 904 text_line_separated: Multiple values allowed (one line for each value).
905 905 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
906 permission_add_subprojects: Create subprojects
907 label_subproject_new: New subproject
@@ -348,6 +348,7 fr:
348 348 setting_rest_api_enabled: Activer l'API REST
349 349
350 350 permission_add_project: CrΓ©er un projet
351 permission_add_subprojects: CrΓ©er des sous-projets
351 352 permission_edit_project: Modifier le projet
352 353 permission_select_project_modules: Choisir les modules
353 354 permission_manage_members: GΓ©rer les members
@@ -483,6 +484,7 fr:
483 484 label_auth_source_new: Nouveau mode d'authentification
484 485 label_auth_source_plural: Modes d'authentification
485 486 label_subproject_plural: Sous-projets
487 label_subproject_new: Nouveau sous-projet
486 488 label_and_its_subprojects: "{{value}} et ses sous-projets"
487 489 label_min_max_length: Longueurs mini - maxi
488 490 label_list: Liste
@@ -893,3 +893,5 gl:
893 893 button_show: Show
894 894 text_line_separated: Multiple values allowed (one line for each value).
895 895 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
896 permission_add_subprojects: Create subprojects
897 label_subproject_new: New subproject
@@ -877,3 +877,5 he:
877 877 button_show: Show
878 878 text_line_separated: Multiple values allowed (one line for each value).
879 879 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
880 permission_add_subprojects: Create subprojects
881 label_subproject_new: New subproject
@@ -898,3 +898,5
898 898 button_show: Show
899 899 text_line_separated: Multiple values allowed (one line for each value).
900 900 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
901 permission_add_subprojects: Create subprojects
902 label_subproject_new: New subproject
@@ -885,3 +885,5 id:
885 885 error_workflow_copy_source: Please select a source tracker or role
886 886 setting_start_of_week: Start calendars on
887 887 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
888 permission_add_subprojects: Create subprojects
889 label_subproject_new: New subproject
@@ -880,3 +880,5 it:
880 880 button_show: Show
881 881 text_line_separated: Multiple values allowed (one line for each value).
882 882 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
883 permission_add_subprojects: Create subprojects
884 label_subproject_new: New subproject
@@ -902,3 +902,5 ja:
902 902 button_show: Show
903 903 text_line_separated: Multiple values allowed (one line for each value).
904 904 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
905 permission_add_subprojects: Create subprojects
906 label_subproject_new: New subproject
@@ -933,3 +933,5 ko:
933 933 button_show: Show
934 934 text_line_separated: Multiple values allowed (one line for each value).
935 935 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
936 permission_add_subprojects: Create subprojects
937 label_subproject_new: New subproject
@@ -941,3 +941,5 lt:
941 941 button_show: Show
942 942 text_line_separated: Multiple values allowed (one line for each value).
943 943 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
944 permission_add_subprojects: Create subprojects
945 label_subproject_new: New subproject
@@ -855,3 +855,5 nl:
855 855 button_show: Show
856 856 text_line_separated: Multiple values allowed (one line for each value).
857 857 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
858 permission_add_subprojects: Create subprojects
859 label_subproject_new: New subproject
@@ -868,3 +868,5
868 868 button_show: Show
869 869 text_line_separated: Multiple values allowed (one line for each value).
870 870 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
871 permission_add_subprojects: Create subprojects
872 label_subproject_new: New subproject
@@ -896,3 +896,5 pl:
896 896 button_show: Show
897 897 text_line_separated: Multiple values allowed (one line for each value).
898 898 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
899 permission_add_subprojects: Create subprojects
900 label_subproject_new: New subproject
@@ -900,3 +900,5 pt-BR:
900 900 label_missing_feeds_access_key: Chave de acesso ao RSS faltando
901 901 text_line_separated: Multiple values allowed (one line for each value).
902 902 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
903 permission_add_subprojects: Create subprojects
904 label_subproject_new: New subproject
@@ -885,3 +885,5 pt:
885 885 button_show: Show
886 886 text_line_separated: Multiple values allowed (one line for each value).
887 887 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
888 permission_add_subprojects: Create subprojects
889 label_subproject_new: New subproject
@@ -870,3 +870,5 ro:
870 870 button_show: Show
871 871 text_line_separated: Multiple values allowed (one line for each value).
872 872 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
873 permission_add_subprojects: Create subprojects
874 label_subproject_new: New subproject
@@ -981,3 +981,5 ru:
981 981 label_missing_api_access_key: Missing an API access key
982 982 label_missing_feeds_access_key: Missing a RSS access key
983 983 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
984 permission_add_subprojects: Create subprojects
985 label_subproject_new: New subproject
@@ -872,3 +872,5 sk:
872 872 button_show: Show
873 873 text_line_separated: Multiple values allowed (one line for each value).
874 874 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
875 permission_add_subprojects: Create subprojects
876 label_subproject_new: New subproject
@@ -869,3 +869,5 sl:
869 869 button_show: Show
870 870 text_line_separated: Multiple values allowed (one line for each value).
871 871 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
872 permission_add_subprojects: Create subprojects
873 label_subproject_new: New subproject
@@ -888,3 +888,5
888 888 button_show: Show
889 889 text_line_separated: Multiple values allowed (one line for each value).
890 890 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
891 permission_add_subprojects: Create subprojects
892 label_subproject_new: New subproject
@@ -923,3 +923,5 sv:
923 923 button_show: Show
924 924 text_line_separated: Multiple values allowed (one line for each value).
925 925 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
926 permission_add_subprojects: Create subprojects
927 label_subproject_new: New subproject
@@ -870,3 +870,5 th:
870 870 button_show: Show
871 871 text_line_separated: Multiple values allowed (one line for each value).
872 872 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
873 permission_add_subprojects: Create subprojects
874 label_subproject_new: New subproject
@@ -900,3 +900,5 tr:
900 900 button_show: Show
901 901 text_line_separated: Multiple values allowed (one line for each value).
902 902 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
903 permission_add_subprojects: Create subprojects
904 label_subproject_new: New subproject
@@ -869,3 +869,5 uk:
869 869 button_show: Show
870 870 text_line_separated: Multiple values allowed (one line for each value).
871 871 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
872 permission_add_subprojects: Create subprojects
873 label_subproject_new: New subproject
@@ -932,3 +932,5 vi:
932 932 button_show: Show
933 933 text_line_separated: Multiple values allowed (one line for each value).
934 934 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
935 permission_add_subprojects: Create subprojects
936 label_subproject_new: New subproject
@@ -966,3 +966,5
966 966 enumeration_doc_categories: ζ–‡δ»Άεˆ†ι‘ž
967 967 enumeration_activities: ζ΄»ε‹• (ζ™‚ι–“θΏ½θΉ€)
968 968 enumeration_system_activity: η³»η΅±ζ΄»ε‹•
969 permission_add_subprojects: Create subprojects
970 label_subproject_new: New subproject
@@ -897,3 +897,5 zh:
897 897 label_missing_api_access_key: Missing an API access key
898 898 label_missing_feeds_access_key: Missing a RSS access key
899 899 setting_mail_handler_body_delimiters: Truncate emails after one of these lines
900 permission_add_subprojects: Create subprojects
901 label_subproject_new: New subproject
@@ -32,6 +32,7 Redmine::AccessControl.map do |map|
32 32 map.permission :select_project_modules, {:projects => :modules}, :require => :member
33 33 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :autocomplete_for_member]}, :require => :member
34 34 map.permission :manage_versions, {:projects => [:settings, :add_version], :versions => [:edit, :close_completed, :destroy]}, :require => :member
35 map.permission :add_subprojects, {:projects => :add}, :require => :member
35 36
36 37 map.project_module :issue_tracking do |map|
37 38 # Issue categories
@@ -89,22 +89,19 class ProjectsControllerTest < ActionController::TestCase
89 89 )
90 90 end
91 91
92 def test_get_add
92 context "#add" do
93 context "by admin user" do
94 setup do
93 95 @request.session[:user_id] = 1
94 get :add
95 assert_response :success
96 assert_template 'add'
97 96 end
98 97
99 def test_get_add_by_non_admin
100 @request.session[:user_id] = 2
98 should "accept get" do
101 99 get :add
102 100 assert_response :success
103 101 assert_template 'add'
104 102 end
105 103
106 def test_post_add
107 @request.session[:user_id] = 1
104 should "accept post" do
108 105 post :add, :project => { :name => "blog",
109 106 :description => "weblog",
110 107 :identifier => "blog",
@@ -120,8 +117,7 class ProjectsControllerTest < ActionController::TestCase
120 117 assert_nil project.parent
121 118 end
122 119
123 def test_post_add_subproject
124 @request.session[:user_id] = 1
120 should "accept post with parent" do
125 121 post :add, :project => { :name => "blog",
126 122 :description => "weblog",
127 123 :identifier => "blog",
@@ -135,15 +131,29 class ProjectsControllerTest < ActionController::TestCase
135 131 assert_kind_of Project, project
136 132 assert_equal Project.find(1), project.parent
137 133 end
134 end
138 135
139 def test_post_add_by_non_admin
140 @request.session[:user_id] = 2
136 context "by non-admin user with add_project permission" do
137 setup do
138 Role.non_member.add_permission! :add_project
139 @request.session[:user_id] = 9
140 end
141
142 should "accept get" do
143 get :add
144 assert_response :success
145 assert_template 'add'
146 assert_no_tag :select, :attributes => {:name => 'project[parent_id]'}
147 end
148
149 should "accept post" do
141 150 post :add, :project => { :name => "blog",
142 151 :description => "weblog",
143 152 :identifier => "blog",
144 153 :is_public => 1,
145 154 :custom_field_values => { '3' => 'Beta' }
146 155 }
156
147 157 assert_redirected_to '/projects/blog/settings'
148 158
149 159 project = Project.find_by_name('blog')
@@ -152,10 +162,92 class ProjectsControllerTest < ActionController::TestCase
152 162 assert_equal true, project.is_public?
153 163
154 164 # User should be added as a project member
155 assert User.find(2).member_of?(project)
165 assert User.find(9).member_of?(project)
156 166 assert_equal 1, project.members.size
157 167 end
158 168
169 should "fail with parent_id" do
170 assert_no_difference 'Project.count' do
171 post :add, :project => { :name => "blog",
172 :description => "weblog",
173 :identifier => "blog",
174 :is_public => 1,
175 :custom_field_values => { '3' => 'Beta' },
176 :parent_id => 1
177 }
178 end
179 assert_response :success
180 project = assigns(:project)
181 assert_kind_of Project, project
182 assert_not_nil project.errors.on(:parent_id)
183 end
184 end
185
186 context "by non-admin user with add_subprojects permission" do
187 setup do
188 Role.find(1).remove_permission! :add_project
189 Role.find(1).add_permission! :add_subprojects
190 @request.session[:user_id] = 2
191 end
192
193 should "accept get" do
194 get :add, :parent_id => 'ecookbook'
195 assert_response :success
196 assert_template 'add'
197 # parent project selected
198 assert_tag :select, :attributes => {:name => 'project[parent_id]'},
199 :child => {:tag => 'option', :attributes => {:value => '1', :selected => 'selected'}}
200 # no empty value
201 assert_no_tag :select, :attributes => {:name => 'project[parent_id]'},
202 :child => {:tag => 'option', :attributes => {:value => ''}}
203 end
204
205 should "accept post with parent_id" do
206 post :add, :project => { :name => "blog",
207 :description => "weblog",
208 :identifier => "blog",
209 :is_public => 1,
210 :custom_field_values => { '3' => 'Beta' },
211 :parent_id => 1
212 }
213 assert_redirected_to '/projects/blog/settings'
214 project = Project.find_by_name('blog')
215 end
216
217 should "fail without parent_id" do
218 assert_no_difference 'Project.count' do
219 post :add, :project => { :name => "blog",
220 :description => "weblog",
221 :identifier => "blog",
222 :is_public => 1,
223 :custom_field_values => { '3' => 'Beta' }
224 }
225 end
226 assert_response :success
227 project = assigns(:project)
228 assert_kind_of Project, project
229 assert_not_nil project.errors.on(:parent_id)
230 end
231
232 should "fail with unauthorized parent_id" do
233 assert !User.find(2).member_of?(Project.find(6))
234 assert_no_difference 'Project.count' do
235 post :add, :project => { :name => "blog",
236 :description => "weblog",
237 :identifier => "blog",
238 :is_public => 1,
239 :custom_field_values => { '3' => 'Beta' },
240 :parent_id => 6
241 }
242 end
243 assert_response :success
244 project = assigns(:project)
245 assert_kind_of Project, project
246 assert_not_nil project.errors.on(:parent_id)
247 end
248 end
249 end
250
159 251 def test_show_routing
160 252 assert_routing(
161 253 {:method => :get, :path => '/projects/test'},
@@ -282,7 +282,7 class ProjectTest < ActiveSupport::TestCase
282 282 user = User.find(9)
283 283 assert user.memberships.empty?
284 284 User.current = user
285 assert Project.new.allowed_parents.empty?
285 assert Project.new.allowed_parents.compact.empty?
286 286 end
287 287
288 288 def test_users_by_role
General Comments 0
You need to be logged in to leave comments. Login now