Redmineカスタマイズその3 チケットメール送信メンバー選択

もうすぐ0.8.0もリリースされそうですが、その前に
Redmineカスタマイズその3です。*1


前回は、チケット編集時に「メール送信する・しない」を選択出来るようにしましたが、
今回はさらに、メール送信するメンバーを選択できるようにしてみます。
ですので、以下のdiffは前回のパッチも含んでますがご了承下さい。

$RAILS_ROOT/app/views/issues/_edit.rhtml

$RAILS_ROOT/app/views/issues/new.rhtml

--- /var/www/html/redmine-0.7.3-org/app/views/issues/new.rhtml  2008-07-06 20:17:48.000000000 +0900
+++ /var/www/html/redmine-0.7.3/app/views/issues/new.rhtml      2008-11-23 02:11:20.000000000 +0900
@@ -6,6 +6,34 @@
     <div class="box">
     <%= render :partial => 'issues/form', :locals => {:f => f} %>
     </div>
+
+<SCRIPT LANGUAGE="JavaScript">
+  function checkChange() {
+   // if(document.rmail.radio1[0].checked == true) {
+    if(document.getElementById('send_mail').checked == true) {
+      document.getElementById('mailbox').style.display = '';
+    } else {
+      document.getElementById('mailbox').style.display = 'none';
+    }
+  }
+   function radioChange( disp ) {
+      if(document.getElementById('mail_kind_select_member').checked == true) {
+        document.getElementById('memberbox').style.display = '';
+      } else {
+        document.getElementById('memberbox').style.display = 'none';
+      }
+   }
+</SCRIPT>
+
+    <fieldset class='box'><legend>メール送信</legend>
+      <%= check_box_tag('send_mail', 1, @send_mail, :onclick =>'checkChange();') %> メール送信を行う
+      <div id="mailbox" style="display:none">
+        &nbsp;<%= radio_button_tag 'mail_kind', 'all_member', (@mail_kind == 'all_member'), :onclick => 'radioChange(true);', :checked => true %> メンバー内全員にメール<br />
+        &nbsp;<%= radio_button_tag 'mail_kind', 'select_member', (@mail_kind == 'select_member'), :onclick => 'radioChange(true);' %> メンバー選択<br />
+        <div id="memberbox" style="display:none">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<%= select_tag "sel_users[]", options_from_collection_for_select(@users, 'id', 'name', 2), :multiple => true %></div>
+      </div>
+    </fieldset>
+
     <%= submit_tag l(:button_create) %>
     <%= link_to_remote l(:label_preview),
                        { :url => { :controller => 'issues', :action => 'preview', :project_id => @project },

まずは前回と同じように、ビュー2つから(上記はnew.htmlのdiffファイルです)。
チェックボックスラジオボタンによって、見た目を変えるようなJavascriptの追加と、
メンバーをSELECTリストにする「select_tag(options_from_collection_for_select)」がポイントです。
(select_tagの使い方を調べ上げるのに結構時間かかりました…)
options_from_collection_for_selectの第4引数は、初期選択のidを指定しています。
Redmineのユーザテーブルは「1:Admin」なので固定で「2」を入力してますが、
場合によって変えてあげるのが良いでしょう。

$RAILS_ROOT/app/controllers/issues_controller.rb

@@ -94,6 +94,8 @@
   end

   def show
+    user_conditions = "status <> 0 and id <> 1"
+    @users =  User.find :all, :conditions => user_conditions
     @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x, :customized => @issue) }
     @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
     @journals.each_with_index {|j,i| j.indice = i+1}
