]> source.dussan.org Git - redmine.git/commitdiff
Adds a 'Add subprojects' permission.
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Thu, 24 Dec 2009 16:18:15 +0000 (16:18 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Thu, 24 Dec 2009 16:18:15 +0000 (16:18 +0000)
* 'Add project' permission will let user create a root project
* 'Add subprojects' permission will let project members create subprojects

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@3238 e93f8b46-1217-0410-a6f0-8f06a7374b81

44 files changed:
app/controllers/projects_controller.rb
app/helpers/projects_helper.rb
app/models/project.rb
app/views/projects/_form.rhtml
app/views/projects/show.rhtml
config/locales/bg.yml
config/locales/bs.yml
config/locales/ca.yml
config/locales/cs.yml
config/locales/da.yml
config/locales/de.yml
config/locales/el.yml
config/locales/en.yml
config/locales/es.yml
config/locales/fi.yml
config/locales/fr.yml
config/locales/gl.yml
config/locales/he.yml
config/locales/hu.yml
config/locales/id.yml
config/locales/it.yml
config/locales/ja.yml
config/locales/ko.yml
config/locales/lt.yml
config/locales/nl.yml
config/locales/no.yml
config/locales/pl.yml
config/locales/pt-BR.yml
config/locales/pt.yml
config/locales/ro.yml
config/locales/ru.yml
config/locales/sk.yml
config/locales/sl.yml
config/locales/sr.yml
config/locales/sv.yml
config/locales/th.yml
config/locales/tr.yml
config/locales/uk.yml
config/locales/vi.yml
config/locales/zh-TW.yml
config/locales/zh.yml
lib/redmine.rb
test/functional/projects_controller_test.rb
test/unit/project_test.rb

index 386807f55d5bedab393e0954ae2084d96970d8ed..7228937982f0e4109c2c1d3c72e9cf3646663354 100644 (file)
@@ -73,7 +73,7 @@ class ProjectsController < ApplicationController
       @project.enabled_module_names = Setting.default_projects_modules
     else
       @project.enabled_module_names = params[:enabled_modules]
-      if @project.save
+      if validate_parent_id && @project.save
         @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
         # Add current user as a project member if he is not admin
         unless User.current.admin?
@@ -104,7 +104,7 @@ class ProjectsController < ApplicationController
     else
       @project = Project.new(params[:project])
       @project.enabled_module_names = params[:enabled_modules]
-      if @project.copy(@source_project, :only => params[:only])
+      if validate_parent_id && @project.copy(@source_project, :only => params[:only])
         @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
         flash[:notice] = l(:notice_successful_create)
         redirect_to :controller => 'admin', :action => 'projects'
@@ -156,7 +156,7 @@ class ProjectsController < ApplicationController
   def edit
     if request.post?
       @project.attributes = params[:project]
-      if @project.save
+      if validate_parent_id && @project.save
         @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
         flash[:notice] = l(:notice_successful_update)
         redirect_to :action => 'settings', :id => @project
@@ -395,4 +395,19 @@ private
       @selected_tracker_ids = (default_trackers || selectable_trackers).collect {|t| t.id.to_s }
     end
   end
+  
+  # Validates parent_id param according to user's permissions
+  # TODO: move it to Project model in a validation that depends on User.current
+  def validate_parent_id
+    return true if User.current.admin?
+    parent_id = params[:project] && params[:project][:parent_id]
+    if parent_id || @project.new_record?
+      parent = parent_id.blank? ? nil : Project.find_by_id(parent_id.to_i)
+      unless @project.allowed_parents.include?(parent)
+        @project.errors.add :parent_id, :invalid
+        return false
+      end
+    end
+    true
+  end
 end
index 7ab0186d55feb854415a25f89ecd251051442ef6..a44d2fb8278314e1f4e6ef2309724b1652796a11 100644 (file)
@@ -36,7 +36,16 @@ module ProjectsHelper
   end
   
   def parent_project_select_tag(project)
-    options = '<option></option>' + project_tree_options_for_select(project.allowed_parents, :selected => project.parent)
+    selected = project.parent
+    # retrieve the requested parent project
+    parent_id = (params[:project] && params[:project][:parent_id]) || params[:parent_id]
+    if parent_id
+      selected = (parent_id.blank? ? nil : Project.find(parent_id))
+    end
+    
+    options = ''
+    options << "<option value=''></option>" if project.allowed_parents.include?(nil)
+    options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected)
     content_tag('select', options, :name => 'project[parent_id]')
   end
   
