Keep track of issue description changes (#746).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4954 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
ca807c8d92
commit
2627419131
|
@ -1,5 +1,5 @@
|
||||||
# redMine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2008 Jean-Philippe Lang
|
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
@ -16,11 +16,12 @@
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
class JournalsController < ApplicationController
|
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_issue, :only => [:new]
|
||||||
before_filter :find_optional_project, :only => [:index]
|
before_filter :find_optional_project, :only => [:index]
|
||||||
before_filter :authorize, :only => [:new, :edit]
|
before_filter :authorize, :only => [:new, :edit, :diff]
|
||||||
accept_key_auth :index
|
accept_key_auth :index
|
||||||
|
menu_item :issues
|
||||||
|
|
||||||
helper :issues
|
helper :issues
|
||||||
helper :queries
|
helper :queries
|
||||||
|
@ -43,6 +44,17 @@ class JournalsController < ApplicationController
|
||||||
render_404
|
render_404
|
||||||
end
|
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
|
def new
|
||||||
journal = Journal.find(params[:journal_id]) if params[:journal_id]
|
journal = Journal.find(params[:journal_id]) if params[:journal_id]
|
||||||
if journal
|
if journal
|
||||||
|
@ -67,6 +79,7 @@ class JournalsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
|
(render_403; return false) unless @journal.editable_by?(User.current)
|
||||||
if request.post?
|
if request.post?
|
||||||
@journal.update_attributes(:notes => params[:notes]) if params[:notes]
|
@journal.update_attributes(:notes => params[:notes]) if params[:notes]
|
||||||
@journal.destroy if @journal.details.empty? && @journal.notes.blank?
|
@journal.destroy if @journal.details.empty? && @journal.notes.blank?
|
||||||
|
@ -86,10 +99,10 @@ class JournalsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def find_journal
|
def find_journal
|
||||||
@journal = Journal.find(params[:id])
|
@journal = Journal.find(params[:id])
|
||||||
(render_403; return false) unless @journal.editable_by?(User.current)
|
|
||||||
@project = @journal.journalized.project
|
@project = @journal.journalized.project
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render_404
|
render_404
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# redMine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006 Jean-Philippe Lang
|
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
@ -183,7 +183,16 @@ module IssuesHelper
|
||||||
end
|
end
|
||||||
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
|
case detail.property
|
||||||
when 'attr', 'cf'
|
when 'attr', 'cf'
|
||||||
if !detail.old_value.blank?
|
if !detail.old_value.blank?
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# redMine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
@ -829,7 +829,7 @@ class Issue < ActiveRecord::Base
|
||||||
def create_journal
|
def create_journal
|
||||||
if @current_journal
|
if @current_journal
|
||||||
# attributes changes
|
# 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',
|
@current_journal.details << JournalDetail.new(:property => 'attr',
|
||||||
:prop_key => c,
|
:prop_key => c,
|
||||||
:old_value => @issue_before_change.send(c),
|
:old_value => @issue_before_change.send(c),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# redMine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006 Jean-Philippe Lang
|
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
@ -17,9 +17,4 @@
|
||||||
|
|
||||||
class JournalDetail < ActiveRecord::Base
|
class JournalDetail < ActiveRecord::Base
|
||||||
belongs_to :journal
|
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
|
end
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<h2><%=h @issue.tracker %> #<%= @issue.id %></h2>
|
||||||
|
<p><%= authoring @journal.created_on, @journal.user, :label => :label_updated_time_by %></p>
|
||||||
|
|
||||||
|
<div class="text-diff">
|
||||||
|
<%= simple_format_without_paragraph @diff.to_html %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p><%= link_to l(:button_back), issue_path(@issue), :onclick => 'history.back(); return false;' %></p>
|
||||||
|
|
||||||
|
<% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %>
|
|
@ -860,6 +860,7 @@ en:
|
||||||
text_are_you_sure: Are you sure ?
|
text_are_you_sure: Are you sure ?
|
||||||
text_are_you_sure_with_children: "Delete issue and all child issues?"
|
text_are_you_sure_with_children: "Delete issue and all child issues?"
|
||||||
text_journal_changed: "%{label} changed from %{old} to %{new}"
|
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_set_to: "%{label} set to %{value}"
|
||||||
text_journal_deleted: "%{label} deleted (%{old})"
|
text_journal_deleted: "%{label} deleted (%{old})"
|
||||||
text_journal_added: "%{label} %{value} added"
|
text_journal_added: "%{label} %{value} added"
|
||||||
|
|
|
@ -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_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)."
|
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: "%{label} changé de %{old} à %{new}"
|
||||||
|
text_journal_changed_no_detail: "%{label} mis à jour"
|
||||||
text_journal_set_to: "%{label} mis à %{value}"
|
text_journal_set_to: "%{label} mis à %{value}"
|
||||||
text_journal_deleted: "%{label} %{old} supprimé"
|
text_journal_deleted: "%{label} %{old} supprimé"
|
||||||
text_journal_added: "%{label} %{value} ajouté"
|
text_journal_added: "%{label} %{value} ajouté"
|
||||||
|
|
|
@ -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
|
|
@ -62,7 +62,7 @@ Redmine::AccessControl.map do |map|
|
||||||
:auto_complete => [:issues],
|
:auto_complete => [:issues],
|
||||||
:context_menus => [:issues],
|
:context_menus => [:issues],
|
||||||
:versions => [:index, :show, :status_by],
|
:versions => [:index, :show, :status_by],
|
||||||
:journals => :index,
|
:journals => [:index, :diff],
|
||||||
:queries => :index,
|
:queries => :index,
|
||||||
:reports => [:issue_report, :issue_report_details]}
|
:reports => [:issue_report, :issue_report_details]}
|
||||||
map.permission :add_issues, {:issues => [:new, :create, :update_form]}
|
map.permission :add_issues, {:issues => [:new, :create, :update_form]}
|
||||||
|
|
|
@ -672,6 +672,13 @@ div.autocomplete ul li span.informal {
|
||||||
.diff_out { background: #fcc; }
|
.diff_out { background: #fcc; }
|
||||||
.diff_in { background: #cfc; }
|
.diff_in { background: #cfc; }
|
||||||
|
|
||||||
|
.text-diff {
|
||||||
|
padding: 1em;
|
||||||
|
background-color:#f6f6f6;
|
||||||
|
color:#505050;
|
||||||
|
border: 1px solid #e4e4e4;
|
||||||
|
}
|
||||||
|
|
||||||
/***** Wiki *****/
|
/***** Wiki *****/
|
||||||
div.wiki table {
|
div.wiki table {
|
||||||
border: 1px solid #505050;
|
border: 1px solid #505050;
|
||||||
|
|
|
@ -20,3 +20,10 @@ journal_details_003:
|
||||||
value: "6"
|
value: "6"
|
||||||
prop_key: fixed_version_id
|
prop_key: fixed_version_id
|
||||||
journal_id: 4
|
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
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# redMine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2008 Jean-Philippe Lang
|
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# 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
|
assert_equal 'application/atom+xml', @response.content_type
|
||||||
end
|
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
|
def test_reply_to_issue
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
get :new, :id => 6
|
get :new, :id => 6
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# redMine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
@ -621,6 +621,27 @@ class IssueTest < ActiveSupport::TestCase
|
||||||
assert ActionMailer::Base.deliveries.empty?
|
assert ActionMailer::Base.deliveries.empty?
|
||||||
end
|
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
|
def test_saving_twice_should_not_duplicate_journal_details
|
||||||
i = Issue.find(:first)
|
i = Issue.find(:first)
|
||||||
i.init_journal(User.find(2), 'Some notes')
|
i.init_journal(User.find(2), 'Some notes')
|
||||||
|
|
Loading…
Reference in New Issue