diff --git a/app/models/issue.rb b/app/models/issue.rb index 1259361da..007339130 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -311,7 +311,6 @@ class Issue < ActiveRecord::Base # Should be called from controllers instead of #attributes= # attr_accessible is too rough because we still want things like # Issue.new(:project => foo) to work - # TODO: move workflow/permission checks from controllers to here def safe_attributes=(attrs, user=User.current) return unless attrs.is_a?(Hash) @@ -321,9 +320,11 @@ class Issue < ActiveRecord::Base # Project and Tracker must be set before since new_statuses_allowed_to depends on it. if p = attrs.delete('project_id') - self.project_id = p + if allowed_target_projects(user).collect(&:id).include?(p.to_i) + self.project_id = p + end end - + if t = attrs.delete('tracker_id') self.tracker_id = t end @@ -769,7 +770,16 @@ class Issue < ActiveRecord::Base end # End ReportsController extraction - # Returns an array of projects that current user can move issues to + # Returns an array of projects that user can assign the issue to + def allowed_target_projects(user=User.current) + if new_record? + Project.all(:conditions => Project.allowed_to_condition(user, :add_issues)) + else + self.class.allowed_target_projects_on_move(user) + end + end + + # Returns an array of projects that user can move issues to def self.allowed_target_projects_on_move(user=User.current) projects = [] if user.admin? diff --git a/app/views/issues/_form.html.erb b/app/views/issues/_form.html.erb index 19b5f08eb..6634723f7 100644 --- a/app/views/issues/_form.html.erb +++ b/app/views/issues/_form.html.erb @@ -8,7 +8,7 @@ <% end %> <% if @issue.safe_attribute? 'project_id' %> -

<%= f.select :project_id, project_tree_options_for_select(Issue.allowed_target_projects_on_move, :selected => @issue.project), :required => true %>

+

<%= f.select :project_id, project_tree_options_for_select(@issue.allowed_target_projects, :selected => @issue.project), :required => true %>

<%= observe_field :issue_project_id, :url => project_issue_form_path(@project, :id => @issue, :project_change => '1'), :with => "Form.serialize('issue-form')" %> <% end %> diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index 5879e666b..c6b96cb3e 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -1630,6 +1630,18 @@ class IssuesControllerTest < ActionController::TestCase assert_tag 'input', :attributes => {:name => 'copy_from', :value => '1'} end + def test_create_as_copy_on_project_without_permission_should_ignore_target_project + @request.session[:user_id] = 2 + assert !User.find(2).member_of?(Project.find(4)) + + assert_difference 'Issue.count' do + post :create, :project_id => 1, :copy_from => 1, + :issue => {:project_id => '4', :tracker_id => '3', :status_id => '1', :subject => 'Copy'} + end + issue = Issue.first(:order => 'id DESC') + assert_equal 1, issue.project_id + end + def test_get_edit @request.session[:user_id] = 2 get :edit, :id => 1