diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 756d7ed4cf..6237fe0f32 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -521,7 +521,7 @@ module IssuesHelper old_value = format_date(detail.old_value.to_date) if detail.old_value when 'project_id', 'status_id', 'tracker_id', 'assigned_to_id', - 'priority_id', 'category_id', 'fixed_version_id' + 'priority_id', 'category_id', 'fixed_version_id', 'author_id' value = find_name_by_reflection(field, detail.value) old_value = find_name_by_reflection(field, detail.old_value) diff --git a/app/models/issue.rb b/app/models/issue.rb index 09f8400cc7..deeda5fe76 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -513,6 +513,9 @@ class Issue < ActiveRecord::Base safe_attributes( 'deleted_attachment_ids', :if => lambda {|issue, user| issue.attachments_deletable?(user)}) + safe_attributes( + 'author_id', + :if => lambda {|issue, user| user.allowed_to?(:change_issue_author, issue.project)}) def safe_attribute_names(user=nil) names = super diff --git a/app/views/issues/_attributes.html.erb b/app/views/issues/_attributes.html.erb index b5003c436b..585524f7a0 100644 --- a/app/views/issues/_attributes.html.erb +++ b/app/views/issues/_attributes.html.erb @@ -3,6 +3,9 @@
<% if @issue.safe_attribute?('status_id') && @allowed_statuses.present? %> +<% if User.current.allowed_to?(:change_issue_author, @project) %> +

<%= f.select :author_id, principals_options_for_select(@issue.assignable_users.select {|m| m.is_a?(User) && m.allowed_to?(:add_issues, @project) }, @issue.author), :include_blank => false, :required => true %> +<% end %>

<%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), {:required => true}, :onchange => "updateIssueFrom('#{escape_javascript(update_issue_form_path(@project, @issue))}', this)" %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 9d779a2fe0..4f32c9987a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -532,6 +532,7 @@ en: permission_view_private_notes: View private notes permission_set_notes_private: Set notes as private permission_delete_issues: Delete issues + permission_change_issue_author: Change issue author permission_manage_public_queries: Manage public queries permission_save_queries: Save queries permission_view_gantt: View gantt chart diff --git a/lib/redmine.rb b/lib/redmine.rb index cabbffe293..df09344387 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -118,6 +118,7 @@ Redmine::AccessControl.map do |map| map.permission :view_private_notes, {}, :read => true, :require => :member map.permission :set_notes_private, {}, :require => :member map.permission :delete_issues, {:issues => :destroy}, :require => :member + map.permission :change_issue_author, {:issues => [:edit, :update]} # Watchers map.permission :view_issue_watchers, {}, :read => true map.permission :add_issue_watchers, {:watchers => [:new, :create, :append, :autocomplete_for_user]} diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb index 797e4eca7f..cbc1973757 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -3406,4 +3406,32 @@ class IssueTest < ActiveSupport::TestCase assert_equal [5], issue2.filter_projects_scope('').ids.sort end + + def test_author_should_be_changed_when_user_with_permission_change_issue_author + Role.all.each do |r| + r.add_permission! :change_issue_author + end + User.current = User.find(2) + + issue = Issue.generate!(:author => User.find(3)) + assert_equal 3, issue.author_id + + issue.safe_attributes = { 'author_id' => 4 } + assert_equal 4, issue.author_id + assert_not_equal 3, issue.author_id + end + + def test_author_should_not_be_changed_when_user_without_permission_change_issue_author + Role.all.each do |r| + r.remove_permission! :change_issue_author + end + User.current = User.find(2) + + issue = Issue.generate!(:author => User.find(3)) + assert_equal 3, issue.author_id + + issue.safe_attributes = { 'author_id' => 4 } + assert_not_equal 4, issue.author_id + assert_equal 3, issue.author_id + end end