From 05b96c4068c590c8b907d2e9c18273b8b5adb06d Mon Sep 17 00:00:00 2001 From: cforce Date: Wed, 25 Jan 2012 10:11:41 +0100 Subject: [PATCH 01/66] german locale --- app/models/question_mailer.rb | 8 ++++---- config/locales/de.yml | 6 ++++++ lang/de.yml | 16 ---------------- lang/en.yml | 16 ---------------- 4 files changed, 10 insertions(+), 36 deletions(-) delete mode 100644 lang/de.yml delete mode 100644 lang/en.yml diff --git a/app/models/question_mailer.rb b/app/models/question_mailer.rb index 3ce6175..6d05e89 100644 --- a/app/models/question_mailer.rb +++ b/app/models/question_mailer.rb @@ -3,9 +3,9 @@ class QuestionMailer < Mailer def asked_question(journal) question = journal.question - subject "[Question #{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" + subject "[Frage #{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" recipients question.assigned_to.mail unless question.assigned_to.nil? - @from = "#{question.author.name} (Redmine) <#{Setting.mail_from}>" unless question.author.nil? + @from = "#{question.author.name} (#{l(:field_system_name)}) <#{Setting.mail_from}>" unless question.author.nil? redmine_headers 'Issue-Id' => question.issue.id redmine_headers 'Question-Asked' => question.author.login if question.author.present? redmine_headers 'Question-Assigned-To' => question.assigned_to.login if question.assigned_to.present? @@ -22,10 +22,10 @@ def asked_question(journal) end def answered_question(question, closing_journal) - subject "[Answered #{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" + subject "[Beantwortet #{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" recipients question.author.mail unless question.author.nil? - @from = "#{question.assigned_to.name} (Redmine) <#{Setting.mail_from}>" unless question.assigned_to.nil? + @from = "#{question.assigned_to.name} (#{l(:field_system_name)}) <#{Setting.mail_from}>" unless question.assigned_to.nil? redmine_headers 'Issue-Id' => question.issue.id redmine_headers 'Question-Answer' => "#{question.issue.id}-#{closing_journal.id}" diff --git a/config/locales/de.yml b/config/locales/de.yml index 190785a..8855e80 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -15,3 +15,9 @@ de: question_text_asked_by: "gefragt von" question_text_assigned_to: "Zugewiesen an" question_text_created_on: "Erstellt am" + question_text_ratio_questions_answered: "{{ratio}} beantwortete Fragen" + field_journal: "Journal" + text_questions_asked_by_me: "meine gestellten Fragen" + questions_asked_by_me: Meine gestellten Fragen + questions_for_me: Fragen fr mich + field_system_name: InfoMine \ No newline at end of file diff --git a/lang/de.yml b/lang/de.yml deleted file mode 100644 index f390902..0000000 --- a/lang/de.yml +++ /dev/null @@ -1,16 +0,0 @@ -field_question_assign_to: Frage zuweisen an -field_question_assigned_to: Frage ist gestellt an -field_question_asked_by: Frage wurde gestellt durch -field_formatted_questions: Fragen -text_question: Frage -text_question_answered: Frage beantwortet -text_answer: Antwort -text_anyone: Irgendwer -text_question_for: Frage für -text_question_for_anyone: Frage für irgendjemanden -text_questions_for_me: Fragen für mich -text_question_asked: Frage gestellt -text_question_remove: "<>" -question_text_asked_by: "gefragt von" -question_text_assigned_to: "Zugewiesen an" -question_text_created_on: "Erstellt am" diff --git a/lang/en.yml b/lang/en.yml deleted file mode 100644 index 360c3f0..0000000 --- a/lang/en.yml +++ /dev/null @@ -1,16 +0,0 @@ -field_question_assign_to: Assign question to -field_question_assigned_to: Question is assigned to -field_question_asked_by: Question was asked by -field_formatted_questions: Questions -text_question: Question -text_question_answered: Question Answered -text_answer: Answer -text_anyone: Anyone -text_question_for: Question for -text_question_for_anyone: Question for anyone -text_questions_for_me: Questions for me -text_question_asked: Question asked -text_question_remove: "<< Remove Question>>" -question_text_asked_by: "Asked By" -question_text_assigned_to: "Assigned To" -question_text_created_on: "Created On" From cfc54347865a87241d412cdde6d2eeaf55c518ac Mon Sep 17 00:00:00 2001 From: Stephen Leavitt Date: Sun, 10 Jun 2012 14:24:36 -0500 Subject: [PATCH 02/66] Updated QuestionMailer templates to work with Redmine >= 1.3.0 --- .../answered_question.text.html.rhtml | 4 ++-- .../answered_question.text.plain.rhtml | 22 +++++++++---------- .../asked_question.text.html.rhtml | 2 +- .../asked_question.text.plain.rhtml | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/views/question_mailer/answered_question.text.html.rhtml b/app/views/question_mailer/answered_question.text.html.rhtml index ceeafe4..d49a853 100644 --- a/app/views/question_mailer/answered_question.text.html.rhtml +++ b/app/views/question_mailer/answered_question.text.html.rhtml @@ -6,9 +6,9 @@
    <% for detail in @journal.details %> -
  • <%= @journal.render_detail(detail, true) %>
  • +
  • <%= show_detail(detail, true) %>
  • <% end %>

-<%= render :partial => "mailer/issue_text_html", :locals => { :issue => @issue, :issue_url => @issue_url } %> +<%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff --git a/app/views/question_mailer/answered_question.text.plain.rhtml b/app/views/question_mailer/answered_question.text.plain.rhtml index d01eb36..c8ab12a 100644 --- a/app/views/question_mailer/answered_question.text.plain.rhtml +++ b/app/views/question_mailer/answered_question.text.plain.rhtml @@ -1,14 +1,14 @@ -<%= l(:text_answer) %> +

<%= l(:text_answer) %>

+<%= textilizable(@journal, :notes, :only_path => false) %> -<%= @journal.notes if @journal.notes? %> +

<%= l(:text_question) %>

+<%= textilizable(@question.journal, :notes, :only_path => false) %> -<%= l(:text_question) %> +
    +<% for detail in @journal.details %> +
  • <%= @journal.render_detail(detail, true) %>
  • +<% end %> +
