diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index ca3309c4..defc0a11 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -19,7 +19,7 @@ class IssuesController < ApplicationController layout 'base' menu_item :new_issue, :only => :new - before_filter :find_issue, :only => [:show, :edit, :destroy_attachment] + before_filter :find_issue, :only => [:show, :edit, :reply, :destroy_attachment] before_filter :find_issues, :only => [:bulk_edit, :move, :destroy] before_filter :find_project, :only => [:new, :update_form, :preview] before_filter :authorize, :except => [:index, :changes, :preview, :update_form, :context_menu] @@ -208,6 +208,26 @@ class IssuesController < ApplicationController flash.now[:error] = l(:notice_locking_conflict) end + def reply + journal = Journal.find(params[:journal_id]) if params[:journal_id] + if journal + user = journal.user + text = journal.notes + else + user = @issue.author + text = @issue.description + end + content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> " + content << text.to_s.strip.gsub(%r{
((.|\s)*?)
}m, '[...]').gsub("\n", "\n> ") + "\n\n" + render(:update) { |page| + page.replace_html "notes", content + page.show 'update' + page << "Form.Element.focus('notes');" + page << "Element.scrollTo('update');" + page << "$('notes').scrollTop = $('notes').scrollHeight - $('notes').clientHeight;" + } + end + # Bulk edit a set of issues def bulk_edit if request.post? diff --git a/app/helpers/journals_helper.rb b/app/helpers/journals_helper.rb index 234bfabc..92d6e559 100644 --- a/app/helpers/journals_helper.rb +++ b/app/helpers/journals_helper.rb @@ -19,13 +19,16 @@ module JournalsHelper def render_notes(journal, options={}) content = '' editable = journal.editable_by?(User.current) - if editable && !journal.notes.blank? - links = [] + links = [] + if !journal.notes.blank? links << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes", { :controller => 'journals', :action => 'edit', :id => journal }, - :title => l(:button_edit)) - content << content_tag('div', links.join(' '), :class => 'contextual') + :title => l(:button_edit)) if editable + links << link_to_remote(image_tag('comment.png'), + { :url => {:controller => 'issues', :action => 'reply', :id => journal.journalized, :journal_id => journal} }, + :title => l(:button_reply)) if options[:reply_links] end + content << content_tag('div', links.join(' '), :class => 'contextual') unless links.empty? content << textilizable(journal, :notes) content_tag('div', content, :id => "journal-#{journal.id}-notes", :class => (editable ? 'wiki editable' : 'wiki')) end diff --git a/app/views/issues/_history.rhtml b/app/views/issues/_history.rhtml index f29a44da..b8efdb40 100644 --- a/app/views/issues/_history.rhtml +++ b/app/views/issues/_history.rhtml @@ -1,3 +1,4 @@ +<% reply_links = authorize_for('issues', 'edit') -%> <% for journal in journals %>

