Feature #1739 » redmine_changeable_author_r21799.patch
app/helpers/issues_helper.rb | ||
---|---|---|
534 | 534 |
old_value = format_date(detail.old_value.to_date) if detail.old_value |
535 | 535 | |
536 | 536 |
when 'project_id', 'status_id', 'tracker_id', 'assigned_to_id', |
537 |
'priority_id', 'category_id', 'fixed_version_id' |
|
537 |
'priority_id', 'category_id', 'fixed_version_id', 'author_id'
|
|
538 | 538 |
value = find_name_by_reflection(field, detail.value) |
539 | 539 |
old_value = find_name_by_reflection(field, detail.old_value) |
540 | 540 | |
... | ... | |
772 | 772 |
issue.allowed_target_projects(User.current) |
773 | 773 |
end |
774 | 774 |
end |
775 | ||
776 |
def author_options_for_select(issue, project) |
|
777 |
users = issue.assignable_users.select {|m| m.is_a?(User) && m.allowed_to?(:add_issues, project) } |
|
778 | ||
779 |
if issue.new_record? |
|
780 |
if users.include?(User.current) |
|
781 |
principals_options_for_select(users, issue.author) |
|
782 |
else |
|
783 |
principals_options_for_select([User.current] + users) |
|
784 |
end |
|
785 |
elsif issue.persisted? |
|
786 |
if users.include?(issue.author) |
|
787 |
principals_options_for_select(users, issue.author) |
|
788 |
else |
|
789 |
author_principal = Principal.find(issue.author_id) |
|
790 |
principals_options_for_select([author_principal] + users, author_principal) |
|
791 |
end |
|
792 |
end |
|
793 |
end |
|
775 | 794 |
end |
app/models/issue.rb | ||
---|---|---|
111 | 111 |
before_validation :clear_disabled_fields |
112 | 112 |
before_save :close_duplicates, :update_done_ratio_from_issue_status, |
113 | 113 |
:force_updated_on_change, :update_closed_on |
114 |
before_create :set_author_journal |
|
114 | 115 |
after_save do |issue| |
115 | 116 |
if !issue.saved_change_to_id? && issue.saved_change_to_project_id? |
116 | 117 |
issue.send :after_project_change |
... | ... | |
519 | 520 |
safe_attributes( |
520 | 521 |
'deleted_attachment_ids', |
521 | 522 |
:if => lambda {|issue, user| issue.attachments_deletable?(user)}) |
523 |
safe_attributes( |
|
524 |
'author_id', |
|
525 |
:if => lambda {|issue, user| user.allowed_to?(:change_issue_author, issue.project)}) |
|
522 | 526 | |
523 | 527 |
def safe_attribute_names(user=nil) |
524 | 528 |
names = super |
... | ... | |
2022 | 2026 |
end |
2023 | 2027 |
end |
2024 | 2028 | |
2029 |
def set_author_journal |
|
2030 |
return unless new_record? |
|
2031 |
return unless self.author.present? && User.current.present? && self.author != User.current |
|
2032 | ||
2033 |
self.init_journal(User.current) |
|
2034 |
self.current_journal.__send__(:add_attribute_detail, 'author_id', User.current.id, self.author.id) |
|
2035 |
end |
|
2036 | ||
2025 | 2037 |
def send_notification |
2026 | 2038 |
if notify? && Setting.notified_events.include?('issue_added') |
2027 | 2039 |
Mailer.deliver_issue_add(self) |
app/views/issues/_attributes.html.erb | ||
---|---|---|
3 | 3 |
<div class="splitcontent"> |
4 | 4 |
<div class="splitcontentleft"> |
5 | 5 |
<% if @issue.safe_attribute?('status_id') && @allowed_statuses.present? %> |
6 |
<% if User.current.allowed_to?(:change_issue_author, @project) %> |
|
7 |
<p><%= f.select :author_id, author_options_for_select(@issue, @project), :include_blank => false, :required => true %></p> |
|
8 |
<% end %> |
|
6 | 9 |
<p> |
7 | 10 |
<%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), {:required => true}, |
8 | 11 |
:onchange => "updateIssueFrom('#{escape_javascript(update_issue_form_path(@project, @issue))}', this)" %> |
config/locales/en.yml | ||
---|---|---|
540 | 540 |
permission_view_private_notes: View private notes |
541 | 541 |
permission_set_notes_private: Set notes as private |
542 | 542 |
permission_delete_issues: Delete issues |
543 |
permission_change_issue_author: Change issue author |
|
543 | 544 |
permission_manage_public_queries: Manage public queries |
544 | 545 |
permission_save_queries: Save queries |
545 | 546 |
permission_view_gantt: View gantt chart |
lib/redmine/preparation.rb | ||
---|---|---|
72 | 72 |
map.permission :view_private_notes, {}, :read => true, :require => :member |
73 | 73 |
map.permission :set_notes_private, {}, :require => :member |
74 | 74 |
map.permission :delete_issues, {:issues => :destroy}, :require => :member |
75 |
map.permission :change_issue_author, {:issues => [:edit, :update]} |
|
75 | 76 |
map.permission :mention_users, {} |
76 | 77 |
# Watchers |
77 | 78 |
map.permission :view_issue_watchers, {}, :read => true |
test/functional/issues_controller_test.rb | ||
---|---|---|
8286 | 8286 |
end |
8287 | 8287 | |
8288 | 8288 |
def test_destroy_child_issue |
8289 |
User.current = User.find(1) |
|
8289 | 8290 |
parent = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Parent Issue') |
8290 | 8291 |
child = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Child Issue', :parent_issue_id => parent.id) |
8291 | 8292 |
assert child.is_descendant_of?(parent.reload) |
test/functional/versions_controller_test.rb | ||
---|---|---|
103 | 103 |
end |
104 | 104 | |
105 | 105 |
def test_index_should_show_issue_assignee |
106 |
User.current = User.find_by_login('jsmith') |
|
106 | 107 |
with_settings :gravatar_enabled => '1' do |
107 | 108 |
Issue.generate!(:project_id => 3, :fixed_version_id => 4, :assigned_to => User.find_by_login('jsmith')) |
108 | 109 |
Issue.generate!(:project_id => 3, :fixed_version_id => 4) |
test/helpers/issues_helper_test.rb | ||
---|---|---|
465 | 465 |
assert_include "<a href=\"/issues?issue_id=#{open_issue.id}%2C#{closed_issue.id}&set_filter=true&status_id=o\">1 open</a>", html |
466 | 466 |
assert_include "<a href=\"/issues?issue_id=#{open_issue.id}%2C#{closed_issue.id}&set_filter=true&status_id=c\">1 closed</a>", html |
467 | 467 |
end |
468 | ||
469 |
def test_author_options_for_select_if_new_record_and_users_includes_current_user |
|
470 |
User.current = User.find(2) |
|
471 |
issue = Issue.new(project_id: 1) |
|
472 |
assignable_users = [User.find(3), User.find(2)] |
|
473 | ||
474 |
assert_includes assignable_users, User.current |
|
475 |
assert_equal( |
|
476 |
principals_options_for_select(assignable_users, nil), |
|
477 |
author_options_for_select(issue, issue.project)) |
|
478 |
end |
|
479 | ||
480 |
def test_author_options_for_select_if_new_record_and_users_not_includes_current_user |
|
481 |
User.current = User.find(1) |
|
482 |
issue = Issue.new(project_id: 1) |
|
483 |
assignable_users = [User.find(3), User.find(2)] |
|
484 |
assert_not_includes assignable_users, User.current |
|
485 | ||
486 |
assert_equal( |
|
487 |
principals_options_for_select([User.current] + assignable_users, nil), |
|
488 |
author_options_for_select(issue, issue.project)) |
|
489 |
end |
|
490 | ||
491 |
def test_author_options_for_select_if_persisted_record_and_users_includes_author |
|
492 |
User.current = User.find(2) |
|
493 |
issue = Issue.find(1) |
|
494 |
issue.update(author_id: 2) |
|
495 |
assignable_users = [User.find(3), User.find(2)] |
|
496 | ||
497 |
assert_includes assignable_users, issue.author |
|
498 |
assert_equal( |
|
499 |
principals_options_for_select(assignable_users, issue.author), |
|
500 |
author_options_for_select(issue, issue.project)) |
|
501 |
end |
|
502 | ||
503 |
def test_author_options_for_select_if_persisted_record_and_users_not_includes_author |
|
504 |
User.current = User.find(2) |
|
505 |
issue = Issue.find(1) |
|
506 |
issue.update(author_id: 1) |
|
507 |
assignable_users = [User.find(3), User.find(2)] |
|
508 | ||
509 |
assert_not_includes assignable_users, issue.author |
|
510 |
assert_equal( |
|
511 |
principals_options_for_select([User.find(1)] + assignable_users, issue.author), |
|
512 |
author_options_for_select(issue, issue.project)) |
|
513 |
end |
|
514 | ||
515 |
def test_author_options_for_select_if_persisted_record_and_author_is_anonymous |
|
516 |
User.current = User.find(2) |
|
517 |
issue = Issue.find(1) |
|
518 |
issue.update(author_id: User.anonymous.id) |
|
519 |
assignable_users = [User.find(3), User.find(2)] |
|
520 | ||
521 |
assert_not_includes assignable_users, issue.author |
|
522 |
assert_equal( |
|
523 |
principals_options_for_select([User.anonymous] + assignable_users, issue.author), |
|
524 |
author_options_for_select(issue, issue.project)) |
|
525 |
end |
|
468 | 526 |
end |
test/helpers/journals_helper_test.rb | ||
---|---|---|
22 | 22 |
class JournalsHelperTest < Redmine::HelperTest |
23 | 23 |
include JournalsHelper |
24 | 24 | |
25 |
fixtures :projects, :trackers, :issue_statuses, :issues, :journals, |
|
25 |
fixtures :projects, :trackers, :issue_statuses, :issues, :journals, :journal_details,
|
|
26 | 26 |
:enumerations, :issue_categories, |
27 | 27 |
:projects_trackers, |
28 | 28 |
:users, :roles, :member_roles, :members, |
test/object_helpers.rb | ||
---|---|---|
95 | 95 |
issue.project ||= Project.find(1) |
96 | 96 |
issue.tracker ||= issue.project.trackers.first |
97 | 97 |
issue.subject = 'Generated' if issue.subject.blank? |
98 |
issue.author ||= User.find(2)
|
|
98 |
issue.author ||= (User.current || User.find(2))
|
|
99 | 99 |
yield issue if block_given? |
100 | 100 |
issue |
101 | 101 |
end |
test/unit/issue_nested_set_test.rb | ||
---|---|---|
60 | 60 |
end |
61 | 61 | |
62 | 62 |
def test_creating_a_child_in_a_subproject_should_validate |
63 |
User.current = User.find(1) |
|
63 | 64 |
issue = Issue.generate! |
64 | 65 |
child = nil |
65 | 66 |
assert_difference 'Journal.count', 1 do |
test/unit/issue_test.rb | ||
---|---|---|
2767 | 2767 |
end |
2768 | 2768 | |
2769 | 2769 |
def test_journalized_multi_custom_field |
2770 |
User.current = User.find(1) |
|
2770 | 2771 |
field = IssueCustomField.create!(:name => 'filter', :field_format => 'list', |
2771 | 2772 |
:is_filter => true, :is_for_all => true, |
2772 | 2773 |
:tracker_ids => [1], |
... | ... | |
3443 | 3444 |
r = Issue.like('issue today') |
3444 | 3445 |
assert_include Issue.find(7), r |
3445 | 3446 |
end |
3447 | ||
3448 |
def test_author_should_be_changed_when_user_with_permission_change_issue_author |
|
3449 |
Role.all.each do |r| |
|
3450 |
r.add_permission! :change_issue_author |
|
3451 |
end |
|
3452 |
User.current = User.find(2) |
|
3453 | ||
3454 |
issue = Issue.generate!(:author => User.find(3)) |
|
3455 |
assert_equal 3, issue.author_id |
|
3456 | ||
3457 |
issue.safe_attributes = { 'author_id' => 4 } |
|
3458 |
assert_equal 4, issue.author_id |
|
3459 |
assert_not_equal 3, issue.author_id |
|
3460 |
end |
|
3461 | ||
3462 |
def test_author_should_not_be_changed_when_user_without_permission_change_issue_author |
|
3463 |
Role.all.each do |r| |
|
3464 |
r.remove_permission! :change_issue_author |
|
3465 |
end |
|
3466 |
User.current = User.find(2) |
|
3467 | ||
3468 |
issue = Issue.generate!(:author => User.find(3)) |
|
3469 |
assert_equal 3, issue.author_id |
|
3470 | ||
3471 |
issue.safe_attributes = { 'author_id' => 4 } |
|
3472 |
assert_not_equal 4, issue.author_id |
|
3473 |
assert_equal 3, issue.author_id |
|
3474 |
end |
|
3475 | ||
3476 |
def test_create_should_create_journal_if_user_other_than_current_user_is_set_as_the_author |
|
3477 |
User.current = User.find(1) |
|
3478 |
issue = nil |
|
3479 |
assert_difference 'Journal.count' do |
|
3480 |
issue = Issue.generate!(author: User.find(2)) |
|
3481 |
end |
|
3482 | ||
3483 |
first_journal_detail = issue.journals.first.details.first |
|
3484 |
assert_equal 'author_id', first_journal_detail.prop_key |
|
3485 |
assert_equal '1', first_journal_detail.old_value |
|
3486 |
assert_equal '2', first_journal_detail.value |
|
3487 |
end |
|
3488 | ||
3489 |
def test_create_should_create_journal_if_current_user_is_set_as_the_author |
|
3490 |
User.current = User.find(1) |
|
3491 |
issue = nil |
|
3492 |
assert_no_difference 'Journal.count' do |
|
3493 |
issue = Issue.generate!(author: User.current) |
|
3494 |
end |
|
3495 | ||
3496 |
assert_not issue.journals.present? |
|
3497 |
end |
|
3446 | 3498 |
end |
- « Previous
- 1
- …
- 10
- 11
- 12
- Next »