@@ -108,11 +110,14 @@
       format.atom { render :action => 'changes', :layout => false, :content_type => 'application/atom+xml' }
       format.pdf  { send_data(render(:template => 'issues/show.rfpdf', :layout => false), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
     end
+
   end

   # Add a new issue
   # The new issue will be created from an existing one if copy_from parameter is given
   def new
+    user_conditions = "status <> 0 and id <> 1"
+    @users =  User.find :all, :conditions => user_conditions
     @issue = params[:copy_from] ? Issue.new.copy_from(params[:copy_from]) : Issue.new(params[:issue])
     @issue.project = @project
     @issue.author = User.current
@@ -148,7 +153,11 @@
       if @issue.save
         attach_files(@issue, params[:attachments])
         flash[:notice] = l(:notice_successful_create)
-        Mailer.deliver_issue_add(@issue) if Setting.notified_events.include?('issue_added')
+        if params[:send_mail]
+          @issue.mail_kind = params[:mail_kind] if params[:mail_kind];
+          @issue.sel_users = params[:sel_users] if params[:sel_users];
+          Mailer.deliver_issue_add(@issue) if Setting.notified_events.include?('issue_added')
+        end
         redirect_to :controller => 'issues', :action => 'show', :id => @issue
         return
       end
@@ -198,7 +207,11 @@
         if !journal.new_record?
           # Only send notification if something was actually changed
           flash[:notice] = l(:notice_successful_update)
-          Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
+          if params[:send_mail]
+            @issue.mail_kind = params[:mail_kind] if params[:mail_kind];
+            @issue.sel_users = params[:sel_users] if params[:sel_users];
+            Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
+          end
         end
         redirect_to(params[:back_to] || {:action => 'show', :id => @issue})
       end
@@ -230,7 +243,11 @@
         # Don't save any change to the issue if the user is not authorized to apply the requested status
         if (status.nil? || (issue.status.new_status_allowed_to?(status, current_role, issue.tracker) && issue.status = status)) && issue.save
           # Send notification for each issue (if changed)
-          Mailer.deliver_issue_edit(journal) if journal.details.any? && Setting.notified_events.include?('issue_updated')
+          if params[:send_mail]
+            @issue.mail_kind = params[:mail_kind] if params[:mail_kind];
+            @issue.sel_users = params[:sel_users] if params[:sel_users];
+            Mailer.deliver_issue_edit(journal) if journal.details.any? && Setting.notified_events.include?('issue_updated')
+          end
         else
           # Keep unsaved issue ids to display them in flash error
           unsaved_issue_ids << issue.id

次にコントローラです。
ポイントは、showメソッドとnewメソッドに追加された「@users」設定個所と、
「params[:send_mail]」の判定個所です。
上記@usersの設定条件は「ステータス有効 かつ id が1(admin)以外」ですが、
これだと全ユーザー分表示されてしまうので、
要件によってuser_conditionsに条件を追加して下さい。
あと前回と異なる点としては「params[:send_mail]」の直後に
@issue.mail_kind と@issue.sel_users の設定個所が追加されています。

$RAILS_ROOT/app/models/issue.rb

--- /var/www/html/redmine-0.7.3-org/app/models/issue.rb 2008-07-06 20:17:46.000000000 +0900
+++ /var/www/html/redmine-0.7.3/app/models/issue.rb     2008-11-23 02:16:08.000000000 +0900
@@ -46,6 +46,9 @@
   validates_numericality_of :estimated_hours, :allow_nil => true
   validates_associated :custom_values, :on => :update

+  attr_accessor :mail_kind
+  attr_accessor :sel_users
+
   def after_initialize
     if new_record?
       # set default values for new records only
@@ -200,13 +203,27 @@
   end

   # Returns the mail adresses of users that should be notified for the issue
+
   def recipients
-    recipients = project.recipients
-    # Author and assignee are always notified unless they have been locked
-    recipients << author.mail if author && author.active?
-    recipients << assigned_to.mail if assigned_to && assigned_to.active?
+    case @mail_kind
+    when 'select_member'
+      # p "----------select_member----------"
+      recipients = []
+      @sel_users.each do |user_id|
+        recipients << User.find(user_id).mail
+      end
+    else
+      # p "----------else----------"
+      recipients = project.recipients
+      # Author and assignee are always notified unless they have been locked
+      recipients << author.mail if author && author.active?
+      recipients << assigned_to.mail if assigned_to && assigned_to.active?
+    end
+
     recipients.compact.uniq
+    # p recipients
   end
+

   def spent_hours
     @spent_hours ||= time_entries.sum(:hours) || 0

最後にモデルです。
ここでのポイントは
「attr_accessor」の設定と「recipients」メソッドの条件判定追加です。
「attr_accessor」には、選択されたラジオボタンの値と、選択されたメンバーの配列が入力されます。
「recipients」メソッドでは、ラジオボタンの値により
recipientsへ追加する処理を変更しています。


画面イメージはこんな感じになります。


次回以降は未定です。0.8.0がどれだけ変更されてるかにもよりますしね。
早くリリースされないかなー

*1:バージョンは0.7.3を対象にしています