index d6526100f6ca3f95fb1a609e3b6e2a938e6a3d23..3f34393b30853fcab2f8a94f5776000692b087b0 100644 (file)
@@ -246,7 +246,11 @@ class Project < ActiveRecord::Base
   # by the current user
   def allowed_parents
     return @allowed_parents if @allowed_parents
-    @allowed_parents = (Project.find(:all, :conditions => Project.allowed_to_condition(User.current, :add_project, :member => true)) - self_and_descendants)
+    @allowed_parents = Project.find(:all, :conditions => Project.allowed_to_condition(User.current, :add_subprojects))
+    @allowed_parents = @allowed_parents - self_and_descendants
+    if User.current.allowed_to?(:add_project, nil, :global => true)
+      @allowed_parents << nil
+    end
     unless parent.nil? || @allowed_parents.empty? || @allowed_parents.include?(parent)
       @allowed_parents << parent
     end
index 0e286fcaed7da7dc701003ef4ca2894a93627472..ef2a188556053228371da5877868bf321be4b5a0 100644 (file)
@@ -4,7 +4,7 @@
 <!--[form:project]-->
 <p><%= f.text_field :name, :required => true %><br /><em><%= l(:text_caracters_maximum, 30) %></em></p>
 
-<% unless @project.allowed_parents.empty? %>
+<% unless @project.allowed_parents.compact.empty? %>
     <p><label><%= l(:field_parent) %></label><%= parent_project_select_tag(@project) %></p>
 <% end %>
 
index a59c329c36b513e5df8a042cda57af67f3d09f74..7d5412af075d21ad1a88678277e409bb57600179 100644 (file)
@@ -1,3 +1,9 @@
+<div class="contextual">
+       <% if User.current.allowed_to?(:add_subprojects, @project) %>
+               <%= link_to l(:label_subproject_new), {:controller => 'projects', :action => 'add', :parent_id => @project}, :class => 'icon icon-add' %>
+       <% end %>
+</div>
+
 <h2><%=l(:label_overview)%></h2> 
        
 <div class="splitcontentleft">
index d70626c9d58bdf01ba5316d73236e0163795a224..4be99796146779c533ec7683dd85b516e3e4a739 100644 (file)
@@ -867,3 +867,5 @@ bg:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 860d1f25407bb05340cbeeaec3e6c2c9a578d309..015b05521dcb3c783b2750a7c7cc83a414037511 100644 (file)
@@ -891,3 +891,5 @@ bs:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 0f4dbf010e06ef41001a644461260523c5b64348..59b3a44f47869b3130af33f1d54b7c1696e80ee6 100644 (file)
@@ -870,3 +870,5 @@ ca:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 6165b6d6fd3b2462d80122e838ae8915d8b4f1d5..bcbf7ac99b5455170d1148213b2c5c596f8c5177 100644 (file)
@@ -873,3 +873,5 @@ cs:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 7877161e59fa90263e1e22e54a4a52595cf5916e..5123f241fad567c6bb725be7b534fcf861fdcbfb 100644 (file)
@@ -893,3 +893,5 @@ da:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index da83637cbfca2de59573a56e26916cf394efad8f..81e69ef23d638f96128024cee3fecb3bbe5ffe37 100644 (file)
@@ -893,3 +893,5 @@ de:
   label_missing_api_access_key: Missing an API access key
   label_missing_feeds_access_key: Missing a RSS access key
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index d4b9616d46878b45a3244109555da347724f8127..98800250057302d89463b1b96128a762b01bf56e 100644 (file)
@@ -873,3 +873,5 @@ el:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 37709072a280e1fe4bb115e34890bd1723578052..1c421cb49e65aaf90b31e506da7312876f7f1d58 100644 (file)
@@ -328,6 +328,7 @@ en:
   setting_rest_api_enabled: Enable REST web service
   
   permission_add_project: Create project
