diff -Nur redmine-1.1.0/app/controllers/issues_controller.rb redmine-1.1.0-rollback/app/controllers/issues_controller.rb --- redmine-1.1.0/app/controllers/issues_controller.rb 2011-01-09 17:05:00.000000000 -0700 +++ redmine-1.1.0-rollback/app/controllers/issues_controller.rb 2011-02-11 10:54:47.912319200 -0700 @@ -19,7 +19,7 @@ menu_item :new_issue, :only => [:new, :create] default_search_scope :issues - before_filter :find_issue, :only => [:show, :edit, :update] + before_filter :find_issue, :only => [:show, :edit, :update, :rollback] before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :move, :perform_move, :destroy] before_filter :check_project_uniqueness, :only => [:move, :perform_move] before_filter :find_project, :only => [:new, :create] @@ -27,7 +27,7 @@ before_filter :find_optional_project, :only => [:index] before_filter :check_for_default_issue_status, :only => [:new, :create] before_filter :build_new_issue_from_params, :only => [:new, :create] - accept_key_auth :index, :show, :create, :update, :destroy + accept_key_auth :index, :show, :create, :update, :destroy, :rollback rescue_from Query::StatementInvalid, :with => :query_statement_invalid @@ -56,10 +56,11 @@ verify :method => [:post, :delete], :only => :destroy, :render => { :nothing => true, :status => :method_not_allowed } - + verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :post, :only => :bulk_update, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } + verify :method => :post, :only => :rollback, :render => { :nothing => true, :status => :method_not_allowed } def index retrieve_query @@ -214,6 +215,21 @@ redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project}) end + def rollback + if @issue.rollback + flash[:notice] = l(:notice_successful_update) + else + # can't seem to bring in the helper method 'error_messages_for' + # and injecting it into show.rhtml doesn't seem to work, since + # the @issue loses the errors on redirect (due to issue reload) + flash[:error] = "" + end + respond_to do |format| + format.html { redirect_back_or_default({:action => 'show', :id => @issue}) } + format.api { render_validation_errors(@issue) } + end + end + def destroy @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f if @hours > 0 diff -Nur redmine-1.1.0/app/models/issue.rb redmine-1.1.0-rollback/app/models/issue.rb --- redmine-1.1.0/app/models/issue.rb 2011-01-25 13:02:02.750334900 -0700 +++ redmine-1.1.0-rollback/app/models/issue.rb 2011-02-11 10:54:47.927944400 -0700 @@ -358,6 +358,32 @@ @current_journal end + # rolls back the last journal entry + def rollback + journal = journals.find(:last, :include => [:details], :order => "#{Journal.table_name}.created_on ASC") + transaction do + old_parent = nil + journal.details.each do |d| + if d.property == 'attr' + if d.prop_key == 'parent_id' + @parent_issue = Issue.find_by_id(d.old_value) + else + send("#{d.prop_key}=", d.old_value) + end + elsif d.property == 'cf' + custom_field_values.each {|v| v.value = d.old_value if v.custom_field_id == d.prop_key.to_i} + elsif d.property == 'attachment' + if d.old_value == nil + @rolling_back = true # avoid journal entries created in 'attachment_removed' + attachments.each {|v| attachments.delete(v) if v.id == d.prop_key.to_i} + remove_instance_variable(:@rolling_back) + end + end + end + journal.destroy if save(false) + end + end + # Return true if the issue is closed, otherwise false def closed? self.status.is_closed? @@ -785,11 +811,13 @@ # Callback on attachment deletion def attachment_removed(obj) - journal = init_journal(User.current) - journal.details << JournalDetail.new(:property => 'attachment', - :prop_key => obj.id, - :old_value => obj.filename) - journal.save + if !@rolling_back + journal = init_journal(User.current) + journal.details << JournalDetail.new(:property => 'attachment', + :prop_key => obj.id, + :old_value => obj.filename) + journal.save + end end # Default assignment based on category @@ -850,7 +878,7 @@ init_journal @current_journal.user, @current_journal.notes end end - + # Query generator for selecting groups of issue counts for a project # based on specific criteria # diff -Nur redmine-1.1.0/app/views/issues/_history.rhtml redmine-1.1.0-rollback/app/views/issues/_history.rhtml --- redmine-1.1.0/app/views/issues/_history.rhtml 2011-01-09 17:05:00.000000000 -0700 +++ redmine-1.1.0-rollback/app/views/issues/_history.rhtml 2011-02-11 10:54:47.943569600 -0700 @@ -2,6 +2,9 @@ <% for journal in journals %>

+ <% if journal == journals.last && authorize_for('issues', 'rollback') %> +
<%= link_to_if_authorized(image_tag('cancel.png'), {:controller => 'issues', :action => 'rollback', :id => @issue}, :confirm => l(:text_are_you_sure), :method => :post, :title => l(:label_rollback)) %> 
+ <% end %> <%= avatar(journal.user, :size => "24") %> <%= content_tag('a', '', :name => "note-#{journal.indice}")%> <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>

diff -Nur redmine-1.1.0/config/locales/en.yml redmine-1.1.0-rollback/config/locales/en.yml --- redmine-1.1.0/config/locales/en.yml 2011-01-09 17:05:00.000000000 -0700 +++ redmine-1.1.0-rollback/config/locales/en.yml 2011-02-11 10:57:04.132812800 -0700 @@ -378,6 +378,7 @@ permission_add_issue_notes: Add notes permission_edit_issue_notes: Edit notes permission_edit_own_issue_notes: Edit own notes + permission_rollback_issues: Rollback issues permission_move_issues: Move issues permission_delete_issues: Delete issues permission_manage_public_queries: Manage public queries @@ -793,6 +794,7 @@ label_project_copy_notifications: Send email notifications during the project copy label_principal_search: "Search for user or group:" label_user_search: "Search for user:" + label_rollback: Rollback button_login: Login button_submit: Submit diff -Nur redmine-1.1.0/lib/redmine.rb redmine-1.1.0-rollback/lib/redmine.rb --- redmine-1.1.0/lib/redmine.rb 2011-01-09 17:05:00.000000000 -0700 +++ redmine-1.1.0-rollback/lib/redmine.rb 2011-02-11 10:56:01.350759200 -0700 @@ -72,6 +72,7 @@ map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]} map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin + map.permission :rollback_issues, {:issues => [:rollback]} map.permission :move_issues, {:issue_moves => [:new, :create]}, :require => :loggedin map.permission :delete_issues, {:issues => :destroy}, :require => :member # Queries diff -Nur redmine-1.1.0/public/stylesheets/application.css redmine-1.1.0-rollback/public/stylesheets/application.css --- redmine-1.1.0/public/stylesheets/application.css 2011-01-09 17:05:00.000000000 -0700 +++ redmine-1.1.0-rollback/public/stylesheets/application.css 2011-02-11 10:54:47.990445200 -0700 @@ -938,6 +938,10 @@ float: right; } +.journal-rollback { + float: right; +} + h2 img { vertical-align:middle; } .hascontextmenu { cursor: context-menu; }