diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index c226288df..8fc5eabd3 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -534,7 +534,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 b51e186cb..933c0764e 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -517,6 +517,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 b5003c436..585524f7a 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 761e4194c..15d615b84 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -533,6 +533,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/preparation.rb b/lib/redmine/preparation.rb index 7223f2797..b8c16a2d9 100644 --- a/lib/redmine/preparation.rb +++ b/lib/redmine/preparation.rb @@ -71,6 +71,7 @@ module Redmine 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 2749a7fc3..7703cb2bb 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -3427,4 +3427,32 @@ class IssueTest < ActiveSupport::TestCase r = Issue.like('issue today') assert_include Issue.find(7), r 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