Redmineカスタマイズその1 全プロジェクト検索


現在会社でRedmineを運用しているのですが、
いろいろと直したい所も出てきたのでそろそろソースをいじりまくろうと思います。
ちなみにワタクシ、Rubyを知らないので(致命的)
間違いも多々あると思いますが…そこは御愛嬌ということでお許しを。
勉強したいんですが時間がなかなかとれないんですよねー


まず今回は全プロジェクトに対して検索可能にするパッチを当てたいと思います。*1
改修対象となるソースは2つほど。


redmine-0.7.1/app/controllers/search_controller.rb

# diff redmine-0.7.1/app/controllers/search_controller.rb redmine-0.7.1-org/app/controllers/search_controller.rb 
49,58c49
< # toritori test start
< 
<       @object_types = %w(issues news documents changesets wiki_pages messages)
< #      @object_types = @object_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, @project)}
<       
<       @scope = @object_types.select {|t| params[t]}
<       @scope = @object_types if @scope.empty?
<       
< #       @object_types = @scope = %w(projects)
< # toritori test end
---
>       @object_types = @scope = %w(projects)
98,140c89,95
< # toritori test start
<         user_projects_by_root = User.current.projects.find(:all).group_by(&:root)
<         #user_projects_by_root = User.current.projects.find(:all, :include => :parent).group_by(&:root)
<         user_projects_by_root.keys.sort.each do |root|
<           user_projects_by_root[root].sort.each do |pj| 
< 
<           @tori_project = pj
< 
<           @scope.each do |s|
<             @results += s.singularize.camelcase.constantize.search(like_tokens, @tori_project,
<               :all_words => @all_words,
<               :titles_only => @titles_only,
<               :limit => (limit+1),
<               :offset => offset,
<               :before => params[:previous].nil?)
<           end
<           @results = @results.sort {|a,b| b.event_datetime <=> a.event_datetime}
<           if params[:previous].nil?
<             @pagination_previous_date = @results[0].event_datetime if offset && @results[0]
<             if @results.size > limit
<               @pagination_next_date = @results[limit-1].event_datetime 
<               @results = @results[0, limit]
<             end
<           else
<             @pagination_next_date = @results[-1].event_datetime if offset && @results[-1]
<             if @results.size > limit
<               @pagination_previous_date = @results[-(limit)].event_datetime 
<               @results = @results[-(limit), limit]
<             end
<           end
< 
<           end
<         end    
<    
< #        operator = @all_words ? ' AND ' : ' OR '
< #        @results += Project.find(:all, 
< #                                 :limit => limit,
< #                                 :conditions => [ (["(#{Project.visible_by(User.current)}) AND (LOWER(name) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort]
< #                                 ) if @scope.include? 'projects'
< #        # if only one project is found, user is redirected to its overview
< #        redirect_to :controller => 'projects', :action => 'show', :id => @results.first and return if @results.size == 1
< # 
< # toritori test end
---
>         operator = @all_words ? ' AND ' : ' OR '
>         @results += Project.find(:all, 
>                                  :limit => limit,
>                                  :conditions => [ (["(#{Project.visible_by(User.current)}) AND (LOWER(name) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort]
>                                  ) if @scope.include? 'projects'
>         # if only one project is found, user is redirected to its overview
>         redirect_to :controller => 'projects', :action => 'show', :id => @results.first and return if @results.size == 1

コントローラの修正です。
49-58は「カレントプロジェクトを見てほにゃららしている部分」をコメント化してます。
98-140は「画面右上のプロジェクトプルダウン作成」のソースを参考にしたのですが、
自分もよくわかってないまま使ってます;

user_projects_by_root = User.current.projects.find(:all).group_by(&:root)
user_projects_by_root.keys.sort.each do |root|
  user_projects_by_root[root].sort.each do |pj|

特にこの辺のコードって、かなり余計な事してるのは自覚してるんですが、
NetBeanの使い方もよくわかってないので追い切れないんですもん(´・ω・`)
どなたか代替して下さい…

redmine-0.7.1/app/views/search/index.rhtml

# diff redmine-0.7.1/app/views/search/index.rhtml redmine-0.7.1-org/app/views/search/index.rhtml 
23,32c23,25
<         <% if @tori_project %>
<           <li><p><%= e.project.name%>-<%= link_to highlight_tokens(truncate(e.event_title, 255), @tokens), e.event_url %><br />
<           <%= highlight_tokens(e.event_description, @tokens) %><br />
<           <span class="author"><%= format_time(e.event_datetime) %></span></p></li>
<         <% else %>
<           <li><p><%= link_to highlight_tokens(truncate(e.event_title, 255), @tokens), e.event_url %><br />
<           <%= highlight_tokens(e.event_description, @tokens) %><br />
<           <span class="author"><%= format_time(e.event_datetime) %></span></p></li>
<         <% end %>
< 
---
>         <li><p><%= link_to highlight_tokens(truncate(e.event_title, 255), @tokens), e.event_url %><br />
>         <%= highlight_tokens(e.event_description, @tokens) %><br />
>         <span class="author"><%= format_time(e.event_datetime) %></span></p></li>

Viewは単純にリストの頭にプロジェクト名を付加しただけですね。
e.event_titleとかe.event_descriptionってどこに定義されてるんだろう…


上記パッチを当てると、ホーム画面(プロジェクト選択前)からの検索で、
ログイン者が所属する全プロジェクトに対して検索することが可能となります。
動作としては以下のような感じ。


全部で5つのプロジェクトが存在していますが、
 現在とりとりが所属するプロジェクトは
 「とりとりテスト」「とりとり子プロジェクト」「とりとり3」の3つです。

次に全てのプロジェクトに「abc」という文字列を挿入します。
(画像では1つですが、所属していないプロジェクトも含めて全てに入れてます)

ホーム画面で検索ボックスに「abc」を入力してエンターキーを押すと…

所属しているプロジェクトのみから検索結果が抽出されます。
 プロジェクト名も付加されてリスト表示されているのがわかります。

以上で終了です。
次回はメール通知のカスタマイズを行う予定です。
メール通知のアクション時に
「メール通知する」「メール通知するメンバーを選択する」
といった選択が出来るといいかなと。
まあ気長にやりたいと思います。

*1:2008/12/13追記:Redmine0.8.0以降、標準で全プロジェクト検索機能が追加されています