<%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %>
@@ -8,6 +9,6 @@
  • <%= show_detail(detail) %>
  • <% end %> - <%= render_notes(journal) unless journal.notes.blank? %> + <%= render_notes(journal, :reply_links => reply_links) unless journal.notes.blank? %>

    <% end %> diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml index f788d0ec..f1c8a82c 100644 --- a/app/views/issues/show.rhtml +++ b/app/views/issues/show.rhtml @@ -56,6 +56,12 @@ end %>
    +
    +<%= link_to_remote(image_tag('comment.png'), + { :url => {:controller => 'issues', :action => 'reply', :id => @issue} }, + :title => l(:button_reply)) if authorize_for('issues', 'edit') %> +
    +

    <%=l(:field_description)%>

    <%= textilizable @issue, :description, :attachments => @issue.attachments %> diff --git a/lang/bg.yml b/lang/bg.yml index 10198bce..05a0b0d6 100644 --- a/lang/bg.yml +++ b/lang/bg.yml @@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/cs.yml b/lang/cs.yml index f90068b3..829f4449 100644 --- a/lang/cs.yml +++ b/lang/cs.yml @@ -626,3 +626,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/da.yml b/lang/da.yml index ca4ddeb4..92df87e3 100644 --- a/lang/da.yml +++ b/lang/da.yml @@ -623,3 +623,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/de.yml b/lang/de.yml index fa33e1c7..1351d194 100644 --- a/lang/de.yml +++ b/lang/de.yml @@ -622,3 +622,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/en.yml b/lang/en.yml index f9e07d21..4184a917 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -596,6 +596,7 @@ text_destroy_time_entries_question: %.02f hours were reported on the issues you text_destroy_time_entries: Delete reported hours text_assign_time_entries_to_project: Assign reported hours to the project text_reassign_time_entries: 'Reassign reported hours to this issue:' +text_user_wrote: '%s wrote:' default_role_manager: Manager default_role_developper: Developer diff --git a/lang/es.yml b/lang/es.yml index 3d8c0a93..ea479630 100644 --- a/lang/es.yml +++ b/lang/es.yml @@ -624,3 +624,4 @@ text_subprojects_destroy_warning: 'Sus subprojectos: %s también se eliminarán' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/fi.yml b/lang/fi.yml index 60428bb4..b3b88862 100644 --- a/lang/fi.yml +++ b/lang/fi.yml @@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Tämän alaprojekti(t): %s tullaan myös pois label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/fr.yml b/lang/fr.yml index 8b002bbf..a802a44c 100644 --- a/lang/fr.yml +++ b/lang/fr.yml @@ -596,6 +596,7 @@ text_destroy_time_entries_question: %.02f heures ont été enregistrées sur les text_destroy_time_entries: Supprimer les heures text_assign_time_entries_to_project: Reporter les heures sur le projet text_reassign_time_entries: 'Reporter les heures sur cette demande:' +text_user_wrote: '%s a écrit:' default_role_manager: Manager default_role_developper: Développeur diff --git a/lang/he.yml b/lang/he.yml index f972ef62..c4d69ebb 100644 --- a/lang/he.yml +++ b/lang/he.yml @@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/hu.yml b/lang/hu.yml index f6d312ce..fd7bf9f5 100644 --- a/lang/hu.yml +++ b/lang/hu.yml @@ -622,3 +622,4 @@ enumeration_doc_categories: Dokumentum kategóriák enumeration_activities: Tevékenységek (idő rögzítés) mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/it.yml b/lang/it.yml index a8646644..519dcd01 100644 --- a/lang/it.yml +++ b/lang/it.yml @@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/ja.yml b/lang/ja.yml index d119cf55..714539c7 100644 --- a/lang/ja.yml +++ b/lang/ja.yml @@ -622,3 +622,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/ko.yml b/lang/ko.yml index 98dde9e0..81656040 100644 --- a/lang/ko.yml +++ b/lang/ko.yml @@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/lt.yml b/lang/lt.yml index 6b791d87..89e607a8 100644 --- a/lang/lt.yml +++ b/lang/lt.yml @@ -623,3 +623,4 @@ label_and_its_subprojects: %s projektas ir jo subprojektai mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/nl.yml b/lang/nl.yml index c36eaecd..eebc7d99 100644 --- a/lang/nl.yml +++ b/lang/nl.yml @@ -622,3 +622,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/no.yml b/lang/no.yml index 5e788dc5..3f6ef6de 100644 --- a/lang/no.yml +++ b/lang/no.yml @@ -622,3 +622,4 @@ enumeration_doc_categories: Dokument-kategorier enumeration_activities: Aktiviteter (tidssporing) mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/pl.yml b/lang/pl.yml index 4476c216..81a7a0db 100644 --- a/lang/pl.yml +++ b/lang/pl.yml @@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/pt-br.yml b/lang/pt-br.yml index 9b3d2315..47e80a14 100644 --- a/lang/pt-br.yml +++ b/lang/pt-br.yml @@ -621,3 +621,4 @@ label_age: Age label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/pt.yml b/lang/pt.yml index c56b76a0..002a1b7f 100644 --- a/lang/pt.yml +++ b/lang/pt.yml @@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/ro.yml b/lang/ro.yml index 30464569..6bcd55a5 100644 --- a/lang/ro.yml +++ b/lang/ro.yml @@ -621,3 +621,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/ru.yml b/lang/ru.yml index f4fd9203..fa8fd69a 100644 --- a/lang/ru.yml +++ b/lang/ru.yml @@ -625,3 +625,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/sr.yml b/lang/sr.yml index 53e4f9f2..9a4adf21 100644 --- a/lang/sr.yml +++ b/lang/sr.yml @@ -622,3 +622,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/sv.yml b/lang/sv.yml index 248f3dcb..1ab11e98 100644 --- a/lang/sv.yml +++ b/lang/sv.yml @@ -622,3 +622,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/th.yml b/lang/th.yml index 444316aa..751aac74 100644 --- a/lang/th.yml +++ b/lang/th.yml @@ -624,3 +624,4 @@ enumeration_activities: กิจกรรม (ใช้ในการติด label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/uk.yml b/lang/uk.yml index 3cc60ef4..3ab4462e 100644 --- a/lang/uk.yml +++ b/lang/uk.yml @@ -623,3 +623,4 @@ text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' label_and_its_subprojects: %s and its subprojects mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/zh-tw.yml b/lang/zh-tw.yml index 3926113b..3b7808aa 100644 --- a/lang/zh-tw.yml +++ b/lang/zh-tw.yml @@ -622,3 +622,4 @@ enumeration_doc_categories: 文件分類 enumeration_activities: 活動 (時間追蹤) mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" +text_user_wrote: '%s wrote:' diff --git a/lang/zh.yml b/lang/zh.yml index 55516e03..b5ecace8 100644 --- a/lang/zh.yml +++ b/lang/zh.yml @@ -622,3 +622,4 @@ enumeration_doc_categories: 文档类别 enumeration_activities: 活动(时间跟踪) mail_subject_reminder: "%d issue(s) due in the next days" mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" +text_user_wrote: '%s wrote:' diff --git a/lib/redmine.rb b/lib/redmine.rb index b21f5716..7b9832d6 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -32,9 +32,9 @@ Redmine::AccessControl.map do |map| :queries => :index, :reports => :issue_report}, :public => true map.permission :add_issues, {:issues => :new} - map.permission :edit_issues, {:issues => [:edit, :bulk_edit, :destroy_attachment]} + map.permission :edit_issues, {:issues => [:edit, :reply, :bulk_edit, :destroy_attachment]} map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]} - map.permission :add_issue_notes, {:issues => :edit} + map.permission :add_issue_notes, {:issues => [:edit, :reply]} map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin map.permission :move_issues, {:issues => :move}, :require => :loggedin diff --git a/public/images/comment.png b/public/images/comment.png new file mode 100644 index 00000000..7bc9233e Binary files /dev/null and b/public/images/comment.png differ diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index c4389fed..7c7d44e5 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -263,6 +263,22 @@ class IssuesControllerTest < Test::Unit::TestCase :content => 'Urgent', :attributes => { :selected => 'selected' } } end + + def test_reply_to_issue + @request.session[:user_id] = 2 + get :reply, :id => 1 + assert_response :success + assert_select_rjs :show, "update" + assert_select_rjs :replace_html, "notes" + end + + def test_reply_to_note + @request.session[:user_id] = 2 + get :reply, :id => 1, :journal_id => 2 + assert_response :success + assert_select_rjs :show, "update" + assert_select_rjs :replace_html, "notes" + end def test_post_edit @request.session[:user_id] = 2