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] = "
" + @issue.errors.full_messages.map {|msg| "- " + ERB::Util.html_escape(msg) + "
"}.join + "
"
+ 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 %>
<%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %>
+ <% 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; }