+  permission_add_subprojects: Create subprojects
   permission_edit_project: Edit project
   permission_select_project_modules: Select project modules
   permission_manage_members: Manage members
@@ -463,6 +464,7 @@ en:
   label_auth_source_new: New authentication mode
   label_auth_source_plural: Authentication modes
   label_subproject_plural: Subprojects
+  label_subproject_new: New subproject
   label_and_its_subprojects: "{{value}} and its subprojects"
   label_min_max_length: Min - Max length
   label_list: List
index e6a8447eafba83992d64111b912b46818bb84c8d..bcf8bd21fb080fa7305e1bec4cc812d754526606 100644 (file)
@@ -917,3 +917,5 @@ es:
   button_show: Mostrar
   text_line_separated: Múltiples valores permitidos (un valor en cada línea).
   setting_mail_handler_body_delimiters: Truncar correos tras una de estas líneas
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 2dcf4574f1297cf4e89b92d43e145697db83a045..6f255d03e1fcfc47df4089c97ec495b312a132f9 100644 (file)
@@ -903,3 +903,5 @@ fi:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index eb9b382ac7c9fa0beb25ba6a26475fc8e4232e35..6ecfc240dbf125e69c88ca2878e3a42ea2313c59 100644 (file)
@@ -348,6 +348,7 @@ fr:
   setting_rest_api_enabled: Activer l'API REST
   
   permission_add_project: Créer un projet
+  permission_add_subprojects: Créer des sous-projets
   permission_edit_project: Modifier le projet
   permission_select_project_modules: Choisir les modules
   permission_manage_members: Gérer les members
@@ -483,6 +484,7 @@ fr:
   label_auth_source_new: Nouveau mode d'authentification
   label_auth_source_plural: Modes d'authentification
   label_subproject_plural: Sous-projets
+  label_subproject_new: Nouveau sous-projet
   label_and_its_subprojects: "{{value}} et ses sous-projets"
   label_min_max_length: Longueurs mini - maxi
   label_list: Liste
