diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb index 189204e26..37e52ca53 100644 --- a/app/controllers/journals_controller.rb +++ b/app/controllers/journals_controller.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -16,12 +16,13 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class JournalsController < ApplicationController - before_filter :find_journal, :only => [:edit] + before_filter :find_journal, :only => [:edit, :diff] before_filter :find_issue, :only => [:new] before_filter :find_optional_project, :only => [:index] - before_filter :authorize, :only => [:new, :edit] + before_filter :authorize, :only => [:new, :edit, :diff] accept_key_auth :index - + menu_item :issues + helper :issues helper :queries include QueriesHelper @@ -43,6 +44,17 @@ class JournalsController < ApplicationController render_404 end + def diff + @issue = @journal.issue + if params[:detail_id].present? + @detail = @journal.details.find_by_id(params[:detail_id]) + else + @detail = @journal.details.detect {|d| d.prop_key == 'description'} + end + (render_404; return false) unless @issue && @detail + @diff = Redmine::Helpers::Diff.new(@detail.value, @detail.old_value) + end + def new journal = Journal.find(params[:journal_id]) if params[:journal_id] if journal @@ -67,6 +79,7 @@ class JournalsController < ApplicationController end def edit + (render_403; return false) unless @journal.editable_by?(User.current) if request.post? @journal.update_attributes(:notes => params[:notes]) if params[:notes] @journal.destroy if @journal.details.empty? && @journal.notes.blank? @@ -86,10 +99,10 @@ class JournalsController < ApplicationController end end -private + private + def find_journal @journal = Journal.find(params[:id]) - (render_403; return false) unless @journal.editable_by?(User.current) @project = @journal.journalized.project rescue ActiveRecord::RecordNotFound render_404 diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index ec027e2e0..f9f1c41ac 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -183,7 +183,16 @@ module IssuesHelper end end - if !detail.value.blank? + if detail.property == 'attr' && detail.prop_key == 'description' + s = l(:text_journal_changed_no_detail, :label => label) + unless no_html + diff_link = link_to 'diff', + {:controller => 'journals', :action => 'diff', :id => detail.journal_id, :detail_id => detail.id}, + :title => l(:label_view_diff) + s << " (#{ diff_link })" + end + s + elsif !detail.value.blank? case detail.property when 'attr', 'cf' if !detail.old_value.blank? diff --git a/app/models/issue.rb b/app/models/issue.rb index 2810138a4..942b654e2 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -829,7 +829,7 @@ class Issue < ActiveRecord::Base def create_journal if @current_journal # attributes changes - (Issue.column_names - %w(id description root_id lft rgt lock_version created_on updated_on)).each {|c| + (Issue.column_names - %w(id root_id lft rgt lock_version created_on updated_on)).each {|c| @current_journal.details << JournalDetail.new(:property => 'attr', :prop_key => c, :old_value => @issue_before_change.send(c), diff --git a/app/models/journal_detail.rb b/app/models/journal_detail.rb index 58239006b..aa22e6f71 100644 --- a/app/models/journal_detail.rb +++ b/app/models/journal_detail.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -17,9 +17,4 @@ class JournalDetail < ActiveRecord::Base belongs_to :journal - - def before_save - self.value = value[0..254] if value && value.is_a?(String) - self.old_value = old_value[0..254] if old_value && old_value.is_a?(String) - end end diff --git a/app/views/journals/diff.html.erb b/app/views/journals/diff.html.erb new file mode 100644 index 000000000..21b8755e7 --- /dev/null +++ b/app/views/journals/diff.html.erb @@ -0,0 +1,10 @@ +
<%= authoring @journal.created_on, @journal.user, :label => :label_updated_time_by %>
+ +<%= link_to l(:button_back), issue_path(@issue), :onclick => 'history.back(); return false;' %>
+ +<% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 40ecbeed5..fb51c23bd 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -860,6 +860,7 @@ en: text_are_you_sure: Are you sure ? text_are_you_sure_with_children: "Delete issue and all child issues?" text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_changed_no_detail: "%{label} updated" text_journal_set_to: "%{label} set to %{value}" text_journal_deleted: "%{label} deleted (%{old})" text_journal_added: "%{label} %{value} added" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 112fe5a44..91a517d9d 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -926,6 +926,7 @@ fr: error_no_tracker_in_project: "Aucun tracker n'est associé à ce projet. Vérifier la configuration du projet." error_no_default_issue_status: "Aucun statut de demande n'est défini par défaut. Vérifier votre configuration (Administration -> Statuts de demandes)." text_journal_changed: "%{label} changé de %{old} à %{new}" + text_journal_changed_no_detail: "%{label} mis à jour" text_journal_set_to: "%{label} mis à %{value}" text_journal_deleted: "%{label} %{old} supprimé" text_journal_added: "%{label} %{value} ajouté" diff --git a/db/migrate/20110227125750_change_journal_details_values_to_text.rb b/db/migrate/20110227125750_change_journal_details_values_to_text.rb new file mode 100644 index 000000000..25886575c --- /dev/null +++ b/db/migrate/20110227125750_change_journal_details_values_to_text.rb @@ -0,0 +1,11 @@ +class ChangeJournalDetailsValuesToText < ActiveRecord::Migration + def self.up + change_column :journal_details, :old_value, :text + change_column :journal_details, :value, :text + end + + def self.down + change_column :journal_details, :old_value, :string + change_column :journal_details, :value, :string + end +end diff --git a/lib/redmine.rb b/lib/redmine.rb index 7fcd76473..87efc72ea 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -62,7 +62,7 @@ Redmine::AccessControl.map do |map| :auto_complete => [:issues], :context_menus => [:issues], :versions => [:index, :show, :status_by], - :journals => :index, + :journals => [:index, :diff], :queries => :index, :reports => [:issue_report, :issue_report_details]} map.permission :add_issues, {:issues => [:new, :create, :update_form]} diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index f7c76e41b..911c7c8ef 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -672,6 +672,13 @@ div.autocomplete ul li span.informal { .diff_out { background: #fcc; } .diff_in { background: #cfc; } +.text-diff { +padding: 1em; +background-color:#f6f6f6; +color:#505050; +border: 1px solid #e4e4e4; +} + /***** Wiki *****/ div.wiki table { border: 1px solid #505050; diff --git a/test/fixtures/journal_details.yml b/test/fixtures/journal_details.yml index 046202dd3..5b2c651b2 100644 --- a/test/fixtures/journal_details.yml +++ b/test/fixtures/journal_details.yml @@ -20,3 +20,10 @@ journal_details_003: value: "6" prop_key: fixed_version_id journal_id: 4 +journal_details_004: + old_value: "This word was removed and an other was" + property: attr + id: 4 + value: "This word was and an other was added" + prop_key: description + journal_id: 3 diff --git a/test/functional/journals_controller_test.rb b/test/functional/journals_controller_test.rb index ff123f915..2060e9c7a 100644 --- a/test/functional/journals_controller_test.rb +++ b/test/functional/journals_controller_test.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -38,6 +38,19 @@ class JournalsControllerTest < ActionController::TestCase assert_equal 'application/atom+xml', @response.content_type end + def test_diff + get :diff, :id => 3, :detail_id => 4 + assert_response :success + assert_template 'diff' + + assert_tag 'span', + :attributes => {:class => 'diff_out'}, + :content => /removed/ + assert_tag 'span', + :attributes => {:class => 'diff_in'}, + :content => /added/ + end + def test_reply_to_issue @request.session[:user_id] = 2 get :new, :id => 6 diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb index 0ecfa2e43..003d51389 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -621,6 +621,27 @@ class IssueTest < ActiveSupport::TestCase assert ActionMailer::Base.deliveries.empty? end + def test_journalized_description + i = Issue.first + old_description = i.description + new_description = "This is the new description" + + i.init_journal(User.find(2)) + i.description = new_description + assert_difference 'Journal.count', 1 do + assert_difference 'JournalDetail.count', 1 do + i.save! + end + end + + detail = JournalDetail.first(:order => 'id DESC') + assert_equal i, detail.journal.journalized + assert_equal 'attr', detail.property + assert_equal 'description', detail.prop_key + assert_equal old_description, detail.old_value + assert_equal new_description, detail.value + end + def test_saving_twice_should_not_duplicate_journal_details i = Issue.find(:first) i.init_journal(User.find(2), 'Some notes')