diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 96a8341d0b..74174210e2 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -72,7 +72,7 @@ class IssuesController < ApplicationController :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") end format.csv do - @issues = @query.issues(:limit => Setting.issues_export_limit.to_i) + @issues = @query.issues(:limit => Setting.issues_export_limit.to_i, :with_notes => (params[:with_notes] == '1')) send_data(query_to_csv(@issues, @query, params[:csv]), :type => 'text/csv; header=present', :filename => 'issues.csv') end diff --git a/app/helpers/queries_helper.rb b/app/helpers/queries_helper.rb index 9b223f84a7..0849a396ef 100644 --- a/app/helpers/queries_helper.rb +++ b/app/helpers/queries_helper.rb @@ -320,11 +320,23 @@ module QueriesHelper columns = query.columns Redmine::Export::CSV.generate(:encoding => params[:encoding]) do |csv| + journal_columns = IssueQuery.journal_columns if params[:with_notes] == '1' + # csv header fields - csv << columns.map {|c| c.caption.to_s} + csv << columns.map {|c| c.caption.to_s} + (journal_columns || []).map{|c| c.caption.to_s} # csv lines items.each do |item| - csv << columns.map {|c| csv_content(c, item)} + if journal_columns + item.journals_with_notes.each_with_index do |journal, index| + if index == 0 + csv << columns.map {|c| csv_content(c, item)} + journal_columns.map {|c| csv_content(c, journal)} + else + csv << columns.map {|c| csv_content(c, item) if c.name == :id } + journal_columns.map {|c| csv_content(c, journal)} + end + end + else + csv << columns.map {|c| csv_content(c, item)} + end end end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 7ce04ad64b..7c9d414c48 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -262,6 +262,7 @@ class Issue < ActiveRecord::Base @total_estimated_hours = nil @last_updated_by = nil @last_notes = nil + @journals_with_notes = nil base_reload(*args) end @@ -1166,11 +1167,21 @@ class Issue < ActiveRecord::Base def last_notes if @last_notes @last_notes + elsif @journals_with_notes.first.notes + @journals_with_notes.first.notes else journals.where.not(notes: '').reorder(:id => :desc).first.try(:notes) end end + def journals_with_notes + if @journals_with_notes + @journals_with_notes + else + journals.where.not(notes: '').reorder(:id => :asc) + end + end + # Preloads relations for a collection of issues def self.load_relations(issues) if issues.any? @@ -1261,8 +1272,15 @@ class Issue < ActiveRecord::Base end # Preloads visible last notes for a collection of issues - def self.load_visible_last_notes(issues, user=User.current) + def self.load_visible_last_notes(issues, user=User.current, has_notes=false) if issues.any? + if has_notes + issues.each do |issue| + issue.instance_variable_set("@last_notes", issue.journals_with_notes.last.notes) + end + return + end + issue_ids = issues.map(&:id) journal_ids = Journal.joins(issue: :project). where(:journalized_type => 'Issue', :journalized_id => issue_ids). @@ -1280,6 +1298,22 @@ class Issue < ActiveRecord::Base end end + # Preloads visible journals_with_notes for a collection of issues + def self.load_visible_journals_with_notes(issues, user=User.current) + if issues.any? + issue_ids = issues.map(&:id) + journals = Journal.joins(issue: :project). + where(:journalized_type => 'Issue', :journalized_id => issue_ids). + where(Journal.visible_notes_condition(user, :skip_pre_condition => true)). + where.not(notes: ''). + reorder(id: :asc) + + issues.each do |issue| + issue.instance_variable_set("@journals_with_notes", journals.where(journalized_id: issue.id)) + end + end + end + # Finds an issue relation given its id. def find_relation(relation_id) IssueRelation.where("issue_to_id = ? OR issue_from_id = ?", id, id).find(relation_id) diff --git a/app/models/issue_query.rb b/app/models/issue_query.rb index efd0ad0f1d..62c6b8e8f0 100644 --- a/app/models/issue_query.rb +++ b/app/models/issue_query.rb @@ -323,6 +323,19 @@ class IssueQuery < Query @available_columns end + def self.journal_columns + columns = + [ + QueryColumn.new(:id, :caption => :label_notes_id, :inline => false), + QueryColumn.new(:notes, :caption => :field_notes, :inline => false), + QueryColumn.new(:user, :caption => :label_notes_author, :inline => false), + QueryColumn.new(:created_on, :caption => :label_notes_created_on, :inline => false) + ] + if User.current.allowed_to?(:set_notes_private, nil, :global => true) + columns << QueryColumn.new(:private_notes, :caption => :field_private_notes, :inline => false) + end + end + def default_columns_names @default_columns_names ||= begin default_columns = Setting.issue_list_default_columns.map(&:to_sym) @@ -405,8 +418,11 @@ class IssueQuery < Query if has_column?(:relations) Issue.load_visible_relations(issues) end + if options[:with_notes] + Issue.load_visible_journals_with_notes(issues) + end if has_column?(:last_notes) - Issue.load_visible_last_notes(issues) + Issue.load_visible_last_notes(issues, User.current, options[:with_notes]) end issues rescue ::ActiveRecord::StatementInvalid => e diff --git a/app/views/issues/index.html.erb b/app/views/issues/index.html.erb index 880c953eaa..e7ad729c89 100644 --- a/app/views/issues/index.html.erb +++ b/app/views/issues/index.html.erb @@ -55,6 +55,7 @@ <% @query.available_block_columns.each do |column| %> <% end %> + <% end %> <%= export_csv_encoding_select_tag %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 952138bf4e..6815081b3e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1121,6 +1121,10 @@ en: label_display_type_board: Board label_my_bookmarks: My bookmarks label_assign_to_me: Assign to me + label_all_notes: All notes + label_notes_id: Notes-# + label_notes_author: Notes author + label_notes_created_on: Notes created button_login: Login button_submit: Submit