-<%= @question.journal.notes if @question.journal && @question.journal.notes? %> - -<% for detail in @journal.details -%> -<%= @journal.render_detail(detail, true) %> -<% end -%> - ----------------------------------------- -<%= render :partial => "mailer/issue_text_plain", :locals => { :issue => @issue, :issue_url => @issue_url } %> +
+<%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff --git a/app/views/question_mailer/asked_question.text.html.rhtml b/app/views/question_mailer/asked_question.text.html.rhtml index 36ca1ff..81a6ad9 100644 --- a/app/views/question_mailer/asked_question.text.html.rhtml +++ b/app/views/question_mailer/asked_question.text.html.rhtml @@ -9,4 +9,4 @@
-<%= render :partial => "mailer/issue_text_html", :locals => { :issue => @issue, :issue_url => @issue_url } %> +<%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff --git a/app/views/question_mailer/asked_question.text.plain.rhtml b/app/views/question_mailer/asked_question.text.plain.rhtml index 658618b..854561f 100644 --- a/app/views/question_mailer/asked_question.text.plain.rhtml +++ b/app/views/question_mailer/asked_question.text.plain.rhtml @@ -7,4 +7,4 @@ <% end -%> ---------------------------------------- -<%= render :partial => "mailer/issue_text_plain", :locals => { :issue => @issue, :issue_url => @issue_url } %> +<%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url } %> From 0ca798f79e0cb5201357923f620a36c301fd43cf Mon Sep 17 00:00:00 2001 From: Stephen Leavitt Date: Sun, 10 Jun 2012 14:26:02 -0500 Subject: [PATCH 03/66] Renamed QuestionMailer templates to work with >= Redmine 1.3.0 --- ...swered_question.text.html.rhtml => answered_question.html.erb} | 0 ...wered_question.text.plain.rhtml => answered_question.text.erb} | 0 .../{asked_question.text.html.rhtml => asked_question.html.erb} | 0 .../{asked_question.text.plain.rhtml => asked_question.text.erb} | 0 ...estion_reminder.text.html.rhtml => question_reminder.html.erb} | 0 ...stion_reminder.text.plain.rhtml => question_reminder.text.erb} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename app/views/question_mailer/{answered_question.text.html.rhtml => answered_question.html.erb} (100%) rename app/views/question_mailer/{answered_question.text.plain.rhtml => answered_question.text.erb} (100%) rename app/views/question_mailer/{asked_question.text.html.rhtml => asked_question.html.erb} (100%) rename app/views/question_mailer/{asked_question.text.plain.rhtml => asked_question.text.erb} (100%) rename app/views/question_mailer/{question_reminder.text.html.rhtml => question_reminder.html.erb} (100%) rename app/views/question_mailer/{question_reminder.text.plain.rhtml => question_reminder.text.erb} (100%) diff --git a/app/views/question_mailer/answered_question.text.html.rhtml b/app/views/question_mailer/answered_question.html.erb similarity index 100% rename from app/views/question_mailer/answered_question.text.html.rhtml rename to app/views/question_mailer/answered_question.html.erb diff --git a/app/views/question_mailer/answered_question.text.plain.rhtml b/app/views/question_mailer/answered_question.text.erb similarity index 100% rename from app/views/question_mailer/answered_question.text.plain.rhtml rename to app/views/question_mailer/answered_question.text.erb diff --git a/app/views/question_mailer/asked_question.text.html.rhtml b/app/views/question_mailer/asked_question.html.erb similarity index 100% rename from app/views/question_mailer/asked_question.text.html.rhtml rename to app/views/question_mailer/asked_question.html.erb diff --git a/app/views/question_mailer/asked_question.text.plain.rhtml b/app/views/question_mailer/asked_question.text.erb similarity index 100% rename from app/views/question_mailer/asked_question.text.plain.rhtml rename to app/views/question_mailer/asked_question.text.erb diff --git a/app/views/question_mailer/question_reminder.text.html.rhtml b/app/views/question_mailer/question_reminder.html.erb similarity index 100% rename from app/views/question_mailer/question_reminder.text.html.rhtml rename to app/views/question_mailer/question_reminder.html.erb diff --git a/app/views/question_mailer/question_reminder.text.plain.rhtml b/app/views/question_mailer/question_reminder.text.erb similarity index 100% rename from app/views/question_mailer/question_reminder.text.plain.rhtml rename to app/views/question_mailer/question_reminder.text.erb From ef654f0701a37b3c122b865504435d9dadf07496 Mon Sep 17 00:00:00 2001 From: Stephen Leavitt Date: Sun, 10 Jun 2012 18:13:15 -0500 Subject: [PATCH 04/66] Updated plugin to work with Redmine 2.0 --- app/models/question.rb | 8 +- app/models/question_mailer.rb | 71 ++++---- config/routes.rb | 3 + init.rb | 20 ++- lib/question_issue_hooks.rb | 19 +- lib/question_issue_patch.rb | 162 +++++++++++------- lib/question_journal_hooks.rb | 2 +- .../patches/journal_observer_patch.rb | 9 +- lib/question_query_patch.rb | 11 +- test/integration/answering_question_test.rb | 4 +- test/integration/asking_question_test.rb | 4 +- test/integration/mail_handler_test.rb | 2 +- test/integration/my_page_blocks_test.rb | 2 +- .../hooks/question_issue_hooks_test.rb | 2 +- test/test_helper.rb | 6 +- .../patches/queries_helper_patch_test.rb | 8 +- test/unit/question_mailer_test.rb | 6 +- 17 files changed, 182 insertions(+), 157 deletions(-) create mode 100644 config/routes.rb diff --git a/app/models/question.rb b/app/models/question.rb index 1834499..ddeda99 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -11,11 +11,11 @@ class Question < ActiveRecord::Base validates_presence_of :issue validates_presence_of :journal - named_scope :opened, :conditions => {:opened => true} - named_scope :for_user, lambda {|user| + scope :opened, :conditions => {:opened => true} + scope :for_user, lambda {|user| { :conditions => {:assigned_to_id => user.id }} } - named_scope :by_user, lambda {|user| + scope :by_user, lambda {|user| { :conditions => {:author_id => user.id }} } @@ -29,7 +29,7 @@ def close!(closing_journal=nil) if self.opened self.opened = false if self.save && closing_journal - QuestionMailer.deliver_answered_question(self, closing_journal) + QuestionMailer.answered_question(self, closing_journal).deliver end end end diff --git a/app/models/question_mailer.rb b/app/models/question_mailer.rb index 3ce6175..7a8a46a 100644 --- a/app/models/question_mailer.rb +++ b/app/models/question_mailer.rb @@ -3,67 +3,70 @@ class QuestionMailer < Mailer def asked_question(journal) question = journal.question - subject "[Question #{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" - recipients question.assigned_to.mail unless question.assigned_to.nil? - @from = "#{question.author.name} (Redmine) <#{Setting.mail_from}>" unless question.author.nil? + + from = question.author ? "#{question.author.name} (Redmine) <#{Setting.mail_from}>" : nil + to = question.assigned_to ? question.assigned_to.mail : nil + subject = "[Question #{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" + + @from = from + @question = question + @issue = question.issue + @journal = journal + @issue_url = url_for(:controller => 'issues', :action => 'show', :id => question.issue) + redmine_headers 'Issue-Id' => question.issue.id redmine_headers 'Question-Asked' => question.author.login if question.author.present? redmine_headers 'Question-Assigned-To' => question.assigned_to.login if question.assigned_to.present? - body({ - :question => question, - :issue => question.issue, - :journal => journal, - :issue_url => url_for(:controller => 'issues', :action => 'show', :id => question.issue) - }) - - RAILS_DEFAULT_LOGGER.debug 'Sending QuestionMailer#asked_question' - render_multipart('asked_question', body) + Rails.logger.debug 'Sending QuestionMailer#asked_question' + mail(:from => from, :to => to, :subject => subject) end def answered_question(question, closing_journal) - subject "[Answered #{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" + from = question.assigned_to ? "#{question.assigned_to.name} (Redmine) <#{Setting.mail_from}>" : nil + to = question.author ? question.author.mail : nil + subject = "[Answered #{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" - recipients question.author.mail unless question.author.nil? @from = "#{question.assigned_to.name} (Redmine) <#{Setting.mail_from}>" unless question.assigned_to.nil? + @question = question + @issue = question.issue + @journal = closing_journal + @issue_url = url_for(:controller => 'issues', :action => 'show', :id => question.issue) + redmine_headers 'Issue-Id' => question.issue.id redmine_headers 'Question-Answer' => "#{question.issue.id}-#{closing_journal.id}" - body({ - :question => question, - :issue => question.issue, - :journal => closing_journal, - :issue_url => url_for(:controller => 'issues', :action => 'show', :id => question.issue) - }) - - RAILS_DEFAULT_LOGGER.debug 'Sending QuestionMailer#answered_question' - render_multipart('answered_question', body) + Rails.logger.debug 'Sending QuestionMailer#answered_question' + mail(:from => from, :to => to, :subject => subject) end # Creates an email with a list of issues that have open questions # assigned to the user def question_reminder(user, issues) - redmine_headers 'Type' => "Question" set_language_if_valid user.language - recipients user.mail - subject l(:question_reminder_subject, :count => issues.size) - body :issues => issues, - :issues_url => url_for(:controller => 'questions', :action => 'my_issue_filter') - render_multipart('question_reminder', body) + + to = user.mail + subject = l(:question_reminder_subject, :count => issues.size) + + @issues = issues + @issues_url = url_for(:controller => 'questions', :action => 'my_issue_filter') + + redmine_headers 'Type' => 'Question' + + mail(:to => to, :subject => subject) end # Send email reminders to users who have open questions. def self.question_reminders - - open_questions_by_assignee = Question.opened.all(:order => 'id desc').group_by(&:assigned_to) + open_questions_by_assignee = Question.opened.order('id desc').all.group_by(&:assigned_to) open_questions_by_assignee.each do |assignee, questions| - next unless assignee.present? + next unless assignee.present? and not assignee.locked? - issues = questions.collect {|q| q.issue.visible?(assignee) ? q.issue : nil }.compact.uniq + issues = questions.reject {|q| not q.issue.visible?(assignee) }.collect {|q| q.issue }.uniq next if issues.count == 0 - deliver_question_reminder(assignee, issues) + question_reminder(assignee, issues).deliver end end end diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..b4305cb --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,3 @@ +match 'questions/autocomplete_for_user_login/project/:id/issue/:issue_id' => 'questions#autocomplete_for_user_login', :format => false, :as => 'questions_autocomplete_for_user_login' +match 'questions/my_issue_filter(/project/:project)' => 'questions#my_issue_filter', :format => false, :as => 'questions_my_issue_filter' +match 'questions/user_issue_filter/user/:user_id' => 'questions#user_issue_filter', :format => false, :as => 'questions_user_issue_filter' diff --git a/init.rb b/init.rb index d1e0648..2616d4a 100644 --- a/init.rb +++ b/init.rb @@ -5,13 +5,10 @@ require 'question_layout_hooks' require 'question_journal_hooks' -# Patches to the Redmine core. -require 'dispatcher' - -Dispatcher.to_prepare :question_plugin do - +Rails.configuration.to_prepare do require_dependency 'journal_observer' - JournalObserver.send(:include, QuestionPlugin::Patches::JournalObserverPatch) + JournalObserver.send(:include, QuestionPlugin::Patches::JournalObserverPatch) unless JournalObserver.included_modules.include? QuestionPlugin::Patches::JournalObserverPatch + require_dependency 'issue' Issue.send(:include, QuestionIssuePatch) unless Issue.included_modules.include? QuestionIssuePatch @@ -21,11 +18,11 @@ require_dependency 'queries_helper' QueriesHelper.send(:include, QuestionQueriesHelperPatch) unless QueriesHelper.included_modules.include? QuestionQueriesHelperPatch - require_dependency "query" + require_dependency 'query' Query.send(:include, QuestionQueryPatch) unless Query.included_modules.include? QuestionQueryPatch end -Redmine::Plugin.register :question_plugin do +p = Redmine::Plugin.register :question_plugin do name 'Redmine Question plugin' author 'Eric Davis' url "https://projects.littlestreamsoftware.com/projects/redmine-questions" if respond_to?(:url) @@ -33,8 +30,13 @@ description 'This is a plugin for Redmine that will allow users to ask questions to each other in issue notes' version '0.3.0' - requires_redmine :version_or_higher => '0.8.0' + requires_redmine :version_or_higher => '2.0.0' +end +# Ensure ActionMailer knows where to find the views for the question plugin +view_path = File.join(p.directory, 'app', 'views') +if File.directory?(view_path) + ActionMailer::Base.prepend_view_path(view_path) end require 'question_plugin/hooks/view_user_kanbans_show_contextual_top_hook' diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index 175a0b1..a58caf5 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -27,7 +27,7 @@ def view_issues_edit_notes_bottom(context = { }) @issue = context[:issue] o = '' o << content_tag(:p, - " " + + " ".html_safe + text_field_tag('note[question_assigned_to]', nil, :size => "40")) o << content_tag(:div,'', :id => "note_question_assigned_to_choices", :class => "autocomplete") @@ -43,13 +43,14 @@ def controller_issues_edit_before_save(context = { }) if params[:note] && !params[:note][:question_assigned_to].blank? unless journal.question # Update handled by Journal hooks # New - issue.extra_journal_attributes = { - :question => Question.new( - :author => User.current, - :issue => journal.issue, - :assigned_to => User.find_by_login(params[:note][:question_assigned_to]) - ) - } + journal.question = Question.new( + :author => User.current, + :issue => journal.issue + ) + if params[:note][:question_assigned_to].downcase != 'anyone' + # Assigned to a specific user + assign_question_to_user(journal, User.find_by_login(params[:note][:question_assigned_to])) + end end end @@ -73,7 +74,7 @@ def view_issues_sidebar_issues_bottom(context = { }) :only_path => true }, { :class => 'question-link' } - ) + '
' + ) + '
'.html_safe else return '' end diff --git a/lib/question_issue_patch.rb b/lib/question_issue_patch.rb index 88ed551..81bbe4b 100644 --- a/lib/question_issue_patch.rb +++ b/lib/question_issue_patch.rb @@ -10,73 +10,14 @@ def self.included(base) # :nodoc: has_many :open_questions, :class_name => 'Question', :conditions => { :opened => true } include ActionView::Helpers::TextHelper # for truncate - - class << self - # I dislike alias method chain, it's not the most readable backtraces - alias_method :default_find, :find - alias_method :find, :find_with_questions_added_to_the_includes - - alias_method :default_count, :count - alias_method :count, :count_with_questions_added_to_the_includes - - alias_method :default_sum, :sum - alias_method :sum, :sum_with_questions_added_to_the_includes - end end + QuestionIssuePatch::ActiveRecord.enable end - - module ClassMethods - def find_with_questions_added_to_the_includes(*args) - scan_for_options_hash_and_add_includes_if_needed(args) - default_find(*args) - end - def count_with_questions_added_to_the_includes(*args) - scan_for_options_hash_and_add_includes_if_needed(args) - default_count(*args) - end - - def sum_with_questions_added_to_the_includes(*args) - scan_for_options_hash_and_add_includes_if_needed(args) - default_sum(*args) - end - - private - - # Finds the options hash. If question is part of the conditions then - # add questions to the includes - def scan_for_options_hash_and_add_includes_if_needed(args) - args.each do |arg| - if arg.is_a?(Hash) && arg[:conditions] - if arg[:conditions].is_a?(String) && arg[:conditions].include?('question') - # String conditions - add_questions_to_the_includes(arg) - elsif arg[:conditions].is_a?(Array) && arg[:conditions][0].include?('question') - # Array conditions - add_questions_to_the_includes(arg) - end - end - end - end - - def add_questions_to_the_includes(arg) - if arg[:include] - # Has includes - if arg[:include].is_a?(Hash) - # Hash includes - arg[:include] << :questions - else - # single includes - arg[:include] = [ arg[:include] , :questions ] - end - else - # No includes - arg[:include] = :questions - end - end + module ClassMethods end - + module InstanceMethods def pending_question?(user) self.open_questions.find(:all).each do |question| @@ -84,7 +25,7 @@ def pending_question?(user) end return false end - + def close_pending_questions(user, closing_journal) self.open_questions.find(:all).each do |question| question.close!(closing_journal) if question.assigned_to == user || question.for_anyone? @@ -97,5 +38,98 @@ def formatted_questions end.join(", ") end end -end + module ActiveRecord + def self.enable + require 'active_record' + + ::ActiveRecord::Calculations.class_eval do + alias_method :count_before_question, :count + alias_method :sum_before_question, :sum + + def count(*args) + QuestionIssuePatch::ActiveRecord::HelperMethods.scan_for_options_hash_and_add_includes_if_needed(self.klass, args) + count_before_question(*args) + end + + def sum(*args) + QuestionIssuePatch::ActiveRecord::HelperMethods.scan_for_options_hash_and_add_includes_if_needed(self.klass, args) + sum_before_question(*args) + end + end + + ::ActiveRecord::FinderMethods.class_eval do + alias_method :find_before_question, :find + alias_method :find_ids_before_question, :find_ids + + def find(*args) + QuestionIssuePatch::ActiveRecord::HelperMethods.scan_for_options_hash_and_add_includes_if_needed(self.klass, args) + find_before_question(*args) + end + + def find_ids(*args) + relation = scan_where_clauses_and_add_includes_if_needed + relation.find_ids_before_question(*args) + end + + private + + def scan_where_clauses_and_add_includes_if_needed + relation = self + # Ensure passed class inherits from the Issue class + if relation.klass <= Issue + @where_values.each do |where_value| + if where_value.is_a?(String) && where_value.include?('question') + relation = relation.includes(:questions) + elsif where_value.is_a?(Array) && where_value[0].include?('question') + relation = relation.includes(:questions) + end + end + end + relation + end + end + end + + class HelperMethods + class << self + # Finds the options hash. If question is part of the conditions then + # add questions to the includes + def scan_for_options_hash_and_add_includes_if_needed(klass, args) + # Ensure passed class inherits from the Issue class + if klass <= Issue + args.each do |arg| + if arg.is_a?(Hash) && arg[:conditions] + if arg[:conditions].is_a?(String) && arg[:conditions].include?('question') + # String conditions + add_questions_to_the_includes(arg) + elsif arg[:conditions].is_a?(Array) && arg[:conditions][0].include?('question') + # Array conditions + add_questions_to_the_includes(arg) + end + end + end + end + end + + private + + def add_questions_to_the_includes(arg) + if arg[:include] + # Has includes + if arg[:include].is_a?(Hash) + # Hash includes + arg[:include] << :questions + else + # single includes + arg[:include] = [ arg[:include] , :questions ] + end + else + # No includes + arg[:include] = :questions + end + end + end + end + end +end diff --git a/lib/question_journal_hooks.rb b/lib/question_journal_hooks.rb index 66ff203..c1c80c8 100644 --- a/lib/question_journal_hooks.rb +++ b/lib/question_journal_hooks.rb @@ -9,7 +9,7 @@ def view_journals_notes_form_after_notes(context = { }) o = '' o << content_tag(:p, - " " + + " ".html_safe + text_field_tag('question[assigned_to]', assigned_to, :size => "40")) o << content_tag(:div,'', :id => "question_assigned_to_choices", :class => "autocomplete") diff --git a/lib/question_plugin/patches/journal_observer_patch.rb b/lib/question_plugin/patches/journal_observer_patch.rb index 9a64d52..0d3f1b5 100644 --- a/lib/question_plugin/patches/journal_observer_patch.rb +++ b/lib/question_plugin/patches/journal_observer_patch.rb @@ -19,21 +19,18 @@ module InstanceMethods def after_create_with_question(journal) after_create_without_question(journal) - if journal.is_a?(IssueJournal) + if journal.is_a?(Journal) if journal.question journal.question.save QuestionMailer.deliver_asked_question(journal) end # Close any open questions - if journal.journaled.present? && journal.journaled.pending_question?(journal.user) - journal.journaled.close_pending_questions(journal.user, journal) + if journal.issue.present? && journal.issue.pending_question?(journal.user) + journal.issue.close_pending_questions(journal.user, journal) end end - - end - end end end diff --git a/lib/question_query_patch.rb b/lib/question_query_patch.rb index 20ff601..04603b7 100644 --- a/lib/question_query_patch.rb +++ b/lib/question_query_patch.rb @@ -7,18 +7,17 @@ def self.included(base) # :nodoc: # Same as typing in the class base.class_eval do unloadable # Send unloadable so it will not be unloaded in development + base.add_available_column(QueryColumn.new(:formatted_questions)) - alias_method :available_filters_before_question, :available_filters alias_method :available_filters, :question_available_filters alias_method :sql_for_field_before_question, :sql_for_field alias_method :sql_for_field, :question_sql_for_field end - end - + module ClassMethods unless Query.respond_to?(:available_columns=) # Setter for +available_columns+ that isn't provided by the core. @@ -36,7 +35,6 @@ def add_available_column(column) end module InstanceMethods - # Wrapper around the +available_filters+ to add a new Question filter def question_available_filters @available_filters = available_filters_before_question @@ -69,7 +67,6 @@ def question_sql_for_field(field, operator, v, db_table, db_field, is_custom_fil db_field = 'author_id' end - # "me" value subsitution v.push(User.current.logged? ? User.current.id.to_s : "0") if v.delete("me") @@ -81,13 +78,9 @@ def question_sql_for_field(field, operator, v, db_table, db_field, is_custom_fil end return sql - else return sql_for_field_before_question(field, operator, v, db_table, db_field, is_custom_filter) end - end - end end - diff --git a/test/integration/answering_question_test.rb b/test/integration/answering_question_test.rb index 38feded..f8b81ef 100644 --- a/test/integration/answering_question_test.rb +++ b/test/integration/answering_question_test.rb @@ -10,9 +10,7 @@ class AnsweringQuestionTest < ActionController::IntegrationTest @question = Question.new(:assigned_to => @author, :author => @author, :issue => @issue) @issue.journal_notes = "Question" - @issue.extra_journal_attributes = { - :question => @question - } + @issue.question = @question assert @issue.save ActionMailer::Base.deliveries.clear end diff --git a/test/integration/asking_question_test.rb b/test/integration/asking_question_test.rb index 8f7ab2e..d56b42e 100644 --- a/test/integration/asking_question_test.rb +++ b/test/integration/asking_question_test.rb @@ -10,9 +10,7 @@ class AskingQuestionTest < ActionController::IntegrationTest @issue = Issue.generate_for_project!(@project) @issue.journal_notes = "Question" - @issue.extra_journal_attributes = { - :question => Question.new(:assigned_to => @author, :author => @author, :issue => @issue) - } + @issue.question = Question.new(:assigned_to => @author, :author => @author, :issue => @issue) assert_difference("Question.count") do assert @issue.save diff --git a/test/integration/mail_handler_test.rb b/test/integration/mail_handler_test.rb index 18cf653..9a03940 100644 --- a/test/integration/mail_handler_test.rb +++ b/test/integration/mail_handler_test.rb @@ -12,7 +12,7 @@ class MailHandlerTest < ActionController::IntegrationTest @issue = Issue.generate_for_project!(@project) @question = Question.new(:issue => @issue, :author => @asker, :assigned_to => @responder) @issue.journal_notes = "Test" - @issue.extra_journal_attributes = { :question => @question } + @issue.question = @question assert @issue.save @question_journal = @issue.journals.last diff --git a/test/integration/my_page_blocks_test.rb b/test/integration/my_page_blocks_test.rb index 3631c5a..47e2877 100644 --- a/test/integration/my_page_blocks_test.rb +++ b/test/integration/my_page_blocks_test.rb @@ -9,7 +9,7 @@ def setup @question = Question.new(:issue => @issue, :author => @me, :assigned_to => @me) @issue.journal_notes = "Test" @issue.journal_user = @me - @issue.extra_journal_attributes = { :question => @question } + @issue.question = @question assert @issue.save @question_journal = @issue.journals.last end diff --git a/test/integration/question_plugin/hooks/question_issue_hooks_test.rb b/test/integration/question_plugin/hooks/question_issue_hooks_test.rb index b070571..5980624 100644 --- a/test/integration/question_plugin/hooks/question_issue_hooks_test.rb +++ b/test/integration/question_plugin/hooks/question_issue_hooks_test.rb @@ -103,7 +103,7 @@ def call_hook(context) @issue = Issue.generate_for_project!(@project) @question = Question.new(:author => @user1, :assigned_to => @user1, :opened => true, :issue => @issue) @issue.journal_notes = "A note" - @issue.extra_journal_attributes = { :question => @question } + @issue.question = @question assert @issue.save @journal = @issue.journals.last User.add_to_project(@user1, @project, Role.generate!(:permissions => [:view_issues, :add_issues, :edit_issues])) diff --git a/test/test_helper.rb b/test/test_helper.rb index e4c3ddb..087988f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,9 +1,5 @@ # Load the normal Rails helper -require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper') - -# Ensure that we are using the temporary fixture path -Engines::Testing.set_fixture_path - +require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper') require "webrat" diff --git a/test/unit/lib/question_plugin/patches/queries_helper_patch_test.rb b/test/unit/lib/question_plugin/patches/queries_helper_patch_test.rb index f8bb367..665e252 100644 --- a/test/unit/lib/question_plugin/patches/queries_helper_patch_test.rb +++ b/test/unit/lib/question_plugin/patches/queries_helper_patch_test.rb @@ -34,7 +34,7 @@ def for_assert_select(response_text) @assignee = User.generate! @question = Question.new(:issue => @issue, :author => @author, :assigned_to => @assignee) @issue.journal_notes = @content - @issue.extra_journal_attributes = { :question => @question } + @issue.question = @question assert @issue.save @questions = [@question] end @@ -82,12 +82,12 @@ def for_assert_select(response_text) @question_two = Question.new(:issue => @issue, :author => @author, :assigned_to => @assignee) @issue.journal_notes = @content_one - @issue.extra_journal_attributes = { :question => @question } + @issue.question = @question assert @issue.save && @issue.reload @journal_one = @issue.journals.last @issue.journal_notes = @content_two - @issue.extra_journal_attributes = { :question => @question_two } + @issue.question = @question_two assert @issue.save && @issue.reload @journal_two = @issue.journals.last @@ -116,7 +116,7 @@ def for_assert_select(response_text) @assignee = User.generate! @question = Question.new(:issue => @issue, :author => @author, :assigned_to => @assignee) @issue.journal_notes = "A question" - @issue.extra_journal_attributes = { :question => @question } + @issue.question = @question assert @issue.save end diff --git a/test/unit/question_mailer_test.rb b/test/unit/question_mailer_test.rb index 03252b3..f0f7a12 100644 --- a/test/unit/question_mailer_test.rb +++ b/test/unit/question_mailer_test.rb @@ -13,7 +13,7 @@ class QuestionMailerTest < ActiveSupport::TestCase @issue = Issue.generate_for_project!(@project, :subject => "Add new stuff") @question = Question.new(:assigned_to => @user, :author => @author, :issue => @issue) @issue.journal_notes = "This is the question for the user" - @issue.extra_journal_attributes = { :question => @question } + @issue.question = @question assert @issue.save @journal = @issue.journals.last @@ -81,7 +81,7 @@ class QuestionMailerTest < ActiveSupport::TestCase @question = Question.new(:assigned_to => nil, :author => @author, :issue => @issue) @issue.journal_notes = "This is the question for the user" - @issue.extra_journal_attributes = { :question => @question } + @issue.question = @question assert @issue.save @journal = @issue.journals.last @@ -101,7 +101,7 @@ class QuestionMailerTest < ActiveSupport::TestCase @question = Question.new(:assigned_to => @user, :author => @author, :issue => @issue) @issue.journal_notes = "This is the question for the user" - @issue.extra_journal_attributes = { :question => @question } + @issue.question = @question assert @issue.save @journal_with_question = @issue.journals.last From c5a171eb93410571512670fb278397e84133986b Mon Sep 17 00:00:00 2001 From: Stephen Leavitt Date: Mon, 11 Jun 2012 11:55:10 -0500 Subject: [PATCH 05/66] @journal.render_detail is not present in Redmine, probably a hold-over from the Chili Project. Changed to use show_detail helper instead. --- app/views/question_mailer/answered_question.text.erb | 2 +- app/views/question_mailer/asked_question.html.erb | 2 +- app/views/question_mailer/asked_question.text.erb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/question_mailer/answered_question.text.erb b/app/views/question_mailer/answered_question.text.erb index c8ab12a..d49a853 100644 --- a/app/views/question_mailer/answered_question.text.erb +++ b/app/views/question_mailer/answered_question.text.erb @@ -6,7 +6,7 @@
    <% for detail in @journal.details %> -
  • <%= @journal.render_detail(detail, true) %>
  • +
  • <%= show_detail(detail, true) %>
  • <% end %>
diff --git a/app/views/question_mailer/asked_question.html.erb b/app/views/question_mailer/asked_question.html.erb index 81a6ad9..c2ebcd2 100644 --- a/app/views/question_mailer/asked_question.html.erb +++ b/app/views/question_mailer/asked_question.html.erb @@ -4,7 +4,7 @@
    <% for detail in @journal.details %> -
  • <%= @journal.render_detail(detail, true) %>
  • +
  • <%= show_detail(detail, true) %>
  • <% end %>
diff --git a/app/views/question_mailer/asked_question.text.erb b/app/views/question_mailer/asked_question.text.erb index 854561f..11cb002 100644 --- a/app/views/question_mailer/asked_question.text.erb +++ b/app/views/question_mailer/asked_question.text.erb @@ -3,7 +3,7 @@ <%= @journal.notes if @journal.notes? %> <% for detail in @journal.details -%> -<%= @journal.render_detail(detail, true) %> +<%= show_detail(detail, true) %> <% end -%> ---------------------------------------- From ccc828c50a41efb447b9d0acf3ba3fea9a8e9b81 Mon Sep 17 00:00:00 2001 From: Stephen Leavitt Date: Fri, 22 Jun 2012 17:50:40 -0500 Subject: [PATCH 06/66] Refactored ActiveRecord::Relation patches to avoid issues relating scope of included files, classes, etc. --- init.rb | 3 + lib/question_active_record_relation_patch.rb | 96 ++++++++++++++++++++ lib/question_issue_patch.rb | 96 -------------------- 3 files changed, 99 insertions(+), 96 deletions(-) create mode 100644 lib/question_active_record_relation_patch.rb diff --git a/init.rb b/init.rb index 2616d4a..d77899a 100644 --- a/init.rb +++ b/init.rb @@ -9,6 +9,9 @@ require_dependency 'journal_observer' JournalObserver.send(:include, QuestionPlugin::Patches::JournalObserverPatch) unless JournalObserver.included_modules.include? QuestionPlugin::Patches::JournalObserverPatch + require_dependency 'active_record' + ActiveRecord::Relation.send(:include, QuestionActiveRecordRelationPatch) unless ActiveRecord::Relation.included_modules.include? QuestionActiveRecordRelationPatch + require_dependency 'issue' Issue.send(:include, QuestionIssuePatch) unless Issue.included_modules.include? QuestionIssuePatch diff --git a/lib/question_active_record_relation_patch.rb b/lib/question_active_record_relation_patch.rb new file mode 100644 index 0000000..7f8babd --- /dev/null +++ b/lib/question_active_record_relation_patch.rb @@ -0,0 +1,96 @@ +module QuestionActiveRecordRelationPatch + def self.included(base) # :nodoc: + base.extend(ClassMethods) + + base.send(:include, InstanceMethods) + + base.class_eval do + unloadable # Send unloadable so it will not be unloaded in development + + alias_method :count_before_question, :count + alias_method :sum_before_question, :sum + alias_method :find_before_question, :find + alias_method :find_ids_before_question, :find_ids + + # Override ActiveRecord::Calculations.count + def count(*args) + scan_for_options_hash_and_add_includes_if_needed(self.klass, args) + count_before_question(*args) + end + + # Override ActiveRecord::Calculations.sum + def sum(*args) + scan_for_options_hash_and_add_includes_if_needed(self.klass, args) + sum_before_question(*args) + end + + # Override ActiveRecord::FinderMethods.find + def find(*args) + scan_for_options_hash_and_add_includes_if_needed(self.klass, args) + find_before_question(*args) + end + + # Override ActiveRecord::FinderMethods.find_ids + def find_ids(*args) + relation = scan_where_clauses_and_add_includes_if_needed + relation.find_ids_before_question(*args) + end + + private + + def scan_where_clauses_and_add_includes_if_needed + relation = self + # Ensure passed class inherits from the Issue class + if relation.klass <= Issue + @where_values.each do |where_value| + if where_value.is_a?(String) && where_value.include?('question') + relation = relation.includes(:questions) + elsif where_value.is_a?(Array) && where_value[0].include?('question') + relation = relation.includes(:questions) + end + end + end + relation + end + + def scan_for_options_hash_and_add_includes_if_needed(klass, args) + # Ensure passed class inherits from the Issue class + if klass <= Issue + args.each do |arg| + if arg.is_a?(Hash) && arg[:conditions] + if arg[:conditions].is_a?(String) && arg[:conditions].include?('question') + # String conditions + add_questions_to_the_includes(arg) + elsif arg[:conditions].is_a?(Array) && arg[:conditions][0].include?('question') + # Array conditions + add_questions_to_the_includes(arg) + end + end + end + end + end + + def add_questions_to_the_includes(arg) + if arg[:include] + # Has includes + if arg[:include].is_a?(Hash) + # Hash includes + arg[:include] << :questions + else + # single includes + arg[:include] = [ arg[:include] , :questions ] + end + else + # No includes + arg[:include] = :questions + end + end + end + end + + module ClassMethods + end + + module InstanceMethods + end +end diff --git a/lib/question_issue_patch.rb b/lib/question_issue_patch.rb index 81bbe4b..0e75c30 100644 --- a/lib/question_issue_patch.rb +++ b/lib/question_issue_patch.rb @@ -11,8 +11,6 @@ def self.included(base) # :nodoc: include ActionView::Helpers::TextHelper # for truncate end - - QuestionIssuePatch::ActiveRecord.enable end module ClassMethods @@ -38,98 +36,4 @@ def formatted_questions end.join(", ") end end - - module ActiveRecord - def self.enable - require 'active_record' - - ::ActiveRecord::Calculations.class_eval do - alias_method :count_before_question, :count - alias_method :sum_before_question, :sum - - def count(*args) - QuestionIssuePatch::ActiveRecord::HelperMethods.scan_for_options_hash_and_add_includes_if_needed(self.klass, args) - count_before_question(*args) - end - - def sum(*args) - QuestionIssuePatch::ActiveRecord::HelperMethods.scan_for_options_hash_and_add_includes_if_needed(self.klass, args) - sum_before_question(*args) - end - end - - ::ActiveRecord::FinderMethods.class_eval do - alias_method :find_before_question, :find - alias_method :find_ids_before_question, :find_ids - - def find(*args) - QuestionIssuePatch::ActiveRecord::HelperMethods.scan_for_options_hash_and_add_includes_if_needed(self.klass, args) - find_before_question(*args) - end - - def find_ids(*args) - relation = scan_where_clauses_and_add_includes_if_needed - relation.find_ids_before_question(*args) - end - - private - - def scan_where_clauses_and_add_includes_if_needed - relation = self - # Ensure passed class inherits from the Issue class - if relation.klass <= Issue - @where_values.each do |where_value| - if where_value.is_a?(String) && where_value.include?('question') - relation = relation.includes(:questions) - elsif where_value.is_a?(Array) && where_value[0].include?('question') - relation = relation.includes(:questions) - end - end - end - relation - end - end - end - - class HelperMethods - class << self - # Finds the options hash. If question is part of the conditions then - # add questions to the includes - def scan_for_options_hash_and_add_includes_if_needed(klass, args) - # Ensure passed class inherits from the Issue class - if klass <= Issue - args.each do |arg| - if arg.is_a?(Hash) && arg[:conditions] - if arg[:conditions].is_a?(String) && arg[:conditions].include?('question') - # String conditions - add_questions_to_the_includes(arg) - elsif arg[:conditions].is_a?(Array) && arg[:conditions][0].include?('question') - # Array conditions - add_questions_to_the_includes(arg) - end - end - end - end - end - - private - - def add_questions_to_the_includes(arg) - if arg[:include] - # Has includes - if arg[:include].is_a?(Hash) - # Hash includes - arg[:include] << :questions - else - # single includes - arg[:include] = [ arg[:include] , :questions ] - end - else - # No includes - arg[:include] = :questions - end - end - end - end - end end From b41980f4dc73ec2f94c8ba6f68b3938b27e66997 Mon Sep 17 00:00:00 2001 From: Stephen Leavitt Date: Tue, 10 Jul 2012 10:54:50 -0500 Subject: [PATCH 07/66] Updated QuestionMailer patch to not use deprecated syntax. --- lib/question_plugin/patches/journal_observer_patch.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/question_plugin/patches/journal_observer_patch.rb b/lib/question_plugin/patches/journal_observer_patch.rb index 0d3f1b5..02b6b85 100644 --- a/lib/question_plugin/patches/journal_observer_patch.rb +++ b/lib/question_plugin/patches/journal_observer_patch.rb @@ -22,7 +22,7 @@ def after_create_with_question(journal) if journal.is_a?(Journal) if journal.question journal.question.save - QuestionMailer.deliver_asked_question(journal) + QuestionMailer.asked_question(journal).deliver end # Close any open questions From 2d517af7b09a0ea62b514d348b8f67a99c8a9ad6 Mon Sep 17 00:00:00 2001 From: cforce Date: Wed, 25 Jul 2012 17:13:49 +0200 Subject: [PATCH 08/66] added redmine 1.4 and 2.0 comatible routes --- config/routes.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index b4305cb..a82a72b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,3 +1,12 @@ -match 'questions/autocomplete_for_user_login/project/:id/issue/:issue_id' => 'questions#autocomplete_for_user_login', :format => false, :as => 'questions_autocomplete_for_user_login' -match 'questions/my_issue_filter(/project/:project)' => 'questions#my_issue_filter', :format => false, :as => 'questions_my_issue_filter' -match 'questions/user_issue_filter/user/:user_id' => 'questions#user_issue_filter', :format => false, :as => 'questions_user_issue_filter' +if Rails::VERSION::MAJOR < 3 + ActionController::Routing::Routes.draw do |map| + map.connect 'questions/autocomplete_for_user_login/project/:id/issue/:issue_id',:controller=> 'questions', :action=> 'autocomplete_for_user_login' + map.connect 'questions/my_issue_filter(/project/:project)' ,:controller=> 'questions', :action=> 'my_issue_filter' + map.connect 'questions/user_issue_filter/user/:user_id' ,:controller=> 'questions', :action=> 'user_issue_filter' + end +else + match 'questions/autocomplete_for_user_login/project/:id/issue/:issue_id' => 'questions#autocomplete_for_user_login', :format => false, :as => 'questions_autocomplete_for_user_login' + match 'questions/my_issue_filter(/project/:project)' => 'questions#my_issue_filter', :format => false, :as => 'questions_my_issue_filter' + match 'questions/user_issue_filter/user/:user_id' => 'questions#user_issue_filter', :format => false, :as => 'questions_user_issue_filter' +end + From ce4323a759a9dc3750ffe4cebe7983b070696787 Mon Sep 17 00:00:00 2001 From: Marek Hulan Date: Thu, 18 Oct 2012 10:17:51 +0200 Subject: [PATCH 09/66] Compatibility with redmine 2.1 --- config/locales/de.yml | 2 +- config/locales/es.yml | 10 +++--- config/locales/hu.yml | 17 ---------- lib/question_hooks_base.rb | 2 +- lib/question_issue_hooks.rb | 63 +++++++++++++++++++---------------- lib/question_journal_hooks.rb | 54 ++++++++++++++++-------------- 6 files changed, 70 insertions(+), 78 deletions(-) delete mode 100644 config/locales/hu.yml diff --git a/config/locales/de.yml b/config/locales/de.yml index 8855e80..33110cb 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -19,5 +19,5 @@ de: field_journal: "Journal" text_questions_asked_by_me: "meine gestellten Fragen" questions_asked_by_me: Meine gestellten Fragen - questions_for_me: Fragen fr mich + questions_for_me: Fragen für mich field_system_name: InfoMine \ No newline at end of file diff --git a/config/locales/es.yml b/config/locales/es.yml index 7d6384d..2525e1d 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -4,16 +4,16 @@ es: field_question_asked_by: Pregunta fue hecha cerca field_formatted_questions: Preguntas text_question: Pregunta - text_question_answered: Pregunta contest + text_question_answered: Pregunta contestó text_answer: Respuesta text_anyone: Cualquier persona text_question_for: Pregunta para text_question_for_anyone: Pregunta para cualquier persona - text_questions_for_me: Preguntas para m - text_question_asked: Pregunta pidi + text_questions_for_me: Preguntas para mí + text_question_asked: Pregunta pidió text_question_remove: "<< Quite la pregunta >>" question_text_asked_by: "Pedido Cerca" question_text_assigned_to: "Asignado A" question_text_created_on: "Creada hace" - question_text_ratio_questions_answered: "{{ratio}} Preguntas contestaron" - field_journal: "Diario" \ No newline at end of file + question_text_ratio_questions_answered: "%{ratio} Preguntas contestaron" + field_journal: "Diario" diff --git a/config/locales/hu.yml b/config/locales/hu.yml deleted file mode 100644 index ffe7d21..0000000 --- a/config/locales/hu.yml +++ /dev/null @@ -1,17 +0,0 @@ -hu: - field_question_assign_to: Kérdés hozzá - field_question_assigned_to: Kérdés hozzá - field_question_asked_by: Kérdést feltette - field_formatted_questions: Kérdések - text_question: Kérdés - text_question_answered: Kérdés megválaszolva - text_answer: Kérdés - text_anyone: - bárkihez - - text_question_for: Kérdés hozzá - text_question_for_anyone: Kérdés bárkinek - text_questions_for_me: Kérdések hozzám - text_question_asked: Feltett kérdések - text_question_remove: "kérdés törlése" - question_text_asked_by: "Kérdezte" - question_text_assigned_to: "Hozzárendelve" - question_text_created_on: "Létrehozta" diff --git a/lib/question_hooks_base.rb b/lib/question_hooks_base.rb index 5aedfcf..c3e5dca 100644 --- a/lib/question_hooks_base.rb +++ b/lib/question_hooks_base.rb @@ -1,6 +1,6 @@ class QuestionHooksBase < Redmine::Hook::ViewListener # Have to inclue Gravatars because ApplicationHelper will not get it - include Gravatarify::Helper + include GravatarHelper::PublicMethods protected diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index a58caf5..fcab7fe 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -4,7 +4,7 @@ def view_issues_history_journal_bottom(context = { }) o = '' if context[:journal] && context[:journal].question && context[:journal].question.opened? question = context[:journal].question - + if question.assigned_to html = assigned_question_html(question) else @@ -13,50 +13,55 @@ def view_issues_history_journal_bottom(context = { }) o += < - $('change-#{context[:journal].id}').addClassName('question'); - $$('#change-#{context[:journal].id} h4 div').each(function(ele) { ele.insert({ top: ' #{html} ' }) }); + $('#change-#{context[:journal].id}').addClass('question'); + $('#change-#{context[:journal].id} h4 .journal-link').prepend(' #{html} '); JS - + end return o end - + def view_issues_edit_notes_bottom(context = { }) - f = context[:form] + f = context[:form] @issue = context[:issue] - o = '' - o << content_tag(:p, + o = '' + o << content_tag(:p, " ".html_safe + - text_field_tag('note[question_assigned_to]', nil, :size => "40")) + text_field_tag('note[question_assigned_to]', nil, :size => "40")) + + users = User.active.all(:order => 'login ASC') + users = users.map {|u| "{value: '#{u.login}',label: '#{u.name(:lastname_coma_firstname)} (#{u.login})'}"}.join(',') + o << javascript_tag("$('#note_question_assigned_to').autocomplete({ + source: [#{users}] + });") + + o << content_tag(:div, '', :id => "note_question_assigned_to_choices", :class => "autocomplete") - o << content_tag(:div,'', :id => "note_question_assigned_to_choices", :class => "autocomplete") - o << javascript_tag("new Ajax.Autocompleter('note_question_assigned_to', 'note_question_assigned_to_choices', '#{ url_for(:controller => 'questions', :action => 'autocomplete_for_user_login', :id => @issue.project, :issue_id => @issue) }', { minChars: 1, frequency: 0.5, paramName: 'user', select: 'field' });") - return o end - + def controller_issues_edit_before_save(context = { }) - params = context[:params] + params = context[:params] journal = context[:journal] - issue = context[:issue] + issue = context[:issue] if params[:note] && !params[:note][:question_assigned_to].blank? unless journal.question # Update handled by Journal hooks - # New + # New journal.question = Question.new( - :author => User.current, - :issue => journal.issue - ) + :author => User.current, + :issue => journal.issue + ) if params[:note][:question_assigned_to].downcase != 'anyone' # Assigned to a specific user assign_question_to_user(journal, User.find_by_login(params[:note][:question_assigned_to])) end end end - + return '' end - + def view_issues_sidebar_issues_bottom(context = { }) project = context[:project] if project @@ -64,25 +69,25 @@ def view_issues_sidebar_issues_bottom(context = { }) else question_count = Question.count_of_open_for_user(User.current) end - + if question_count > 0 return link_to(l(:text_questions_for_me) + " (#{question_count})", { - :controller => 'questions', - :action => 'my_issue_filter', - :project => project, - :only_path => true + :controller => 'questions', + :action => 'my_issue_filter', + :project => project, + :only_path => true }, { :class => 'question-link' } - ) + '
'.html_safe + ) + '
'.html_safe else return '' end - + end private - + def assign_question_to_user(journal, user) journal.question.assigned_to = user end diff --git a/lib/question_journal_hooks.rb b/lib/question_journal_hooks.rb index c1c80c8..721dbee 100644 --- a/lib/question_journal_hooks.rb +++ b/lib/question_journal_hooks.rb @@ -6,25 +6,28 @@ def view_journals_notes_form_after_notes(context = { }) else assigned_to = '' end - + o = '' - o << content_tag(:p, + o << content_tag(:p, " ".html_safe + - text_field_tag('question[assigned_to]', assigned_to, :size => "40")) + text_field_tag('question[assigned_to]', assigned_to, :size => "40")) - o << content_tag(:div,'', :id => "question_assigned_to_choices", :class => "autocomplete") - o << javascript_tag("new Ajax.Autocompleter('question_assigned_to', 'question_assigned_to_choices', '#{ url_for(:controller => 'questions', :action => 'autocomplete_for_user_login', :id => @journal.project, :issue_id => @journal.issue) }', { minChars: 1, frequency: 0.5, paramName: 'user', select: 'field' });") + users = User.active.all(:order => 'login ASC') + users = users.map { |u| "{value: '#{u.login}',label: '#{u.name(:lastname_coma_firstname)} (#{u.login})'}" }.join(',') + o << javascript_tag("$('#question_assigned_to').autocomplete({ + source: [#{users}] + });") return o end - + def controller_journals_edit_post(context = { }) journal = context[:journal] - params = context[:params] + params = context[:params] # Handle destroying journals through the 'edit' action (done by clearing notes) return '' if journal.destroyed? - + if params[:question] && params[:question][:assigned_to] if journal.question && params[:question][:assigned_to].blank? # Wants to remove the question @@ -51,13 +54,14 @@ def controller_journals_edit_post(context = { }) end end - + return '' end - - def view_journals_update_rjs_bottom(context = { }) + + def view_journals_update_js_bottom(context = { }) @journal = context[:journal] - page = context[:page] + page = context[:page] + page = "" unless @journal.frozen? @journal.reload if @journal && @journal.question && @journal.question.opened? @@ -69,27 +73,27 @@ def view_journals_update_rjs_bottom(context = { }) html = unassigned_question_html(question) end - page << "$('change-#{@journal.id}').addClassName('question');" - page << "$$('#change-#{@journal.id} h4 div span.question-line').each(function(ele) {ele.remove()});" - page << "$$('#change-#{@journal.id} h4 div').each(function(ele) { ele.insert({ top: ' #{html} ' }) });" - + page << "$('#change-#{@journal.id}').addClass('question');" + page << "$('#change-#{@journal.id} h4 span.question-line').remove();" + page << "$('#change-#{@journal.id} h4 .journal-link').prepend(' #{html} ') ;" + elsif @journal && @journal.question.nil? # No question found, make sure the UI reflects this - page << "$('change-#{@journal.id}').removeClassName('question');" - page << "$$('#change-#{@journal.id} h4 div span.question-line').each(function(ele) {ele.remove()});" + page << "$('#change-#{@journal.id}').removeClass('question');" + page << "$('#change-#{@journal.id} h4 span.question-line').remove();" end end - return '' + return page end - + private - + def add_new_question(journal, assigned_to=nil) journal.question = Question.new( - :author => User.current, - :issue => journal.issue, - :assigned_to => assigned_to - ) + :author => User.current, + :issue => journal.issue, + :assigned_to => assigned_to + ) journal.question.save! journal.save end From 461d304416dac1b8281bec415ddf2d5a12ab5e8d Mon Sep 17 00:00:00 2001 From: Thorin Date: Thu, 25 Oct 2012 00:25:59 +0200 Subject: [PATCH 10/66] Fixed question filtering/ordering and locales encoding --- config/locales/de.yml | 30 ++++++++++++++-------------- config/locales/es.yml | 26 ++++++++++++------------ config/locales/hu.yml | 17 ++++++++++++++++ lib/question_queries_helper_patch.rb | 2 +- lib/question_query_patch.rb | 28 ++++++++++---------------- 5 files changed, 57 insertions(+), 46 deletions(-) create mode 100644 config/locales/hu.yml diff --git a/config/locales/de.yml b/config/locales/de.yml index 33110cb..0ed7de9 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1,16 +1,16 @@ de: - field_question_assign_to: Frage zuweisen an - field_question_assigned_to: Frage ist gestellt an - field_question_asked_by: Frage wurde gestellt durch - field_formatted_questions: Fragen - text_question: Frage - text_question_answered: Frage beantwortet - text_answer: Antwort - text_anyone: Irgendwer - text_question_for: Frage für - text_question_for_anyone: Frage für irgendjemanden - text_questions_for_me: Fragen für mich - text_question_asked: Frage gestellt + field_question_assign_to: "Frage zuweisen an" + field_question_assigned_to: "Frage ist gestellt an" + field_question_asked_by: "Frage wurde gestellt durch" + field_formatted_questions: "Fragen" + text_question: "Frage" + text_question_answered: "Frage beantwortet" + text_answer: "Antwort" + text_anyone: "Irgendwer" + text_question_for: "Frage für" + text_question_for_anyone: "Frage für irgendjemanden" + text_questions_for_me: "Fragen für mich" + text_question_asked: "Frage gestellt" text_question_remove: "<>" question_text_asked_by: "gefragt von" question_text_assigned_to: "Zugewiesen an" @@ -18,6 +18,6 @@ de: question_text_ratio_questions_answered: "{{ratio}} beantwortete Fragen" field_journal: "Journal" text_questions_asked_by_me: "meine gestellten Fragen" - questions_asked_by_me: Meine gestellten Fragen - questions_for_me: Fragen für mich - field_system_name: InfoMine \ No newline at end of file + questions_asked_by_me: "Meine gestellten Fragen" + questions_for_me: "Fragen für mich" + field_system_name: "InfoMine" diff --git a/config/locales/es.yml b/config/locales/es.yml index 2525e1d..b30e402 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,19 +1,19 @@ es: - field_question_assign_to: Asigne la pregunta a - field_question_assigned_to: Pregunata se asigna a - field_question_asked_by: Pregunta fue hecha cerca - field_formatted_questions: Preguntas - text_question: Pregunta - text_question_answered: Pregunta contestó - text_answer: Respuesta - text_anyone: Cualquier persona - text_question_for: Pregunta para - text_question_for_anyone: Pregunta para cualquier persona - text_questions_for_me: Preguntas para mí - text_question_asked: Pregunta pidió + field_question_assign_to: "Asigne la pregunta a" + field_question_assigned_to: "Pregunata se asigna a" + field_question_asked_by: "Pregunta fue hecha cerca" + field_formatted_questions: "Preguntas" + text_question: "Pregunta" + text_question_answered: "Pregunta contestó" + text_answer: "Respuesta" + text_anyone: "Cualquier persona" + text_question_for: "Pregunta para" + text_question_for_anyone: "Pregunta para cualquier persona" + text_questions_for_me: "Preguntas para mí" + text_question_asked: "Pregunta pidió" text_question_remove: "<< Quite la pregunta >>" question_text_asked_by: "Pedido Cerca" question_text_assigned_to: "Asignado A" question_text_created_on: "Creada hace" - question_text_ratio_questions_answered: "%{ratio} Preguntas contestaron" + question_text_ratio_questions_answered: "{{ratio}} Preguntas contestaron" field_journal: "Diario" diff --git a/config/locales/hu.yml b/config/locales/hu.yml new file mode 100644 index 0000000..4ecc704 --- /dev/null +++ b/config/locales/hu.yml @@ -0,0 +1,17 @@ +hu: + field_question_assign_to: "Kérdés hozzá" + field_question_assigned_to: "Kérdés hozzá" + field_question_asked_by: "Kérdést feltette" + field_formatted_questions: "Kérdések" + text_question: "Kérdés" + text_question_answered: "Kérdés megválaszolva" + text_answer: "Kérdés" + text_anyone: "- bárkihez -" + text_question_for: "Kérdés hozzá" + text_question_for_anyone: "Kérdés bárkinek" + text_questions_for_me: "Kérdések hozzám" + text_question_asked: "Feltett kérdések" + text_question_remove: "kérdés törlése" + question_text_asked_by: "Kérdezte" + question_text_assigned_to: "Hozzárendelve" + question_text_created_on: "Létrehozta" diff --git a/lib/question_queries_helper_patch.rb b/lib/question_queries_helper_patch.rb index 35a3bac..933be95 100644 --- a/lib/question_queries_helper_patch.rb +++ b/lib/question_queries_helper_patch.rb @@ -29,7 +29,7 @@ def format_questions(questions) html << "
  • " html << "
    " html << " " - html << link_to(h(truncate(question.journal.notes, Question::TruncateTo)), + html << link_to(h(truncate(question.journal.notes, :length => Question::TruncateTo)), :controller => 'issues', :action => 'show', :id => question.issue, diff --git a/lib/question_query_patch.rb b/lib/question_query_patch.rb index 04603b7..453cdfe 100644 --- a/lib/question_query_patch.rb +++ b/lib/question_query_patch.rb @@ -9,9 +9,8 @@ def self.included(base) # :nodoc: unloadable # Send unloadable so it will not be unloaded in development base.add_available_column(QueryColumn.new(:formatted_questions)) - - alias_method :available_filters_before_question, :available_filters - alias_method :available_filters, :question_available_filters + + alias_method_chain :available_filters, :question alias_method :sql_for_field_before_question, :sql_for_field alias_method :sql_for_field, :question_sql_for_field @@ -36,23 +35,18 @@ def add_available_column(column) module InstanceMethods # Wrapper around the +available_filters+ to add a new Question filter - def question_available_filters - @available_filters = available_filters_before_question + def available_filters_with_question + return @available_filters if @available_filters + available_filters_without_question - user_values = [] - user_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? - if project - user_values += project.users.sort.collect{|s| [s.name, s.id.to_s] } - else - user_values += User.current.projects.collect(&:users).flatten.uniq.sort.collect{|s| [s.name, s.id.to_s] } - end + if @available_filters["assigned_to_id"] + user_values = @available_filters["assigned_to_id"][:values] - question_filters = { - "question_assigned_to_id" => { :type => :list, :order => 14, :values => user_values }, - "question_asked_by_id" => { :type => :list, :order => 14, :values => user_values } - } + @available_filters["question_assigned_to_id"] = { :name => l("question_text_assigned_to"), :type => :list_optional, :order => 16, :values => user_values } + @available_filters["question_asked_by_id"] = { :name => l("question_text_asked_by"), :type => :list_optional, :order => 16, :values => user_values } + end - return @available_filters.merge(question_filters) + @available_filters end # Wrapper for +sql_for_field+ so Questions can use a different table than Issues From a1dec3eee96ea2c5668fce49b4d1f73c01cec59c Mon Sep 17 00:00:00 2001 From: Thorin Date: Mon, 5 Nov 2012 21:59:53 +0100 Subject: [PATCH 11/66] Disabled gravatar of the inquired user: bronken since we don't have access to the request on the hook --- lib/question_hooks_base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/question_hooks_base.rb b/lib/question_hooks_base.rb index c3e5dca..fc8da05 100644 --- a/lib/question_hooks_base.rb +++ b/lib/question_hooks_base.rb @@ -9,7 +9,7 @@ def assigned_question_html(question) html << " " html << "#{l(:text_question_for)} #{question.assigned_to.to_s}" html << " " - html << "#{avatar(question.assigned_to, { :size => 16, :class => '' })} " if question.assigned_to && question.assigned_to.mail + html << "" html end From 0775f5e8ca4cc9cc5996baf971a8fcb34af39aad Mon Sep 17 00:00:00 2001 From: Marek Hulan Date: Wed, 14 Nov 2012 13:49:23 +0100 Subject: [PATCH 12/66] Czech translation --- config/locales/cs.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 config/locales/cs.yml diff --git a/config/locales/cs.yml b/config/locales/cs.yml new file mode 100644 index 0000000..477a821 --- /dev/null +++ b/config/locales/cs.yml @@ -0,0 +1,23 @@ +en: + field_question_assign_to: Přiřadit otázku + field_question_assigned_to: Otázka přiřazena + field_question_asked_by: Otázku položil + field_formatted_questions: Otázky + text_question: Otázka + text_question_answered: Otázka zodpovězena + text_answer: Odpověď + text_anyone: Kdokoliv + text_question_for: Otázka pro + text_question_for_anyone: Otázka pro kohokoliv + text_questions_for_me: Otázky pro mě + text_question_asked: Položené otázky + text_question_remove: "<< Odstranit Otázku>>" + question_text_asked_by: "Položeno" + question_text_assigned_to: "Přiřazeno" + question_text_created_on: "Vytvořeno" + question_text_ratio_questions_answered: "{{ratio}} zodpovězených otázek" + field_journal: "Žurnál" + text_questions_asked_by_me: "Otázky položené mnou" + question_reminder_subject: "%{count} nezodpovězených otázek" + question_reminder_body: "%{count} Vám položených nezodpovězených otázek:" + From 41074b597d2f35651b09de851d207bc79d088523 Mon Sep 17 00:00:00 2001 From: Marek Hulan Date: Wed, 14 Nov 2012 14:12:49 +0100 Subject: [PATCH 13/66] Added missing czech translation Also ungermanize answer subject :) --- app/models/question_mailer.rb | 2 +- config/locales/cs.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/question_mailer.rb b/app/models/question_mailer.rb index af98178..7431502 100644 --- a/app/models/question_mailer.rb +++ b/app/models/question_mailer.rb @@ -25,7 +25,7 @@ def asked_question(journal) def answered_question(question, closing_journal) from = question.assigned_to ? "#{question.assigned_to.name} (#{l(:field_system_name)}) <#{Setting.mail_from}>" : nil to = question.author ? question.author.mail : nil - subject = "[Antwort #{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" + subject = "[#{I18n.t(:text_answer)} #{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" @from = "#{question.assigned_to.name} (#{l(:field_system_name)}) <#{Setting.mail_from}>" unless question.assigned_to.nil? @question = question diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 477a821..11a1cf6 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -20,4 +20,4 @@ en: text_questions_asked_by_me: "Otázky položené mnou" question_reminder_subject: "%{count} nezodpovězených otázek" question_reminder_body: "%{count} Vám položených nezodpovězených otázek:" - + field_system_name: igloonet, s.r.o. From 776485ffd1746c755204a47326d74d03e0e93cd1 Mon Sep 17 00:00:00 2001 From: Marek Hulan Date: Wed, 14 Nov 2012 15:25:28 +0100 Subject: [PATCH 14/66] Limit autocomplete users only to members of a given project --- app/controllers/questions_controller.rb | 13 ++++++++----- lib/question_issue_hooks.rb | 2 +- lib/question_journal_hooks.rb | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/controllers/questions_controller.rb b/app/controllers/questions_controller.rb index 16e9c4e..4207886 100644 --- a/app/controllers/questions_controller.rb +++ b/app/controllers/questions_controller.rb @@ -14,17 +14,20 @@ def user_issue_filter end def autocomplete_for_user_login + if params[:issue_id] + @issue = Issue.find_by_id(params[:issue_id]) + base = issue.project.users + else + User + end if params[:user] - @users = User.active.all(:conditions => ["LOWER(login) LIKE :user OR LOWER(firstname) LIKE :user OR LOWER(lastname) LIKE :user", {:user => params[:user]+"%" }], + @users = base.active.all(:conditions => ["LOWER(login) LIKE :user OR LOWER(firstname) LIKE :user OR LOWER(lastname) LIKE :user", {:user => params[:user]+"%" }], :limit => 10, :order => 'login ASC') end @users ||=[] - if params[:issue_id] - @issue = Issue.find_by_id(params[:issue_id]) - end - render :layout => false + render :layout => false end private diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index fcab7fe..a511abb 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -30,7 +30,7 @@ def view_issues_edit_notes_bottom(context = { }) " ".html_safe + text_field_tag('note[question_assigned_to]', nil, :size => "40")) - users = User.active.all(:order => 'login ASC') + users = @issue.project.users.active.all(:order => 'login ASC') users = users.map {|u| "{value: '#{u.login}',label: '#{u.name(:lastname_coma_firstname)} (#{u.login})'}"}.join(',') o << javascript_tag("$('#note_question_assigned_to').autocomplete({ source: [#{users}] diff --git a/lib/question_journal_hooks.rb b/lib/question_journal_hooks.rb index 721dbee..845155a 100644 --- a/lib/question_journal_hooks.rb +++ b/lib/question_journal_hooks.rb @@ -12,7 +12,7 @@ def view_journals_notes_form_after_notes(context = { }) " ".html_safe + text_field_tag('question[assigned_to]', assigned_to, :size => "40")) - users = User.active.all(:order => 'login ASC') + users = @journal.issue.project.users.active.all(:order => 'login ASC') users = users.map { |u| "{value: '#{u.login}',label: '#{u.name(:lastname_coma_firstname)} (#{u.login})'}" }.join(',') o << javascript_tag("$('#question_assigned_to').autocomplete({ source: [#{users}] From 93e5892951752cc056ecc4d56c9a1a4f6c6660bd Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Tue, 18 Dec 2012 11:40:37 +0200 Subject: [PATCH 15/66] Russian translation added --- config/locales/ru.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 config/locales/ru.yml diff --git a/config/locales/ru.yml b/config/locales/ru.yml new file mode 100644 index 0000000..4e8d5f2 --- /dev/null +++ b/config/locales/ru.yml @@ -0,0 +1,22 @@ +ru: + field_question_assign_to: Спросить у + field_question_assigned_to: Вопрос к + field_question_asked_by: Вопрос задал + field_formatted_questions: Вопросы + text_question: Вопрос + text_question_answered: Вопрос отвечен + text_answer: Ответ + text_anyone: Все + text_question_for: Вопрос к + text_question_for_anyone: Вопрос ко всем + text_questions_for_me: Вопросы ко мне + text_question_asked: Вопрос задан + text_question_remove: "<< Удалить вопрос >>" + question_text_asked_by: "Задан" + question_text_assigned_to: "Назначен" + question_text_created_on: "Создан" + question_text_ratio_questions_answered: "{{ratio}} вопросов отвечено" + field_journal: "Journal" + text_questions_asked_by_me: "Вопросы заданные мной" + question_reminder_subject: "%{count} не отвеченных вопросов" + question_reminder_body: "%{count} не отвеченных вопросов заданных Вам:" From f292b311b4240f9e58f1b2a94f7f644b27d40e32 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Tue, 18 Dec 2012 12:31:06 +0200 Subject: [PATCH 16/66] More elegant look --- lib/question_hooks_base.rb | 9 +++------ lib/question_issue_hooks.rb | 2 +- lib/question_journal_hooks.rb | 2 +- lib/question_layout_hooks.rb | 1 + 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/question_hooks_base.rb b/lib/question_hooks_base.rb index c3e5dca..b984bcc 100644 --- a/lib/question_hooks_base.rb +++ b/lib/question_hooks_base.rb @@ -6,18 +6,15 @@ class QuestionHooksBase < Redmine::Hook::ViewListener def assigned_question_html(question) html = "" - html << " " - html << "#{l(:text_question_for)} #{question.assigned_to.to_s}" - html << " " - html << "#{avatar(question.assigned_to, { :size => 16, :class => '' })} " if question.assigned_to && question.assigned_to.mail + html << " #{l(:text_question_for)} " + html << link_to_user(question.assigned_to) + html << " #{avatar(question.assigned_to, { :size => 24, :class => '' })} " if question.assigned_to && question.assigned_to.mail html end def unassigned_question_html(question) html = "" - html << " " html << l(:text_question_for_anyone) - html << " " html << "" html end diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index a511abb..731a10c 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -14,7 +14,7 @@ def view_issues_history_journal_bottom(context = { }) o += < $('#change-#{context[:journal].id}').addClass('question'); - $('#change-#{context[:journal].id} h4 .journal-link').prepend(' #{html} '); + $('#change-#{context[:journal].id} h4 .journal-link').after(' #{html} '); JS diff --git a/lib/question_journal_hooks.rb b/lib/question_journal_hooks.rb index 845155a..006ab7c 100644 --- a/lib/question_journal_hooks.rb +++ b/lib/question_journal_hooks.rb @@ -75,7 +75,7 @@ def view_journals_update_js_bottom(context = { }) page << "$('#change-#{@journal.id}').addClass('question');" page << "$('#change-#{@journal.id} h4 span.question-line').remove();" - page << "$('#change-#{@journal.id} h4 .journal-link').prepend(' #{html} ') ;" + page << "$('#change-#{@journal.id} h4 .journal-link').after(' #{html} ') ;" elsif @journal && @journal.question.nil? # No question found, make sure the UI reflects this diff --git a/lib/question_layout_hooks.rb b/lib/question_layout_hooks.rb index 2870471..057a62c 100644 --- a/lib/question_layout_hooks.rb +++ b/lib/question_layout_hooks.rb @@ -5,6 +5,7 @@ def view_layouts_base_html_head(context = { }) o = < .question { background-color:#FFEBC1; border:2px solid #FDBD3B; margin-bottom:12px; padding:0px 4px 8px 4px; } +.question-line { float: right; } td.formatted_questions { text-align: left; white-space: normal} td.formatted_questions ol { margin-top: 0px; margin-bottom: 0px; } From e82772071398577981c625e202c41c8c7d86f982 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Tue, 18 Dec 2012 13:11:13 +0200 Subject: [PATCH 17/66] Display answered questions in history as question but with another style --- lib/question_issue_hooks.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index 731a10c..d4c94f6 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -2,7 +2,7 @@ class QuestionIssueHooks < QuestionHooksBase # Applies the question class to each journal div if they are questions def view_issues_history_journal_bottom(context = { }) o = '' - if context[:journal] && context[:journal].question && context[:journal].question.opened? + if context[:journal] && context[:journal].question question = context[:journal].question if question.assigned_to @@ -11,13 +11,13 @@ def view_issues_history_journal_bottom(context = { }) html = unassigned_question_html(question) end + className = question.opened == 1 ? 'question' : 'question-closed' o += < - $('#change-#{context[:journal].id}').addClass('question'); + $('#change-#{context[:journal].id}').addClass('#{className}'); $('#change-#{context[:journal].id} h4 .journal-link').after(' #{html} '); JS - end return o end From 8bd06fad4f04151fa6bff49e16886188356224f5 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Tue, 18 Dec 2012 17:10:55 +0200 Subject: [PATCH 18/66] Configurable option for autocomplete Limit autocomplete users only to members of a given project or use any user --- app/controllers/questions_controller.rb | 11 +++---- .../autocomplete_for_user_login.html.erb | 29 +++++-------------- app/views/settings/_question_plugin.html.erb | 8 +++++ config/locales/en.yml | 4 ++- config/locales/ru.yml | 3 ++ config/routes.rb | 2 +- init.rb | 5 ++++ lib/question_issue_hooks.rb | 8 +---- lib/question_journal_hooks.rb | 6 +--- 9 files changed, 35 insertions(+), 41 deletions(-) create mode 100644 app/views/settings/_question_plugin.html.erb diff --git a/app/controllers/questions_controller.rb b/app/controllers/questions_controller.rb index 4207886..87d93f8 100644 --- a/app/controllers/questions_controller.rb +++ b/app/controllers/questions_controller.rb @@ -14,14 +14,15 @@ def user_issue_filter end def autocomplete_for_user_login - if params[:issue_id] + if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == "1" @issue = Issue.find_by_id(params[:issue_id]) - base = issue.project.users + base = @issue.project.users else - User + base = User end - if params[:user] - @users = base.active.all(:conditions => ["LOWER(login) LIKE :user OR LOWER(firstname) LIKE :user OR LOWER(lastname) LIKE :user", {:user => params[:user]+"%" }], + q = (params[:q] || params[:term] || params[:user]).to_s.strip.downcase + if q.present? + @users = base.active.all(:conditions => ["LOWER(login) LIKE :user OR LOWER(firstname) LIKE :user OR LOWER(lastname) LIKE :user", {:user => q + "%" }], :limit => 10, :order => 'login ASC') end diff --git a/app/views/questions/autocomplete_for_user_login.html.erb b/app/views/questions/autocomplete_for_user_login.html.erb index c6057b4..8c1bf6d 100644 --- a/app/views/questions/autocomplete_for_user_login.html.erb +++ b/app/views/questions/autocomplete_for_user_login.html.erb @@ -1,22 +1,7 @@ -
      -
    • <%= l(:text_anyone) %>
    • - - <% if @issue %> -
    • - <%= l(:field_issue) %> <%= l(:field_author) %> - - <%= h @issue.author.login %> - (<%= h(@issue.author.name(:lastname_coma_firstname)) %>) -
    • - <% if @issue.assigned_to %> -
    • - <%= l(:field_issue) %> <%= l(:field_assigned_to) %> - - <%= h @issue.assigned_to.login %> - (<%= h(@issue.assigned_to.name(:lastname_coma_firstname)) %>) -
    • - <% end %> - <% end %> - - <% @users.each do |user| -%> -
    • <%= h user.login %> (<%= h(user.name(:lastname_coma_firstname)) %>)
    • - <% end -%> -
    +<%= raw @users.map {|user| { + 'id' => user.login, + 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", + 'value' => user.login + } + }.to_json +%> \ No newline at end of file diff --git a/app/views/settings/_question_plugin.html.erb b/app/views/settings/_question_plugin.html.erb new file mode 100644 index 0000000..0032260 --- /dev/null +++ b/app/views/settings/_question_plugin.html.erb @@ -0,0 +1,8 @@ +

    + <%= label_tag "label_settings", l(:label_question_plugin_only_members) %> + <%= select_tag 'settings[only_members]', options_for_select([ + [l(:text_question_all), 0], + [l(:text_question_project_member), 1], + ], Setting.plugin_question_plugin[:only_members]) %> + +

    \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 8098bf2..b48739a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -20,4 +20,6 @@ en: text_questions_asked_by_me: "Questions asked by me" question_reminder_subject: "%{count} open question(s)" question_reminder_body: "%{count} open questions(s) that are assigned to you:" - + label_question_plugin_only_members: Question can be assigned to + text_question_all: Any user + text_question_project_member: Project members only diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 4e8d5f2..3c12db1 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -20,3 +20,6 @@ ru: text_questions_asked_by_me: "Вопросы заданные мной" question_reminder_subject: "%{count} не отвеченных вопросов" question_reminder_body: "%{count} не отвеченных вопросов заданных Вам:" + label_question_plugin_only_members: Вопрос может быть задан + text_question_all: Любому пользователю + text_question_project_member: Только участникам проекта \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index a82a72b..e234cf6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,6 @@ if Rails::VERSION::MAJOR < 3 ActionController::Routing::Routes.draw do |map| - map.connect 'questions/autocomplete_for_user_login/project/:id/issue/:issue_id',:controller=> 'questions', :action=> 'autocomplete_for_user_login' + map.connect 'questions/autocomplete_for_user_login/project/:id/issue/:issue_id', :controller=> 'questions', :action=> 'autocomplete_for_user_login' map.connect 'questions/my_issue_filter(/project/:project)' ,:controller=> 'questions', :action=> 'my_issue_filter' map.connect 'questions/user_issue_filter/user/:user_id' ,:controller=> 'questions', :action=> 'user_issue_filter' end diff --git a/init.rb b/init.rb index d77899a..1db9688 100644 --- a/init.rb +++ b/init.rb @@ -34,6 +34,11 @@ version '0.3.0' requires_redmine :version_or_higher => '2.0.0' + + settings :default => { + :only_members => 0 + }, :partial => 'settings/question_plugin' + end # Ensure ActionMailer knows where to find the views for the question plugin diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index d4c94f6..011d715 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -30,13 +30,7 @@ def view_issues_edit_notes_bottom(context = { }) " ".html_safe + text_field_tag('note[question_assigned_to]', nil, :size => "40")) - users = @issue.project.users.active.all(:order => 'login ASC') - users = users.map {|u| "{value: '#{u.login}',label: '#{u.name(:lastname_coma_firstname)} (#{u.login})'}"}.join(',') - o << javascript_tag("$('#note_question_assigned_to').autocomplete({ - source: [#{users}] - });") - - o << content_tag(:div, '', :id => "note_question_assigned_to_choices", :class => "autocomplete") + o << javascript_tag("observeAutocompleteField('note_question_assigned_to', '#{escape_javascript questions_autocomplete_for_user_login_path(@issue.project, @issue)}')") return o end diff --git a/lib/question_journal_hooks.rb b/lib/question_journal_hooks.rb index 006ab7c..b54799b 100644 --- a/lib/question_journal_hooks.rb +++ b/lib/question_journal_hooks.rb @@ -12,11 +12,7 @@ def view_journals_notes_form_after_notes(context = { }) " ".html_safe + text_field_tag('question[assigned_to]', assigned_to, :size => "40")) - users = @journal.issue.project.users.active.all(:order => 'login ASC') - users = users.map { |u| "{value: '#{u.login}',label: '#{u.name(:lastname_coma_firstname)} (#{u.login})'}" }.join(',') - o << javascript_tag("$('#question_assigned_to').autocomplete({ - source: [#{users}] - });") + o << javascript_tag("observeAutocompleteField('question_assigned_to', '#{escape_javascript questions_autocomplete_for_user_login_path(@journal.issue.project, @journal.issue)}')") return o end From 5064f194af556d1ff88d6759a5da7d5c04b46aa3 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Wed, 19 Dec 2012 10:55:25 +0200 Subject: [PATCH 19/66] Possibility choose questions for answer (configurable option) --- app/views/settings/_question_plugin.html.erb | 9 ++++++- config/locales/en.yml | 4 ++++ config/locales/ru.yml | 6 ++++- init.rb | 3 ++- lib/question_issue_hooks.rb | 24 +++++++++++++++++-- lib/question_issue_patch.rb | 12 ++++++++-- .../patches/journal_observer_patch.rb | 5 ---- 7 files changed, 51 insertions(+), 12 deletions(-) diff --git a/app/views/settings/_question_plugin.html.erb b/app/views/settings/_question_plugin.html.erb index 0032260..a527ff1 100644 --- a/app/views/settings/_question_plugin.html.erb +++ b/app/views/settings/_question_plugin.html.erb @@ -1,8 +1,15 @@

    - <%= label_tag "label_settings", l(:label_question_plugin_only_members) %> + <%= label_tag "settings[only_members]", l(:label_question_plugin_only_members) %> <%= select_tag 'settings[only_members]', options_for_select([ [l(:text_question_all), 0], [l(:text_question_project_member), 1], ], Setting.plugin_question_plugin[:only_members]) %> +

    +

    + <%= label_tag "settings[close_all_questions]", l(:label_question_plugin_close_settings) %> + <%= select_tag 'settings[close_all_questions]', options_for_select([ + [l(:text_question_close_all), 1], + [l(:text_question_close_selected), 0], + ], Setting.plugin_question_plugin[:close_all_questions]) %>

    \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index b48739a..f541861 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -23,3 +23,7 @@ en: label_question_plugin_only_members: Question can be assigned to text_question_all: Any user text_question_project_member: Project members only + label_question_plugin_close_settings: When add comment close + text_question_close_all: all opened questions in issue + text_question_close_selected: only selected question + field_question_to_answer: Answer question diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 3c12db1..4524a1f 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -22,4 +22,8 @@ ru: question_reminder_body: "%{count} не отвеченных вопросов заданных Вам:" label_question_plugin_only_members: Вопрос может быть задан text_question_all: Любому пользователю - text_question_project_member: Только участникам проекта \ No newline at end of file + text_question_project_member: Только участникам проекта + label_question_plugin_close_settings: При добавлении комментария закрывать + text_question_close_all: все неотвеченные вопросы в задаче + text_question_close_selected: только выбранный вопрос + field_question_to_answer: Ответ на вопрос diff --git a/init.rb b/init.rb index 1db9688..6319b16 100644 --- a/init.rb +++ b/init.rb @@ -36,7 +36,8 @@ requires_redmine :version_or_higher => '2.0.0' settings :default => { - :only_members => 0 + :only_members => 1, + :close_all_questions => 1, }, :partial => 'settings/question_plugin' end diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index 011d715..74f73d6 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -26,10 +26,17 @@ def view_issues_edit_notes_bottom(context = { }) f = context[:form] @issue = context[:issue] o = '' + + if @issue.pending_question?(User.current) && Setting.plugin_question_plugin[:close_all_questions] != "1" + questions = @issue.pending_questions(User.current) + o << content_tag(:p, + " ".html_safe + + select_tag('question_to_answer', options_for_select([[]] + questions.collect {|q| [truncate(q.journal.notes, :length => Question::TruncateTo), q.id]})) + ) + end o << content_tag(:p, " ".html_safe + - text_field_tag('note[question_assigned_to]', nil, :size => "40")) - + text_field_tag('note[question_assigned_to]', nil, :size => "40")) o << javascript_tag("observeAutocompleteField('note_question_assigned_to', '#{escape_javascript questions_autocomplete_for_user_login_path(@issue.project, @issue)}')") return o @@ -53,6 +60,19 @@ def controller_issues_edit_before_save(context = { }) end end + if Setting.plugin_question_plugin[:close_all_questions] == "1" + # Close any open questions + if journal.issue.present? && journal.issue.pending_question?(journal.user) + journal.issue.close_pending_questions(journal.user, journal) + end + else + # Close specific question + if params[:question_to_answer] and !params[:question_to_answer].empty? + question = Question.find(params[:question_to_answer]) + question.close!(journal) + end + end + return '' end diff --git a/lib/question_issue_patch.rb b/lib/question_issue_patch.rb index 0e75c30..f3deec2 100644 --- a/lib/question_issue_patch.rb +++ b/lib/question_issue_patch.rb @@ -24,9 +24,17 @@ def pending_question?(user) return false end - def close_pending_questions(user, closing_journal) + def pending_questions(user) + q = [] self.open_questions.find(:all).each do |question| - question.close!(closing_journal) if question.assigned_to == user || question.for_anyone? + q << question if question.assigned_to == user || question.for_anyone? + end + return q + end + + def close_pending_questions(user, closing_journal) + self.pending_questions(user).each do |question| + question.close!(closing_journal) end end diff --git a/lib/question_plugin/patches/journal_observer_patch.rb b/lib/question_plugin/patches/journal_observer_patch.rb index 02b6b85..4684b57 100644 --- a/lib/question_plugin/patches/journal_observer_patch.rb +++ b/lib/question_plugin/patches/journal_observer_patch.rb @@ -24,11 +24,6 @@ def after_create_with_question(journal) journal.question.save QuestionMailer.asked_question(journal).deliver end - - # Close any open questions - if journal.issue.present? && journal.issue.pending_question?(journal.user) - journal.issue.close_pending_questions(journal.user, journal) - end end end end From b99b2a844d1d33be11f89a9e16d97fe431ee9532 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Wed, 19 Dec 2012 12:24:24 +0200 Subject: [PATCH 20/66] Changed subject & sender in mailer --- app/models/question_mailer.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/models/question_mailer.rb b/app/models/question_mailer.rb index 7431502..4a00f9e 100644 --- a/app/models/question_mailer.rb +++ b/app/models/question_mailer.rb @@ -4,9 +4,9 @@ class QuestionMailer < Mailer def asked_question(journal) question = journal.question - from = question.author ? "#{question.author.name} (#{l(:field_system_name)}) <#{Setting.mail_from}>" : nil + from = question.author ? "#{question.author.name} (#{l(:field_system_name)} - #{I18n.t(:text_question)}) <#{Setting.mail_from}>" : nil to = question.assigned_to ? question.assigned_to.mail : nil - subject = "[Frage #{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" + subject = "[#{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" @from = from @question = question @@ -23,11 +23,11 @@ def asked_question(journal) end def answered_question(question, closing_journal) - from = question.assigned_to ? "#{question.assigned_to.name} (#{l(:field_system_name)}) <#{Setting.mail_from}>" : nil + from = question.assigned_to ? "#{question.assigned_to.name} (#{l(:field_system_name)} - #{I18n.t(:text_answer)}) <#{Setting.mail_from}>" : nil to = question.author ? question.author.mail : nil - subject = "[#{I18n.t(:text_answer)} #{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" + subject = "[#{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" - @from = "#{question.assigned_to.name} (#{l(:field_system_name)}) <#{Setting.mail_from}>" unless question.assigned_to.nil? + @from = "#{question.assigned_to.name} (#{l(:field_system_name)} - #{I18n.t(:text_answer)}) <#{Setting.mail_from}>" unless question.assigned_to.nil? @question = question @issue = question.issue @journal = closing_journal From 60bcdf7487faf71909c7d845f24f1f79e9408d14 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Thu, 20 Dec 2012 14:51:45 +0200 Subject: [PATCH 21/66] Small fix for russian translation --- config/locales/ru.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 4524a1f..45f01b7 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -12,8 +12,8 @@ ru: text_questions_for_me: Вопросы ко мне text_question_asked: Вопрос задан text_question_remove: "<< Удалить вопрос >>" - question_text_asked_by: "Задан" - question_text_assigned_to: "Назначен" + question_text_asked_by: "Автор вопроса" + question_text_assigned_to: "Вопрос назначен" question_text_created_on: "Создан" question_text_ratio_questions_answered: "{{ratio}} вопросов отвечено" field_journal: "Journal" From 8e36a1470424611e1bd28bdb2e6907b5d9bd0d4b Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Thu, 20 Dec 2012 14:53:39 +0200 Subject: [PATCH 22/66] Some fixes for compatibility with latest redmine trunk --- app/controllers/questions_controller.rb | 2 +- init.rb | 20 +++++++++++++++----- lib/question_active_record_relation_patch.rb | 9 ++++++++- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/app/controllers/questions_controller.rb b/app/controllers/questions_controller.rb index 87d93f8..bdd2030 100644 --- a/app/controllers/questions_controller.rb +++ b/app/controllers/questions_controller.rb @@ -36,7 +36,7 @@ def autocomplete_for_user_login def new_filter_for_questions_assigned_to(user_id) @project = Project.find(params[:project]) unless params[:project].nil? - @query = Query.new(:name => "_", + @query = (ActiveSupport::Dependencies::search_for_file('issue_query') ? IssueQuery : Query).new(:name => "_", :filters => {'status_id' => {:operator => '*', :values => [""]}} ) @query.project = @project unless params[:project].nil? diff --git a/init.rb b/init.rb index 6319b16..99a6b98 100644 --- a/init.rb +++ b/init.rb @@ -18,11 +18,21 @@ require_dependency 'journal' Journal.send(:include, QuestionJournalPatch) unless Journal.included_modules.include? QuestionJournalPatch - require_dependency 'queries_helper' - QueriesHelper.send(:include, QuestionQueriesHelperPatch) unless QueriesHelper.included_modules.include? QuestionQueriesHelperPatch - - require_dependency 'query' - Query.send(:include, QuestionQueryPatch) unless Query.included_modules.include? QuestionQueryPatch + if ActiveSupport::Dependencies::search_for_file('issue_queries_helper') + require_dependency 'issue_queries_helper' + IssueQueriesHelper.send(:include, QuestionQueriesHelperPatch) unless QueriesHelper.included_modules.include? QuestionQueriesHelperPatch + else + require_dependency 'queries_helper' + QueriesHelper.send(:include, QuestionQueriesHelperPatch) unless QueriesHelper.included_modules.include? QuestionQueriesHelperPatch + end + + if ActiveSupport::Dependencies::search_for_file('issue_query') + require_dependency 'issue_query' + IssueQuery.send(:include, QuestionQueryPatch) unless Query.included_modules.include? QuestionQueryPatch + else + require_dependency 'query' + Query.send(:include, QuestionQueryPatch) unless Query.included_modules.include? QuestionQueryPatch + end end p = Redmine::Plugin.register :question_plugin do diff --git a/lib/question_active_record_relation_patch.rb b/lib/question_active_record_relation_patch.rb index 7f8babd..e276dc3 100644 --- a/lib/question_active_record_relation_patch.rb +++ b/lib/question_active_record_relation_patch.rb @@ -10,6 +10,7 @@ def self.included(base) # :nodoc: alias_method :count_before_question, :count alias_method :sum_before_question, :sum alias_method :find_before_question, :find + alias_method :all_before_question, :all alias_method :find_ids_before_question, :find_ids # Override ActiveRecord::Calculations.count @@ -30,6 +31,12 @@ def find(*args) find_before_question(*args) end + # Override ActiveRecord::FinderMethods.all + def all(*args) + scan_for_options_hash_and_add_includes_if_needed(self.klass, args) + all_before_question(*args) + end + # Override ActiveRecord::FinderMethods.find_ids def find_ids(*args) relation = scan_where_clauses_and_add_includes_if_needed @@ -73,7 +80,7 @@ def scan_for_options_hash_and_add_includes_if_needed(klass, args) def add_questions_to_the_includes(arg) if arg[:include] # Has includes - if arg[:include].is_a?(Hash) + if arg[:include].is_a?(Hash) || arg[:include].is_a?(Array) # Hash includes arg[:include] << :questions else From 67bd45e8dd0c6af189c225957ba0732e8cca7527 Mon Sep 17 00:00:00 2001 From: Stephen Leavitt Date: Sat, 12 Jan 2013 19:51:32 -0600 Subject: [PATCH 23/66] Minor spacing change for readability --- lib/question_hooks_base.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/question_hooks_base.rb b/lib/question_hooks_base.rb index b984bcc..683b503 100644 --- a/lib/question_hooks_base.rb +++ b/lib/question_hooks_base.rb @@ -8,14 +8,14 @@ def assigned_question_html(question) html = "" html << " #{l(:text_question_for)} " html << link_to_user(question.assigned_to) - html << " #{avatar(question.assigned_to, { :size => 24, :class => '' })} " if question.assigned_to && question.assigned_to.mail + html << " #{avatar(question.assigned_to, { :size => 24, :class => '' })} " if question.assigned_to && question.assigned_to.mail html end def unassigned_question_html(question) html = "" html << l(:text_question_for_anyone) - html << "" + html << " " html end end From 09f126e666b6fdaa2c3fd7b8c7f40e5a15c00f70 Mon Sep 17 00:00:00 2001 From: Stephen Leavitt Date: Sat, 12 Jan 2013 19:51:59 -0600 Subject: [PATCH 24/66] Fix to ensure proper color coding of open questions on an issue --- lib/question_issue_hooks.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index 74f73d6..5db2e9a 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -11,7 +11,7 @@ def view_issues_history_journal_bottom(context = { }) html = unassigned_question_html(question) end - className = question.opened == 1 ? 'question' : 'question-closed' + className = question.opened ? 'question' : 'question-closed' o += < $('#change-#{context[:journal].id}').addClass('#{className}'); From 567c92e0cff2597844b0a5b94e564de3a4337e05 Mon Sep 17 00:00:00 2001 From: Thorin Date: Fri, 10 May 2013 10:26:49 +0100 Subject: [PATCH 25/66] Fixed to work with the latest redmine version --- init.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/init.rb b/init.rb index d77899a..b527ee1 100644 --- a/init.rb +++ b/init.rb @@ -21,8 +21,8 @@ require_dependency 'queries_helper' QueriesHelper.send(:include, QuestionQueriesHelperPatch) unless QueriesHelper.included_modules.include? QuestionQueriesHelperPatch - require_dependency 'query' - Query.send(:include, QuestionQueryPatch) unless Query.included_modules.include? QuestionQueryPatch + require_dependency 'issue_query' + IssueQuery.send(:include, QuestionQueryPatch) unless IssueQuery.included_modules.include? QuestionQueryPatch end p = Redmine::Plugin.register :question_plugin do From 5af11569f973a9c448f1405610b0ec67759c70e1 Mon Sep 17 00:00:00 2001 From: Thorin Date: Fri, 10 May 2013 11:20:50 +0100 Subject: [PATCH 26/66] Question assigned to filter not working when assigned to none or any --- config/locales/en.yml | 2 +- lib/question_query_patch.rb | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 8098bf2..8eba727 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -13,7 +13,7 @@ en: text_question_asked: Question asked text_question_remove: "<< Remove Question>>" question_text_asked_by: "Asked By" - question_text_assigned_to: "Assigned To" + question_text_assigned_to: "Question assigned To" question_text_created_on: "Created On" question_text_ratio_questions_answered: "{{ratio}} questions answered" field_journal: "Journal" diff --git a/lib/question_query_patch.rb b/lib/question_query_patch.rb index 453cdfe..0ce51a8 100644 --- a/lib/question_query_patch.rb +++ b/lib/question_query_patch.rb @@ -69,6 +69,8 @@ def question_sql_for_field(field, operator, v, db_table, db_field, is_custom_fil sql = "#{db_table}.#{db_field} IN (" + v.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ") AND #{db_table}.opened = true" when "!" sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + v.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")) AND #{db_table}.opened = true" + else + sql = "1=1" end return sql From 5b3665a413e5a6cbb72593f3f0e1b488e01a415b Mon Sep 17 00:00:00 2001 From: Thorin Date: Thu, 16 May 2013 21:34:06 +0100 Subject: [PATCH 27/66] Changed from Query to IssueQuery --- app/controllers/questions_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/questions_controller.rb b/app/controllers/questions_controller.rb index 4207886..89f97d1 100644 --- a/app/controllers/questions_controller.rb +++ b/app/controllers/questions_controller.rb @@ -35,7 +35,7 @@ def autocomplete_for_user_login def new_filter_for_questions_assigned_to(user_id) @project = Project.find(params[:project]) unless params[:project].nil? - @query = Query.new(:name => "_", + @query = IssueQuery.new(:name => "_", :filters => {'status_id' => {:operator => '*', :values => [""]}} ) @query.project = @project unless params[:project].nil? From 794d26416515954e607073183af64c6cb7e8cca9 Mon Sep 17 00:00:00 2001 From: Thorin Date: Tue, 2 Jul 2013 16:39:24 +0100 Subject: [PATCH 28/66] Fixed truncate on question_issue_patch --- lib/question_issue_patch.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/question_issue_patch.rb b/lib/question_issue_patch.rb index f3deec2..2a26f63 100644 --- a/lib/question_issue_patch.rb +++ b/lib/question_issue_patch.rb @@ -40,7 +40,7 @@ def close_pending_questions(user, closing_journal) def formatted_questions open_questions.collect do |question| - truncate(question.journal.notes, Question::TruncateTo) + truncate(question.journal.notes, :length => Question::TruncateTo) end.join(", ") end end From c51f08404588a6f862f326f9c936390b66f395a0 Mon Sep 17 00:00:00 2001 From: cforce Date: Wed, 17 Jul 2013 11:40:01 +0200 Subject: [PATCH 29/66] fixed plugin incompatibility http://redminecrm.com/boards/18/topics/1211-bug-on-0-0-5-the-action-index-could-not-be-found-for-questionscontroller-when-clicking-on-questions --- ...roller.rb => issuequestions_controller.rb} | 96 +++++++++---------- app/models/question_mailer.rb | 2 +- config/routes.rb | 12 +-- lib/question_issue_hooks.rb | 2 +- lib/question_kanban_hooks.rb | 2 +- ...w_user_kanbans_show_contextual_top_hook.rb | 2 +- question_plugin.gemspec | 2 +- 7 files changed, 59 insertions(+), 59 deletions(-) rename app/controllers/{questions_controller.rb => issuequestions_controller.rb} (94%) diff --git a/app/controllers/questions_controller.rb b/app/controllers/issuequestions_controller.rb similarity index 94% rename from app/controllers/questions_controller.rb rename to app/controllers/issuequestions_controller.rb index bdd2030..03ef346 100644 --- a/app/controllers/questions_controller.rb +++ b/app/controllers/issuequestions_controller.rb @@ -1,48 +1,48 @@ -class QuestionsController < ApplicationController - unloadable - layout 'base' - - # Create a query in the session and redirects to the issue list with that query - def my_issue_filter - new_filter_for_questions_assigned_to('me') - redirect_to :controller => 'issues', :action => 'index', :project_id => params[:project] - end - - def user_issue_filter - new_filter_for_questions_assigned_to(params[:user_id]) - redirect_to :controller => 'issues', :action => 'index', :project_id => params[:project] - end - - def autocomplete_for_user_login - if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == "1" - @issue = Issue.find_by_id(params[:issue_id]) - base = @issue.project.users - else - base = User - end - q = (params[:q] || params[:term] || params[:user]).to_s.strip.downcase - if q.present? - @users = base.active.all(:conditions => ["LOWER(login) LIKE :user OR LOWER(firstname) LIKE :user OR LOWER(lastname) LIKE :user", {:user => q + "%" }], - :limit => 10, - :order => 'login ASC') - end - @users ||=[] - - render :layout => false - end - - private - - def new_filter_for_questions_assigned_to(user_id) - @project = Project.find(params[:project]) unless params[:project].nil? - - @query = (ActiveSupport::Dependencies::search_for_file('issue_query') ? IssueQuery : Query).new(:name => "_", - :filters => {'status_id' => {:operator => '*', :values => [""]}} - ) - @query.project = @project unless params[:project].nil? - @query.add_filter("question_assigned_to_id", '=',[user_id]) - - session[:query] = {:project_id => @query.project_id, :filters => @query.filters} - end - -end +class IssuequestionsController < ApplicationController + unloadable + layout 'base' + + # Create a query in the session and redirects to the issue list with that query + def my_issue_filter + new_filter_for_questions_assigned_to('me') + redirect_to :controller => 'issues', :action => 'index', :project_id => params[:project] + end + + def user_issue_filter + new_filter_for_questions_assigned_to(params[:user_id]) + redirect_to :controller => 'issues', :action => 'index', :project_id => params[:project] + end + + def autocomplete_for_user_login + if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == "1" + @issue = Issue.find_by_id(params[:issue_id]) + base = @issue.project.users + else + base = User + end + q = (params[:q] || params[:term] || params[:user]).to_s.strip.downcase + if q.present? + @users = base.active.all(:conditions => ["LOWER(login) LIKE :user OR LOWER(firstname) LIKE :user OR LOWER(lastname) LIKE :user", {:user => q + "%" }], + :limit => 10, + :order => 'login ASC') + end + @users ||=[] + + render :layout => false + end + + private + + def new_filter_for_questions_assigned_to(user_id) + @project = Project.find(params[:project]) unless params[:project].nil? + + @query = (ActiveSupport::Dependencies::search_for_file('issue_query') ? IssueQuery : Query).new(:name => "_", + :filters => {'status_id' => {:operator => '*', :values => [""]}} + ) + @query.project = @project unless params[:project].nil? + @query.add_filter("question_assigned_to_id", '=',[user_id]) + + session[:query] = {:project_id => @query.project_id, :filters => @query.filters} + end + +end diff --git a/app/models/question_mailer.rb b/app/models/question_mailer.rb index 4a00f9e..47fc4b6 100644 --- a/app/models/question_mailer.rb +++ b/app/models/question_mailer.rb @@ -49,7 +49,7 @@ def question_reminder(user, issues) subject = l(:question_reminder_subject, :count => issues.size) @issues = issues - @issues_url = url_for(:controller => 'questions', :action => 'my_issue_filter') + @issues_url = url_for(:controller => 'issuequestions', :action => 'my_issue_filter') redmine_headers 'Type' => 'Question' diff --git a/config/routes.rb b/config/routes.rb index e234cf6..18cd11e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,12 +1,12 @@ if Rails::VERSION::MAJOR < 3 ActionController::Routing::Routes.draw do |map| - map.connect 'questions/autocomplete_for_user_login/project/:id/issue/:issue_id', :controller=> 'questions', :action=> 'autocomplete_for_user_login' - map.connect 'questions/my_issue_filter(/project/:project)' ,:controller=> 'questions', :action=> 'my_issue_filter' - map.connect 'questions/user_issue_filter/user/:user_id' ,:controller=> 'questions', :action=> 'user_issue_filter' + map.connect 'questions/autocomplete_for_user_login/project/:id/issue/:issue_id', :controller=> 'issuequestions', :action=> 'autocomplete_for_user_login' + map.connect 'questions/my_issue_filter(/project/:project)' ,:controller=> 'issuequestions', :action=> 'my_issue_filter' + map.connect 'questions/user_issue_filter/user/:user_id' ,:controller=> 'issuequestions', :action=> 'user_issue_filter' end else - match 'questions/autocomplete_for_user_login/project/:id/issue/:issue_id' => 'questions#autocomplete_for_user_login', :format => false, :as => 'questions_autocomplete_for_user_login' - match 'questions/my_issue_filter(/project/:project)' => 'questions#my_issue_filter', :format => false, :as => 'questions_my_issue_filter' - match 'questions/user_issue_filter/user/:user_id' => 'questions#user_issue_filter', :format => false, :as => 'questions_user_issue_filter' + match 'questions/autocomplete_for_user_login/project/:id/issue/:issue_id' => 'issuequestions#autocomplete_for_user_login', :format => false, :as => 'questions_autocomplete_for_user_login' + match 'questions/my_issue_filter(/project/:project)' => 'issuequestions#my_issue_filter', :format => false, :as => 'questions_my_issue_filter' + match 'questions/user_issue_filter/user/:user_id' => 'issuequestions#user_issue_filter', :format => false, :as => 'questions_user_issue_filter' end diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index 5db2e9a..38d9c7c 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -87,7 +87,7 @@ def view_issues_sidebar_issues_bottom(context = { }) if question_count > 0 return link_to(l(:text_questions_for_me) + " (#{question_count})", { - :controller => 'questions', + :controller => 'issuequestions', :action => 'my_issue_filter', :project => project, :only_path => true diff --git a/lib/question_kanban_hooks.rb b/lib/question_kanban_hooks.rb index f308378..caeacf6 100644 --- a/lib/question_kanban_hooks.rb +++ b/lib/question_kanban_hooks.rb @@ -31,7 +31,7 @@ def view_kanbans_user_name(context = {}) if count > 0 return content_tag(:p, link_to(l(:field_formatted_questions) + " (#{count})", { - :controller => 'questions', + :controller => 'issuequestions', :action => 'user_issue_filter', :user_id => user.id, :only_path => true diff --git a/lib/question_plugin/hooks/view_user_kanbans_show_contextual_top_hook.rb b/lib/question_plugin/hooks/view_user_kanbans_show_contextual_top_hook.rb index db4e995..1c23230 100644 --- a/lib/question_plugin/hooks/view_user_kanbans_show_contextual_top_hook.rb +++ b/lib/question_plugin/hooks/view_user_kanbans_show_contextual_top_hook.rb @@ -10,7 +10,7 @@ def view_user_kanbans_show_contextual_top(context={}) if count > 0 return link_to(l(:field_formatted_questions) + " (#{count})", { - :controller => 'questions', + :controller => 'issuequestions', :action => 'user_issue_filter', :user_id => user.id, :only_path => true diff --git a/question_plugin.gemspec b/question_plugin.gemspec index 7c034b5..bde82ae 100644 --- a/question_plugin.gemspec +++ b/question_plugin.gemspec @@ -22,7 +22,7 @@ Gem::Specification.new do |s| "README.rdoc", "Rakefile", "VERSION", - "app/controllers/questions_controller.rb", + "app/controllers/issuequestions_controller.rb", "app/models/journal_questions_observer.rb", "app/models/question.rb", "app/models/question_mailer.rb", From a4028fbd92c2d0b20317503da885c463e09aac11 Mon Sep 17 00:00:00 2001 From: cforce Date: Wed, 17 Jul 2013 13:28:06 +0200 Subject: [PATCH 30/66] updated locale --- config/locales/de.yml | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index 0ed7de9..4711e79 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -7,17 +7,23 @@ de: text_question_answered: "Frage beantwortet" text_answer: "Antwort" text_anyone: "Irgendwer" - text_question_for: "Frage für" - text_question_for_anyone: "Frage für irgendjemanden" - text_questions_for_me: "Fragen für mich" + text_question_for: "Frage für" + text_question_for_anyone: "Frage für irgendjemanden" + text_questions_for_me: "Fragen für mich" text_question_asked: "Frage gestellt" text_question_remove: "<>" question_text_asked_by: "gefragt von" question_text_assigned_to: "Zugewiesen an" - question_text_created_on: "Erstellt am" + question_text_created_on: "erstellt am" question_text_ratio_questions_answered: "{{ratio}} beantwortete Fragen" field_journal: "Journal" text_questions_asked_by_me: "meine gestellten Fragen" - questions_asked_by_me: "Meine gestellten Fragen" - questions_for_me: "Fragen für mich" - field_system_name: "InfoMine" + question_reminder_subject: "%{count} offene Frage(n)" + question_reminder_body: "%{count} offene dir zugewiesene Frage(n)" + label_question_plugin_only_members: Die Frage kann diesem Benutzer zugewiesen werden + text_question_all: jedem Benutzer + text_question_project_member: Projektmitarbeitern + label_question_plugin_close_settings: Frage des Tickets abschließend beantworten + text_question_close_all: alle offene Fragen + text_question_close_selected: ausschließlich aktuell ausgewählte Frage + field_question_to_answer: Frage beantworten From 61fde4f00885ae538bb5e4764117366fbbb81f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vaisar?= Date: Fri, 9 Aug 2013 15:34:35 +0200 Subject: [PATCH 31/66] After merge fixes * autocomplete view moved to directory app/views/issuequestions * fixed :only_members value in Settings (comparing with "1", but value was 1 - string vs. integer) --- app/controllers/issuequestions_controller.rb | 2 +- .../issuequestions/autocomplete_for_user_login.html.erb | 7 +++++++ app/views/questions/autocomplete_for_user_login.html.erb | 7 ------- 3 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 app/views/issuequestions/autocomplete_for_user_login.html.erb delete mode 100644 app/views/questions/autocomplete_for_user_login.html.erb diff --git a/app/controllers/issuequestions_controller.rb b/app/controllers/issuequestions_controller.rb index 03ef346..34ead06 100644 --- a/app/controllers/issuequestions_controller.rb +++ b/app/controllers/issuequestions_controller.rb @@ -14,7 +14,7 @@ def user_issue_filter end def autocomplete_for_user_login - if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == "1" + if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == 1 @issue = Issue.find_by_id(params[:issue_id]) base = @issue.project.users else diff --git a/app/views/issuequestions/autocomplete_for_user_login.html.erb b/app/views/issuequestions/autocomplete_for_user_login.html.erb new file mode 100644 index 0000000..14c0ccd --- /dev/null +++ b/app/views/issuequestions/autocomplete_for_user_login.html.erb @@ -0,0 +1,7 @@ +<%= raw @users.map {|user| { + 'id' => user.login, + 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", + 'value' => user.login + } + }.to_json +%> \ No newline at end of file diff --git a/app/views/questions/autocomplete_for_user_login.html.erb b/app/views/questions/autocomplete_for_user_login.html.erb deleted file mode 100644 index 8c1bf6d..0000000 --- a/app/views/questions/autocomplete_for_user_login.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -<%= raw @users.map {|user| { - 'id' => user.login, - 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", - 'value' => user.login - } - }.to_json -%> \ No newline at end of file From 6545eb50a18b430f5f10b4a342180244aea74a3a Mon Sep 17 00:00:00 2001 From: cforce Date: Fri, 16 Aug 2013 17:35:18 +0200 Subject: [PATCH 32/66] works and fixed for redmine 2.3.2 compatibility with redminecrm question plugin --- .../autocomplete_for_user_login.html.erb | 7 - config/routes.rb | 24 +- lib/question_issue_hooks.rb | 216 +++++++++--------- 3 files changed, 120 insertions(+), 127 deletions(-) delete mode 100644 app/views/questions/autocomplete_for_user_login.html.erb diff --git a/app/views/questions/autocomplete_for_user_login.html.erb b/app/views/questions/autocomplete_for_user_login.html.erb deleted file mode 100644 index 8c1bf6d..0000000 --- a/app/views/questions/autocomplete_for_user_login.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -<%= raw @users.map {|user| { - 'id' => user.login, - 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", - 'value' => user.login - } - }.to_json -%> \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 18cd11e..a284f5a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,12 +1,12 @@ -if Rails::VERSION::MAJOR < 3 - ActionController::Routing::Routes.draw do |map| - map.connect 'questions/autocomplete_for_user_login/project/:id/issue/:issue_id', :controller=> 'issuequestions', :action=> 'autocomplete_for_user_login' - map.connect 'questions/my_issue_filter(/project/:project)' ,:controller=> 'issuequestions', :action=> 'my_issue_filter' - map.connect 'questions/user_issue_filter/user/:user_id' ,:controller=> 'issuequestions', :action=> 'user_issue_filter' - end -else - match 'questions/autocomplete_for_user_login/project/:id/issue/:issue_id' => 'issuequestions#autocomplete_for_user_login', :format => false, :as => 'questions_autocomplete_for_user_login' - match 'questions/my_issue_filter(/project/:project)' => 'issuequestions#my_issue_filter', :format => false, :as => 'questions_my_issue_filter' - match 'questions/user_issue_filter/user/:user_id' => 'issuequestions#user_issue_filter', :format => false, :as => 'questions_user_issue_filter' -end - +if Rails::VERSION::MAJOR < 3 + ActionController::Routing::Routes.draw do |map| + map.connect 'issuequestions/autocomplete_for_user_login/project/:id/issue/:issue_id', :controller=> 'issuequestions', :action=> 'autocomplete_for_user_login' + map.connect 'issuequestions/my_issue_filter(/project/:project)' ,:controller=> 'issuequestions', :action=> 'my_issue_filter' + map.connect 'issuequestions/user_issue_filter/user/:user_id' ,:controller=> 'issuequestions', :action=> 'user_issue_filter' + end +else + match 'issuequestions/autocomplete_for_user_login/project/:id/issue/:issue_id' => 'issuequestions#autocomplete_for_user_login', :format => false, :as => 'issuequestions_autocomplete_for_user_login' + match 'issuequestions/my_issue_filter(/project/:project)' => 'issuequestions#my_issue_filter', :format => false, :as => 'questions_my_issue_filter' + match 'issuequestions/user_issue_filter/user/:user_id' => 'issuequestions#user_issue_filter', :format => false, :as => 'questions_user_issue_filter' +end + diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index 38d9c7c..3abb007 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -1,108 +1,108 @@ -class QuestionIssueHooks < QuestionHooksBase - # Applies the question class to each journal div if they are questions - def view_issues_history_journal_bottom(context = { }) - o = '' - if context[:journal] && context[:journal].question - question = context[:journal].question - - if question.assigned_to - html = assigned_question_html(question) - else - html = unassigned_question_html(question) - end - - className = question.opened ? 'question' : 'question-closed' - o += < - $('#change-#{context[:journal].id}').addClass('#{className}'); - $('#change-#{context[:journal].id} h4 .journal-link').after(' #{html} '); - -JS - end - return o - end - - def view_issues_edit_notes_bottom(context = { }) - f = context[:form] - @issue = context[:issue] - o = '' - - if @issue.pending_question?(User.current) && Setting.plugin_question_plugin[:close_all_questions] != "1" - questions = @issue.pending_questions(User.current) - o << content_tag(:p, - " ".html_safe + - select_tag('question_to_answer', options_for_select([[]] + questions.collect {|q| [truncate(q.journal.notes, :length => Question::TruncateTo), q.id]})) - ) - end - o << content_tag(:p, - " ".html_safe + - text_field_tag('note[question_assigned_to]', nil, :size => "40")) - o << javascript_tag("observeAutocompleteField('note_question_assigned_to', '#{escape_javascript questions_autocomplete_for_user_login_path(@issue.project, @issue)}')") - - return o - end - - def controller_issues_edit_before_save(context = { }) - params = context[:params] - journal = context[:journal] - issue = context[:issue] - if params[:note] && !params[:note][:question_assigned_to].blank? - unless journal.question # Update handled by Journal hooks - # New - journal.question = Question.new( - :author => User.current, - :issue => journal.issue - ) - if params[:note][:question_assigned_to].downcase != 'anyone' - # Assigned to a specific user - assign_question_to_user(journal, User.find_by_login(params[:note][:question_assigned_to])) - end - end - end - - if Setting.plugin_question_plugin[:close_all_questions] == "1" - # Close any open questions - if journal.issue.present? && journal.issue.pending_question?(journal.user) - journal.issue.close_pending_questions(journal.user, journal) - end - else - # Close specific question - if params[:question_to_answer] and !params[:question_to_answer].empty? - question = Question.find(params[:question_to_answer]) - question.close!(journal) - end - end - - return '' - end - - def view_issues_sidebar_issues_bottom(context = { }) - project = context[:project] - if project - question_count = Question.count_of_open_for_user_on_project(User.current, project) - else - question_count = Question.count_of_open_for_user(User.current) - end - - if question_count > 0 - return link_to(l(:text_questions_for_me) + " (#{question_count})", - { - :controller => 'issuequestions', - :action => 'my_issue_filter', - :project => project, - :only_path => true - }, - { :class => 'question-link' } - ) + '
    '.html_safe - else - return '' - end - - end - - private - - def assign_question_to_user(journal, user) - journal.question.assigned_to = user - end -end +class QuestionIssueHooks < QuestionHooksBase + # Applies the question class to each journal div if they are questions + def view_issues_history_journal_bottom(context = { }) + o = '' + if context[:journal] && context[:journal].question + question = context[:journal].question + + if question.assigned_to + html = assigned_question_html(question) + else + html = unassigned_question_html(question) + end + + className = question.opened ? 'question' : 'question-closed' + o += < + $('#change-#{context[:journal].id}').addClass('#{className}'); + $('#change-#{context[:journal].id} h4 .journal-link').after(' #{html} '); + +JS + end + return o + end + + def view_issues_edit_notes_bottom(context = { }) + f = context[:form] + @issue = context[:issue] + o = '' + + if @issue.pending_question?(User.current) && Setting.plugin_question_plugin[:close_all_questions] != "1" + questions = @issue.pending_questions(User.current) + o << content_tag(:p, + " ".html_safe + + select_tag('question_to_answer', options_for_select([[]] + questions.collect {|q| [truncate(q.journal.notes, :length => Question::TruncateTo), q.id]})) + ) + end + o << content_tag(:p, + " ".html_safe + + text_field_tag('note[question_assigned_to]', nil, :size => "40")) + o << javascript_tag("observeAutocompleteField('note_question_assigned_to', '#{escape_javascript issuequestions_autocomplete_for_user_login_path(@issue.project, @issue)}')") + + return o + end + + def controller_issues_edit_before_save(context = { }) + params = context[:params] + journal = context[:journal] + issue = context[:issue] + if params[:note] && !params[:note][:question_assigned_to].blank? + unless journal.question # Update handled by Journal hooks + # New + journal.question = Question.new( + :author => User.current, + :issue => journal.issue + ) + if params[:note][:question_assigned_to].downcase != 'anyone' + # Assigned to a specific user + assign_question_to_user(journal, User.find_by_login(params[:note][:question_assigned_to])) + end + end + end + + if Setting.plugin_question_plugin[:close_all_questions] == "1" + # Close any open questions + if journal.issue.present? && journal.issue.pending_question?(journal.user) + journal.issue.close_pending_questions(journal.user, journal) + end + else + # Close specific question + if params[:question_to_answer] and !params[:question_to_answer].empty? + question = Question.find(params[:question_to_answer]) + question.close!(journal) + end + end + + return '' + end + + def view_issues_sidebar_issues_bottom(context = { }) + project = context[:project] + if project + question_count = Question.count_of_open_for_user_on_project(User.current, project) + else + question_count = Question.count_of_open_for_user(User.current) + end + + if question_count > 0 + return link_to(l(:text_questions_for_me) + " (#{question_count})", + { + :controller => 'issuequestions', + :action => 'my_issue_filter', + :project => project, + :only_path => true + }, + { :class => 'question-link' } + ) + '
    '.html_safe + else + return '' + end + + end + + private + + def assign_question_to_user(journal, user) + journal.question.assigned_to = user + end +end From 26d4a5fb9e0aaa8086c30081c1b6965457569539 Mon Sep 17 00:00:00 2001 From: cforce Date: Fri, 16 Aug 2013 17:41:12 +0200 Subject: [PATCH 33/66] fix settings --- app/controllers/issuequestions_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/issuequestions_controller.rb b/app/controllers/issuequestions_controller.rb index 03ef346..34ead06 100644 --- a/app/controllers/issuequestions_controller.rb +++ b/app/controllers/issuequestions_controller.rb @@ -14,7 +14,7 @@ def user_issue_filter end def autocomplete_for_user_login - if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == "1" + if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == 1 @issue = Issue.find_by_id(params[:issue_id]) base = @issue.project.users else From 5dbbaf8225e8ffb96e58e6381ac9917a98739358 Mon Sep 17 00:00:00 2001 From: DUVERGIER Claude Date: Tue, 27 Aug 2013 18:42:44 +0200 Subject: [PATCH 34/66] New feature: Can obfuscate name/address of asker/answerer and/or question/answer text in notifications (configurable option) --- app/models/question_mailer.rb | 19 ++++++++++++++++--- .../answered_question.html.erb | 7 +++++++ .../answered_question.text.erb | 7 +++++++ .../question_mailer/asked_question.html.erb | 7 ++++++- .../question_mailer/asked_question.text.erb | 7 ++++++- app/views/settings/_question_plugin.html.erb | 9 +++++++++ config/locales/en.yml | 4 ++++ init.rb | 2 ++ 8 files changed, 57 insertions(+), 5 deletions(-) diff --git a/app/models/question_mailer.rb b/app/models/question_mailer.rb index 4a00f9e..6a7ab45 100644 --- a/app/models/question_mailer.rb +++ b/app/models/question_mailer.rb @@ -4,7 +4,13 @@ class QuestionMailer < Mailer def asked_question(journal) question = journal.question - from = question.author ? "#{question.author.name} (#{l(:field_system_name)} - #{I18n.t(:text_question)}) <#{Setting.mail_from}>" : nil + if Setting.plugin_question_plugin[:obfuscate_author] == "1" + # Obfuscate author infos + from = "#{Setting.app_title} <#{Setting.mail_from}>" + else + # Clear author infos + from = question.author ? "#{question.author.name} (#{l(:field_system_name)} - #{I18n.t(:text_question)}) <#{Setting.mail_from}>" : nil + end to = question.assigned_to ? question.assigned_to.mail : nil subject = "[#{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" @@ -23,11 +29,18 @@ def asked_question(journal) end def answered_question(question, closing_journal) - from = question.assigned_to ? "#{question.assigned_to.name} (#{l(:field_system_name)} - #{I18n.t(:text_answer)}) <#{Setting.mail_from}>" : nil + if Setting.plugin_question_plugin[:obfuscate_author] == "1" + # Obfuscate author infos + from = "#{Setting.app_title} <#{Setting.mail_from}>" + @from = from + else + # Clear author infos + from = question.assigned_to ? "#{question.assigned_to.name} (#{l(:field_system_name)} - #{I18n.t(:text_answer)}) <#{Setting.mail_from}>" : nil + @from = "#{question.assigned_to.name} (#{l(:field_system_name)} - #{I18n.t(:text_answer)}) <#{Setting.mail_from}>" unless question.assigned_to.nil? + end to = question.author ? question.author.mail : nil subject = "[#{question.issue.project.name} ##{question.issue.id}] #{question.issue.subject}" - @from = "#{question.assigned_to.name} (#{l(:field_system_name)} - #{I18n.t(:text_answer)}) <#{Setting.mail_from}>" unless question.assigned_to.nil? @question = question @issue = question.issue @journal = closing_journal diff --git a/app/views/question_mailer/answered_question.html.erb b/app/views/question_mailer/answered_question.html.erb index d49a853..c62144b 100644 --- a/app/views/question_mailer/answered_question.html.erb +++ b/app/views/question_mailer/answered_question.html.erb @@ -1,9 +1,14 @@ +<% if Setting.plugin_question_plugin[:obfuscate_content] == "1" %> +<%= textilizable(l(:mail_body_answer_link)) %> +<% else %>

    <%= l(:text_answer) %>

    <%= textilizable(@journal, :notes, :only_path => false) %> +<% end %>

    <%= l(:text_question) %>

    <%= textilizable(@question.journal, :notes, :only_path => false) %> +<% if Setting.plugin_question_plugin[:obfuscate_content] == "0" %>
      <% for detail in @journal.details %>
    • <%= show_detail(detail, true) %>
    • @@ -11,4 +16,6 @@

    +<% end %> + <%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff --git a/app/views/question_mailer/answered_question.text.erb b/app/views/question_mailer/answered_question.text.erb index d49a853..fcfe8be 100644 --- a/app/views/question_mailer/answered_question.text.erb +++ b/app/views/question_mailer/answered_question.text.erb @@ -1,9 +1,14 @@ +<% if Setting.plugin_question_plugin[:obfuscate_content] == "1" %> +<%= l(:mail_body_answer_link) %> +<% else %>

    <%= l(:text_answer) %>

    <%= textilizable(@journal, :notes, :only_path => false) %> +<% end %>

    <%= l(:text_question) %>

    <%= textilizable(@question.journal, :notes, :only_path => false) %> +<% if Setting.plugin_question_plugin[:obfuscate_content] == "0" %>
      <% for detail in @journal.details %>
    • <%= show_detail(detail, true) %>
    • @@ -11,4 +16,6 @@

    +<% end %> + <%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff --git a/app/views/question_mailer/asked_question.html.erb b/app/views/question_mailer/asked_question.html.erb index c2ebcd2..c062b73 100644 --- a/app/views/question_mailer/asked_question.html.erb +++ b/app/views/question_mailer/asked_question.html.erb @@ -1,5 +1,8 @@ -<%= l(:text_question_asked) %> <%= h "##{@issue.id}" %> <%= @question.author %> +<%= l(:text_question_asked) %> <%= h "##{@issue.id}" %> <%= @question.author unless Setting.plugin_question_plugin[:obfuscate_author] == "1" %> +<% if Setting.plugin_question_plugin[:obfuscate_content] == "1" %> +<%= textilizable(l(:mail_body_question_link)) %> +<% else %> <%= textilizable(@journal, :notes, :only_path => false) %>
      @@ -9,4 +12,6 @@

    +<% end %> + <%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff --git a/app/views/question_mailer/asked_question.text.erb b/app/views/question_mailer/asked_question.text.erb index 11cb002..b4e90ab 100644 --- a/app/views/question_mailer/asked_question.text.erb +++ b/app/views/question_mailer/asked_question.text.erb @@ -1,5 +1,8 @@ -<%= l(:text_question_asked) %> <%= h "##{@issue.id}" %> <%= @question.author %> +<%= l(:text_question_asked) %> <%= h "##{@issue.id}" %> <%= @question.author unless Setting.plugin_question_plugin[:obfuscate_author] == "1" %> +<% if Setting.plugin_question_plugin[:obfuscate_content] == "1" %> +<%= l(:mail_body_question_link) %> +<% else %> <%= @journal.notes if @journal.notes? %> <% for detail in @journal.details -%> @@ -7,4 +10,6 @@ <% end -%> ---------------------------------------- +<% end %> + <%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url } %> diff --git a/app/views/settings/_question_plugin.html.erb b/app/views/settings/_question_plugin.html.erb index a527ff1..0ed3078 100644 --- a/app/views/settings/_question_plugin.html.erb +++ b/app/views/settings/_question_plugin.html.erb @@ -12,4 +12,13 @@ [l(:text_question_close_selected), 0], ], Setting.plugin_question_plugin[:close_all_questions]) %> +

    +

    + <%= label_tag "settings[obfuscate_author]", l(:label_question_plugin_notifications_obfuscate_author_settings) %> + <%= check_box_tag 'settings[obfuscate_author]', 1, (Setting.plugin_question_plugin[:obfuscate_author] ? true : false) %> + +

    +

    + <%= label_tag "settings[obfuscate_content]", l(:label_question_plugin_notifications_obfuscate_content_settings) %> + <%= check_box_tag 'settings[obfuscate_content]', 1, (Setting.plugin_question_plugin[:obfuscate_content] ? true : false) %>

    \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 4ca877c..3a1a7c6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -11,6 +11,8 @@ en: text_question_for_anyone: Question for anyone text_questions_for_me: Questions for me text_question_asked: Question asked + mail_body_question_link: Display question by clicking on the issue link below + mail_body_answer_link: "Your question has received an answer: click on the issue link below to display it" text_question_remove: "<< Remove Question>>" question_text_asked_by: "Asked By" question_text_assigned_to: "Question assigned To" @@ -26,4 +28,6 @@ en: label_question_plugin_close_settings: When add comment close text_question_close_all: all opened questions in issue text_question_close_selected: only selected question + label_question_plugin_notifications_obfuscate_author_settings: Obfuscate asker/answerer name and e-mail address in notifications + label_question_plugin_notifications_obfuscate_content_settings: Obfuscate question/answer text in notifications field_question_to_answer: Answer question diff --git a/init.rb b/init.rb index 99a6b98..3351229 100644 --- a/init.rb +++ b/init.rb @@ -48,6 +48,8 @@ settings :default => { :only_members => 1, :close_all_questions => 1, + :obfuscate_author => 0, + :obfuscate_content => 0, }, :partial => 'settings/question_plugin' end From 930533be7753fd7b2abea5d69d6d69896dbb4ea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Vaisar?= Date: Tue, 10 Sep 2013 22:16:22 +0200 Subject: [PATCH 35/66] Imitation of previous behavior * hiding question selectbox * always answers last question in ticket --- lib/question_issue_hooks.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index 38d9c7c..12decb0 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -31,8 +31,8 @@ def view_issues_edit_notes_bottom(context = { }) questions = @issue.pending_questions(User.current) o << content_tag(:p, " ".html_safe + - select_tag('question_to_answer', options_for_select([[]] + questions.collect {|q| [truncate(q.journal.notes, :length => Question::TruncateTo), q.id]})) - ) + select_tag('question_to_answer', options_for_select([[]] + questions.collect {|q| [truncate(q.journal.notes, :length => Question::TruncateTo), q.id]}, [questions.last.id])), + :style => 'display: none;') end o << content_tag(:p, " ".html_safe + From 01ff18962a46417f750d70af44e3c03b36109296 Mon Sep 17 00:00:00 2001 From: cforce Date: Fri, 27 Sep 2013 18:31:12 +0200 Subject: [PATCH 36/66] duno --- .../issuequestions/autocomplete_for_user_login.html.erb | 7 +++++++ .../issuequestions/autocomplete_for_user_login.json.erb | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 app/views/issuequestions/autocomplete_for_user_login.html.erb create mode 100644 app/views/issuequestions/autocomplete_for_user_login.json.erb diff --git a/app/views/issuequestions/autocomplete_for_user_login.html.erb b/app/views/issuequestions/autocomplete_for_user_login.html.erb new file mode 100644 index 0000000..7c4c6ee --- /dev/null +++ b/app/views/issuequestions/autocomplete_for_user_login.html.erb @@ -0,0 +1,7 @@ +<%= raw @users.map {|user| { + 'id' => user.login, + 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", + 'value' => user.login + } + }.to_json +%> \ No newline at end of file diff --git a/app/views/issuequestions/autocomplete_for_user_login.json.erb b/app/views/issuequestions/autocomplete_for_user_login.json.erb new file mode 100644 index 0000000..7c4c6ee --- /dev/null +++ b/app/views/issuequestions/autocomplete_for_user_login.json.erb @@ -0,0 +1,7 @@ +<%= raw @users.map {|user| { + 'id' => user.login, + 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", + 'value' => user.login + } + }.to_json +%> \ No newline at end of file From bc34396a45cc3d05e8a5fbfaee89c15564fb9451 Mon Sep 17 00:00:00 2001 From: cforce Date: Sun, 29 Sep 2013 15:18:12 +0200 Subject: [PATCH 37/66] fixed javascript ref bug --- app/controllers/issuequestions_controller.rb | 2 +- .../autocomplete_for_user_login.html.erb | 7 + .../autocomplete_for_user_login.json.erb | 7 + .../autocomplete_for_user_login.html.erb | 7 + lib/question_issue_hooks.rb | 216 +++++++++--------- lib/question_journal_hooks.rb | 192 ++++++++-------- 6 files changed, 226 insertions(+), 205 deletions(-) create mode 100644 app/views/issuequestions/autocomplete_for_user_login.html.erb create mode 100644 app/views/issuequestions/autocomplete_for_user_login.json.erb create mode 100644 app/views/questions/autocomplete_for_user_login.html.erb diff --git a/app/controllers/issuequestions_controller.rb b/app/controllers/issuequestions_controller.rb index 34ead06..03ef346 100644 --- a/app/controllers/issuequestions_controller.rb +++ b/app/controllers/issuequestions_controller.rb @@ -14,7 +14,7 @@ def user_issue_filter end def autocomplete_for_user_login - if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == 1 + if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == "1" @issue = Issue.find_by_id(params[:issue_id]) base = @issue.project.users else diff --git a/app/views/issuequestions/autocomplete_for_user_login.html.erb b/app/views/issuequestions/autocomplete_for_user_login.html.erb new file mode 100644 index 0000000..7c4c6ee --- /dev/null +++ b/app/views/issuequestions/autocomplete_for_user_login.html.erb @@ -0,0 +1,7 @@ +<%= raw @users.map {|user| { + 'id' => user.login, + 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", + 'value' => user.login + } + }.to_json +%> \ No newline at end of file diff --git a/app/views/issuequestions/autocomplete_for_user_login.json.erb b/app/views/issuequestions/autocomplete_for_user_login.json.erb new file mode 100644 index 0000000..7c4c6ee --- /dev/null +++ b/app/views/issuequestions/autocomplete_for_user_login.json.erb @@ -0,0 +1,7 @@ +<%= raw @users.map {|user| { + 'id' => user.login, + 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", + 'value' => user.login + } + }.to_json +%> \ No newline at end of file diff --git a/app/views/questions/autocomplete_for_user_login.html.erb b/app/views/questions/autocomplete_for_user_login.html.erb new file mode 100644 index 0000000..8c1bf6d --- /dev/null +++ b/app/views/questions/autocomplete_for_user_login.html.erb @@ -0,0 +1,7 @@ +<%= raw @users.map {|user| { + 'id' => user.login, + 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", + 'value' => user.login + } + }.to_json +%> \ No newline at end of file diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index 3abb007..7f86735 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -1,108 +1,108 @@ -class QuestionIssueHooks < QuestionHooksBase - # Applies the question class to each journal div if they are questions - def view_issues_history_journal_bottom(context = { }) - o = '' - if context[:journal] && context[:journal].question - question = context[:journal].question - - if question.assigned_to - html = assigned_question_html(question) - else - html = unassigned_question_html(question) - end - - className = question.opened ? 'question' : 'question-closed' - o += < - $('#change-#{context[:journal].id}').addClass('#{className}'); - $('#change-#{context[:journal].id} h4 .journal-link').after(' #{html} '); - -JS - end - return o - end - - def view_issues_edit_notes_bottom(context = { }) - f = context[:form] - @issue = context[:issue] - o = '' - - if @issue.pending_question?(User.current) && Setting.plugin_question_plugin[:close_all_questions] != "1" - questions = @issue.pending_questions(User.current) - o << content_tag(:p, - " ".html_safe + - select_tag('question_to_answer', options_for_select([[]] + questions.collect {|q| [truncate(q.journal.notes, :length => Question::TruncateTo), q.id]})) - ) - end - o << content_tag(:p, - " ".html_safe + - text_field_tag('note[question_assigned_to]', nil, :size => "40")) - o << javascript_tag("observeAutocompleteField('note_question_assigned_to', '#{escape_javascript issuequestions_autocomplete_for_user_login_path(@issue.project, @issue)}')") - - return o - end - - def controller_issues_edit_before_save(context = { }) - params = context[:params] - journal = context[:journal] - issue = context[:issue] - if params[:note] && !params[:note][:question_assigned_to].blank? - unless journal.question # Update handled by Journal hooks - # New - journal.question = Question.new( - :author => User.current, - :issue => journal.issue - ) - if params[:note][:question_assigned_to].downcase != 'anyone' - # Assigned to a specific user - assign_question_to_user(journal, User.find_by_login(params[:note][:question_assigned_to])) - end - end - end - - if Setting.plugin_question_plugin[:close_all_questions] == "1" - # Close any open questions - if journal.issue.present? && journal.issue.pending_question?(journal.user) - journal.issue.close_pending_questions(journal.user, journal) - end - else - # Close specific question - if params[:question_to_answer] and !params[:question_to_answer].empty? - question = Question.find(params[:question_to_answer]) - question.close!(journal) - end - end - - return '' - end - - def view_issues_sidebar_issues_bottom(context = { }) - project = context[:project] - if project - question_count = Question.count_of_open_for_user_on_project(User.current, project) - else - question_count = Question.count_of_open_for_user(User.current) - end - - if question_count > 0 - return link_to(l(:text_questions_for_me) + " (#{question_count})", - { - :controller => 'issuequestions', - :action => 'my_issue_filter', - :project => project, - :only_path => true - }, - { :class => 'question-link' } - ) + '
    '.html_safe - else - return '' - end - - end - - private - - def assign_question_to_user(journal, user) - journal.question.assigned_to = user - end -end +class QuestionIssueHooks < QuestionHooksBase + # Applies the question class to each journal div if they are questions + def view_issues_history_journal_bottom(context = { }) + o = '' + if context[:journal] && context[:journal].question + question = context[:journal].question + + if question.assigned_to + html = assigned_question_html(question) + else + html = unassigned_question_html(question) + end + + className = question.opened ? 'question' : 'question-closed' + o += < + $('#change-#{context[:journal].id}').addClass('#{className}'); + $('#change-#{context[:journal].id} h4 .journal-link').after(' #{html} '); + +JS + end + return o + end + + def view_issues_edit_notes_bottom(context = { }) + f = context[:form] + @issue = context[:issue] + o = '' + + if @issue.pending_question?(User.current) && Setting.plugin_question_plugin[:close_all_questions] != "1" + questions = @issue.pending_questions(User.current) + o << content_tag(:p, + " ".html_safe + + select_tag('question_to_answer', options_for_select([[]] + questions.collect {|q| [truncate(q.journal.notes, :length => Question::TruncateTo), q.id]})) + ) + end + o << content_tag(:p, + " ".html_safe + + text_field_tag('note[question_assigned_to]', nil, :size => "40")) + o << javascript_tag("observeAutocompleteField('note_question_assigned_to', '#{escape_javascript issuequestions_autocomplete_for_user_login_path(@issue.project, @issue)}')") + + return o + end + + def controller_issues_edit_before_save(context = { }) + params = context[:params] + journal = context[:journal] + issue = context[:issue] + if params[:note] && !params[:note][:question_assigned_to].blank? + unless journal.question # Update handled by Journal hooks + # New + journal.question = Question.new( + :author => User.current, + :issue => journal.issue + ) + if params[:note][:question_assigned_to].downcase != 'anyone' + # Assigned to a specific user + assign_question_to_user(journal, User.find_by_login(params[:note][:question_assigned_to])) + end + end + end + + if Setting.plugin_question_plugin[:close_all_questions] == "1" + # Close any open questions + if journal.issue.present? && journal.issue.pending_question?(journal.user) + journal.issue.close_pending_questions(journal.user, journal) + end + else + # Close specific question + if params[:question_to_answer] and !params[:question_to_answer].empty? + question = Question.find(params[:question_to_answer]) + question.close!(journal) + end + end + + return '' + end + + def view_issues_sidebar_issues_bottom(context = { }) + project = context[:project] + if project + question_count = Question.count_of_open_for_user_on_project(User.current, project) + else + question_count = Question.count_of_open_for_user(User.current) + end + + if question_count > 0 + return link_to(l(:text_questions_for_me) + " (#{question_count})", + { + :controller => 'issuequestions', + :action => 'my_issue_filter', + :project => project, + :only_path => true + }, + { :class => 'question-link' } + ) + '
    '.html_safe + else + return '' + end + + end + + private + + def assign_question_to_user(journal, user) + journal.question.assigned_to = user + end +end diff --git a/lib/question_journal_hooks.rb b/lib/question_journal_hooks.rb index b54799b..0f43d10 100644 --- a/lib/question_journal_hooks.rb +++ b/lib/question_journal_hooks.rb @@ -1,96 +1,96 @@ -class QuestionJournalHooks < QuestionHooksBase - def view_journals_notes_form_after_notes(context = { }) - @journal = context[:journal] - if @journal.question && @journal.question.opened && @journal.question.assigned_to - assigned_to = @journal.question.assigned_to.login - else - assigned_to = '' - end - - o = '' - o << content_tag(:p, - " ".html_safe + - text_field_tag('question[assigned_to]', assigned_to, :size => "40")) - - o << javascript_tag("observeAutocompleteField('question_assigned_to', '#{escape_javascript questions_autocomplete_for_user_login_path(@journal.issue.project, @journal.issue)}')") - - return o - end - - def controller_journals_edit_post(context = { }) - journal = context[:journal] - params = context[:params] - - # Handle destroying journals through the 'edit' action (done by clearing notes) - return '' if journal.destroyed? - - if params[:question] && params[:question][:assigned_to] - if journal.question && params[:question][:assigned_to].blank? - # Wants to remove the question - journal.question.destroy - elsif journal.question && journal.question.opened - # Reassignment - if params[:question][:assigned_to].downcase == 'anyone' - journal.question.update_attributes(:assigned_to => nil) - else - journal.question.update_attributes(:assigned_to => User.find_by_login(params[:question][:assigned_to])) - end - elsif journal.question && !journal.question.opened - # Existing question, destry it first and then add a new question - journal.question.destroy - add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) - else - if params[:question][:assigned_to].downcase == 'anyone' - add_new_question(journal) - elsif !params[:question][:assigned_to].blank? - add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) - else - # No question - end - end - - end - - return '' - end - - def view_journals_update_js_bottom(context = { }) - @journal = context[:journal] - page = context[:page] - page = "" - unless @journal.frozen? - @journal.reload - if @journal && @journal.question && @journal.question.opened? - question = @journal.question - - if question.assigned_to - html = assigned_question_html(question) - else - html = unassigned_question_html(question) - end - - page << "$('#change-#{@journal.id}').addClass('question');" - page << "$('#change-#{@journal.id} h4 span.question-line').remove();" - page << "$('#change-#{@journal.id} h4 .journal-link').after(' #{html} ') ;" - - elsif @journal && @journal.question.nil? - # No question found, make sure the UI reflects this - page << "$('#change-#{@journal.id}').removeClass('question');" - page << "$('#change-#{@journal.id} h4 span.question-line').remove();" - end - end - return page - end - - private - - def add_new_question(journal, assigned_to=nil) - journal.question = Question.new( - :author => User.current, - :issue => journal.issue, - :assigned_to => assigned_to - ) - journal.question.save! - journal.save - end -end +class QuestionJournalHooks < QuestionHooksBase + def view_journals_notes_form_after_notes(context = { }) + @journal = context[:journal] + if @journal.question && @journal.question.opened && @journal.question.assigned_to + assigned_to = @journal.question.assigned_to.login + else + assigned_to = '' + end + + o = '' + o << content_tag(:p, + " ".html_safe + + text_field_tag('question[assigned_to]', assigned_to, :size => "40")) + + o << javascript_tag("observeAutocompleteField('question_assigned_to', '#{escape_javascript issuequestions_autocomplete_for_user_login_path(@journal.issue.project, @journal.issue)}')") + + return o + end + + def controller_journals_edit_post(context = { }) + journal = context[:journal] + params = context[:params] + + # Handle destroying journals through the 'edit' action (done by clearing notes) + return '' if journal.destroyed? + + if params[:question] && params[:question][:assigned_to] + if journal.question && params[:question][:assigned_to].blank? + # Wants to remove the question + journal.question.destroy + elsif journal.question && journal.question.opened + # Reassignment + if params[:question][:assigned_to].downcase == 'anyone' + journal.question.update_attributes(:assigned_to => nil) + else + journal.question.update_attributes(:assigned_to => User.find_by_login(params[:question][:assigned_to])) + end + elsif journal.question && !journal.question.opened + # Existing question, destry it first and then add a new question + journal.question.destroy + add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) + else + if params[:question][:assigned_to].downcase == 'anyone' + add_new_question(journal) + elsif !params[:question][:assigned_to].blank? + add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) + else + # No question + end + end + + end + + return '' + end + + def view_journals_update_js_bottom(context = { }) + @journal = context[:journal] + page = context[:page] + page = "" + unless @journal.frozen? + @journal.reload + if @journal && @journal.question && @journal.question.opened? + question = @journal.question + + if question.assigned_to + html = assigned_question_html(question) + else + html = unassigned_question_html(question) + end + + page << "$('#change-#{@journal.id}').addClass('question');" + page << "$('#change-#{@journal.id} h4 span.question-line').remove();" + page << "$('#change-#{@journal.id} h4 .journal-link').after(' #{html} ') ;" + + elsif @journal && @journal.question.nil? + # No question found, make sure the UI reflects this + page << "$('#change-#{@journal.id}').removeClass('question');" + page << "$('#change-#{@journal.id} h4 span.question-line').remove();" + end + end + return page + end + + private + + def add_new_question(journal, assigned_to=nil) + journal.question = Question.new( + :author => User.current, + :issue => journal.issue, + :assigned_to => assigned_to + ) + journal.question.save! + journal.save + end +end From 55ffe3ade71bf295482fcc89cb721e0ac5ed70dc Mon Sep 17 00:00:00 2001 From: cforce Date: Mon, 30 Sep 2013 11:34:47 +0200 Subject: [PATCH 38/66] mefrged all in and fixed bugs works on redmine 2.3.3 --- .../issuequestions/autocomplete_for_user_login.html.erb | 9 --------- lib/question_issue_hooks.rb | 4 ++-- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/app/views/issuequestions/autocomplete_for_user_login.html.erb b/app/views/issuequestions/autocomplete_for_user_login.html.erb index e016d98..285e336 100644 --- a/app/views/issuequestions/autocomplete_for_user_login.html.erb +++ b/app/views/issuequestions/autocomplete_for_user_login.html.erb @@ -1,16 +1,7 @@ -<<<<<<< HEAD <%= raw @users.map {|user| { - 'id' => user.login, - 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", - 'value' => user.login - } - }.to_json -======= -<%= raw @users.map {|user| { 'id' => user.login, 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", 'value' => user.login } }.to_json ->>>>>>> 930533be7753fd7b2abea5d69d6d69896dbb4ea7 %> \ No newline at end of file diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb index 5f9ae3b..47d2350 100644 --- a/lib/question_issue_hooks.rb +++ b/lib/question_issue_hooks.rb @@ -31,8 +31,8 @@ def view_issues_edit_notes_bottom(context = { }) questions = @issue.pending_questions(User.current) o << content_tag(:p, " ".html_safe + - select_tag('question_to_answer', options_for_select([[]] + questions.collect {|q| [truncate(q.journal.notes, :length => Question::TruncateTo), q.id]}, [questions.last.id])), - :style => 'display: none;') + select_tag('question_to_answer', options_for_select([[]] + questions.collect {|q| [truncate(q.journal.notes, :length => Question::TruncateTo), q.id]})) + ) end o << content_tag(:p, " ".html_safe + From 271548ba71a57679894d7126f967d2e621b58dbc Mon Sep 17 00:00:00 2001 From: cforce Date: Mon, 30 Sep 2013 16:09:18 +0200 Subject: [PATCH 39/66] added locale --- config/locales/de.yml | 62 +++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index 4711e79..2425d00 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1,29 +1,33 @@ -de: - field_question_assign_to: "Frage zuweisen an" - field_question_assigned_to: "Frage ist gestellt an" - field_question_asked_by: "Frage wurde gestellt durch" - field_formatted_questions: "Fragen" - text_question: "Frage" - text_question_answered: "Frage beantwortet" - text_answer: "Antwort" - text_anyone: "Irgendwer" - text_question_for: "Frage für" - text_question_for_anyone: "Frage für irgendjemanden" - text_questions_for_me: "Fragen für mich" - text_question_asked: "Frage gestellt" - text_question_remove: "<>" - question_text_asked_by: "gefragt von" - question_text_assigned_to: "Zugewiesen an" - question_text_created_on: "erstellt am" - question_text_ratio_questions_answered: "{{ratio}} beantwortete Fragen" - field_journal: "Journal" - text_questions_asked_by_me: "meine gestellten Fragen" - question_reminder_subject: "%{count} offene Frage(n)" - question_reminder_body: "%{count} offene dir zugewiesene Frage(n)" - label_question_plugin_only_members: Die Frage kann diesem Benutzer zugewiesen werden - text_question_all: jedem Benutzer - text_question_project_member: Projektmitarbeitern - label_question_plugin_close_settings: Frage des Tickets abschließend beantworten - text_question_close_all: alle offene Fragen - text_question_close_selected: ausschließlich aktuell ausgewählte Frage - field_question_to_answer: Frage beantworten +de: + field_question_assign_to: "Frage zuweisen an" + field_question_assigned_to: "Frage ist gestellt an" + field_question_asked_by: "Frage wurde gestellt durch" + field_formatted_questions: "Fragen" + text_question: "Frage" + text_question_answered: "Frage beantwortet" + text_answer: "Antwort" + text_anyone: "Irgendwer" + text_question_for: "Frage für" + text_question_for_anyone: "Frage für irgendjemanden" + text_questions_for_me: "Fragen für mich" + text_question_asked: "Frage gestellt" + text_question_remove: "<>" + question_text_asked_by: "gefragt von" + question_text_assigned_to: "Zugewiesen an" + question_text_created_on: "erstellt am" + question_text_ratio_questions_answered: "{{ratio}} beantwortete Fragen" + field_journal: "Journal" + text_questions_asked_by_me: "meine gestellten Fragen" + question_reminder_subject: "%{count} offene Frage(n)" + question_reminder_body: "%{count} offene dir zugewiesene Frage(n)" + label_question_plugin_only_members: Die Frage kann diesem Benutzer zugewiesen werden + text_question_all: jedem Benutzer + text_question_project_member: Projektmitarbeitern + label_question_plugin_close_settings: Frage des Tickets abschließend beantworten + text_question_close_all: alle offene Fragen + text_question_close_selected: ausschließlich aktuell ausgewählte Frage + label_question_plugin_notifications_obfuscate_author_settings: Name und Email des Fragestellers in Email Benachrichtigungen verbergen + label_question_plugin_notifications_obfuscate_content_settings: Frage- und Anworttext in Email Benachrichtigungen verbergen + field_question_to_answer: Frage beantworten + mail_body_question_link: Zeige Sie die Frage für sich an, indem sie auf den nachfolgenden Link für das Ticket klicken + mail_body_answer_link: "Ihre Frage wurde beantwortet: Klicken Sie auf den nachfolgenden Link für das Ticket um die Antwort zu sehen" From 4538a340e4ed1abac51a9913d1ae6f6750281a22 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Tue, 11 Feb 2014 12:55:01 +0200 Subject: [PATCH 40/66] Replaced windows \r\n to linux \n --- Rakefile | 0 app/controllers/issuequestions_controller.rb | 96 ++++----- .../autocomplete_for_user_login.html.erb | 2 +- .../autocomplete_for_user_login.json.erb | 12 +- config/locales/de.yml | 66 +++--- config/routes.rb | 24 +-- lib/question_journal_hooks.rb | 192 +++++++++--------- 7 files changed, 196 insertions(+), 196 deletions(-) mode change 100755 => 100644 Rakefile diff --git a/Rakefile b/Rakefile old mode 100755 new mode 100644 diff --git a/app/controllers/issuequestions_controller.rb b/app/controllers/issuequestions_controller.rb index 34ead06..5db7352 100644 --- a/app/controllers/issuequestions_controller.rb +++ b/app/controllers/issuequestions_controller.rb @@ -1,48 +1,48 @@ -class IssuequestionsController < ApplicationController - unloadable - layout 'base' - - # Create a query in the session and redirects to the issue list with that query - def my_issue_filter - new_filter_for_questions_assigned_to('me') - redirect_to :controller => 'issues', :action => 'index', :project_id => params[:project] - end - - def user_issue_filter - new_filter_for_questions_assigned_to(params[:user_id]) - redirect_to :controller => 'issues', :action => 'index', :project_id => params[:project] - end - - def autocomplete_for_user_login - if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == 1 - @issue = Issue.find_by_id(params[:issue_id]) - base = @issue.project.users - else - base = User - end - q = (params[:q] || params[:term] || params[:user]).to_s.strip.downcase - if q.present? - @users = base.active.all(:conditions => ["LOWER(login) LIKE :user OR LOWER(firstname) LIKE :user OR LOWER(lastname) LIKE :user", {:user => q + "%" }], - :limit => 10, - :order => 'login ASC') - end - @users ||=[] - - render :layout => false - end - - private - - def new_filter_for_questions_assigned_to(user_id) - @project = Project.find(params[:project]) unless params[:project].nil? - - @query = (ActiveSupport::Dependencies::search_for_file('issue_query') ? IssueQuery : Query).new(:name => "_", - :filters => {'status_id' => {:operator => '*', :values => [""]}} - ) - @query.project = @project unless params[:project].nil? - @query.add_filter("question_assigned_to_id", '=',[user_id]) - - session[:query] = {:project_id => @query.project_id, :filters => @query.filters} - end - -end +class IssuequestionsController < ApplicationController + unloadable + layout 'base' + + # Create a query in the session and redirects to the issue list with that query + def my_issue_filter + new_filter_for_questions_assigned_to('me') + redirect_to :controller => 'issues', :action => 'index', :project_id => params[:project] + end + + def user_issue_filter + new_filter_for_questions_assigned_to(params[:user_id]) + redirect_to :controller => 'issues', :action => 'index', :project_id => params[:project] + end + + def autocomplete_for_user_login + if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == 1 + @issue = Issue.find_by_id(params[:issue_id]) + base = @issue.project.users + else + base = User + end + q = (params[:q] || params[:term] || params[:user]).to_s.strip.downcase + if q.present? + @users = base.active.all(:conditions => ["LOWER(login) LIKE :user OR LOWER(firstname) LIKE :user OR LOWER(lastname) LIKE :user", {:user => q + "%" }], + :limit => 10, + :order => 'login ASC') + end + @users ||=[] + + render :layout => false + end + + private + + def new_filter_for_questions_assigned_to(user_id) + @project = Project.find(params[:project]) unless params[:project].nil? + + @query = (ActiveSupport::Dependencies::search_for_file('issue_query') ? IssueQuery : Query).new(:name => "_", + :filters => {'status_id' => {:operator => '*', :values => [""]}} + ) + @query.project = @project unless params[:project].nil? + @query.add_filter("question_assigned_to_id", '=',[user_id]) + + session[:query] = {:project_id => @query.project_id, :filters => @query.filters} + end + +end diff --git a/app/views/issuequestions/autocomplete_for_user_login.html.erb b/app/views/issuequestions/autocomplete_for_user_login.html.erb index 285e336..14c0ccd 100644 --- a/app/views/issuequestions/autocomplete_for_user_login.html.erb +++ b/app/views/issuequestions/autocomplete_for_user_login.html.erb @@ -1,4 +1,4 @@ -<%= raw @users.map {|user| { +<%= raw @users.map {|user| { 'id' => user.login, 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", 'value' => user.login diff --git a/app/views/issuequestions/autocomplete_for_user_login.json.erb b/app/views/issuequestions/autocomplete_for_user_login.json.erb index 7c4c6ee..8c1bf6d 100644 --- a/app/views/issuequestions/autocomplete_for_user_login.json.erb +++ b/app/views/issuequestions/autocomplete_for_user_login.json.erb @@ -1,7 +1,7 @@ -<%= raw @users.map {|user| { - 'id' => user.login, - 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", - 'value' => user.login - } - }.to_json +<%= raw @users.map {|user| { + 'id' => user.login, + 'label' => "#{user.login}: #{user.name(:lastname_coma_firstname)}", + 'value' => user.login + } + }.to_json %> \ No newline at end of file diff --git a/config/locales/de.yml b/config/locales/de.yml index 2425d00..31b1577 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1,33 +1,33 @@ -de: - field_question_assign_to: "Frage zuweisen an" - field_question_assigned_to: "Frage ist gestellt an" - field_question_asked_by: "Frage wurde gestellt durch" - field_formatted_questions: "Fragen" - text_question: "Frage" - text_question_answered: "Frage beantwortet" - text_answer: "Antwort" - text_anyone: "Irgendwer" - text_question_for: "Frage für" - text_question_for_anyone: "Frage für irgendjemanden" - text_questions_for_me: "Fragen für mich" - text_question_asked: "Frage gestellt" - text_question_remove: "<>" - question_text_asked_by: "gefragt von" - question_text_assigned_to: "Zugewiesen an" - question_text_created_on: "erstellt am" - question_text_ratio_questions_answered: "{{ratio}} beantwortete Fragen" - field_journal: "Journal" - text_questions_asked_by_me: "meine gestellten Fragen" - question_reminder_subject: "%{count} offene Frage(n)" - question_reminder_body: "%{count} offene dir zugewiesene Frage(n)" - label_question_plugin_only_members: Die Frage kann diesem Benutzer zugewiesen werden - text_question_all: jedem Benutzer - text_question_project_member: Projektmitarbeitern - label_question_plugin_close_settings: Frage des Tickets abschließend beantworten - text_question_close_all: alle offene Fragen - text_question_close_selected: ausschließlich aktuell ausgewählte Frage - label_question_plugin_notifications_obfuscate_author_settings: Name und Email des Fragestellers in Email Benachrichtigungen verbergen - label_question_plugin_notifications_obfuscate_content_settings: Frage- und Anworttext in Email Benachrichtigungen verbergen - field_question_to_answer: Frage beantworten - mail_body_question_link: Zeige Sie die Frage für sich an, indem sie auf den nachfolgenden Link für das Ticket klicken - mail_body_answer_link: "Ihre Frage wurde beantwortet: Klicken Sie auf den nachfolgenden Link für das Ticket um die Antwort zu sehen" +de: + field_question_assign_to: "Frage zuweisen an" + field_question_assigned_to: "Frage ist gestellt an" + field_question_asked_by: "Frage wurde gestellt durch" + field_formatted_questions: "Fragen" + text_question: "Frage" + text_question_answered: "Frage beantwortet" + text_answer: "Antwort" + text_anyone: "Irgendwer" + text_question_for: "Frage für" + text_question_for_anyone: "Frage für irgendjemanden" + text_questions_for_me: "Fragen für mich" + text_question_asked: "Frage gestellt" + text_question_remove: "<>" + question_text_asked_by: "gefragt von" + question_text_assigned_to: "Zugewiesen an" + question_text_created_on: "erstellt am" + question_text_ratio_questions_answered: "{{ratio}} beantwortete Fragen" + field_journal: "Journal" + text_questions_asked_by_me: "meine gestellten Fragen" + question_reminder_subject: "%{count} offene Frage(n)" + question_reminder_body: "%{count} offene dir zugewiesene Frage(n)" + label_question_plugin_only_members: Die Frage kann diesem Benutzer zugewiesen werden + text_question_all: jedem Benutzer + text_question_project_member: Projektmitarbeitern + label_question_plugin_close_settings: Frage des Tickets abschließend beantworten + text_question_close_all: alle offene Fragen + text_question_close_selected: ausschließlich aktuell ausgewählte Frage + label_question_plugin_notifications_obfuscate_author_settings: Name und Email des Fragestellers in Email Benachrichtigungen verbergen + label_question_plugin_notifications_obfuscate_content_settings: Frage- und Anworttext in Email Benachrichtigungen verbergen + field_question_to_answer: Frage beantworten + mail_body_question_link: Zeige Sie die Frage für sich an, indem sie auf den nachfolgenden Link für das Ticket klicken + mail_body_answer_link: "Ihre Frage wurde beantwortet: Klicken Sie auf den nachfolgenden Link für das Ticket um die Antwort zu sehen" diff --git a/config/routes.rb b/config/routes.rb index a284f5a..2492258 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,12 +1,12 @@ -if Rails::VERSION::MAJOR < 3 - ActionController::Routing::Routes.draw do |map| - map.connect 'issuequestions/autocomplete_for_user_login/project/:id/issue/:issue_id', :controller=> 'issuequestions', :action=> 'autocomplete_for_user_login' - map.connect 'issuequestions/my_issue_filter(/project/:project)' ,:controller=> 'issuequestions', :action=> 'my_issue_filter' - map.connect 'issuequestions/user_issue_filter/user/:user_id' ,:controller=> 'issuequestions', :action=> 'user_issue_filter' - end -else - match 'issuequestions/autocomplete_for_user_login/project/:id/issue/:issue_id' => 'issuequestions#autocomplete_for_user_login', :format => false, :as => 'issuequestions_autocomplete_for_user_login' - match 'issuequestions/my_issue_filter(/project/:project)' => 'issuequestions#my_issue_filter', :format => false, :as => 'questions_my_issue_filter' - match 'issuequestions/user_issue_filter/user/:user_id' => 'issuequestions#user_issue_filter', :format => false, :as => 'questions_user_issue_filter' -end - +if Rails::VERSION::MAJOR < 3 + ActionController::Routing::Routes.draw do |map| + map.connect 'issuequestions/autocomplete_for_user_login/project/:id/issue/:issue_id', :controller=> 'issuequestions', :action=> 'autocomplete_for_user_login' + map.connect 'issuequestions/my_issue_filter(/project/:project)' ,:controller=> 'issuequestions', :action=> 'my_issue_filter' + map.connect 'issuequestions/user_issue_filter/user/:user_id' ,:controller=> 'issuequestions', :action=> 'user_issue_filter' + end +else + match 'issuequestions/autocomplete_for_user_login/project/:id/issue/:issue_id' => 'issuequestions#autocomplete_for_user_login', :format => false, :as => 'issuequestions_autocomplete_for_user_login' + match 'issuequestions/my_issue_filter(/project/:project)' => 'issuequestions#my_issue_filter', :format => false, :as => 'questions_my_issue_filter' + match 'issuequestions/user_issue_filter/user/:user_id' => 'issuequestions#user_issue_filter', :format => false, :as => 'questions_user_issue_filter' +end + diff --git a/lib/question_journal_hooks.rb b/lib/question_journal_hooks.rb index 0f43d10..91b8954 100644 --- a/lib/question_journal_hooks.rb +++ b/lib/question_journal_hooks.rb @@ -1,96 +1,96 @@ -class QuestionJournalHooks < QuestionHooksBase - def view_journals_notes_form_after_notes(context = { }) - @journal = context[:journal] - if @journal.question && @journal.question.opened && @journal.question.assigned_to - assigned_to = @journal.question.assigned_to.login - else - assigned_to = '' - end - - o = '' - o << content_tag(:p, - " ".html_safe + - text_field_tag('question[assigned_to]', assigned_to, :size => "40")) - - o << javascript_tag("observeAutocompleteField('question_assigned_to', '#{escape_javascript issuequestions_autocomplete_for_user_login_path(@journal.issue.project, @journal.issue)}')") - - return o - end - - def controller_journals_edit_post(context = { }) - journal = context[:journal] - params = context[:params] - - # Handle destroying journals through the 'edit' action (done by clearing notes) - return '' if journal.destroyed? - - if params[:question] && params[:question][:assigned_to] - if journal.question && params[:question][:assigned_to].blank? - # Wants to remove the question - journal.question.destroy - elsif journal.question && journal.question.opened - # Reassignment - if params[:question][:assigned_to].downcase == 'anyone' - journal.question.update_attributes(:assigned_to => nil) - else - journal.question.update_attributes(:assigned_to => User.find_by_login(params[:question][:assigned_to])) - end - elsif journal.question && !journal.question.opened - # Existing question, destry it first and then add a new question - journal.question.destroy - add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) - else - if params[:question][:assigned_to].downcase == 'anyone' - add_new_question(journal) - elsif !params[:question][:assigned_to].blank? - add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) - else - # No question - end - end - - end - - return '' - end - - def view_journals_update_js_bottom(context = { }) - @journal = context[:journal] - page = context[:page] - page = "" - unless @journal.frozen? - @journal.reload - if @journal && @journal.question && @journal.question.opened? - question = @journal.question - - if question.assigned_to - html = assigned_question_html(question) - else - html = unassigned_question_html(question) - end - - page << "$('#change-#{@journal.id}').addClass('question');" - page << "$('#change-#{@journal.id} h4 span.question-line').remove();" - page << "$('#change-#{@journal.id} h4 .journal-link').after(' #{html} ') ;" - - elsif @journal && @journal.question.nil? - # No question found, make sure the UI reflects this - page << "$('#change-#{@journal.id}').removeClass('question');" - page << "$('#change-#{@journal.id} h4 span.question-line').remove();" - end - end - return page - end - - private - - def add_new_question(journal, assigned_to=nil) - journal.question = Question.new( - :author => User.current, - :issue => journal.issue, - :assigned_to => assigned_to - ) - journal.question.save! - journal.save - end -end +class QuestionJournalHooks < QuestionHooksBase + def view_journals_notes_form_after_notes(context = { }) + @journal = context[:journal] + if @journal.question && @journal.question.opened && @journal.question.assigned_to + assigned_to = @journal.question.assigned_to.login + else + assigned_to = '' + end + + o = '' + o << content_tag(:p, + " ".html_safe + + text_field_tag('question[assigned_to]', assigned_to, :size => "40")) + + o << javascript_tag("observeAutocompleteField('question_assigned_to', '#{escape_javascript issuequestions_autocomplete_for_user_login_path(@journal.issue.project, @journal.issue)}')") + + return o + end + + def controller_journals_edit_post(context = { }) + journal = context[:journal] + params = context[:params] + + # Handle destroying journals through the 'edit' action (done by clearing notes) + return '' if journal.destroyed? + + if params[:question] && params[:question][:assigned_to] + if journal.question && params[:question][:assigned_to].blank? + # Wants to remove the question + journal.question.destroy + elsif journal.question && journal.question.opened + # Reassignment + if params[:question][:assigned_to].downcase == 'anyone' + journal.question.update_attributes(:assigned_to => nil) + else + journal.question.update_attributes(:assigned_to => User.find_by_login(params[:question][:assigned_to])) + end + elsif journal.question && !journal.question.opened + # Existing question, destry it first and then add a new question + journal.question.destroy + add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) + else + if params[:question][:assigned_to].downcase == 'anyone' + add_new_question(journal) + elsif !params[:question][:assigned_to].blank? + add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) + else + # No question + end + end + + end + + return '' + end + + def view_journals_update_js_bottom(context = { }) + @journal = context[:journal] + page = context[:page] + page = "" + unless @journal.frozen? + @journal.reload + if @journal && @journal.question && @journal.question.opened? + question = @journal.question + + if question.assigned_to + html = assigned_question_html(question) + else + html = unassigned_question_html(question) + end + + page << "$('#change-#{@journal.id}').addClass('question');" + page << "$('#change-#{@journal.id} h4 span.question-line').remove();" + page << "$('#change-#{@journal.id} h4 .journal-link').after(' #{html} ') ;" + + elsif @journal && @journal.question.nil? + # No question found, make sure the UI reflects this + page << "$('#change-#{@journal.id}').removeClass('question');" + page << "$('#change-#{@journal.id} h4 span.question-line').remove();" + end + end + return page + end + + private + + def add_new_question(journal, assigned_to=nil) + journal.question = Question.new( + :author => User.current, + :issue => journal.issue, + :assigned_to => assigned_to + ) + journal.question.save! + journal.save + end +end From 14037769a2504624517dfbc80843059c43657aa3 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Thu, 13 Feb 2014 11:54:32 +0200 Subject: [PATCH 41/66] Refactor & last redmine trunk compatibility --- app/models/question.rb | 10 +- init.rb | 31 +++-- lib/question_active_record_relation_patch.rb | 103 ---------------- lib/question_hooks_base.rb | 21 ---- lib/question_issue_hooks.rb | 108 ----------------- lib/question_issue_patch.rb | 47 -------- lib/question_journal_hooks.rb | 96 --------------- lib/question_journal_patch.rb | 22 ---- lib/question_kanban_hooks.rb | 59 --------- lib/question_plugin/hooks/hooks_base.rb | 25 ++++ lib/question_plugin/hooks/issue_hooks.rb | 112 ++++++++++++++++++ lib/question_plugin/hooks/journal_hooks.rb | 100 ++++++++++++++++ lib/question_plugin/hooks/kanban_hooks.rb | 63 ++++++++++ .../hooks/layout_hooks.rb} | 18 +-- lib/question_plugin/patches/issue_patch.rb | 51 ++++++++ .../patches/journal_observer_patch.rb | 5 +- lib/question_plugin/patches/journal_patch.rb | 32 +++++ .../patches/queries_helper_patch.rb | 55 +++++++++ lib/question_plugin/patches/query_patch.rb | 94 +++++++++++++++ lib/question_queries_helper_patch.rb | 54 --------- lib/question_query_patch.rb | 82 ------------- rails/init.rb | 1 - 22 files changed, 570 insertions(+), 619 deletions(-) delete mode 100644 lib/question_active_record_relation_patch.rb delete mode 100644 lib/question_hooks_base.rb delete mode 100644 lib/question_issue_hooks.rb delete mode 100644 lib/question_issue_patch.rb delete mode 100644 lib/question_journal_hooks.rb delete mode 100644 lib/question_journal_patch.rb delete mode 100644 lib/question_kanban_hooks.rb create mode 100644 lib/question_plugin/hooks/hooks_base.rb create mode 100644 lib/question_plugin/hooks/issue_hooks.rb create mode 100644 lib/question_plugin/hooks/journal_hooks.rb create mode 100644 lib/question_plugin/hooks/kanban_hooks.rb rename lib/{question_layout_hooks.rb => question_plugin/hooks/layout_hooks.rb} (68%) create mode 100644 lib/question_plugin/patches/issue_patch.rb create mode 100644 lib/question_plugin/patches/journal_patch.rb create mode 100644 lib/question_plugin/patches/queries_helper_patch.rb create mode 100644 lib/question_plugin/patches/query_patch.rb delete mode 100644 lib/question_queries_helper_patch.rb delete mode 100644 lib/question_query_patch.rb delete mode 100644 rails/init.rb diff --git a/app/models/question.rb b/app/models/question.rb index ddeda99..c880292 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -5,12 +5,12 @@ class Question < ActiveRecord::Base belongs_to :assigned_to, :class_name => "User", :foreign_key => "assigned_to_id" belongs_to :author, :class_name => "User", :foreign_key => "author_id" belongs_to :issue - belongs_to :journal + belongs_to :journal, :class_name => "Journal", :foreign_key => "journal_id" validates_presence_of :author validates_presence_of :issue validates_presence_of :journal - + scope :opened, :conditions => {:opened => true} scope :for_user, lambda {|user| { :conditions => {:assigned_to_id => user.id }} @@ -21,6 +21,8 @@ class Question < ActiveRecord::Base delegate :notes, :to => :journal, :allow_nil => true + after_save :send_notification + def for_anyone? self.assigned_to.nil? end @@ -33,6 +35,10 @@ def close!(closing_journal=nil) end end end + + def send_notification + QuestionMailer.asked_question(self.journal).deliver + end # TODO: refactor to named_scope def self.count_of_open_for_user(user) diff --git a/init.rb b/init.rb index 3351229..bdb119a 100644 --- a/init.rb +++ b/init.rb @@ -1,37 +1,36 @@ require 'redmine' -require 'question_issue_hooks' -require 'question_kanban_hooks' -require 'question_layout_hooks' -require 'question_journal_hooks' +require 'question_plugin/hooks/issue_hooks' +require 'question_plugin/hooks/kanban_hooks' +require 'question_plugin/hooks/layout_hooks' +require 'question_plugin/hooks/journal_hooks' Rails.configuration.to_prepare do - require_dependency 'journal_observer' - JournalObserver.send(:include, QuestionPlugin::Patches::JournalObserverPatch) unless JournalObserver.included_modules.include? QuestionPlugin::Patches::JournalObserverPatch - - require_dependency 'active_record' - ActiveRecord::Relation.send(:include, QuestionActiveRecordRelationPatch) unless ActiveRecord::Relation.included_modules.include? QuestionActiveRecordRelationPatch - require_dependency 'issue' - Issue.send(:include, QuestionIssuePatch) unless Issue.included_modules.include? QuestionIssuePatch + Issue.send(:include, QuestionPlugin::Patches::IssuePatch) unless Issue.included_modules.include? QuestionPlugin::Patches::IssuePatch require_dependency 'journal' - Journal.send(:include, QuestionJournalPatch) unless Journal.included_modules.include? QuestionJournalPatch + Journal.send(:include, QuestionPlugin::Patches::JournalPatch) unless Journal.included_modules.include? QuestionPlugin::Patches::JournalPatch + + if ActiveSupport::Dependencies::search_for_file('journal_observer') + require_dependency 'journal_observer' + JournalObserver.send(:include, QuestionPlugin::Patches::JournalObserverPatch) unless JournalObserver.included_modules.include? QuestionPlugin::Patches::JournalObserverPatch + end if ActiveSupport::Dependencies::search_for_file('issue_queries_helper') require_dependency 'issue_queries_helper' - IssueQueriesHelper.send(:include, QuestionQueriesHelperPatch) unless QueriesHelper.included_modules.include? QuestionQueriesHelperPatch + IssueQueriesHelper.send(:include, QuestionPlugin::Patches::QueriesHelperPatch) unless IssueQueriesHelper.included_modules.include? QuestionPlugin::Patches::QueriesHelperPatch else require_dependency 'queries_helper' - QueriesHelper.send(:include, QuestionQueriesHelperPatch) unless QueriesHelper.included_modules.include? QuestionQueriesHelperPatch + QueriesHelper.send(:include, QuestionPlugin::Patches::QueriesHelperPatch) unless QueriesHelper.included_modules.include? QuestionPlugin::Patches::QueriesHelperPatch end if ActiveSupport::Dependencies::search_for_file('issue_query') require_dependency 'issue_query' - IssueQuery.send(:include, QuestionQueryPatch) unless Query.included_modules.include? QuestionQueryPatch + IssueQuery.send(:include, QuestionPlugin::Patches::QueryPatch) unless Query.included_modules.include? QuestionPlugin::Patches::QueryPatch else require_dependency 'query' - Query.send(:include, QuestionQueryPatch) unless Query.included_modules.include? QuestionQueryPatch + Query.send(:include, QuestionPlugin::Patches::QueryPatch) unless Query.included_modules.include? QuestionPlugin::Patches::QueryPatch end end diff --git a/lib/question_active_record_relation_patch.rb b/lib/question_active_record_relation_patch.rb deleted file mode 100644 index e276dc3..0000000 --- a/lib/question_active_record_relation_patch.rb +++ /dev/null @@ -1,103 +0,0 @@ -module QuestionActiveRecordRelationPatch - def self.included(base) # :nodoc: - base.extend(ClassMethods) - - base.send(:include, InstanceMethods) - - base.class_eval do - unloadable # Send unloadable so it will not be unloaded in development - - alias_method :count_before_question, :count - alias_method :sum_before_question, :sum - alias_method :find_before_question, :find - alias_method :all_before_question, :all - alias_method :find_ids_before_question, :find_ids - - # Override ActiveRecord::Calculations.count - def count(*args) - scan_for_options_hash_and_add_includes_if_needed(self.klass, args) - count_before_question(*args) - end - - # Override ActiveRecord::Calculations.sum - def sum(*args) - scan_for_options_hash_and_add_includes_if_needed(self.klass, args) - sum_before_question(*args) - end - - # Override ActiveRecord::FinderMethods.find - def find(*args) - scan_for_options_hash_and_add_includes_if_needed(self.klass, args) - find_before_question(*args) - end - - # Override ActiveRecord::FinderMethods.all - def all(*args) - scan_for_options_hash_and_add_includes_if_needed(self.klass, args) - all_before_question(*args) - end - - # Override ActiveRecord::FinderMethods.find_ids - def find_ids(*args) - relation = scan_where_clauses_and_add_includes_if_needed - relation.find_ids_before_question(*args) - end - - private - - def scan_where_clauses_and_add_includes_if_needed - relation = self - # Ensure passed class inherits from the Issue class - if relation.klass <= Issue - @where_values.each do |where_value| - if where_value.is_a?(String) && where_value.include?('question') - relation = relation.includes(:questions) - elsif where_value.is_a?(Array) && where_value[0].include?('question') - relation = relation.includes(:questions) - end - end - end - relation - end - - def scan_for_options_hash_and_add_includes_if_needed(klass, args) - # Ensure passed class inherits from the Issue class - if klass <= Issue - args.each do |arg| - if arg.is_a?(Hash) && arg[:conditions] - if arg[:conditions].is_a?(String) && arg[:conditions].include?('question') - # String conditions - add_questions_to_the_includes(arg) - elsif arg[:conditions].is_a?(Array) && arg[:conditions][0].include?('question') - # Array conditions - add_questions_to_the_includes(arg) - end - end - end - end - end - - def add_questions_to_the_includes(arg) - if arg[:include] - # Has includes - if arg[:include].is_a?(Hash) || arg[:include].is_a?(Array) - # Hash includes - arg[:include] << :questions - else - # single includes - arg[:include] = [ arg[:include] , :questions ] - end - else - # No includes - arg[:include] = :questions - end - end - end - end - - module ClassMethods - end - - module InstanceMethods - end -end diff --git a/lib/question_hooks_base.rb b/lib/question_hooks_base.rb deleted file mode 100644 index 5034dd2..0000000 --- a/lib/question_hooks_base.rb +++ /dev/null @@ -1,21 +0,0 @@ -class QuestionHooksBase < Redmine::Hook::ViewListener - # Have to inclue Gravatars because ApplicationHelper will not get it - include GravatarHelper::PublicMethods - - protected - - def assigned_question_html(question) - html = "" - html << " #{l(:text_question_for)} " - html << link_to_user(question.assigned_to) - html << " " if question.assigned_to && question.assigned_to.mail - html - end - - def unassigned_question_html(question) - html = "" - html << l(:text_question_for_anyone) - html << " " - html - end -end diff --git a/lib/question_issue_hooks.rb b/lib/question_issue_hooks.rb deleted file mode 100644 index 47d2350..0000000 --- a/lib/question_issue_hooks.rb +++ /dev/null @@ -1,108 +0,0 @@ -class QuestionIssueHooks < QuestionHooksBase - # Applies the question class to each journal div if they are questions - def view_issues_history_journal_bottom(context = { }) - o = '' - if context[:journal] && context[:journal].question - question = context[:journal].question - - if question.assigned_to - html = assigned_question_html(question) - else - html = unassigned_question_html(question) - end - - className = question.opened ? 'question' : 'question-closed' - o += < - $('#change-#{context[:journal].id}').addClass('#{className}'); - $('#change-#{context[:journal].id} h4 .journal-link').after(' #{html} '); - -JS - end - return o - end - - def view_issues_edit_notes_bottom(context = { }) - f = context[:form] - @issue = context[:issue] - o = '' - - if @issue.pending_question?(User.current) && Setting.plugin_question_plugin[:close_all_questions] != "1" - questions = @issue.pending_questions(User.current) - o << content_tag(:p, - " ".html_safe + - select_tag('question_to_answer', options_for_select([[]] + questions.collect {|q| [truncate(q.journal.notes, :length => Question::TruncateTo), q.id]})) - ) - end - o << content_tag(:p, - " ".html_safe + - text_field_tag('note[question_assigned_to]', nil, :size => "40")) - o << javascript_tag("observeAutocompleteField('note_question_assigned_to', '#{escape_javascript issuequestions_autocomplete_for_user_login_path(@issue.project, @issue)}')") - - return o - end - - def controller_issues_edit_before_save(context = { }) - params = context[:params] - journal = context[:journal] - issue = context[:issue] - if params[:note] && !params[:note][:question_assigned_to].blank? - unless journal.question # Update handled by Journal hooks - # New - journal.question = Question.new( - :author => User.current, - :issue => journal.issue - ) - if params[:note][:question_assigned_to].downcase != 'anyone' - # Assigned to a specific user - assign_question_to_user(journal, User.find_by_login(params[:note][:question_assigned_to])) - end - end - end - - if Setting.plugin_question_plugin[:close_all_questions] == "1" - # Close any open questions - if journal.issue.present? && journal.issue.pending_question?(journal.user) - journal.issue.close_pending_questions(journal.user, journal) - end - else - # Close specific question - if params[:question_to_answer] and !params[:question_to_answer].empty? - question = Question.find(params[:question_to_answer]) - question.close!(journal) - end - end - - return '' - end - - def view_issues_sidebar_issues_bottom(context = { }) - project = context[:project] - if project - question_count = Question.count_of_open_for_user_on_project(User.current, project) - else - question_count = Question.count_of_open_for_user(User.current) - end - - if question_count > 0 - return link_to(l(:text_questions_for_me) + " (#{question_count})", - { - :controller => 'issuequestions', - :action => 'my_issue_filter', - :project => project, - :only_path => true - }, - { :class => 'question-link' } - ) + '
    '.html_safe - else - return '' - end - - end - - private - - def assign_question_to_user(journal, user) - journal.question.assigned_to = user - end -end diff --git a/lib/question_issue_patch.rb b/lib/question_issue_patch.rb deleted file mode 100644 index 2a26f63..0000000 --- a/lib/question_issue_patch.rb +++ /dev/null @@ -1,47 +0,0 @@ -module QuestionIssuePatch - def self.included(base) # :nodoc: - base.extend(ClassMethods) - - base.send(:include, InstanceMethods) - - base.class_eval do - unloadable # Send unloadable so it will not be unloaded in development - has_many :questions - has_many :open_questions, :class_name => 'Question', :conditions => { :opened => true } - - include ActionView::Helpers::TextHelper # for truncate - end - end - - module ClassMethods - end - - module InstanceMethods - def pending_question?(user) - self.open_questions.find(:all).each do |question| - return true if question.assigned_to == user || question.for_anyone? - end - return false - end - - def pending_questions(user) - q = [] - self.open_questions.find(:all).each do |question| - q << question if question.assigned_to == user || question.for_anyone? - end - return q - end - - def close_pending_questions(user, closing_journal) - self.pending_questions(user).each do |question| - question.close!(closing_journal) - end - end - - def formatted_questions - open_questions.collect do |question| - truncate(question.journal.notes, :length => Question::TruncateTo) - end.join(", ") - end - end -end diff --git a/lib/question_journal_hooks.rb b/lib/question_journal_hooks.rb deleted file mode 100644 index 91b8954..0000000 --- a/lib/question_journal_hooks.rb +++ /dev/null @@ -1,96 +0,0 @@ -class QuestionJournalHooks < QuestionHooksBase - def view_journals_notes_form_after_notes(context = { }) - @journal = context[:journal] - if @journal.question && @journal.question.opened && @journal.question.assigned_to - assigned_to = @journal.question.assigned_to.login - else - assigned_to = '' - end - - o = '' - o << content_tag(:p, - " ".html_safe + - text_field_tag('question[assigned_to]', assigned_to, :size => "40")) - - o << javascript_tag("observeAutocompleteField('question_assigned_to', '#{escape_javascript issuequestions_autocomplete_for_user_login_path(@journal.issue.project, @journal.issue)}')") - - return o - end - - def controller_journals_edit_post(context = { }) - journal = context[:journal] - params = context[:params] - - # Handle destroying journals through the 'edit' action (done by clearing notes) - return '' if journal.destroyed? - - if params[:question] && params[:question][:assigned_to] - if journal.question && params[:question][:assigned_to].blank? - # Wants to remove the question - journal.question.destroy - elsif journal.question && journal.question.opened - # Reassignment - if params[:question][:assigned_to].downcase == 'anyone' - journal.question.update_attributes(:assigned_to => nil) - else - journal.question.update_attributes(:assigned_to => User.find_by_login(params[:question][:assigned_to])) - end - elsif journal.question && !journal.question.opened - # Existing question, destry it first and then add a new question - journal.question.destroy - add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) - else - if params[:question][:assigned_to].downcase == 'anyone' - add_new_question(journal) - elsif !params[:question][:assigned_to].blank? - add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) - else - # No question - end - end - - end - - return '' - end - - def view_journals_update_js_bottom(context = { }) - @journal = context[:journal] - page = context[:page] - page = "" - unless @journal.frozen? - @journal.reload - if @journal && @journal.question && @journal.question.opened? - question = @journal.question - - if question.assigned_to - html = assigned_question_html(question) - else - html = unassigned_question_html(question) - end - - page << "$('#change-#{@journal.id}').addClass('question');" - page << "$('#change-#{@journal.id} h4 span.question-line').remove();" - page << "$('#change-#{@journal.id} h4 .journal-link').after(' #{html} ') ;" - - elsif @journal && @journal.question.nil? - # No question found, make sure the UI reflects this - page << "$('#change-#{@journal.id}').removeClass('question');" - page << "$('#change-#{@journal.id} h4 span.question-line').remove();" - end - end - return page - end - - private - - def add_new_question(journal, assigned_to=nil) - journal.question = Question.new( - :author => User.current, - :issue => journal.issue, - :assigned_to => assigned_to - ) - journal.question.save! - journal.save - end -end diff --git a/lib/question_journal_patch.rb b/lib/question_journal_patch.rb deleted file mode 100644 index 5070005..0000000 --- a/lib/question_journal_patch.rb +++ /dev/null @@ -1,22 +0,0 @@ -module QuestionJournalPatch - def self.included(base) # :nodoc: - base.extend(ClassMethods) - - base.send(:include, InstanceMethods) - - base.class_eval do - unloadable # Send unloadable so it will not be unloaded in development - has_one :question, :dependent => :destroy - end - - end - - module ClassMethods - end - - module InstanceMethods - def question_assigned_to - # TODO: pull out the assigned user on edits - end - end -end diff --git a/lib/question_kanban_hooks.rb b/lib/question_kanban_hooks.rb deleted file mode 100644 index caeacf6..0000000 --- a/lib/question_kanban_hooks.rb +++ /dev/null @@ -1,59 +0,0 @@ -class QuestionKanbanHooks < QuestionHooksBase - def view_kanbans_issue_details(context = {}) - # GREY when there are no questions - # RED when there are open questions - # BLACK if all questions are answered - issue = context[:issue] - - return '' unless issue - - if issue.questions.count == 0 - return question_icon(:gray, issue) - end - - if issue.open_questions.count > 0 - return question_icon(:red, issue) - end - - if issue.questions.count > 0 && issue.open_questions.count == 0 - return question_icon(:black, issue) - end - - return '' - end - - # * :user - def view_kanbans_user_name(context = {}) - user = context[:user] - if user - count = Question.count_of_open_for_user(user) - - if count > 0 - return content_tag(:p, link_to(l(:field_formatted_questions) + " (#{count})", - { - :controller => 'issuequestions', - :action => 'user_issue_filter', - :user_id => user.id, - :only_path => true - }, - { :class => 'question-link' })) - end - end - - return '' - - end - - protected - - def question_icon(color, issue) - total_questions = issue.questions.count - open_questions = issue.open_questions.count - answered_questions = total_questions - open_questions - - title = l(:question_text_ratio_questions_answered, :ratio => "#{answered_questions}/#{total_questions}") - link_to(image_tag("question-#{color}.png", :plugin => 'question_plugin', :title => title, :class => "kanban-question #{color}"), - { :controller => 'issues', :action => 'show', :id => issue }, - :class => "issue-show-popup issue-id-#{h(issue.id)}") - end -end diff --git a/lib/question_plugin/hooks/hooks_base.rb b/lib/question_plugin/hooks/hooks_base.rb new file mode 100644 index 0000000..aace9dc --- /dev/null +++ b/lib/question_plugin/hooks/hooks_base.rb @@ -0,0 +1,25 @@ +module QuestionPlugin + module Hooks + class HooksBase < Redmine::Hook::ViewListener + # Have to inclue Gravatars because ApplicationHelper will not get it + include GravatarHelper::PublicMethods + + protected + + def assigned_question_html(question) + html = "" + html << " #{l(:text_question_for)} " + html << link_to_user(question.assigned_to) + html << " " if question.assigned_to && question.assigned_to.mail + html + end + + def unassigned_question_html(question) + html = "" + html << l(:text_question_for_anyone) + html << " " + html + end + end + end +end diff --git a/lib/question_plugin/hooks/issue_hooks.rb b/lib/question_plugin/hooks/issue_hooks.rb new file mode 100644 index 0000000..45718e2 --- /dev/null +++ b/lib/question_plugin/hooks/issue_hooks.rb @@ -0,0 +1,112 @@ +module QuestionPlugin + module Hooks + class IssueHooks < HooksBase + # Applies the question class to each journal div if they are questions + def view_issues_history_journal_bottom(context = { }) + o = '' + if context[:journal] && context[:journal].question + question = context[:journal].question + + if question.assigned_to + html = assigned_question_html(question) + else + html = unassigned_question_html(question) + end + + className = question.opened ? 'question' : 'question-closed' + o += < + $('#change-#{context[:journal].id}').addClass('#{className}'); + $('#change-#{context[:journal].id} h4 .journal-link').after(' #{html} '); + +JS + end + return o + end + + def view_issues_edit_notes_bottom(context = { }) + f = context[:form] + @issue = context[:issue] + o = '' + + if @issue.pending_question?(User.current) && Setting.plugin_question_plugin[:close_all_questions] != "1" + questions = @issue.pending_questions(User.current) + o << content_tag(:p, + " ".html_safe + + select_tag('question_to_answer', options_for_select([[]] + questions.collect {|q| [truncate(q.journal.notes, :length => Question::TruncateTo), q.id]})) + ) + end + o << content_tag(:p, + " ".html_safe + + text_field_tag('note[question_assigned_to]', nil, :size => "40")) + o << javascript_tag("observeAutocompleteField('note_question_assigned_to', '#{escape_javascript issuequestions_autocomplete_for_user_login_path(@issue.project, @issue)}')") + + return o + end + + def controller_issues_edit_before_save(context = { }) + params = context[:params] + journal = context[:journal] + issue = context[:issue] + if params[:note] && !params[:note][:question_assigned_to].blank? + unless journal.question # Update handled by Journal hooks + # New + journal.question = Question.new( + :author => User.current, + :issue => journal.issue + ) + if params[:note][:question_assigned_to].downcase != 'anyone' + # Assigned to a specific user + assign_question_to_user(journal, User.find_by_login(params[:note][:question_assigned_to])) + end + end + end + + if Setting.plugin_question_plugin[:close_all_questions] == "1" + # Close any open questions + if journal.issue.present? && journal.issue.pending_question?(journal.user) + journal.issue.close_pending_questions(journal.user, journal) + end + else + # Close specific question + if params[:question_to_answer] and !params[:question_to_answer].empty? + question = Question.find(params[:question_to_answer]) + question.close!(journal) + end + end + + return '' + end + + def view_issues_sidebar_issues_bottom(context = { }) + project = context[:project] + if project + question_count = Question.count_of_open_for_user_on_project(User.current, project) + else + question_count = Question.count_of_open_for_user(User.current) + end + + if question_count > 0 + return link_to(l(:text_questions_for_me) + " (#{question_count})", + { + :controller => 'issuequestions', + :action => 'my_issue_filter', + :project => project, + :only_path => true + }, + { :class => 'question-link' } + ) + '
    '.html_safe + else + return '' + end + + end + + private + + def assign_question_to_user(journal, user) + journal.question.assigned_to = user + end + end + end +end diff --git a/lib/question_plugin/hooks/journal_hooks.rb b/lib/question_plugin/hooks/journal_hooks.rb new file mode 100644 index 0000000..141f6cb --- /dev/null +++ b/lib/question_plugin/hooks/journal_hooks.rb @@ -0,0 +1,100 @@ +module QuestionPlugin + module Hooks + class JournalHooks < HooksBase + def view_journals_notes_form_after_notes(context = { }) + @journal = context[:journal] + if @journal.question && @journal.question.opened && @journal.question.assigned_to + assigned_to = @journal.question.assigned_to.login + else + assigned_to = '' + end + + o = '' + o << content_tag(:p, + " ".html_safe + + text_field_tag('question[assigned_to]', assigned_to, :size => "40")) + + o << javascript_tag("observeAutocompleteField('question_assigned_to', '#{escape_javascript issuequestions_autocomplete_for_user_login_path(@journal.issue.project, @journal.issue)}')") + + return o + end + + def controller_journals_edit_post(context = { }) + journal = context[:journal] + params = context[:params] + + # Handle destroying journals through the 'edit' action (done by clearing notes) + return '' if journal.destroyed? + + if params[:question] && params[:question][:assigned_to] + if journal.question && params[:question][:assigned_to].blank? + # Wants to remove the question + journal.question.destroy + elsif journal.question && journal.question.opened + # Reassignment + if params[:question][:assigned_to].downcase == 'anyone' + journal.question.update_attributes(:assigned_to => nil) + else + journal.question.update_attributes(:assigned_to => User.find_by_login(params[:question][:assigned_to])) + end + elsif journal.question && !journal.question.opened + # Existing question, destry it first and then add a new question + journal.question.destroy + add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) + else + if params[:question][:assigned_to].downcase == 'anyone' + add_new_question(journal) + elsif !params[:question][:assigned_to].blank? + add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) + else + # No question + end + end + + end + + return '' + end + + def view_journals_update_js_bottom(context = { }) + @journal = context[:journal] + page = context[:page] + page = "" + unless @journal.frozen? + @journal.reload + if @journal && @journal.question && @journal.question.opened? + question = @journal.question + + if question.assigned_to + html = assigned_question_html(question) + else + html = unassigned_question_html(question) + end + + page << "$('#change-#{@journal.id}').addClass('question');" + page << "$('#change-#{@journal.id} h4 span.question-line').remove();" + page << "$('#change-#{@journal.id} h4 .journal-link').after(' #{html} ') ;" + + elsif @journal && @journal.question.nil? + # No question found, make sure the UI reflects this + page << "$('#change-#{@journal.id}').removeClass('question');" + page << "$('#change-#{@journal.id} h4 span.question-line').remove();" + end + end + return page + end + + private + + def add_new_question(journal, assigned_to=nil) + journal.question = Question.new( + :author => User.current, + :issue => journal.issue, + :assigned_to => assigned_to + ) + journal.question.save! + journal.save + end + end + end +end diff --git a/lib/question_plugin/hooks/kanban_hooks.rb b/lib/question_plugin/hooks/kanban_hooks.rb new file mode 100644 index 0000000..e775f22 --- /dev/null +++ b/lib/question_plugin/hooks/kanban_hooks.rb @@ -0,0 +1,63 @@ +module QuestionPlugin + module Hooks + class KanbanHooks < HooksBase + def view_kanbans_issue_details(context = {}) + # GREY when there are no questions + # RED when there are open questions + # BLACK if all questions are answered + issue = context[:issue] + + return '' unless issue + + if issue.questions.count == 0 + return question_icon(:gray, issue) + end + + if issue.open_questions.count > 0 + return question_icon(:red, issue) + end + + if issue.questions.count > 0 && issue.open_questions.count == 0 + return question_icon(:black, issue) + end + + return '' + end + + # * :user + def view_kanbans_user_name(context = {}) + user = context[:user] + if user + count = Question.count_of_open_for_user(user) + + if count > 0 + return content_tag(:p, link_to(l(:field_formatted_questions) + " (#{count})", + { + :controller => 'issuequestions', + :action => 'user_issue_filter', + :user_id => user.id, + :only_path => true + }, + { :class => 'question-link' })) + end + end + + return '' + + end + + protected + + def question_icon(color, issue) + total_questions = issue.questions.count + open_questions = issue.open_questions.count + answered_questions = total_questions - open_questions + + title = l(:question_text_ratio_questions_answered, :ratio => "#{answered_questions}/#{total_questions}") + link_to(image_tag("question-#{color}.png", :plugin => 'question_plugin', :title => title, :class => "kanban-question #{color}"), + { :controller => 'issues', :action => 'show', :id => issue }, + :class => "issue-show-popup issue-id-#{h(issue.id)}") + end + end + end +end diff --git a/lib/question_layout_hooks.rb b/lib/question_plugin/hooks/layout_hooks.rb similarity index 68% rename from lib/question_layout_hooks.rb rename to lib/question_plugin/hooks/layout_hooks.rb index 057a62c..1417622 100644 --- a/lib/question_layout_hooks.rb +++ b/lib/question_plugin/hooks/layout_hooks.rb @@ -1,8 +1,10 @@ -class QuestionLayoutHooks < Redmine::Hook::ViewListener - - # Add a question CSS class - def view_layouts_base_html_head(context = { }) - o = < .question { background-color:#FFEBC1; border:2px solid #FDBD3B; margin-bottom:12px; padding:0px 4px 8px 4px; } .question-line { float: right; } @@ -14,6 +16,8 @@ def view_layouts_base_html_head(context = { }) CSS - return o + return o + end + end end -end +end \ No newline at end of file diff --git a/lib/question_plugin/patches/issue_patch.rb b/lib/question_plugin/patches/issue_patch.rb new file mode 100644 index 0000000..0808ccd --- /dev/null +++ b/lib/question_plugin/patches/issue_patch.rb @@ -0,0 +1,51 @@ +module QuestionPlugin + module Patches + module IssuePatch + def self.included(base) # :nodoc: + base.extend(ClassMethods) + + base.send(:include, InstanceMethods) + + base.class_eval do + unloadable # Send unloadable so it will not be unloaded in development + has_many :questions + has_many :open_questions, :class_name => 'Question', :conditions => { :opened => true } + + include ActionView::Helpers::TextHelper # for truncate + end + end + + module ClassMethods + end + + module InstanceMethods + def pending_question?(user) + self.open_questions.find(:all).each do |question| + return true if question.assigned_to == user || question.for_anyone? + end + return false + end + + def pending_questions(user) + q = [] + self.open_questions.find(:all).each do |question| + q << question if question.assigned_to == user || question.for_anyone? + end + return q + end + + def close_pending_questions(user, closing_journal) + self.pending_questions(user).each do |question| + question.close!(closing_journal) + end + end + + def formatted_questions + open_questions.collect do |question| + truncate(question.journal.notes, :length => Question::TruncateTo) + end.join(", ") + end + end + end + end +end diff --git a/lib/question_plugin/patches/journal_observer_patch.rb b/lib/question_plugin/patches/journal_observer_patch.rb index 4684b57..d0c9301 100644 --- a/lib/question_plugin/patches/journal_observer_patch.rb +++ b/lib/question_plugin/patches/journal_observer_patch.rb @@ -1,3 +1,7 @@ +# +# used for redmine < 2.3.2 +# + module QuestionPlugin module Patches module JournalObserverPatch @@ -21,7 +25,6 @@ def after_create_with_question(journal) if journal.is_a?(Journal) if journal.question - journal.question.save QuestionMailer.asked_question(journal).deliver end end diff --git a/lib/question_plugin/patches/journal_patch.rb b/lib/question_plugin/patches/journal_patch.rb new file mode 100644 index 0000000..0b9e71f --- /dev/null +++ b/lib/question_plugin/patches/journal_patch.rb @@ -0,0 +1,32 @@ +module QuestionPlugin + module Patches + module JournalPatch + def self.included(base) + base.extend(ClassMethods) + + base.send(:include, InstanceMethods) + base.class_eval do + unloadable + has_one :question, :dependent => :destroy + + # + # used for redmine >= 2.3.2 + # + alias_method_chain :send_notification, :question unless ActiveSupport::Dependencies::search_for_file('journal_observer') + end + end + + module ClassMethods + end + + module InstanceMethods + def send_notification_with_question + send_notification_without_question + if journal.question + QuestionMailer.asked_question(self).deliver + end + end + end + end + end +end diff --git a/lib/question_plugin/patches/queries_helper_patch.rb b/lib/question_plugin/patches/queries_helper_patch.rb new file mode 100644 index 0000000..ed75b65 --- /dev/null +++ b/lib/question_plugin/patches/queries_helper_patch.rb @@ -0,0 +1,55 @@ +module QuestionPlugin + module Patches + module QueriesHelperPatch + def self.included(base) # :nodoc: + base.extend(ClassMethods) + + base.send(:include, InstanceMethods) + + base.class_eval do + alias_method_chain :column_content, :question + end + end + + module ClassMethods + end + + module InstanceMethods + def column_content_with_question(column, issue) + if column.name == :formatted_questions + return format_questions(issue.open_questions) + else + column_content_without_question(column, issue) + end + end + + def format_questions(questions) + return '' if questions.empty? + html = '
      ' + questions.each do |question| + html << "
    1. " + html << "
      " + html << " " + html << link_to(h(truncate(question.journal.notes, :length => Question::TruncateTo)), + :controller => 'issues', + :action => 'show', + :id => question.issue, + :anchor => "question-#{question.id}") + html << " " + html << " " + html << link_to_issue(question.issue) + html << ": #{h(question.journal.notes)}

      " + html << "#{l(:question_text_asked_by)}: #{question.author.to_s}
      " + html << "#{l(:question_text_assigned_to)}: #{question.assigned_to.to_s}
      " + html << "#{l(:question_text_created_on)}: #{format_date(question.journal.created_on)}" + html << "
      " + html << "
      " + html << "
    2. " + end + html << '
    ' + return html + end + end + end + end +end diff --git a/lib/question_plugin/patches/query_patch.rb b/lib/question_plugin/patches/query_patch.rb new file mode 100644 index 0000000..287f592 --- /dev/null +++ b/lib/question_plugin/patches/query_patch.rb @@ -0,0 +1,94 @@ +module QuestionPlugin + module Patches + module QueryPatch + def self.included(base) # :nodoc: + base.extend(ClassMethods) + + base.send(:include, InstanceMethods) + + # Same as typing in the class + base.class_eval do + unloadable # Send unloadable so it will not be unloaded in development + + base.add_available_column(QueryColumn.new(:formatted_questions)) + + alias_method_chain :available_filters, :question + alias_method_chain :sql_for_field, :question + + end + end + + module ClassMethods + unless Query.respond_to?(:available_columns=) + # Setter for +available_columns+ that isn't provided by the core. + def available_columns=(v) + self.available_columns = (v) + end + end + + unless Query.respond_to?(:add_available_column) + # Method to add a column to the +available_columns+ that isn't provided by the core. + def add_available_column(column) + self.available_columns << (column) + end + end + end + + module InstanceMethods + # Wrapper around the +available_filters+ to add a new Question filter + def available_filters_with_question + return @available_filters if @available_filters + available_filters_without_question + + if @available_filters["assigned_to_id"] + user_values = @available_filters["assigned_to_id"][:values] + + @available_filters["question_assigned_to_id"] = { :name => l("question_text_assigned_to"), :type => :list_optional, :order => 16, :values => user_values } + @available_filters["question_asked_by_id"] = { :name => l("question_text_asked_by"), :type => :list_optional, :order => 16, :values => user_values } + end + + @available_filters + end + + # Wrapper for +sql_for_field+ so Questions can use a different table than Issues + def sql_for_field_with_question(field, operator, v, db_table, db_field, is_custom_filter=false) + if field == "question_assigned_to_id" || field == "question_asked_by_id" + v = values_for(field).clone + + db_table = Question.table_name + if field == "question_assigned_to_id" + db_field = 'assigned_to_id' + else + db_field = 'author_id' + end + + # "me" value subsitution + v.push(User.current.logged? ? User.current.id.to_s : "0") if v.delete("me") + where_sql = [] + case operator + when "=" + where_sql << "#{db_table}.#{db_field} in (?)" + when "!" + where_sql << "#{db_table}.#{db_field} not in (?)" + when "!*" + where_sql << "#{db_table}.#{db_field} is null" +# when "*" + end + + where_sql << "#{db_table}.opened = true" + + subselect_sql = Question.select("#{Journal.table_name}.journalized_id") + .joins(:journal) + .where(where_sql.join(' and '),[v.join(",")]).to_sql; + + sql = "#{Issue.table_name}.id in (#{subselect_sql})" + + return sql + else + return sql_for_field_without_question(field, operator, v, db_table, db_field, is_custom_filter) + end + end + end + end + end +end diff --git a/lib/question_queries_helper_patch.rb b/lib/question_queries_helper_patch.rb deleted file mode 100644 index 933be95..0000000 --- a/lib/question_queries_helper_patch.rb +++ /dev/null @@ -1,54 +0,0 @@ -module QuestionQueriesHelperPatch - def self.included(base) # :nodoc: - base.extend(ClassMethods) - - base.send(:include, InstanceMethods) - - base.class_eval do - alias_method :default_column_content, :column_content - alias_method :column_content, :question_column_content - end - end - - module ClassMethods - end - - module InstanceMethods - def question_column_content(column, issue) - if column.name == :formatted_questions - return format_questions(issue.open_questions) - else - default_column_content(column, issue) - end - end - - def format_questions(questions) - return '' if questions.empty? - html = '
      ' - questions.each do |question| - html << "
    1. " - html << "
      " - html << " " - html << link_to(h(truncate(question.journal.notes, :length => Question::TruncateTo)), - :controller => 'issues', - :action => 'show', - :id => question.issue, - :anchor => "question-#{question.id}") - html << " " - html << " " - html << link_to_issue(question.issue) - html << ": #{h(question.journal.notes)}

      " - html << "#{l(:question_text_asked_by)}: #{question.author.to_s}
      " - html << "#{l(:question_text_assigned_to)}: #{question.assigned_to.to_s}
      " - html << "#{l(:question_text_created_on)}: #{format_date(question.journal.created_on)}" - html << "
      " - html << "
      " - html << "
    2. " - end - html << '
    ' - return html - end - end -end - - diff --git a/lib/question_query_patch.rb b/lib/question_query_patch.rb deleted file mode 100644 index 0ce51a8..0000000 --- a/lib/question_query_patch.rb +++ /dev/null @@ -1,82 +0,0 @@ -module QuestionQueryPatch - def self.included(base) # :nodoc: - base.extend(ClassMethods) - - base.send(:include, InstanceMethods) - - # Same as typing in the class - base.class_eval do - unloadable # Send unloadable so it will not be unloaded in development - - base.add_available_column(QueryColumn.new(:formatted_questions)) - - alias_method_chain :available_filters, :question - - alias_method :sql_for_field_before_question, :sql_for_field - alias_method :sql_for_field, :question_sql_for_field - end - end - - module ClassMethods - unless Query.respond_to?(:available_columns=) - # Setter for +available_columns+ that isn't provided by the core. - def available_columns=(v) - self.available_columns = (v) - end - end - - unless Query.respond_to?(:add_available_column) - # Method to add a column to the +available_columns+ that isn't provided by the core. - def add_available_column(column) - self.available_columns << (column) - end - end - end - - module InstanceMethods - # Wrapper around the +available_filters+ to add a new Question filter - def available_filters_with_question - return @available_filters if @available_filters - available_filters_without_question - - if @available_filters["assigned_to_id"] - user_values = @available_filters["assigned_to_id"][:values] - - @available_filters["question_assigned_to_id"] = { :name => l("question_text_assigned_to"), :type => :list_optional, :order => 16, :values => user_values } - @available_filters["question_asked_by_id"] = { :name => l("question_text_asked_by"), :type => :list_optional, :order => 16, :values => user_values } - end - - @available_filters - end - - # Wrapper for +sql_for_field+ so Questions can use a different table than Issues - def question_sql_for_field(field, operator, v, db_table, db_field, is_custom_filter=false) - if field == "question_assigned_to_id" || field == "question_asked_by_id" - v = values_for(field).clone - - db_table = Question.table_name - if field == "question_assigned_to_id" - db_field = 'assigned_to_id' - else - db_field = 'author_id' - end - - # "me" value subsitution - v.push(User.current.logged? ? User.current.id.to_s : "0") if v.delete("me") - - case operator - when "=" - sql = "#{db_table}.#{db_field} IN (" + v.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ") AND #{db_table}.opened = true" - when "!" - sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + v.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")) AND #{db_table}.opened = true" - else - sql = "1=1" - end - - return sql - else - return sql_for_field_before_question(field, operator, v, db_table, db_field, is_custom_filter) - end - end - end -end diff --git a/rails/init.rb b/rails/init.rb deleted file mode 100644 index 48087f0..0000000 --- a/rails/init.rb +++ /dev/null @@ -1 +0,0 @@ -require File.dirname(__FILE__) + "/../init" From bddb4206f74b3e9409212a279ef641a02e2fba1e Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Thu, 13 Feb 2014 11:55:58 +0200 Subject: [PATCH 42/66] "Questions for me" on *every* page --- app/views/layouts/_questions.html.erb | 27 +++++++++++++++++++ init.rb | 3 +++ .../patches/application_helper_patch.rb | 27 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 app/views/layouts/_questions.html.erb create mode 100644 lib/question_plugin/patches/application_helper_patch.rb diff --git a/app/views/layouts/_questions.html.erb b/app/views/layouts/_questions.html.erb new file mode 100644 index 0000000..79f7dc3 --- /dev/null +++ b/app/views/layouts/_questions.html.erb @@ -0,0 +1,27 @@ +<% questions = Question.opened.for_user(User.current) %> +<% if questions && questions.any? %> +
    +

    <%= l(:text_questions_for_me)%> (<%= h(questions.length) %>)

    + + + + + + + . + <% questions.each do |question| %> + + + + + + <% end %> + +
    <%=l(:field_project)%><%=l(:field_issue)%><%=l(:text_question)%>
    <%= link_to_project(question.issue.project) %><%= link_to_issue(question.issue, :project => false) %> + <%= link_to h(truncate(question.notes, :length => 60)), :controller => 'issues', :action => 'show', :id => question.issue %> +
    +
    +<% end %> + + + diff --git a/init.rb b/init.rb index bdb119a..6b672ba 100644 --- a/init.rb +++ b/init.rb @@ -12,6 +12,9 @@ require_dependency 'journal' Journal.send(:include, QuestionPlugin::Patches::JournalPatch) unless Journal.included_modules.include? QuestionPlugin::Patches::JournalPatch + require_dependency 'application_helper' + ApplicationHelper.send(:include, QuestionPlugin::Patches::ApplicationHelperPatch) unless ApplicationHelper.included_modules.include? QuestionPlugin::Patches::ApplicationHelperPatch + if ActiveSupport::Dependencies::search_for_file('journal_observer') require_dependency 'journal_observer' JournalObserver.send(:include, QuestionPlugin::Patches::JournalObserverPatch) unless JournalObserver.included_modules.include? QuestionPlugin::Patches::JournalObserverPatch diff --git a/lib/question_plugin/patches/application_helper_patch.rb b/lib/question_plugin/patches/application_helper_patch.rb new file mode 100644 index 0000000..42f8b5a --- /dev/null +++ b/lib/question_plugin/patches/application_helper_patch.rb @@ -0,0 +1,27 @@ +module QuestionPlugin + module Patches + module ApplicationHelperPatch + def self.included(base) # :nodoc: + base.extend(ClassMethods) + + base.send(:include, InstanceMethods) + + base.class_eval do + unloadable # Send unloadable so it will not be unloaded in development + alias_method_chain :render_flash_messages, :question + end + end + + module ClassMethods + end + + module InstanceMethods + def render_flash_messages_with_question + s = render :partial => 'layouts/questions', :layout => false + s << render_flash_messages_without_question + s.html_safe + end + end + end + end +end From a955e3fc1457e046e3b7879834e36a4ef620c976 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Thu, 13 Feb 2014 12:23:20 +0200 Subject: [PATCH 43/66] settings for questions banner on/off --- app/views/settings/_question_plugin.html.erb | 6 +++++- config/locales/en.yml | 1 + config/locales/ru.yml | 5 +++++ lib/question_plugin/patches/application_helper_patch.rb | 3 ++- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/app/views/settings/_question_plugin.html.erb b/app/views/settings/_question_plugin.html.erb index 0ed3078..28117c6 100644 --- a/app/views/settings/_question_plugin.html.erb +++ b/app/views/settings/_question_plugin.html.erb @@ -21,4 +21,8 @@

    <%= label_tag "settings[obfuscate_content]", l(:label_question_plugin_notifications_obfuscate_content_settings) %> <%= check_box_tag 'settings[obfuscate_content]', 1, (Setting.plugin_question_plugin[:obfuscate_content] ? true : false) %> -

    \ No newline at end of file +

    +

    + <%= label_tag "settings[show_banner]", l(:label_question_plugin_show_banner_settings) %> + <%= check_box_tag 'settings[show_banner]', 1, (Setting.plugin_question_plugin[:show_banner] ? true : false) %> +

    diff --git a/config/locales/en.yml b/config/locales/en.yml index 3a1a7c6..ab4b7e1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -31,3 +31,4 @@ en: label_question_plugin_notifications_obfuscate_author_settings: Obfuscate asker/answerer name and e-mail address in notifications label_question_plugin_notifications_obfuscate_content_settings: Obfuscate question/answer text in notifications field_question_to_answer: Answer question + label_question_plugin_show_banner_settings: Show unanswered questions on every page diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 45f01b7..f76e031 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -10,6 +10,8 @@ ru: text_question_for: Вопрос к text_question_for_anyone: Вопрос ко всем text_questions_for_me: Вопросы ко мне + mail_body_question_link: Для просмотра вопроса нажмите на нижеследующую ссылку на задачу + mail_body_answer_link: "Ваш вопрос получил ответ: Для его просмотра нажмите на нижеследующую ссылку на задачу" text_question_asked: Вопрос задан text_question_remove: "<< Удалить вопрос >>" question_text_asked_by: "Автор вопроса" @@ -26,4 +28,7 @@ ru: label_question_plugin_close_settings: При добавлении комментария закрывать text_question_close_all: все неотвеченные вопросы в задаче text_question_close_selected: только выбранный вопрос + label_question_plugin_notifications_obfuscate_author_settings: Прятать имя и e-mail спрашивающего/отвечающего в оповещениях + label_question_plugin_notifications_obfuscate_content_settings: Прятать текст вопроса/ответа в оповещениях field_question_to_answer: Ответ на вопрос + label_question_plugin_show_banner_settings: Показывать неотвеченные вопросы на каждой странице \ No newline at end of file diff --git a/lib/question_plugin/patches/application_helper_patch.rb b/lib/question_plugin/patches/application_helper_patch.rb index 42f8b5a..920c8c0 100644 --- a/lib/question_plugin/patches/application_helper_patch.rb +++ b/lib/question_plugin/patches/application_helper_patch.rb @@ -17,7 +17,8 @@ module ClassMethods module InstanceMethods def render_flash_messages_with_question - s = render :partial => 'layouts/questions', :layout => false + s = "" + s = render :partial => 'layouts/questions', :layout => false unless Setting.plugin_question_plugin[:show_banner] != "1" s << render_flash_messages_without_question s.html_safe end From b7015aca0ba3d9e0066db1316921a545b6f7ee88 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Thu, 13 Feb 2014 16:42:42 +0200 Subject: [PATCH 44/66] More nice looking banner --- app/views/layouts/_questions.html.erb | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/app/views/layouts/_questions.html.erb b/app/views/layouts/_questions.html.erb index 79f7dc3..5ecb785 100644 --- a/app/views/layouts/_questions.html.erb +++ b/app/views/layouts/_questions.html.erb @@ -2,24 +2,13 @@ <% if questions && questions.any? %>

    <%= l(:text_questions_for_me)%> (<%= h(questions.length) %>)

    - - - - - - - . +
      <% questions.each do |question| %> -
    - - - - +
  • + <%= link_to_issue(question.issue, :project => true, :subject => false) %>: <%= truncate(question.notes, :length => 120) %>
    +
  • <% end %> - -
    <%=l(:field_project)%><%=l(:field_issue)%><%=l(:text_question)%>
    <%= link_to_project(question.issue.project) %><%= link_to_issue(question.issue, :project => false) %> - <%= link_to h(truncate(question.notes, :length => 60)), :controller => 'issues', :action => 'show', :id => question.issue %> -
    +
    <% end %> From 965f2662c0bd40fc5feeda0391670cf0bdc54a41 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Thu, 13 Feb 2014 16:43:41 +0200 Subject: [PATCH 45/66] Double sending removed --- app/models/question.rb | 6 ------ lib/question_plugin/patches/journal_patch.rb | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/app/models/question.rb b/app/models/question.rb index c880292..8205150 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -21,8 +21,6 @@ class Question < ActiveRecord::Base delegate :notes, :to => :journal, :allow_nil => true - after_save :send_notification - def for_anyone? self.assigned_to.nil? end @@ -36,10 +34,6 @@ def close!(closing_journal=nil) end end - def send_notification - QuestionMailer.asked_question(self.journal).deliver - end - # TODO: refactor to named_scope def self.count_of_open_for_user(user) Question.count(:conditions => {:assigned_to_id => user.id, :opened => true}) diff --git a/lib/question_plugin/patches/journal_patch.rb b/lib/question_plugin/patches/journal_patch.rb index 0b9e71f..61805ed 100644 --- a/lib/question_plugin/patches/journal_patch.rb +++ b/lib/question_plugin/patches/journal_patch.rb @@ -22,7 +22,7 @@ module ClassMethods module InstanceMethods def send_notification_with_question send_notification_without_question - if journal.question + if question QuestionMailer.asked_question(self).deliver end end From 096c22f60fa2c5a18d066fd94dffe13fcad6e1e8 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Thu, 20 Feb 2014 10:41:49 +0200 Subject: [PATCH 46/66] Possibility remove question from banner (hide) --- app/controllers/issuequestions_controller.rb | 9 +++++++++ app/models/question.rb | 2 ++ app/views/layouts/_questions.html.erb | 6 ++++-- config/locales/en.yml | 3 ++- config/locales/ru.yml | 3 ++- config/routes.rb | 8 +++++--- db/migrate/006_add_hidden_to_questions.rb | 9 +++++++++ 7 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 db/migrate/006_add_hidden_to_questions.rb diff --git a/app/controllers/issuequestions_controller.rb b/app/controllers/issuequestions_controller.rb index 5db7352..ebd46eb 100644 --- a/app/controllers/issuequestions_controller.rb +++ b/app/controllers/issuequestions_controller.rb @@ -12,6 +12,15 @@ def user_issue_filter new_filter_for_questions_assigned_to(params[:user_id]) redirect_to :controller => 'issues', :action => 'index', :project_id => params[:project] end + + def hide + @question = Question.find(params[:id]) + @question.hidden = true + if @question.save + redirect_to :back + end + + end def autocomplete_for_user_login if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == 1 diff --git a/app/models/question.rb b/app/models/question.rb index 8205150..641d408 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -12,6 +12,8 @@ class Question < ActiveRecord::Base validates_presence_of :journal scope :opened, :conditions => {:opened => true} + scope :not_hidden, :conditions => {:hidden => false} + scope :for_user, lambda {|user| { :conditions => {:assigned_to_id => user.id }} } diff --git a/app/views/layouts/_questions.html.erb b/app/views/layouts/_questions.html.erb index 5ecb785..d078de6 100644 --- a/app/views/layouts/_questions.html.erb +++ b/app/views/layouts/_questions.html.erb @@ -1,11 +1,13 @@ -<% questions = Question.opened.for_user(User.current) %> +<% questions = Question.opened.not_hidden.for_user(User.current) %> <% if questions && questions.any? %>

    <%= l(:text_questions_for_me)%> (<%= h(questions.length) %>)

      <% questions.each do |question| %>
    1. - <%= link_to_issue(question.issue, :project => true, :subject => false) %>: <%= truncate(question.notes, :length => 120) %>
      + <%= link_to_issue(question.issue, :project => true, :subject => false) %>: + <%= truncate(question.notes, :length => 120) %> + <%= link_to l(:label_question_plugin_hide), hide_path(question) %>
    2. <% end %>
    diff --git a/config/locales/en.yml b/config/locales/en.yml index ab4b7e1..387204e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -31,4 +31,5 @@ en: label_question_plugin_notifications_obfuscate_author_settings: Obfuscate asker/answerer name and e-mail address in notifications label_question_plugin_notifications_obfuscate_content_settings: Obfuscate question/answer text in notifications field_question_to_answer: Answer question - label_question_plugin_show_banner_settings: Show unanswered questions on every page + label_question_plugin_show_banner_settings: Show unanswered questions on every page + label_question_plugin_hide: Hide diff --git a/config/locales/ru.yml b/config/locales/ru.yml index f76e031..dd3adb5 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -31,4 +31,5 @@ ru: label_question_plugin_notifications_obfuscate_author_settings: Прятать имя и e-mail спрашивающего/отвечающего в оповещениях label_question_plugin_notifications_obfuscate_content_settings: Прятать текст вопроса/ответа в оповещениях field_question_to_answer: Ответ на вопрос - label_question_plugin_show_banner_settings: Показывать неотвеченные вопросы на каждой странице \ No newline at end of file + label_question_plugin_show_banner_settings: Показывать неотвеченные вопросы на каждой странице + label_question_plugin_hide: Скрыть diff --git a/config/routes.rb b/config/routes.rb index 2492258..d8c3dd3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,12 +1,14 @@ if Rails::VERSION::MAJOR < 3 ActionController::Routing::Routes.draw do |map| - map.connect 'issuequestions/autocomplete_for_user_login/project/:id/issue/:issue_id', :controller=> 'issuequestions', :action=> 'autocomplete_for_user_login' - map.connect 'issuequestions/my_issue_filter(/project/:project)' ,:controller=> 'issuequestions', :action=> 'my_issue_filter' - map.connect 'issuequestions/user_issue_filter/user/:user_id' ,:controller=> 'issuequestions', :action=> 'user_issue_filter' + map.connect 'issuequestions/autocomplete_for_user_login/project/:id/issue/:issue_id', :controller=> 'issuequestions', :action=> 'autocomplete_for_user_login' + map.connect 'issuequestions/my_issue_filter(/project/:project)' ,:controller=> 'issuequestions', :action=> 'my_issue_filter' + map.connect 'issuequestions/user_issue_filter/user/:user_id' ,:controller=> 'issuequestions', :action=> 'user_issue_filter' + map.connect 'issuequestions/hide/:id', :controller => 'issuequestions', :action => 'hide' end else match 'issuequestions/autocomplete_for_user_login/project/:id/issue/:issue_id' => 'issuequestions#autocomplete_for_user_login', :format => false, :as => 'issuequestions_autocomplete_for_user_login' match 'issuequestions/my_issue_filter(/project/:project)' => 'issuequestions#my_issue_filter', :format => false, :as => 'questions_my_issue_filter' match 'issuequestions/user_issue_filter/user/:user_id' => 'issuequestions#user_issue_filter', :format => false, :as => 'questions_user_issue_filter' + match 'issuequestions/hide/:id' => 'issuequestions#hide', :as => 'hide' end diff --git a/db/migrate/006_add_hidden_to_questions.rb b/db/migrate/006_add_hidden_to_questions.rb new file mode 100644 index 0000000..55d7cdd --- /dev/null +++ b/db/migrate/006_add_hidden_to_questions.rb @@ -0,0 +1,9 @@ +class AddHiddenToQuestions < ActiveRecord::Migration + def self.up + add_column :questions, :hidden, :boolean, :default => false + end + + def self.down + remove_column :questions, :hidden + end +end From 80caa6cdbfc06e78a53a5f8562c38e18342403b6 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Thu, 20 Feb 2014 10:42:59 +0200 Subject: [PATCH 47/66] Fix internal error when "questions" column visible in issue list (in Redmine > 2.3) --- .../patches/queries_helper_patch.rb | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/lib/question_plugin/patches/queries_helper_patch.rb b/lib/question_plugin/patches/queries_helper_patch.rb index ed75b65..4dd776e 100644 --- a/lib/question_plugin/patches/queries_helper_patch.rb +++ b/lib/question_plugin/patches/queries_helper_patch.rb @@ -7,6 +7,7 @@ def self.included(base) # :nodoc: base.send(:include, InstanceMethods) base.class_eval do + unloadable alias_method_chain :column_content, :question end end @@ -15,40 +16,42 @@ module ClassMethods end module InstanceMethods + + + # removed format_questions for compatibility with redmine >= 2.3 + # see http://www.redmine.org/boards/3/topics/37345, + # http://www.redmine.org/issues/13753 def column_content_with_question(column, issue) if column.name == :formatted_questions - return format_questions(issue.open_questions) + return '' if issue.open_questions.empty? + html = '
      ' + issue.open_questions.each do |question| + html << "
    1. " + html << "
      " + html << " " + html << link_to(h(truncate(question.journal.notes, :length => Question::TruncateTo)), + :controller => 'issues', + :action => 'show', + :id => question.issue, + :anchor => "question-#{question.id}") + html << " " + html << " " + html << link_to_issue(question.issue) + html << ": #{h(question.journal.notes)}

      " + html << "#{l(:question_text_asked_by)}: #{question.author.to_s}
      " + html << "#{l(:question_text_assigned_to)}: #{question.assigned_to.to_s}
      " + html << "#{l(:question_text_created_on)}: #{format_date(question.journal.created_on)}" + html << "
      " + html << "
      " + html << "
    2. " + end + html << '
    ' + return html else column_content_without_question(column, issue) end end - def format_questions(questions) - return '' if questions.empty? - html = '
      ' - questions.each do |question| - html << "
    1. " - html << "
      " - html << " " - html << link_to(h(truncate(question.journal.notes, :length => Question::TruncateTo)), - :controller => 'issues', - :action => 'show', - :id => question.issue, - :anchor => "question-#{question.id}") - html << " " - html << " " - html << link_to_issue(question.issue) - html << ": #{h(question.journal.notes)}

      " - html << "#{l(:question_text_asked_by)}: #{question.author.to_s}
      " - html << "#{l(:question_text_assigned_to)}: #{question.assigned_to.to_s}
      " - html << "#{l(:question_text_created_on)}: #{format_date(question.journal.created_on)}" - html << "
      " - html << "
      " - html << "
    2. " - end - html << '
    ' - return html - end end end end From e8ae612b1528dc4654631a7f9fa8fb28a0a4ef3d Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Thu, 20 Feb 2014 10:43:33 +0200 Subject: [PATCH 48/66] Fix question mailing crash in redmine > 2.3 --- app/models/question_mailer.rb | 1 + app/views/question_mailer/answered_question.html.erb | 2 +- app/views/question_mailer/answered_question.text.erb | 2 +- app/views/question_mailer/asked_question.html.erb | 2 +- app/views/question_mailer/asked_question.text.erb | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/models/question_mailer.rb b/app/models/question_mailer.rb index f5e805a..c0fb00a 100644 --- a/app/models/question_mailer.rb +++ b/app/models/question_mailer.rb @@ -19,6 +19,7 @@ def asked_question(journal) @issue = question.issue @journal = journal @issue_url = url_for(:controller => 'issues', :action => 'show', :id => question.issue) + @users = [question.assigned_to] redmine_headers 'Issue-Id' => question.issue.id redmine_headers 'Question-Asked' => question.author.login if question.author.present? diff --git a/app/views/question_mailer/answered_question.html.erb b/app/views/question_mailer/answered_question.html.erb index c62144b..c72a8a5 100644 --- a/app/views/question_mailer/answered_question.html.erb +++ b/app/views/question_mailer/answered_question.html.erb @@ -18,4 +18,4 @@
    <% end %> -<%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url } %> +<%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url, :users => @users } %> diff --git a/app/views/question_mailer/answered_question.text.erb b/app/views/question_mailer/answered_question.text.erb index fcfe8be..d0d1345 100644 --- a/app/views/question_mailer/answered_question.text.erb +++ b/app/views/question_mailer/answered_question.text.erb @@ -18,4 +18,4 @@
    <% end %> -<%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url } %> +<%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url, :users => @users } %> diff --git a/app/views/question_mailer/asked_question.html.erb b/app/views/question_mailer/asked_question.html.erb index c062b73..28bd2d5 100644 --- a/app/views/question_mailer/asked_question.html.erb +++ b/app/views/question_mailer/asked_question.html.erb @@ -14,4 +14,4 @@
    <% end %> -<%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url } %> +<%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url, :users => @users } %> diff --git a/app/views/question_mailer/asked_question.text.erb b/app/views/question_mailer/asked_question.text.erb index b4e90ab..e2f0701 100644 --- a/app/views/question_mailer/asked_question.text.erb +++ b/app/views/question_mailer/asked_question.text.erb @@ -12,4 +12,4 @@ ---------------------------------------- <% end %> -<%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url } %> +<%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url, :users => @users } %> From 86981c40225cc101ccd0873eb17b4d9df30c5551 Mon Sep 17 00:00:00 2001 From: Yuri Tkachenko Date: Tue, 25 Mar 2014 14:34:14 +0300 Subject: [PATCH 49/66] Fix answering questions --- app/models/question_mailer.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/question_mailer.rb b/app/models/question_mailer.rb index c0fb00a..267d06a 100644 --- a/app/models/question_mailer.rb +++ b/app/models/question_mailer.rb @@ -46,6 +46,7 @@ def answered_question(question, closing_journal) @issue = question.issue @journal = closing_journal @issue_url = url_for(:controller => 'issues', :action => 'show', :id => question.issue) + @users = [question.author] redmine_headers 'Issue-Id' => question.issue.id redmine_headers 'Question-Answer' => "#{question.issue.id}-#{closing_journal.id}" From 0e155d6d77ba43cc09d1eebbc64c427356379964 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Mon, 14 Apr 2014 13:48:09 +0300 Subject: [PATCH 50/66] When counting questions use display_subproject_issues setting --- app/models/question.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/models/question.rb b/app/models/question.rb index 641d408..b8902f3 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -43,9 +43,8 @@ def self.count_of_open_for_user(user) # TODO: refactor to named_scope def self.count_of_open_for_user_on_project(user, project) - Question.count(:conditions => ["#{Question.table_name}.assigned_to_id = ? AND #{Project.table_name}.id = ? AND #{Question.table_name}.opened = ?", + Question.count(:conditions => ["(#{Question.table_name}.assigned_to_id = ?) AND #{project.project_condition(Setting.display_subprojects_issues?)} AND (#{Question.table_name}.opened = ?)", user.id, - project.id, true], :include => [:issue => [:project]]) end From e01d025c372614c34fb834f8d5fb6aebfee0ff23 Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Mon, 19 May 2014 10:23:42 +0300 Subject: [PATCH 51/66] Preload questions for all journal entries for faster display --- lib/question_plugin/patches/journal_patch.rb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/question_plugin/patches/journal_patch.rb b/lib/question_plugin/patches/journal_patch.rb index 61805ed..b5b8bf0 100644 --- a/lib/question_plugin/patches/journal_patch.rb +++ b/lib/question_plugin/patches/journal_patch.rb @@ -2,6 +2,7 @@ module QuestionPlugin module Patches module JournalPatch def self.included(base) + base.extend(ClassMethods) base.send(:include, InstanceMethods) @@ -9,14 +10,26 @@ def self.included(base) unloadable has_one :question, :dependent => :destroy + + class << self + alias_method_chain :preload_journals_details_custom_fields, :question + end + # # used for redmine >= 2.3.2 # alias_method_chain :send_notification, :question unless ActiveSupport::Dependencies::search_for_file('journal_observer') end end - + module ClassMethods + def preload_journals_details_custom_fields_with_question(journals) + + # preload questions for all journal entries for faster display + ActiveRecord::Associations::Preloader.new(journals, :question).run + + preload_journals_details_custom_fields_without_question(journals) + end end module InstanceMethods From 9e6085029a905667deb0374b1b8b6c871b64d1bd Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Wed, 28 May 2014 17:13:12 +0300 Subject: [PATCH 52/66] add 'flash' class to banner --- app/views/layouts/_questions.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/_questions.html.erb b/app/views/layouts/_questions.html.erb index d078de6..4da7ee5 100644 --- a/app/views/layouts/_questions.html.erb +++ b/app/views/layouts/_questions.html.erb @@ -1,6 +1,6 @@ <% questions = Question.opened.not_hidden.for_user(User.current) %> <% if questions && questions.any? %> -
    +

    <%= l(:text_questions_for_me)%> (<%= h(questions.length) %>)

      <% questions.each do |question| %> From da5953f93bf4ca04404b5a74567f9dd13c6b6e8c Mon Sep 17 00:00:00 2001 From: Dmitry Salashnik Date: Thu, 29 May 2014 14:11:45 +0300 Subject: [PATCH 53/66] fix css for banner --- lib/question_plugin/hooks/layout_hooks.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/question_plugin/hooks/layout_hooks.rb b/lib/question_plugin/hooks/layout_hooks.rb index 1417622..47f0055 100644 --- a/lib/question_plugin/hooks/layout_hooks.rb +++ b/lib/question_plugin/hooks/layout_hooks.rb @@ -6,7 +6,8 @@ class LayoutHooks < Redmine::Hook::ViewListener def view_layouts_base_html_head(context = { }) o = < -.question { background-color:#FFEBC1; border:2px solid #FDBD3B; margin-bottom:12px; padding:0px 4px 8px 4px; } + +.question, div.flash.question { background-color:#FFEBC1; border:2px solid; margin-bottom:12px; padding:0px 4px 8px 4px; border-color: #fdbd2b} .question-line { float: right; } td.formatted_questions { text-align: left; white-space: normal} td.formatted_questions ol { margin-top: 0px; margin-bottom: 0px; } @@ -20,4 +21,4 @@ def view_layouts_base_html_head(context = { }) end end end -end \ No newline at end of file +end From c08703435eddfd9dc9d03bac5b7b096e3e03da4c Mon Sep 17 00:00:00 2001 From: ichizok Date: Wed, 4 Mar 2015 05:56:51 +0900 Subject: [PATCH 54/66] append 'via' parameter to match method --- config/routes.rb | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index d8c3dd3..811bff0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,14 +1,6 @@ -if Rails::VERSION::MAJOR < 3 - ActionController::Routing::Routes.draw do |map| - map.connect 'issuequestions/autocomplete_for_user_login/project/:id/issue/:issue_id', :controller=> 'issuequestions', :action=> 'autocomplete_for_user_login' - map.connect 'issuequestions/my_issue_filter(/project/:project)' ,:controller=> 'issuequestions', :action=> 'my_issue_filter' - map.connect 'issuequestions/user_issue_filter/user/:user_id' ,:controller=> 'issuequestions', :action=> 'user_issue_filter' - map.connect 'issuequestions/hide/:id', :controller => 'issuequestions', :action => 'hide' - end -else - match 'issuequestions/autocomplete_for_user_login/project/:id/issue/:issue_id' => 'issuequestions#autocomplete_for_user_login', :format => false, :as => 'issuequestions_autocomplete_for_user_login' - match 'issuequestions/my_issue_filter(/project/:project)' => 'issuequestions#my_issue_filter', :format => false, :as => 'questions_my_issue_filter' - match 'issuequestions/user_issue_filter/user/:user_id' => 'issuequestions#user_issue_filter', :format => false, :as => 'questions_user_issue_filter' - match 'issuequestions/hide/:id' => 'issuequestions#hide', :as => 'hide' +RedmineApp::Application.routes.draw do + match 'issuequestions/autocomplete_for_user_login/project/:id/issue/:issue_id' => 'issuequestions#autocomplete_for_user_login', :format => false, :as => 'issuequestions_autocomplete_for_user_login', :via => [:get, :post] + match 'issuequestions/my_issue_filter(/project/:project)' => 'issuequestions#my_issue_filter', :format => false, :as => 'questions_my_issue_filter', :via => [:get, :post] + match 'issuequestions/user_issue_filter/user/:user_id' => 'issuequestions#user_issue_filter', :format => false, :as => 'questions_user_issue_filter', :via => [:get, :post] + match 'issuequestions/hide/:id' => 'issuequestions#hide', :as => 'hide', :via => [:get, :post] end - From 9e52ff9d5c120d16e2416428693a619af3b52ab7 Mon Sep 17 00:00:00 2001 From: ichizok Date: Tue, 3 Mar 2015 19:53:11 +0900 Subject: [PATCH 55/66] update requires_redmine version --- init.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/init.rb b/init.rb index 6b672ba..cf3fcdb 100644 --- a/init.rb +++ b/init.rb @@ -45,7 +45,7 @@ description 'This is a plugin for Redmine that will allow users to ask questions to each other in issue notes' version '0.3.0' - requires_redmine :version_or_higher => '2.0.0' + requires_redmine :version_or_higher => '3.0.0' settings :default => { :only_members => 1, From 6a987ec19dbf1f770eec8796cc2a3e7bcbf2784d Mon Sep 17 00:00:00 2001 From: ichizok Date: Tue, 3 Mar 2015 19:52:53 +0900 Subject: [PATCH 56/66] fix finder-method to be compatible with Redmine 3.0 --- app/controllers/issuequestions_controller.rb | 10 +++++----- app/models/question.rb | 17 ++++++++--------- lib/question_plugin/hooks/issue_hooks.rb | 2 +- lib/question_plugin/hooks/journal_hooks.rb | 6 +++--- lib/question_plugin/patches/issue_patch.rb | 6 +++--- lib/question_plugin/patches/journal_patch.rb | 2 +- 6 files changed, 21 insertions(+), 22 deletions(-) diff --git a/app/controllers/issuequestions_controller.rb b/app/controllers/issuequestions_controller.rb index ebd46eb..0ec70ce 100644 --- a/app/controllers/issuequestions_controller.rb +++ b/app/controllers/issuequestions_controller.rb @@ -24,20 +24,20 @@ def hide def autocomplete_for_user_login if params[:issue_id] && Setting.plugin_question_plugin[:only_members] == 1 - @issue = Issue.find_by_id(params[:issue_id]) + @issue = Issue.find(params[:issue_id]) base = @issue.project.users else base = User end q = (params[:q] || params[:term] || params[:user]).to_s.strip.downcase if q.present? - @users = base.active.all(:conditions => ["LOWER(login) LIKE :user OR LOWER(firstname) LIKE :user OR LOWER(lastname) LIKE :user", {:user => q + "%" }], - :limit => 10, - :order => 'login ASC') + @users = base.active.where(["LOWER(login) LIKE :user OR LOWER(firstname) LIKE :user OR LOWER(lastname) LIKE :user", {:user => q + "%" }]). + limit(10). + order('login ASC') end @users ||=[] - render :layout => false + render :layout => false end private diff --git a/app/models/question.rb b/app/models/question.rb index b8902f3..1673829 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -11,14 +11,14 @@ class Question < ActiveRecord::Base validates_presence_of :issue validates_presence_of :journal - scope :opened, :conditions => {:opened => true} - scope :not_hidden, :conditions => {:hidden => false} + scope :opened, lambda { where(:opened => true) } + scope :not_hidden, lambda { where(:hidden => false) } scope :for_user, lambda {|user| - { :conditions => {:assigned_to_id => user.id }} + where(:assigned_to_id => user.id) } scope :by_user, lambda {|user| - { :conditions => {:author_id => user.id }} + where(:author_id => user.id) } delegate :notes, :to => :journal, :allow_nil => true @@ -38,14 +38,13 @@ def close!(closing_journal=nil) # TODO: refactor to named_scope def self.count_of_open_for_user(user) - Question.count(:conditions => {:assigned_to_id => user.id, :opened => true}) + Question.where(:assigned_to_id => user.id, :opened => true).count end # TODO: refactor to named_scope def self.count_of_open_for_user_on_project(user, project) - Question.count(:conditions => ["(#{Question.table_name}.assigned_to_id = ?) AND #{project.project_condition(Setting.display_subprojects_issues?)} AND (#{Question.table_name}.opened = ?)", - user.id, - true], - :include => [:issue => [:project]]) + Question.where(["(#{Question.table_name}.assigned_to_id = ?) AND #{project.project_condition(Setting.display_subprojects_issues?)} AND (#{Question.table_name}.opened = ?)", + user.id, true]). + joins(:issue => :project).preload(:project).count end end diff --git a/lib/question_plugin/hooks/issue_hooks.rb b/lib/question_plugin/hooks/issue_hooks.rb index 45718e2..6817cb1 100644 --- a/lib/question_plugin/hooks/issue_hooks.rb +++ b/lib/question_plugin/hooks/issue_hooks.rb @@ -57,7 +57,7 @@ def controller_issues_edit_before_save(context = { }) ) if params[:note][:question_assigned_to].downcase != 'anyone' # Assigned to a specific user - assign_question_to_user(journal, User.find_by_login(params[:note][:question_assigned_to])) + assign_question_to_user(journal, User.find_by(:login => params[:note][:question_assigned_to])) end end end diff --git a/lib/question_plugin/hooks/journal_hooks.rb b/lib/question_plugin/hooks/journal_hooks.rb index 141f6cb..dca1e9e 100644 --- a/lib/question_plugin/hooks/journal_hooks.rb +++ b/lib/question_plugin/hooks/journal_hooks.rb @@ -35,17 +35,17 @@ def controller_journals_edit_post(context = { }) if params[:question][:assigned_to].downcase == 'anyone' journal.question.update_attributes(:assigned_to => nil) else - journal.question.update_attributes(:assigned_to => User.find_by_login(params[:question][:assigned_to])) + journal.question.update_attributes(:assigned_to => User.find_by(:login => params[:question][:assigned_to])) end elsif journal.question && !journal.question.opened # Existing question, destry it first and then add a new question journal.question.destroy - add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) + add_new_question(journal, User.find_by(:login => params[:question][:assigned_to])) else if params[:question][:assigned_to].downcase == 'anyone' add_new_question(journal) elsif !params[:question][:assigned_to].blank? - add_new_question(journal, User.find_by_login(params[:question][:assigned_to])) + add_new_question(journal, User.find_by(:login => params[:question][:assigned_to])) else # No question end diff --git a/lib/question_plugin/patches/issue_patch.rb b/lib/question_plugin/patches/issue_patch.rb index 0808ccd..47e84dd 100644 --- a/lib/question_plugin/patches/issue_patch.rb +++ b/lib/question_plugin/patches/issue_patch.rb @@ -9,7 +9,7 @@ def self.included(base) # :nodoc: base.class_eval do unloadable # Send unloadable so it will not be unloaded in development has_many :questions - has_many :open_questions, :class_name => 'Question', :conditions => { :opened => true } + has_many :open_questions, lambda { Question.opened }, :class_name => 'Question' include ActionView::Helpers::TextHelper # for truncate end @@ -20,7 +20,7 @@ module ClassMethods module InstanceMethods def pending_question?(user) - self.open_questions.find(:all).each do |question| + self.open_questions.all.each do |question| return true if question.assigned_to == user || question.for_anyone? end return false @@ -28,7 +28,7 @@ def pending_question?(user) def pending_questions(user) q = [] - self.open_questions.find(:all).each do |question| + self.open_questions.all.each do |question| q << question if question.assigned_to == user || question.for_anyone? end return q diff --git a/lib/question_plugin/patches/journal_patch.rb b/lib/question_plugin/patches/journal_patch.rb index b5b8bf0..774201a 100644 --- a/lib/question_plugin/patches/journal_patch.rb +++ b/lib/question_plugin/patches/journal_patch.rb @@ -26,7 +26,7 @@ module ClassMethods def preload_journals_details_custom_fields_with_question(journals) # preload questions for all journal entries for faster display - ActiveRecord::Associations::Preloader.new(journals, :question).run + ActiveRecord::Associations::Preloader.new.preload(journals, :question) preload_journals_details_custom_fields_without_question(journals) end From c721c1e66c2c337c772555d169be312653d383b6 Mon Sep 17 00:00:00 2001 From: ichizok Date: Wed, 4 Mar 2015 19:21:57 +0900 Subject: [PATCH 57/66] fix an error while saving question set 'attr_protected' --- app/models/question.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/question.rb b/app/models/question.rb index 1673829..54ddf23 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -11,6 +11,8 @@ class Question < ActiveRecord::Base validates_presence_of :issue validates_presence_of :journal + attr_protected :journal + scope :opened, lambda { where(:opened => true) } scope :not_hidden, lambda { where(:hidden => false) } From f50c9f99635f6cfd952a90abd76a40bc78563bcc Mon Sep 17 00:00:00 2001 From: Michal Gritzbach Date: Mon, 26 Jan 2015 09:43:38 +0100 Subject: [PATCH 58/66] More expressive notification mail --- app/models/question_mailer.rb | 1 + app/views/question_mailer/answered_question.html.erb | 2 +- app/views/question_mailer/answered_question.text.erb | 2 +- app/views/question_mailer/asked_question.html.erb | 2 +- app/views/question_mailer/asked_question.text.erb | 2 +- config/locales/cs.yml | 1 + 6 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/models/question_mailer.rb b/app/models/question_mailer.rb index 267d06a..bb1d70b 100644 --- a/app/models/question_mailer.rb +++ b/app/models/question_mailer.rb @@ -1,3 +1,4 @@ +# encoding: utf-8 class QuestionMailer < Mailer unloadable diff --git a/app/views/question_mailer/answered_question.html.erb b/app/views/question_mailer/answered_question.html.erb index c72a8a5..61789d3 100644 --- a/app/views/question_mailer/answered_question.html.erb +++ b/app/views/question_mailer/answered_question.html.erb @@ -5,7 +5,7 @@ <%= textilizable(@journal, :notes, :only_path => false) %> <% end %> -

      <%= l(:text_question) %>

      +

      <%= l(:text_question_for) %> <%= @question.assigned_to.try(:full_name) %>

      <%= textilizable(@question.journal, :notes, :only_path => false) %> <% if Setting.plugin_question_plugin[:obfuscate_content] == "0" %> diff --git a/app/views/question_mailer/answered_question.text.erb b/app/views/question_mailer/answered_question.text.erb index d0d1345..9a8eae5 100644 --- a/app/views/question_mailer/answered_question.text.erb +++ b/app/views/question_mailer/answered_question.text.erb @@ -5,7 +5,7 @@ <%= textilizable(@journal, :notes, :only_path => false) %> <% end %> -

      <%= l(:text_question) %>

      +

      <%= l(:text_question_for) %> <%= @question.assigned_to.try(:full_name) %>

      <%= textilizable(@question.journal, :notes, :only_path => false) %> <% if Setting.plugin_question_plugin[:obfuscate_content] == "0" %> diff --git a/app/views/question_mailer/asked_question.html.erb b/app/views/question_mailer/asked_question.html.erb index 28bd2d5..7106d2a 100644 --- a/app/views/question_mailer/asked_question.html.erb +++ b/app/views/question_mailer/asked_question.html.erb @@ -1,4 +1,4 @@ -<%= l(:text_question_asked) %> <%= h "##{@issue.id}" %> <%= @question.author unless Setting.plugin_question_plugin[:obfuscate_author] == "1" %> +

      <%= l(:text_question_for_in_by, name: @question.assigned_to, issue: "##{@issue.id}", author: @question.author) %>

      <% if Setting.plugin_question_plugin[:obfuscate_content] == "1" %> <%= textilizable(l(:mail_body_question_link)) %> diff --git a/app/views/question_mailer/asked_question.text.erb b/app/views/question_mailer/asked_question.text.erb index e2f0701..54c50f4 100644 --- a/app/views/question_mailer/asked_question.text.erb +++ b/app/views/question_mailer/asked_question.text.erb @@ -1,4 +1,4 @@ -<%= l(:text_question_asked) %> <%= h "##{@issue.id}" %> <%= @question.author unless Setting.plugin_question_plugin[:obfuscate_author] == "1" %> +<%= l(:text_question_for_in_by, name: @question.assigned_to, issue: "##{@issue.id}", author: @question.author) %> <% if Setting.plugin_question_plugin[:obfuscate_content] == "1" %> <%= l(:mail_body_question_link) %> diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 11a1cf6..396a26b 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -10,6 +10,7 @@ en: text_question_for: Otázka pro text_question_for_anyone: Otázka pro kohokoliv text_questions_for_me: Otázky pro mě + text_question_for_in_by: "Dotaz na %{name} u %{issue} položil/a %{author}" text_question_asked: Položené otázky text_question_remove: "<< Odstranit Otázku>>" question_text_asked_by: "Položeno" From 73761bedeae5329ece71266be6960f71f5e47d0f Mon Sep 17 00:00:00 2001 From: Michal Gritzbach Date: Mon, 26 Jan 2015 09:53:51 +0100 Subject: [PATCH 59/66] User#full_name does not exist --- app/views/question_mailer/answered_question.html.erb | 2 +- app/views/question_mailer/answered_question.text.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/question_mailer/answered_question.html.erb b/app/views/question_mailer/answered_question.html.erb index 61789d3..38d63a1 100644 --- a/app/views/question_mailer/answered_question.html.erb +++ b/app/views/question_mailer/answered_question.html.erb @@ -5,7 +5,7 @@ <%= textilizable(@journal, :notes, :only_path => false) %> <% end %> -

      <%= l(:text_question_for) %> <%= @question.assigned_to.try(:full_name) %>

      +

      <%= l(:text_question_for) %> <%= @question.assigned_to %>

      <%= textilizable(@question.journal, :notes, :only_path => false) %> <% if Setting.plugin_question_plugin[:obfuscate_content] == "0" %> diff --git a/app/views/question_mailer/answered_question.text.erb b/app/views/question_mailer/answered_question.text.erb index 9a8eae5..9207894 100644 --- a/app/views/question_mailer/answered_question.text.erb +++ b/app/views/question_mailer/answered_question.text.erb @@ -5,7 +5,7 @@ <%= textilizable(@journal, :notes, :only_path => false) %> <% end %> -

      <%= l(:text_question_for) %> <%= @question.assigned_to.try(:full_name) %>

      +

      <%= l(:text_question_for) %> <%= @question.assigned_to %>

      <%= textilizable(@question.journal, :notes, :only_path => false) %> <% if Setting.plugin_question_plugin[:obfuscate_content] == "0" %> From e0a175900a443796eb1f93f29fd06c67444826ef Mon Sep 17 00:00:00 2001 From: Kepi Date: Thu, 19 Feb 2015 17:57:42 +0100 Subject: [PATCH 60/66] Odstraneni webratu z gemfile - dela problemy pri deployi --- Gemfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Gemfile b/Gemfile index 9a69086..e69de29 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +0,0 @@ -group :test do - gem 'webrat' -end From 1f4e6a4879f2b14d3d00a1a8c29172ac07166fdb Mon Sep 17 00:00:00 2001 From: Michal Gritzbach Date: Mon, 23 Feb 2015 16:22:11 +0100 Subject: [PATCH 61/66] Journal Observer patch moved to Journal patch --- config/locales/cs.yml | 2 +- init.rb | 5 --- .../patches/journal_observer_patch.rb | 35 ------------------- 3 files changed, 1 insertion(+), 41 deletions(-) delete mode 100644 lib/question_plugin/patches/journal_observer_patch.rb diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 396a26b..214e6c9 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -1,4 +1,4 @@ -en: +cs: field_question_assign_to: Přiřadit otázku field_question_assigned_to: Otázka přiřazena field_question_asked_by: Otázku položil diff --git a/init.rb b/init.rb index cf3fcdb..5a476df 100644 --- a/init.rb +++ b/init.rb @@ -15,11 +15,6 @@ require_dependency 'application_helper' ApplicationHelper.send(:include, QuestionPlugin::Patches::ApplicationHelperPatch) unless ApplicationHelper.included_modules.include? QuestionPlugin::Patches::ApplicationHelperPatch - if ActiveSupport::Dependencies::search_for_file('journal_observer') - require_dependency 'journal_observer' - JournalObserver.send(:include, QuestionPlugin::Patches::JournalObserverPatch) unless JournalObserver.included_modules.include? QuestionPlugin::Patches::JournalObserverPatch - end - if ActiveSupport::Dependencies::search_for_file('issue_queries_helper') require_dependency 'issue_queries_helper' IssueQueriesHelper.send(:include, QuestionPlugin::Patches::QueriesHelperPatch) unless IssueQueriesHelper.included_modules.include? QuestionPlugin::Patches::QueriesHelperPatch diff --git a/lib/question_plugin/patches/journal_observer_patch.rb b/lib/question_plugin/patches/journal_observer_patch.rb deleted file mode 100644 index d0c9301..0000000 --- a/lib/question_plugin/patches/journal_observer_patch.rb +++ /dev/null @@ -1,35 +0,0 @@ -# -# used for redmine < 2.3.2 -# - -module QuestionPlugin - module Patches - module JournalObserverPatch - def self.included(base) - base.extend(ClassMethods) - - base.send(:include, InstanceMethods) - base.class_eval do - unloadable - - alias_method_chain :after_create, :question - end - end - - module ClassMethods - end - - module InstanceMethods - def after_create_with_question(journal) - after_create_without_question(journal) - - if journal.is_a?(Journal) - if journal.question - QuestionMailer.asked_question(journal).deliver - end - end - end - end - end - end -end From fbff470e3ed0c20f7dd032b2baf876d692ec25a6 Mon Sep 17 00:00:00 2001 From: Michal Gritzbach Date: Fri, 13 Mar 2015 16:42:22 +0100 Subject: [PATCH 62/66] Added users array in mails (for RM core issue mail partial) --- app/models/question_mailer.rb | 2 ++ app/views/question_mailer/answered_question.html.erb | 1 - app/views/question_mailer/answered_question.text.erb | 1 - app/views/question_mailer/asked_question.html.erb | 1 - app/views/question_mailer/asked_question.text.erb | 1 - 5 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/models/question_mailer.rb b/app/models/question_mailer.rb index bb1d70b..b5496ff 100644 --- a/app/models/question_mailer.rb +++ b/app/models/question_mailer.rb @@ -19,6 +19,7 @@ def asked_question(journal) @question = question @issue = question.issue @journal = journal + @users = [question.assigned_to] @issue_url = url_for(:controller => 'issues', :action => 'show', :id => question.issue) @users = [question.assigned_to] @@ -46,6 +47,7 @@ def answered_question(question, closing_journal) @question = question @issue = question.issue @journal = closing_journal + @users = [question.author] @issue_url = url_for(:controller => 'issues', :action => 'show', :id => question.issue) @users = [question.author] diff --git a/app/views/question_mailer/answered_question.html.erb b/app/views/question_mailer/answered_question.html.erb index 38d63a1..b9a7b01 100644 --- a/app/views/question_mailer/answered_question.html.erb +++ b/app/views/question_mailer/answered_question.html.erb @@ -17,5 +17,4 @@
      <% end %> - <%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url, :users => @users } %> diff --git a/app/views/question_mailer/answered_question.text.erb b/app/views/question_mailer/answered_question.text.erb index 9207894..ae1118c 100644 --- a/app/views/question_mailer/answered_question.text.erb +++ b/app/views/question_mailer/answered_question.text.erb @@ -17,5 +17,4 @@
      <% end %> - <%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url, :users => @users } %> diff --git a/app/views/question_mailer/asked_question.html.erb b/app/views/question_mailer/asked_question.html.erb index 7106d2a..fc912cb 100644 --- a/app/views/question_mailer/asked_question.html.erb +++ b/app/views/question_mailer/asked_question.html.erb @@ -13,5 +13,4 @@
      <% end %> - <%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url, :users => @users } %> diff --git a/app/views/question_mailer/asked_question.text.erb b/app/views/question_mailer/asked_question.text.erb index 54c50f4..2fd0992 100644 --- a/app/views/question_mailer/asked_question.text.erb +++ b/app/views/question_mailer/asked_question.text.erb @@ -11,5 +11,4 @@ ---------------------------------------- <% end %> - <%= render :partial => "mailer/issue", :locals => { :issue => @issue, :issue_url => @issue_url, :users => @users } %> From 10baa73c87c2934a1f4a7798d8357fa3cdbdb076 Mon Sep 17 00:00:00 2001 From: Giray Pultar Date: Sat, 25 Jul 2015 10:32:30 +0300 Subject: [PATCH 63/66] turkish translation --- config/locales/tr.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 config/locales/tr.yml diff --git a/config/locales/tr.yml b/config/locales/tr.yml new file mode 100644 index 0000000..a8f157c --- /dev/null +++ b/config/locales/tr.yml @@ -0,0 +1,29 @@ +tr: + field_question_assign_to: Soruyu şu kişiye ata + field_question_assigned_to: Soru şu kişiye atanmış + field_question_asked_by: Soruyu soran + field_formatted_questions: Sorular + text_question: Soru + text_question_answered: Soru Cevaplandı + text_answer: Cevap + text_anyone: Herhangi biri + text_question_for: Şu kişiye sor + text_question_for_anyone: Herhangi birine sor + text_questions_for_me: Bana sorulmuş sorular + text_question_asked: Sorulmuş sorular + text_question_remove: "<< Soruyu Sil >>" + question_text_asked_by: "Şu kişi sormuş" + question_text_assigned_to: "Soru şu kişiye atanmış" + question_text_created_on: "Oluşturulma" + question_text_ratio_questions_answered: "{{ratio}} soru cevaplandı" + field_journal: "Günlük" + text_questions_asked_by_me: "Benim sorduğum sorular" + question_reminder_subject: "%{count} açık soru" + question_reminder_body: "Bana atanmış %{count} açık soru:" + label_question_plugin_only_members: Soru şu kişilere atanabilir + text_question_all: Herhangi bir kullanıcı + text_question_project_member: Sadece birim üyeleri + label_question_plugin_close_settings: Not ekleyince kapat + text_question_close_all: İş içindeki tüm sorular + text_question_close_selected: sadece seçilmiş soru + field_question_to_answer: Soruyu cevapla From a4ab515eaff8052ab0d19cffc1df5aa3af1f2170 Mon Sep 17 00:00:00 2001 From: Kepi Date: Wed, 13 Mar 2019 14:42:55 +0100 Subject: [PATCH 64/66] Updated and improved Czech translation --- config/locales/cs.yml | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 214e6c9..d792282 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -1,7 +1,7 @@ cs: - field_question_assign_to: Přiřadit otázku - field_question_assigned_to: Otázka přiřazena - field_question_asked_by: Otázku položil + field_question_assign_to: Položit otázku na + field_question_assigned_to: Otázka pro + field_question_asked_by: Otázka od field_formatted_questions: Otázky text_question: Otázka text_question_answered: Otázka zodpovězena @@ -10,15 +10,26 @@ cs: text_question_for: Otázka pro text_question_for_anyone: Otázka pro kohokoliv text_questions_for_me: Otázky pro mě - text_question_for_in_by: "Dotaz na %{name} u %{issue} položil/a %{author}" text_question_asked: Položené otázky - text_question_remove: "<< Odstranit Otázku>>" - question_text_asked_by: "Položeno" - question_text_assigned_to: "Přiřazeno" + mail_body_question_link: Otázku zobrazíte kliknutím na odkaz níže + mail_body_answer_link: "Vaše otázka byla zodpovězena: klikněte na odkaz níže k jejímu zobrazení" + text_question_remove: "<< Odstranit Otázku >>" + question_text_asked_by: "Otázka od" + question_text_assigned_to: "Otázka pro" question_text_created_on: "Vytvořeno" question_text_ratio_questions_answered: "{{ratio}} zodpovězených otázek" field_journal: "Žurnál" - text_questions_asked_by_me: "Otázky položené mnou" + text_questions_asked_by_me: "Otázky ode mne" question_reminder_subject: "%{count} nezodpovězených otázek" - question_reminder_body: "%{count} Vám položených nezodpovězených otázek:" - field_system_name: igloonet, s.r.o. + question_reminder_body: "%{count} nezodpovězených otázek, které jsou položeny na vás:" + label_question_plugin_only_members: Otázku lze položit na + text_question_all: Jakéhokoliv uživatele + text_question_project_member: Pouze členy projektu + label_question_plugin_close_settings: Zodpovědět při přidání komentáře + text_question_close_all: všechny nezodpovězené otázky v úkolu + text_question_close_selected: pouze vybranou otázku + label_question_plugin_notifications_obfuscate_author_settings: Skrýt jméno a e-mail dotazujícího/dotazovaného v notifikacích + label_question_plugin_notifications_obfuscate_content_settings: Skrýt otázku/odpověď v notifikacích + field_question_to_answer: Otázka k zodpovězení + label_question_plugin_show_banner_settings: Zobrazit nezodpovězenou otázku na každé stránce + label_question_plugin_hide: Skrýt From 4913a141af438f44115945d93044544aaa8cac6d Mon Sep 17 00:00:00 2001 From: Kepi Date: Wed, 27 Mar 2019 16:21:56 +0100 Subject: [PATCH 65/66] Reimplemented new question e-mail title --- config/locales/cs.yml | 3 ++- config/locales/en.yml | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/config/locales/cs.yml b/config/locales/cs.yml index d792282..71d150b 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -11,7 +11,8 @@ cs: text_question_for_anyone: Otázka pro kohokoliv text_questions_for_me: Otázky pro mě text_question_asked: Položené otázky - mail_body_question_link: Otázku zobrazíte kliknutím na odkaz níže + mail_body_title: "Máte novou otázku od %{author}" + mail_body_question_link: Otázku zobrazíte kliknutím na následující odkaz mail_body_answer_link: "Vaše otázka byla zodpovězena: klikněte na odkaz níže k jejímu zobrazení" text_question_remove: "<< Odstranit Otázku >>" question_text_asked_by: "Otázka od" diff --git a/config/locales/en.yml b/config/locales/en.yml index 387204e..a1afce1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -11,6 +11,7 @@ en: text_question_for_anyone: Question for anyone text_questions_for_me: Questions for me text_question_asked: Question asked + mail_body_title: "You have new question from %{author}" mail_body_question_link: Display question by clicking on the issue link below mail_body_answer_link: "Your question has received an answer: click on the issue link below to display it" text_question_remove: "<< Remove Question>>" From 67a3645be4f6a4295ba3a8dcb845e1d2289254dc Mon Sep 17 00:00:00 2001 From: Kepi Date: Fri, 29 Mar 2019 02:22:03 +0100 Subject: [PATCH 66/66] Fix forgotten localization symbols for previous commit --- app/views/question_mailer/asked_question.html.erb | 2 +- app/views/question_mailer/asked_question.text.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/question_mailer/asked_question.html.erb b/app/views/question_mailer/asked_question.html.erb index fc912cb..6749a00 100644 --- a/app/views/question_mailer/asked_question.html.erb +++ b/app/views/question_mailer/asked_question.html.erb @@ -1,4 +1,4 @@ -

      <%= l(:text_question_for_in_by, name: @question.assigned_to, issue: "##{@issue.id}", author: @question.author) %>

      +

      <%= l(:mail_body_title, name: @question.assigned_to, issue: "##{@issue.id}", author: @question.author) %>

      <% if Setting.plugin_question_plugin[:obfuscate_content] == "1" %> <%= textilizable(l(:mail_body_question_link)) %> diff --git a/app/views/question_mailer/asked_question.text.erb b/app/views/question_mailer/asked_question.text.erb index 2fd0992..8dc8bf3 100644 --- a/app/views/question_mailer/asked_question.text.erb +++ b/app/views/question_mailer/asked_question.text.erb @@ -1,4 +1,4 @@ -<%= l(:text_question_for_in_by, name: @question.assigned_to, issue: "##{@issue.id}", author: @question.author) %> +<%= l(:mail_body_title, name: @question.assigned_to, issue: "##{@issue.id}", author: @question.author) %> <% if Setting.plugin_question_plugin[:obfuscate_content] == "1" %> <%= l(:mail_body_question_link) %>