index 90a07f3d9d20de1df85150afe360948440ca2b55..af1c6eb9a79364cc2ca0dd57a6839ba7d885169c 100644 (file)
@@ -893,3 +893,5 @@ gl:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 48300414abd3d7bf7ba9b5f515882d7cb81c4a69..f66970cc32f7dca2cbd9a661eb0b4f521fe80632 100644 (file)
@@ -877,3 +877,5 @@ he:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index bc303fa45def8c3ca5ae4b7427c7cb351e73c705..a48228cdf64d325f92e22b411d18240c4c3d8a5c 100644 (file)
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 233b2fb494a3f9492a118fbd59c21d1a8427a5a3..e124764c7a6851a9b651b5c1efd51a4df889769a 100644 (file)
@@ -885,3 +885,5 @@ id:
   error_workflow_copy_source: Please select a source tracker or role
   setting_start_of_week: Start calendars on
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index b06e00c8f4e1551db6816d29c7aecdbec58d25d4..b469099e39249fcb734081d346e6ad8104500960 100644 (file)
@@ -880,3 +880,5 @@ it:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index d2dfb2beecf3616b1a60c9c0910c280c3c37fe5e..0de5160e0aea9392bc2c6aab0244b8a6471ad369 100644 (file)
@@ -902,3 +902,5 @@ ja:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index ce9dbf9b57185f8492b5db200741a437a632de6f..4b82b77f7cf64346d53ed11d0377e2630917d7d5 100644 (file)
@@ -933,3 +933,5 @@ ko:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 9294d2dc5a31a8240863077291674244bc4fa41c..8c874065f796ac3ba18a5350aa70fcc7c302adc3 100644 (file)
@@ -941,3 +941,5 @@ lt:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 9ee414071257beee116606328d6dc3c61fede593..223df9b44792194f04a3debf9d100abff42acca1 100644 (file)
@@ -855,3 +855,5 @@ nl:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index f6f9da3a32c9551e91b405797c9044e5ba5bb327..461708b3b16f32878acd643ae3b9b19bebc20afd 100644 (file)
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index affd8dceefec3c7e655b3722d32c85f163a20db5..ad8040aa55f4e5b7cb0ad303e42949dc672cd3f7 100644 (file)
@@ -896,3 +896,5 @@ pl:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 1bb61edb184cc729da36f020a347fe0618135743..ed8e83e33e01a21153f2a6477f5c5f7680b5675d 100644 (file)
@@ -900,3 +900,5 @@ pt-BR:
   label_missing_feeds_access_key: Chave de acesso ao RSS faltando
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 0a567a6bc9c49787b2f59376274269599ceec8cc..9441e56c27aa4ec587c50360497cb855a3245abb 100644 (file)
@@ -885,3 +885,5 @@ pt:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 45956a4d8010e98b3c02443b3451f4df1b89b4af..f91525b735201e924fef081aafafeff83769f268 100644 (file)
@@ -870,3 +870,5 @@ ro:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index e484c3bcbc3957126e29440d85ba0a5c9f52d089..4c2822504ac5512d7896bd54259a93e7c38f01fa 100644 (file)
@@ -981,3 +981,5 @@ ru:
   label_missing_api_access_key: Missing an API access key
   label_missing_feeds_access_key: Missing a RSS access key
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index e95eefab657230fcdd86905e073bb0bc46879723..53b06dc8d88fc2b8181b3dc901b0968e3048a691 100644 (file)
@@ -872,3 +872,5 @@ sk:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 5845ee009a89779ca14ea7c2d29c462608d0864f..852ad6ac33a40cc541c4426a1bde15832b35c2cb 100644 (file)
@@ -869,3 +869,5 @@ sl:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 5cbd596431d79fda24ae4239747559d4717f325f..fd0a5db92c419ea4b536abb42d25c8d303534e7b 100644 (file)
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 81d287f2aa6bd5c22bd3efd704cb74138705f0a5..109ca7e6edc2a159d0f9eff4b2eec3809e18768d 100644 (file)
@@ -923,3 +923,5 @@ sv:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 07de4c4b6c60193f0c11b3d448520a2471f49487..294880baaeeb7be9f2ce47d54012670fd013e096 100644 (file)
@@ -870,3 +870,5 @@ th:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 056cb5656ee9f704088457c8098db008dc2d3532..42677a8707a6f632eea12a0f7a0491103ef56767 100644 (file)
@@ -900,3 +900,5 @@ tr:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index f5b83b241a33e49f71a02e2362f85708a5ca66b0..879b0aaa89c1ad334c52bd5480d29ec80cc52240 100644 (file)
@@ -869,3 +869,5 @@ uk:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 50ac2d8b9e7984dbdd143e599219b203c40370dd..afd63e9b4cb908da2bec82cf29008e0f654b3f1a 100644 (file)
@@ -932,3 +932,5 @@ vi:
   button_show: Show
   text_line_separated: Multiple values allowed (one line for each value).
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index ff0e1993bb840e57e40812ca01c626b3f057bec0..44066dbd8d72d4049630b92e63a4bf3941c129f8 100644 (file)
   enumeration_doc_categories: 文件分類
   enumeration_activities: 活動 (時間追蹤)
   enumeration_system_activity: 系統活動
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index ea5ddb8fb4bff6f476c792e775c2786e81601c2a..63143e1d9601a37840211435f3af8cbd48a6f17c 100644 (file)
@@ -897,3 +897,5 @@ zh:
   label_missing_api_access_key: Missing an API access key
   label_missing_feeds_access_key: Missing a RSS access key
   setting_mail_handler_body_delimiters: Truncate emails after one of these lines
+  permission_add_subprojects: Create subprojects
+  label_subproject_new: New subproject
index 50d090c4d4c1b8f045dde6e2a93f18dd9ee97ac4..ecf9abc1c40ea8ec971add60787b9ebbb7f3329a 100644 (file)
@@ -32,6 +32,7 @@ Redmine::AccessControl.map do |map|
   map.permission :select_project_modules, {:projects => :modules}, :require => :member
   map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :autocomplete_for_member]}, :require => :member
   map.permission :manage_versions, {:projects => [:settings, :add_version], :versions => [:edit, :close_completed, :destroy]}, :require => :member
