Patch #7610 » rollback-2.4.4-fixed.patch
| redmine-2.4.4-rollback/app/controllers/journals_controller.rb 2014-04-17 10:33:21.234634640 -0600 | ||
|---|---|---|
| 16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 17 | 17 | |
| 18 | 18 |
class JournalsController < ApplicationController |
| 19 |
before_filter :find_journal, :only => [:edit, :diff] |
|
| 19 |
before_filter :find_journal, :only => [:edit, :diff, :rollback]
|
|
| 20 | 20 |
before_filter :find_issue, :only => [:new] |
| 21 | 21 |
before_filter :find_optional_project, :only => [:index] |
| 22 |
before_filter :authorize, :only => [:new, :edit, :diff] |
|
| 22 |
before_filter :authorize, :only => [:new, :edit, :diff, :rollback]
|
|
| 23 | 23 |
accept_rss_auth :index |
| 24 | 24 |
menu_item :issues |
| 25 | 25 | |
| ... | ... | |
| 94 | 94 |
end |
| 95 | 95 |
end |
| 96 | 96 | |
| 97 |
private |
|
| 97 |
def rollback |
|
| 98 |
(render_403; return false) unless @journal.can_rollback?(User.current) |
|
| 99 | ||
| 100 |
if @journal.rollback |
|
| 101 |
flash[:notice] = l(:notice_successful_update) |
|
| 102 |
else |
|
| 103 |
# can't seem to bring in the helper method 'error_messages_for' |
|
| 104 |
# and injecting it into show.rhtml doesn't seem to work, since |
|
| 105 |
# the @issue loses the errors on redirect (due to issue reload) |
|
| 106 |
flash[:error] = "<ul>" + @journal.errors.full_messages.map {|msg| "<li>" + ERB::Util.html_escape(msg) + "</li>"}.join + "</ul>"
|
|
| 107 |
end |
|
| 108 |
respond_to do |format| |
|
| 109 |
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @journal.journalized_id }
|
|
| 110 |
format.api { render_validation_errors(@issue) }
|
|
| 111 |
end |
|
| 112 |
end |
|
| 113 | ||
| 114 |
private |
|
| 98 | 115 | |
| 99 | 116 |
def find_journal |
| 100 | 117 |
@journal = Journal.visible.find(params[:id]) |
| redmine-2.4.4-rollback/app/models/issue.rb 2014-04-17 10:33:21.234634640 -0600 | ||
|---|---|---|
| 672 | 672 |
end |
| 673 | 673 |
end |
| 674 | 674 | |
| 675 |
# rollback the changes in a journal, the journal is destroyed on success |
|
| 676 |
def rollback(journal) |
|
| 677 |
# only allow rollback of journal details for the last journal |
|
| 678 |
(errors.add_to_base(l(:notice_locking_conflict)); return) if !journal.last_valid_journal?(journals) |
|
| 679 | ||
| 680 |
# avoid the creation of journals during rollback (see 'attachment removed') |
|
| 681 |
@rolling_back = true |
|
| 682 | ||
| 683 |
# roll back each change detailed by the journal |
|
| 684 |
journal.details.each do |d| |
|
| 685 |
case d.property |
|
| 686 |
# issue attribute change |
|
| 687 |
when 'attr'; send "#{d.prop_key}=", d.old_value
|
|
| 688 |
# rollback custom field change |
|
| 689 |
when 'cf'; custom_field_values.each {|v| v.value = d.old_value if v.custom_field_id == d.prop_key.to_i}
|
|
| 690 |
# remove any added attachments (we can't recover removed attachments) |
|
| 691 |
when 'attachment'; attachments.each {|v| attachments.delete(v) if v.id == d.prop_key.to_i}
|
|
| 692 |
end |
|
| 693 |
end |
|
| 694 | ||
| 695 |
# allow the creation of journals again |
|
| 696 |
remove_instance_variable(:@rolling_back) |
|
| 697 | ||
| 698 |
# destroy the journal once we save the issue changes |
|
| 699 |
if save(:validate => false) |
|
| 700 |
journal.rolled_back = true |
|
| 701 |
journal.save |
|
| 702 |
end |
|
| 703 |
end |
|
| 704 | ||
| 675 | 705 |
# Return true if the issue is closed, otherwise false |
| 676 | 706 |
def closed? |
| 677 | 707 |
self.status.is_closed? |
| redmine-2.4.4-rollback/app/models/journal.rb 2014-04-17 10:33:21.234634640 -0600 | ||
|---|---|---|
| 95 | 95 |
usr && usr.logged? && (usr.allowed_to?(:edit_issue_notes, project) || (self.user == usr && usr.allowed_to?(:edit_own_issue_notes, project))) |
| 96 | 96 |
end |
| 97 | 97 | |
| 98 |
def last_valid_journal?(journals) |
|
| 99 |
self == journals.reject{|j| j.rolled_back}.last
|
|
| 100 |
end |
|
| 101 | ||
| 102 |
def can_rollback?(usr = nil) |
|
| 103 |
user ||= User.current |
|
| 104 |
editable_by?(user) && (details.empty? || user.allowed_to?(:rollback_issue_notes, project)) |
|
| 105 |
end |
|
| 106 |
|
|
| 107 |
def show? |
|
| 108 |
!self.rolled_back || User.current.pref.hide_rolled_back_issue_notes == '0' |
|
| 109 |
end |
|
| 110 | ||
| 111 |
# rollback the changes in a journal, the journal is destroyed on success |
|
| 112 |
def rollback |
|
| 113 |
# we could have details to rollback, so let the issue take care of this more complicated task |
|
| 114 |
journalized.rollback(self) || |
|
| 115 |
# on failure, collect the error messages from the issue on failure |
|
| 116 |
(journalized.errors.each_full {|msg| errors.add_to_base(msg)}; false)
|
|
| 117 |
end |
|
| 118 | ||
| 98 | 119 |
def project |
| 99 | 120 |
journalized.respond_to?(:project) ? journalized.project : nil |
| 100 | 121 |
end |
| redmine-2.4.4-rollback/app/models/user_preference.rb 2014-04-17 10:35:35.682637045 -0600 | ||
|---|---|---|
| 57 | 57 |
def warn_on_leaving_unsaved; self[:warn_on_leaving_unsaved] || '1'; end |
| 58 | 58 |
def warn_on_leaving_unsaved=(value); self[:warn_on_leaving_unsaved]=value; end |
| 59 | 59 | |
| 60 |
def hide_rolled_back_issue_notes; self[:hide_rolled_back_issue_notes] || '0'; end |
|
| 61 |
def hide_rolled_back_issue_notes=(value); self[:hide_rolled_back_issue_notes]=value; end |
|
| 62 | ||
| 60 | 63 |
def no_self_notified; (self[:no_self_notified] == true || self[:no_self_notified] == '1'); end |
| 61 | 64 |
def no_self_notified=(value); self[:no_self_notified]=value; end |
| 62 | 65 |
end |
| redmine-2.4.4-rollback/app/views/issues/_history.html.erb 2014-04-17 12:04:34.686732511 -0600 | ||
|---|---|---|
| 1 | 1 |
<% reply_links = authorize_for('issues', 'edit') -%>
|
| 2 | 2 |
<% for journal in journals %> |
| 3 |
<% if journal.show? %> |
|
| 4 | ||
| 5 |
<% if journal.rolled_back? %> |
|
| 6 |
<strike> |
|
| 7 |
<% end %> |
|
| 8 | ||
| 3 | 9 |
<div id="change-<%= journal.id %>" class="<%= journal.css_classes %>"> |
| 4 | 10 |
<div id="note-<%= journal.indice %>"> |
| 5 | 11 |
<h4><%= link_to "##{journal.indice}", {:anchor => "note-#{journal.indice}"}, :class => "journal-link" %>
|
| 12 |
<% if journal.last_valid_journal?(journals) && journal.can_rollback? %> |
|
| 13 |
<div class="journal-link"><%= link_to(image_tag('cancel.png'), {:controller => 'journals', :action => 'rollback', :id => journal}, :confirm => l(:text_are_you_sure), :method => :post, :title => l(:button_rollback)) %> </div>
|
|
| 14 |
<% end %> |
|
| 6 | 15 |
<%= avatar(journal.user, :size => "24") %> |
| 7 | 16 |
<%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %></h4> |
| 8 | 17 | |
| ... | ... | |
| 17 | 26 |
</div> |
| 18 | 27 |
</div> |
| 19 | 28 |
<%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %>
|
| 29 | ||
| 30 |
<% if journal.rolled_back? %> |
|
| 31 |
</strike> |
|
| 32 |
<% end %> |
|
| 33 | ||
| 34 |
<% end %> |
|
| 20 | 35 |
<% end %> |
| 21 | 36 | |
| 22 | 37 |
<% heads_for_wiki_formatter if User.current.allowed_to?(:edit_issue_notes, issue.project) || User.current.allowed_to?(:edit_own_issue_notes, issue.project) %> |
| redmine-2.4.4-rollback/app/views/users/_preferences.html.erb 2014-04-17 10:33:21.234634640 -0600 | ||
|---|---|---|
| 3 | 3 |
<p><%= pref_fields.time_zone_select :time_zone, nil, :include_blank => true %></p> |
| 4 | 4 |
<p><%= pref_fields.select :comments_sorting, [[l(:label_chronological_order), 'asc'], [l(:label_reverse_chronological_order), 'desc']] %></p> |
| 5 | 5 |
<p><%= pref_fields.check_box :warn_on_leaving_unsaved %></p> |
| 6 |
<p><%= pref_fields.check_box :hide_rolled_back_issue_notes %></p> |
|
| 6 | 7 |
<% end %> |
| redmine-2.4.4-rollback/config/locales/en.yml 2014-04-17 11:02:25.618665831 -0600 | ||
|---|---|---|
| 337 | 337 |
field_inherit_members: Inherit members |
| 338 | 338 |
field_generate_password: Generate password |
| 339 | 339 |
field_must_change_passwd: Must change password at next logon |
| 340 |
field_hide_rolled_back_issue_notes: "Hide rolled-back issue notes" |
|
| 340 | 341 | |
| 341 | 342 |
setting_app_title: Application title |
| 342 | 343 |
setting_app_subtitle: Application subtitle |
| ... | ... | |
| 472 | 473 |
permission_export_wiki_pages: Export wiki pages |
| 473 | 474 |
permission_manage_subtasks: Manage subtasks |
| 474 | 475 |
permission_manage_related_issues: Manage related issues |
| 476 |
permission_rollback_issue_notes: Rollback issue notes |
|
| 475 | 477 | |
| 476 | 478 |
project_module_issue_tracking: Issue tracking |
| 477 | 479 |
project_module_time_tracking: Time tracking |
| ... | ... | |
| 956 | 958 |
button_delete_my_account: Delete my account |
| 957 | 959 |
button_close: Close |
| 958 | 960 |
button_reopen: Reopen |
| 961 |
button_rollback: Rollback |
|
| 959 | 962 | |
| 960 | 963 |
status_active: active |
| 961 | 964 |
status_registered: registered |
| redmine-2.4.4-rollback/config/routes.rb 2014-04-17 12:07:01.410735133 -0600 | ||
|---|---|---|
| 51 | 51 | |
| 52 | 52 |
match '/journals/diff/:id', :to => 'journals#diff', :id => /\d+/, :via => :get |
| 53 | 53 |
match '/journals/edit/:id', :to => 'journals#edit', :id => /\d+/, :via => [:get, :post] |
| 54 |
match '/journals/rollback/:id', :to => 'journals#rollback', :id => /\d+/, :via => :post |
|
| 54 | 55 | |
| 55 | 56 |
get '/projects/:project_id/issues/gantt', :to => 'gantts#show', :as => 'project_gantt' |
| 56 | 57 |
get '/issues/gantt', :to => 'gantts#show' |
| redmine-2.4.4-rollback/db/migrate/20140417000000_add_journals_rolled_back.rb 2014-04-17 10:33:21.238634641 -0600 | ||
|---|---|---|
| 1 |
class AddJournalsRolledBack < ActiveRecord::Migration |
|
| 2 |
def up |
|
| 3 |
add_column :journals, :rolled_back, :boolean, :default => 0 |
|
| 4 |
end |
|
| 5 | ||
| 6 |
def down |
|
| 7 |
remove_column :journals, :rolled_back |
|
| 8 |
end |
|
| 9 |
end |
|
| redmine-2.4.4-rollback/lib/redmine.rb 2014-04-17 11:07:10.274670924 -0600 | ||
|---|---|---|
| 118 | 118 |
map.permission :add_issue_notes, {:issues => [:edit, :update, :update_form], :journals => [:new], :attachments => :upload}
|
| 119 | 119 |
map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
|
| 120 | 120 |
map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
|
| 121 |
map.permission :rollback_issue_notes, {:journals => [:rollback]}
|
|
| 121 | 122 |
map.permission :view_private_notes, {}, :read => true, :require => :member
|
| 122 | 123 |
map.permission :set_notes_private, {}, :require => :member
|
| 123 | 124 |
map.permission :move_issues, {:issues => [:bulk_edit, :bulk_update]}, :require => :loggedin
|