Project

General

Profile

Patch #7610 » rollback-1.1.0.patch

improved1 - Brian Lindahl, 2011-02-12 01:33

View differences:

redmine-1.1.0-rollback/app/controllers/journals_controller.rb 2011-02-11 17:15:13.829487200 -0700
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]
19
  before_filter :find_journal, :only => [:edit, :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]
22
  before_filter :authorize, :only => [:new, :edit, :rollback]
23 23
  accept_key_auth :index
24 24

  
25 25
  helper :issues
......
67 67
  end
68 68
  
69 69
  def edit
70
    (render_403; return false) unless @journal.editable_by?(User.current)
71
    
70 72
    if request.post?
71 73
      @journal.update_attributes(:notes => params[:notes]) if params[:notes]
72 74
      @journal.destroy if @journal.details.empty? && @journal.notes.blank?
......
77 79
      end
78 80
    end
79 81
  end
82
   
83
  def rollback
84
    (render_403; return false) unless @journal.can_rollback?(User.current)
85
    
86
    if @journal.rollback
87
      flash[:notice] = l(:notice_successful_update)
88
    else
89
      # can't seem to bring in the helper method 'error_messages_for'
90
      # and injecting it into show.rhtml doesn't seem to work, since 
91
      # the @issue loses the errors on redirect (due to issue reload)
92
      flash[:error] = "<ul>" + @journal.errors.full_messages.map {|msg| "<li>" + ERB::Util.html_escape(msg) + "</li>"}.join + "</ul>"
93
    end
94
    respond_to do |format|
95
      format.html { redirect_to :controller => 'issues', :action => 'show', :id => @journal.journalized_id }
96
      format.api  { render_validation_errors(@issue) }
97
    end
98
  end
80 99
  
81 100
private
82 101
  def find_journal
83 102
    @journal = Journal.find(params[:id])
84
    (render_403; return false) unless @journal.editable_by?(User.current)
85 103
    @project = @journal.journalized.project
86 104
  rescue ActiveRecord::RecordNotFound
87 105
    render_404
redmine-1.1.0-rollback/app/models/issue.rb 2011-02-11 17:17:51.065874800 -0700
182 182
    end
183 183
    issue
184 184
  end
185
  
186
  # parent_id is never set directly, see :after_save
187
  def parent_id=(id)
188
    @parent_issue = Issue.find_by_id(id)
189
  end
185 190

  
186 191
  def status_id=(sid)
187 192
    self.status = nil
......
358 363
    @current_journal
359 364
  end
360 365
  
366
  # rollback the changes in a journal, the journal is destroyed on success
367
  def rollback(journal)
368
    # only allow rollback of journal details for the last journal
369
    (errors.add_to_base(l(:notice_locking_conflict)); return) if journal != journals.last
370
    
371
    # avoid the creation of journals during rollback (see 'attachment removed')
372
    @rolling_back = true
373
    
374
    # roll back each change detailed by the journal
375
    journal.details.each do |d|
376
      case d.property
377
        # issue attribute change
378
        when 'attr'; send("#{d.prop_key}=", d.old_value)
379
        # rollback custom field change
380
        when 'cf'; custom_field_values.each {|v| v.value = d.old_value if v.custom_field_id == d.prop_key.to_i}
381
        # remove any added attachments (we can't recover removed attachments)
382
        when 'attachment'; attachments.each {|v| attachments.delete(v) if v.id == d.prop_key.to_i}
383
      end
384
    end
385
    
386
    # allow the creation of journals again
387
    remove_instance_variable(:@rolling_back)
388
    
389
    # destroy the journal once we save the issue changes
390
    journal.destroy if save(false)
391
  end 
392

  
361 393
  # Return true if the issue is closed, otherwise false
362 394
  def closed?
363 395
    self.status.is_closed?
......
785 817
  
786 818
  # Callback on attachment deletion
787 819
  def attachment_removed(obj)
820
    return if @rolling_back
788 821
    journal = init_journal(User.current)
789 822
    journal.details << JournalDetail.new(:property => 'attachment',
790 823
                                         :prop_key => obj.id,
redmine-1.1.0-rollback/app/models/journal.rb 2011-02-11 17:10:38.544713600 -0700
58 58
    usr && usr.logged? && (usr.allowed_to?(:edit_issue_notes, project) || (self.user == usr && usr.allowed_to?(:edit_own_issue_notes, project)))
59 59
  end
60 60
  
61
  def can_rollback?(usr = nil)
62
    user = usr || User.current
63
    editable_by?(user) && (details.empty? || user.allowed_to?(:rollback_issue_notes, project))
64
  end
65
  
66
  # rollback the changes in a journal, the journal is destroyed on success
67
  def rollback
68
    # we could have details to rollback, so let the issue 
69
    # take care of this more complicated task
70
    journalized.rollback(self) || 
71
    # on failure, collect the error messages from the issue on failure
72
      (journalized.errors.each_full {|msg| errors.add_to_base(msg)}; false)
73
  end
74
  
61 75
  def project
62 76
    journalized.respond_to?(:project) ? journalized.project : nil
63 77
  end
redmine-1.1.0-rollback/app/views/issues/_history.rhtml 2011-02-11 17:10:38.560338800 -0700
2 2
<% for journal in journals %>
3 3
  <div id="change-<%= journal.id %>" class="<%= journal.css_classes %>">
4 4
    <h4><div class="journal-link"><%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %></div>
5
    <% if journal == journals.last && journal.can_rollback? %>
6
      <div class="journal-rollback"><%= link_to(image_tag('cancel.png'), {:controller => 'journals', :action => 'rollback', :id => journal}, :confirm => l(:text_are_you_sure), :method => :post, :title => l(:label_rollback)) %>&nbsp;</div>
7
    <% end %>
5 8
    <%= avatar(journal.user, :size => "24") %>
6 9
    <%= content_tag('a', '', :name => "note-#{journal.indice}")%>
7 10
		<%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %></h4>
redmine-1.1.0-rollback/config/locales/en.yml 2011-02-11 17:10:38.560338800 -0700
378 378
  permission_add_issue_notes: Add notes
379 379
  permission_edit_issue_notes: Edit notes
380 380
  permission_edit_own_issue_notes: Edit own notes
381
  permission_rollback_issue_notes: Rollback issue notes
381 382
  permission_move_issues: Move issues
382 383
  permission_delete_issues: Delete issues
383 384
  permission_manage_public_queries: Manage public queries
......
793 794
  label_project_copy_notifications: Send email notifications during the project copy
794 795
  label_principal_search: "Search for user or group:"
795 796
  label_user_search: "Search for user:"
797
  label_rollback: Rollback
796 798
  
797 799
  button_login: Login
798 800
  button_submit: Submit
redmine-1.1.0-rollback/lib/redmine.rb 2011-02-11 17:10:38.575964000 -0700
72 72
    map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]}
73 73
    map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
74 74
    map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
75
    map.permission :rollback_issue_notes, {:journals => [:rollback]}
75 76
    map.permission :move_issues, {:issue_moves => [:new, :create]}, :require => :loggedin
76 77
    map.permission :delete_issues, {:issues => :destroy}, :require => :member
77 78
    # Queries
redmine-1.1.0-rollback/public/stylesheets/application.css 2011-02-11 15:59:42.537112400 -0700
938 938
	float: right;
939 939
}
940 940

  
941
.journal-rollback {
942
	float: right;
943
}
944

  
941 945
h2 img { vertical-align:middle; }
942 946

  
943 947
.hascontextmenu { cursor: context-menu; }
(4-4/15)