+  map.permission :add_subprojects, {:projects => :add}, :require => :member
   
   map.project_module :issue_tracking do |map|
     # Issue categories
index 6bdfc167c2988f4f3736d4d6eacb8b173dde2e20..6c88e41d74f2ea9c6c1b2f2572088854c6d41ac4 100644 (file)
@@ -89,71 +89,163 @@ class ProjectsControllerTest < ActionController::TestCase
     )
   end
   
-  def test_get_add
-    @request.session[:user_id] = 1
-    get :add
-    assert_response :success
-    assert_template 'add'
-  end
-  
-  def test_get_add_by_non_admin
-    @request.session[:user_id] = 2
-    get :add
-    assert_response :success
-    assert_template 'add'
-  end
-  
-  def test_post_add
-    @request.session[:user_id] = 1
-    post :add, :project => { :name => "blog", 
-                             :description => "weblog",
-                             :identifier => "blog",
-                             :is_public => 1,
-                             :custom_field_values => { '3' => 'Beta' }
-                            }
-    assert_redirected_to '/projects/blog/settings'
-    
-    project = Project.find_by_name('blog')
-    assert_kind_of Project, project
-    assert_equal 'weblog', project.description 
-    assert_equal true, project.is_public?
-    assert_nil project.parent
-  end
-  
-  def test_post_add_subproject
-    @request.session[:user_id] = 1
-    post :add, :project => { :name => "blog", 
-                             :description => "weblog",
-                             :identifier => "blog",
-                             :is_public => 1,
-                             :custom_field_values => { '3' => 'Beta' },
-                             :parent_id => 1
-                            }
-    assert_redirected_to '/projects/blog/settings'
-    
-    project = Project.find_by_name('blog')
-    assert_kind_of Project, project
-    assert_equal Project.find(1), project.parent
-  end
-  
-  def test_post_add_by_non_admin
-    @request.session[:user_id] = 2
-    post :add, :project => { :name => "blog", 
-                             :description => "weblog",
-                             :identifier => "blog",
-                             :is_public => 1,
-                             :custom_field_values => { '3' => 'Beta' }
-                            }
-    assert_redirected_to '/projects/blog/settings'
+  context "#add" do
+    context "by admin user" do
+      setup do
+        @request.session[:user_id] = 1
+      end
+      
+      should "accept get" do
+        get :add
+        assert_response :success
+        assert_template 'add'
+      end
+      
+      should "accept post" do
+        post :add, :project => { :name => "blog", 
+                                 :description => "weblog",
+                                 :identifier => "blog",
+                                 :is_public => 1,
+                                 :custom_field_values => { '3' => 'Beta' }
+                                }
+        assert_redirected_to '/projects/blog/settings'
+        
+        project = Project.find_by_name('blog')
+        assert_kind_of Project, project
+        assert_equal 'weblog', project.description 
+        assert_equal true, project.is_public?
+        assert_nil project.parent
+      end
+      
+      should "accept post with parent" do
+        post :add, :project => { :name => "blog", 
+                                 :description => "weblog",
+                                 :identifier => "blog",
+                                 :is_public => 1,
+                                 :custom_field_values => { '3' => 'Beta' },
+                                 :parent_id => 1
+                                }
+        assert_redirected_to '/projects/blog/settings'
+        
+        project = Project.find_by_name('blog')
+        assert_kind_of Project, project
+        assert_equal Project.find(1), project.parent
+      end
+    end
     
