##// END OF EJS Templates
query model/controller added...
Jean-Philippe Lang -
r76:da91e5e95a54
parent child
Show More
@@ -0,0 +1,55
1 class QueriesController < ApplicationController
2 layout 'base'
3
4 def index
5 list
6 render :action => 'list'
7 end
8
9 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
10 verify :method => :post, :only => [ :destroy, :create, :update ],
11 :redirect_to => { :action => :list }
12
13 def list
14 @query_pages, @queries = paginate :queries, :per_page => 10
15 end
16
17 def show
18 @query = Query.find(params[:id])
19 end
20
21 def new
22 @query = Query.new(params[:query])
23
24 params[:fields].each do |field|
25 @query.add_filter(field, params[:operators][field], params[:values][field])
26 end if params[:fields]
27
28 if request.post? and @query.save
29 flash[:notice] = 'Query was successfully created.'
30 redirect_to :action => 'list'
31 end
32 end
33
34 def edit
35 @query = Query.find(params[:id])
36
37 if request.post?
38 @query.filters = {}
39 params[:fields].each do |field|
40 @query.add_filter(field, params[:operators][field], params[:values][field])
41 end if params[:fields]
42 @query.attributes = params[:query]
43
44 if @query.save
45 flash[:notice] = 'Query was successfully updated.'
46 redirect_to :action => 'show', :id => @query
47 end
48 end
49 end
50
51 def destroy
52 Query.find(params[:id]).destroy
53 redirect_to :action => 'list'
54 end
55 end
@@ -0,0 +1,2
1 module QueriesHelper
2 end
@@ -0,0 +1,123
1 class Query < ActiveRecord::Base
2 serialize :filters
3
4 validates_presence_of :name
5
6 @@operators = { "=" => "Egal",
7 "!" => "Different",
8 "o" => "Ouvert",
9 "c" => "Ferme",
10 "!*" => "Aucun",
11 "*" => "Tous",
12 "<t+" => "Dans moins de",
13 ">t+" => "Dans plus de",
14 "t+" => "Dans exactement",
15 "t" => "Aujourd'hui",
16 ">t-" => "Il y a moins de",
17 "<t-" => "Il y a plus de",
18 "t-" => "Il y a exactement" }
19
20 @@operators_by_filter_type = { :list => [ "=", "!" ],
21 :list_status => [ "o", "=", "!", "c" ],
22 :list_optional => [ "=", "!", "!*", "*" ],
23 :date => [ "<t+", ">t+", "t+", "t", ">t-", "<t-", "t-" ],
24 :date_past => [ ">t-", "<t-", "t-", "t" ] }
25
26 @@available_filters = { "status_id" => { :type => :list_status, :order => 1,
27 :values => IssueStatus.find(:all).collect{|s| [s.name, s.id.to_s] } },
28 "tracker_id" => { :type => :list, :order => 2,
29 :values => Tracker.find(:all).collect{|s| [s.name, s.id.to_s] } },
30 "assigned_to_id" => { :type => :list_optional, :order => 3,
31 :values => User.find(:all).collect{|s| [s.display_name, s.id.to_s] } },
32 "priority_id" => { :type => :list, :order => 4,
33 :values => Enumeration.find(:all, :conditions => ['opt=?','IPRI']).collect{|s| [s.name, s.id.to_s] } },
34 "created_on" => { :type => :date_past, :order => 5 },
35 "updated_on" => { :type => :date_past, :order => 6 },
36 "start_date" => { :type => :date, :order => 7 },
37 "due_date" => { :type => :date, :order => 8 } }
38
39 cattr_accessor :available_filters
40
41 def initialize(attributes = nil)
42 super
43 self.filters ||= { 'status_id' => {:operator => "o"} }
44 end
45
46 def validate
47 errors.add_to_base "Au moins un critere doit etre selectionne" unless filters && !filters.empty?
48 filters.each_key do |field|
49 errors.add field.gsub(/\_id$/, ""), "doit etre renseigne" unless
50 # filter requires one or more values
51 (values_for(field) and !values_for(field).first.empty?) or
52 # filter doesn't require any value
53 ["o", "c", "!*", "*", "t"].include? operator_for(field)
54 end if filters
55 end
56
57 def add_filter(field, operator, values)
58 # values must be an array
59 return unless values and values.is_a? Array
60 # check if field is defined as an available filter
61 if @@available_filters.has_key? field
62 filter_options = @@available_filters[field]
63 # check if operator is allowed for that filter
64 if @@operators_by_filter_type[filter_options[:type]].include? operator
65 filters[field] = {:operator => operator, :values => values }
66 end
67 end
68 end
69
70 def has_filter?(field)
71 filters and filters[field]
72 end
73
74 def operator_for(field)
75 has_filter?(field) ? filters[field][:operator] : nil
76 end
77
78 def values_for(field)
79 has_filter?(field) ? filters[field][:values] : nil
80 end
81
82 def statement
83 sql = "1=1"
84 filters.each_key do |field|
85 sql = sql + " AND " unless sql.empty?
86 v = values_for field
87 case operator_for field
88 when "="
89 sql = sql + "issues.#{field} IN (" + v.each(&:to_i).join(",") + ")"
90 when "!"
91 sql = sql + "issues.#{field} NOT IN (" + v.each(&:to_i).join(",") + ")"
92 when "!*"
93 sql = sql + "issues.#{field} IS NULL"
94 when "*"
95 sql = sql + "issues.#{field} IS NOT NULL"
96 when "o"
97 sql = sql + "issue_statuses.is_closed=#{connection.quoted_false}" if field == "status_id"
98 when "c"
99 sql = sql + "issue_statuses.is_closed=#{connection.quoted_true}" if field == "status_id"
100 when ">t-"
101 sql = sql + "issues.#{field} >= '%s'" % connection.quoted_date(Date.today - v.first.to_i)
102 when "<t-"
103 sql = sql + "issues.#{field} <= '" + (Date.today - v.first.to_i).strftime("%Y-%m-%d") + "'"
104 when "t-"
105 sql = sql + "issues.#{field} = '" + (Date.today - v.first.to_i).strftime("%Y-%m-%d") + "'"
106 when ">t+"
107 sql = sql + "issues.#{field} >= '" + (Date.today + v.first.to_i).strftime("%Y-%m-%d") + "'"
108 when "<t+"
109 sql = sql + "issues.#{field} <= '" + (Date.today + v.first.to_i).strftime("%Y-%m-%d") + "'"
110 when "t+"
111 sql = sql + "issues.#{field} = '" + (Date.today + v.first.to_i).strftime("%Y-%m-%d") + "'"
112 when "t"
113 sql = sql + "issues.#{field} = '%s'" % connection.quoted_date(Date.today)
114 end
115 end if filters
116 sql
117 end
118
119 def self.operators_for_select(filter_type)
120 @@operators_by_filter_type[filter_type].collect {|o| [@@operators[o], o]}
121 end
122
123 end
@@ -0,0 +1,72
1 <script>
2
3 function toggle_filter(field) {
4 check_box = $('cb_' + field);
5
6 if (check_box.checked) {
7 Element.show("operators[" + field + "]");
8 toggle_operator(field);
9 } else {
10 Element.hide("operators[" + field + "]");
11 Element.hide("values_div[" + field + "]");
12 }
13 }
14
15 function toggle_operator(field) {
16 operator = $("operators[" + field + "]");
17 switch (operator.value) {
18 case "!*":
19 case "*":
20 case "t":
21 case "o":
22 case "c":
23 Element.hide("values_div[" + field + "]");
24 break;
25 default:
26 Element.show("values_div[" + field + "]");
27 break;
28 }
29 }
30
31 function toggle_multi_select(field) {
32 select = $('values[' + field + '][]');
33 if (select.multiple == true) {
34 select.multiple = false;
35 } else {
36 select.multiple = true;
37 }
38 }
39
40 </script>
41
42 <fieldset><legend>Filtres</legend>
43 <table>
44 <% Query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.each do |filter| %>
45 <% field = filter[0]
46 options = filter[1] %>
47 <tr>
48 <td valign="top" width="200">
49 <%= check_box_tag 'fields[]', field, query.has_filter?(field), :onclick => "toggle_filter('#{field}');", :id => "cb_#{field}" %>
50 <label for="cb_<%= field %>"><%= l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) %></label>
51 </td>
52 <td valign="top" width="150">
53 <%= select_tag "operators[#{field}]", options_for_select(Query.operators_for_select(options[:type]), query.operator_for(field)), :onchange => "toggle_operator('#{field}');", :class => "select-small", :style => "vertical-align: top;" %>
54 </td>
55 <td valign="top">
56 <div id="values_div[<%= field %>]">
57 <% case options[:type]
58 when :list, :list_optional, :list_status %>
59 <select <%= "multiple=true" if query.values_for(field) and query.values_for(field).length > 1 %>" name="values[<%= field %>][]" id="values[<%= field %>][]" class="select-small" style="vertical-align: top;">
60 <%= options_for_select options[:values], query.values_for(field) %>
61 </select>
62 <%= link_to_function '+', "toggle_multi_select('#{field}');" %>
63 <% when :date, :date_past %>
64 <%= text_field_tag "values[#{field}][]", query.values_for(field), :size => 3, :class => "select-small" %> jours
65 <% end %>
66 </div>
67 </td>
68 </tr>
69 <script>toggle_filter('<%= field %>');</script>
70 <% end %>
71 </table>
72 </fieldset> No newline at end of file
@@ -0,0 +1,18
1 <%= error_messages_for 'query' %>
2
3 <!--[form:query]-->
4 <div class="box">
5
6 <div class="tabular">
7 <p><label for="query_name">Name</label>
8 <%= text_field 'query', 'name', :size => 80 %></p>
9
10 <p><label for="query_is_public">Public</label>
11 <%= check_box 'query', 'is_public' %></p>
12 </div>
13
14 <%= render :partial => 'filters', :locals => {:query => query}%>
15
16 </div>
17 <!--[eoform:query]-->
18
@@ -0,0 +1,8
1 <h1>Editing query</h1>
2
3 <%= start_form_tag :action => 'edit', :id => @query %>
4 <%= render :partial => 'form', :locals => {:query => @query} %>
5 <%= submit_tag 'Edit' %>
6 <%= end_form_tag %>
7
8 <%= debug @query.statement %> No newline at end of file
@@ -0,0 +1,27
1 <h1>Listing queries</h1>
2
3 <table>
4 <tr>
5 <% for column in Query.content_columns %>
6 <th><%= column.human_name %></th>
7 <% end %>
8 </tr>
9
10 <% for query in @queries %>
11 <tr>
12 <% for column in Query.content_columns %>
13 <td><%=h query.send(column.name) %></td>
14 <% end %>
15 <td><%= link_to 'Show', :action => 'show', :id => query %></td>
16 <td><%= link_to 'Edit', :action => 'edit', :id => query %></td>
17 <td><%= link_to 'Destroy', { :action => 'destroy', :id => query }, :confirm => 'Are you sure?', :post => true %></td>
18 </tr>
19 <% end %>
20 </table>
21
22 <%= link_to 'Previous page', { :page => @query_pages.current.previous } if @query_pages.current.previous %>
23 <%= link_to 'Next page', { :page => @query_pages.current.next } if @query_pages.current.next %>
24
25 <br />
26
27 <%= link_to 'New query', :action => 'new' %>
@@ -0,0 +1,9
1 <h1>New query</h1>
2
3 <%= start_form_tag :action => 'new' %>
4 <%= render :partial => 'form', :locals => {:query => @query} %>
5 <%= submit_tag "Create" %>
6 <%= end_form_tag %>
7
8 <%= debug @query %>
9 <%= debug params %>
@@ -0,0 +1,8
1 <% for column in Query.content_columns %>
2 <p>
3 <b><%= column.human_name %>:</b> <%=h @query.send(column.name) %>
4 </p>
5 <% end %>
6
7 <%= link_to 'Edit', :action => 'edit', :id => @query %> |
8 <%= link_to 'Back', :action => 'list' %>
@@ -208,8 +208,10 class ProjectsController < ApplicationController
208 sort_init 'issues.id', 'desc'
208 sort_init 'issues.id', 'desc'
209 sort_update
209 sort_update
210
210
211 search_filter_init_list_issues
211 @query = Query.new
212 search_filter_update if params[:set_filter]
212 params[:fields].each do |field|
213 @query.add_filter(field, params[:operators][field], params[:values][field])
214 end if params[:fields]
213
215
214 @results_per_page_options = [ 15, 25, 50, 100 ]
216 @results_per_page_options = [ 15, 25, 50, 100 ]
215 if params[:per_page] and @results_per_page_options.include? params[:per_page].to_i
217 if params[:per_page] and @results_per_page_options.include? params[:per_page].to_i
@@ -219,11 +221,11 class ProjectsController < ApplicationController
219 @results_per_page = session[:results_per_page] || 25
221 @results_per_page = session[:results_per_page] || 25
220 end
222 end
221
223
222 @issue_count = Issue.count(:include => [:status, :project], :conditions => search_filter_clause)
224 @issue_count = Issue.count(:include => [:status, :project], :conditions => @query.statement)
223 @issue_pages = Paginator.new self, @issue_count, @results_per_page, @params['page']
225 @issue_pages = Paginator.new self, @issue_count, @results_per_page, @params['page']
224 @issues = Issue.find :all, :order => sort_clause,
226 @issues = Issue.find :all, :order => sort_clause,
225 :include => [ :author, :status, :tracker, :project ],
227 :include => [ :author, :status, :tracker, :project ],
226 :conditions => search_filter_clause,
228 :conditions => @query.statement,
227 :limit => @issue_pages.items_per_page,
229 :limit => @issue_pages.items_per_page,
228 :offset => @issue_pages.current.offset
230 :offset => @issue_pages.current.offset
229
231
@@ -7,28 +7,12
7 </small>
7 </small>
8 </div>
8 </div>
9
9
10 <div>
10 <%= start_form_tag :action => 'list_issues' %>
11 <%= start_form_tag :action => 'list_issues' %>
11 <table cellpadding=2>
12 <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
12 <tr>
13 <%= submit_tag l(:button_apply), :class => "button-small" %>
13 <td valign="bottom"><small><%=l(:field_status)%>:</small><br /><%= search_filter_tag 'status_id', :class => 'select-small' %></td>
14 <td valign="bottom"><small><%=l(:field_tracker)%>:</small><br /><%= search_filter_tag 'tracker_id', :class => 'select-small' %></td>
15 <td valign="bottom"><small><%=l(:field_priority)%>:</small><br /><%= search_filter_tag 'priority_id', :class => 'select-small' %></td>
16 <td valign="bottom"><small><%=l(:field_category)%>:</small><br /><%= search_filter_tag 'category_id', :class => 'select-small' %></td>
17 <td valign="bottom"><small><%=l(:field_fixed_version)%>:</small><br /><%= search_filter_tag 'fixed_version_id', :class => 'select-small' %></td>
18 <td valign="bottom"><small><%=l(:field_author)%>:</small><br /><%= search_filter_tag 'author_id', :class => 'select-small' %></td>
19 <td valign="bottom"><small><%=l(:field_assigned_to)%>:</small><br /><%= search_filter_tag 'assigned_to_id', :class => 'select-small' %></td>
20 <td valign="bottom"><small><%=l(:label_subproject_plural)%>:</small><br /><%= search_filter_tag 'subproject_id', :class => 'select-small' %></td>
21 <td valign="bottom">
22 <%= hidden_field_tag 'set_filter', 1 %>
23 <%= submit_tag l(:button_apply), :class => 'button-small' %>
24 </td>
25 <td valign="bottom">
26 <%= link_to l(:button_clear), :action => 'list_issues', :id => @project, :set_filter => 1 %>
27 </td>
28 </tr>
29 </table>
30 <%= end_form_tag %>
14 <%= end_form_tag %>
31
15 </div>
32 &nbsp;
16 &nbsp;
33 <table class="listTableContent">
17 <table class="listTableContent">
34 <tr>
18 <tr>
@@ -213,7 +213,7 select {
213 vertical-align: middle;
213 vertical-align: middle;
214 }
214 }
215
215
216 select.select-small
216 .select-small
217 {
217 {
218 border: 1px solid #7F9DB9;
218 border: 1px solid #7F9DB9;
219 padding: 1px;
219 padding: 1px;
General Comments 0
You need to be logged in to leave comments. Login now