-    project = Project.find_by_name('blog')
-    assert_kind_of Project, project
-    assert_equal 'weblog', project.description 
-    assert_equal true, project.is_public?
+    context "by non-admin user with add_project permission" do
+      setup do
+        Role.non_member.add_permission! :add_project
+        @request.session[:user_id] = 9
+      end
+      
+      should "accept get" do
+        get :add
+        assert_response :success
+        assert_template 'add'
+        assert_no_tag :select, :attributes => {:name => 'project[parent_id]'}
+      end
+      
+      should "accept post" do
+        post :add, :project => { :name => "blog", 
+                                 :description => "weblog",
+                                 :identifier => "blog",
+                                 :is_public => 1,
+                                 :custom_field_values => { '3' => 'Beta' }
+                                }
+        
+        assert_redirected_to '/projects/blog/settings'
+        
+        project = Project.find_by_name('blog')
+        assert_kind_of Project, project
+        assert_equal 'weblog', project.description 
+        assert_equal true, project.is_public?
+        
+        # User should be added as a project member
+        assert User.find(9).member_of?(project)
+        assert_equal 1, project.members.size
+      end
+      
+      should "fail with parent_id" do
+        assert_no_difference 'Project.count' do
+          post :add, :project => { :name => "blog", 
+                                   :description => "weblog",
+                                   :identifier => "blog",
+                                   :is_public => 1,
+                                   :custom_field_values => { '3' => 'Beta' },
+                                   :parent_id => 1
+                                  }
+        end
+        assert_response :success
+        project = assigns(:project)
+        assert_kind_of Project, project
+        assert_not_nil project.errors.on(:parent_id)
+      end
+    end
     
-    # User should be added as a project member
-    assert User.find(2).member_of?(project)
-    assert_equal 1, project.members.size
+    context "by non-admin user with add_subprojects permission" do
+      setup do
+        Role.find(1).remove_permission! :add_project
+        Role.find(1).add_permission! :add_subprojects
+        @request.session[:user_id] = 2
+      end
+      
+      should "accept get" do
+        get :add, :parent_id => 'ecookbook'
+        assert_response :success
+        assert_template 'add'
+        # parent project selected
+        assert_tag :select, :attributes => {:name => 'project[parent_id]'},
+                            :child => {:tag => 'option', :attributes => {:value => '1', :selected => 'selected'}}
+        # no empty value
+        assert_no_tag :select, :attributes => {:name => 'project[parent_id]'},
+                               :child => {:tag => 'option', :attributes => {:value => ''}}
+      end
+      
+      should "accept post with parent_id" do
+        post :add, :project => { :name => "blog", 
+                                 :description => "weblog",
+                                 :identifier => "blog",
+                                 :is_public => 1,
+                                 :custom_field_values => { '3' => 'Beta' },
+                                 :parent_id => 1
+                                }
+        assert_redirected_to '/projects/blog/settings'
+        project = Project.find_by_name('blog')
+      end
+      
+      should "fail without parent_id" do
+        assert_no_difference 'Project.count' do
+          post :add, :project => { :name => "blog", 
+                                   :description => "weblog",
+                                   :identifier => "blog",
+                                   :is_public => 1,
+                                   :custom_field_values => { '3' => 'Beta' }
+                                  }
+        end
+        assert_response :success
+        project = assigns(:project)
+        assert_kind_of Project, project
+        assert_not_nil project.errors.on(:parent_id)
+      end
+      
+      should "fail with unauthorized parent_id" do
+        assert !User.find(2).member_of?(Project.find(6))
+        assert_no_difference 'Project.count' do
+          post :add, :project => { :name => "blog", 
+                                   :description => "weblog",
+                                   :identifier => "blog",
+                                   :is_public => 1,
+                                   :custom_field_values => { '3' => 'Beta' },
+                                   :parent_id => 6
+                                  }
+        end
+        assert_response :success
+        project = assigns(:project)
+        assert_kind_of Project, project
+        assert_not_nil project.errors.on(:parent_id)
+      end
+    end
   end
   
   def test_show_routing
index 0633c95deb4a37ac66a493fb030130d570e004c6..e61ab03fcfe2f16c227605a39943e3f45edc46bf 100644 (file)
@@ -282,7 +282,7 @@ class ProjectTest < ActiveSupport::TestCase
     user = User.find(9)
     assert user.memberships.empty?
     User.current = user
-    assert Project.new.allowed_parents.empty?
+    assert Project.new.allowed_parents.compact.empty?
   end
   
   def test_users_by_role