Commit 6e82bdc7062af8f0447fff19593054948cbeb5e5
1 parent
144d5783
Exists in
staging
and in
42 other branches
[otw] products action... =/
Showing
34 changed files
with
604 additions
and
338 deletions
Show diff stats
app/controllers/public/search_controller.rb
| ... | ... | @@ -8,6 +8,7 @@ class SearchController < PublicController |
| 8 | 8 | before_filter :load_category |
| 9 | 9 | before_filter :load_search_assets |
| 10 | 10 | before_filter :load_query |
| 11 | + before_filter :load_search_engine | |
| 11 | 12 | |
| 12 | 13 | # Backwards compatibility with old URLs |
| 13 | 14 | def redirect_asset_param |
| ... | ... | @@ -18,7 +19,7 @@ class SearchController < PublicController |
| 18 | 19 | no_design_blocks |
| 19 | 20 | |
| 20 | 21 | def facets_browse |
| 21 | - @asset = params[:asset] | |
| 22 | + @asset = params[:asset].to_sym | |
| 22 | 23 | @asset_class = asset_class(@asset) |
| 23 | 24 | |
| 24 | 25 | @facets_only = true |
| ... | ... | @@ -31,11 +32,12 @@ class SearchController < PublicController |
| 31 | 32 | end |
| 32 | 33 | |
| 33 | 34 | def articles |
| 34 | - if !@empty_query | |
| 35 | - full_text_search ['public:true'] | |
| 35 | + if @search_engine && !@empty_query | |
| 36 | + full_text_search | |
| 36 | 37 | else |
| 37 | 38 | @results[@asset] = @environment.articles.public.send(@filter).paginate(paginate_options) |
| 38 | 39 | end |
| 40 | + render :template => 'search/search_page' | |
| 39 | 41 | end |
| 40 | 42 | |
| 41 | 43 | def contents |
| ... | ... | @@ -43,49 +45,51 @@ class SearchController < PublicController |
| 43 | 45 | end |
| 44 | 46 | |
| 45 | 47 | def people |
| 46 | - if !@empty_query | |
| 47 | - full_text_search ['public:true'] | |
| 48 | + if @search_engine && !@empty_query | |
| 49 | + full_text_search | |
| 48 | 50 | else |
| 49 | 51 | @results[@asset] = visible_profiles(Person).send(@filter).paginate(paginate_options) |
| 50 | 52 | end |
| 53 | + render :template => 'search/search_page' | |
| 51 | 54 | end |
| 52 | 55 | |
| 53 | 56 | def products |
| 54 | - public_filters = ['public:true', 'enabled:true'] | |
| 55 | - if !@empty_query | |
| 56 | - full_text_search public_filters | |
| 57 | + if @search_engine && !@empty_query | |
| 58 | + full_text_search | |
| 57 | 59 | else |
| 58 | - @one_page = true | |
| 59 | 60 | @geosearch = logged_in? && current_user.person.lat && current_user.person.lng |
| 60 | 61 | |
| 61 | 62 | extra_limit = LIST_SEARCH_LIMIT*5 |
| 62 | 63 | sql_options = {:limit => LIST_SEARCH_LIMIT, :order => 'random()'} |
| 63 | 64 | if @geosearch |
| 64 | - full_text_search public_filters, :sql_options => sql_options, :extra_limit => extra_limit, | |
| 65 | + full_text_search :sql_options => sql_options, :extra_limit => extra_limit, | |
| 65 | 66 | :alternate_query => "{!boost b=recip(geodist(),#{"%e" % (1.to_f/DistBoost)},1,1)}", |
| 66 | 67 | :radius => DistFilt, :latitude => current_user.person.lat, :longitude => current_user.person.lng |
| 67 | 68 | else |
| 68 | - full_text_search public_filters, :sql_options => sql_options, :extra_limit => extra_limit, | |
| 69 | + full_text_search :sql_options => sql_options, :extra_limit => extra_limit, | |
| 69 | 70 | :boost_functions => ['recip(ms(NOW/HOUR,updated_at),1.3e-10,1,1)'] |
| 70 | 71 | end |
| 71 | 72 | end |
| 73 | + render :template => 'search/search_page' | |
| 72 | 74 | end |
| 73 | 75 | |
| 74 | 76 | def enterprises |
| 75 | - if !@empty_query | |
| 76 | - full_text_search ['public:true'] | |
| 77 | + if @search_engine && !@empty_query | |
| 78 | + full_text_search | |
| 77 | 79 | else |
| 78 | 80 | @filter_title = _('Enterprises from network') |
| 79 | 81 | @results[@asset] = visible_profiles(Enterprise, [{:products => :product_category}]).paginate(paginate_options) |
| 80 | 82 | end |
| 83 | + render :template => 'search/search_page' | |
| 81 | 84 | end |
| 82 | 85 | |
| 83 | 86 | def communities |
| 84 | - if !@empty_query | |
| 85 | - full_text_search ['public:true'] | |
| 87 | + if @search_engine && !@empty_query | |
| 88 | + full_text_search | |
| 86 | 89 | else |
| 87 | 90 | @results[@asset] = visible_profiles(Community).send(@filter).paginate(paginate_options) |
| 88 | 91 | end |
| 92 | + render :template => 'search/search_page' | |
| 89 | 93 | end |
| 90 | 94 | |
| 91 | 95 | def events |
| ... | ... | @@ -104,7 +108,7 @@ class SearchController < PublicController |
| 104 | 108 | environment.events.by_day(@selected_day) |
| 105 | 109 | end |
| 106 | 110 | |
| 107 | - if !@empty_query | |
| 111 | + if @search_engine && !@empty_query | |
| 108 | 112 | full_text_search |
| 109 | 113 | else |
| 110 | 114 | @results[@asset] = date_range ? environment.events.by_range(date_range) : environment.events |
| ... | ... | @@ -189,6 +193,7 @@ class SearchController < PublicController |
| 189 | 193 | def load_query |
| 190 | 194 | @asset = params[:action].to_sym |
| 191 | 195 | @order ||= [@asset] |
| 196 | + params[:display] ||= 'list' | |
| 192 | 197 | @results ||= {} |
| 193 | 198 | @filter = filter |
| 194 | 199 | @filter_title = filter_description(@asset, @filter) |
| ... | ... | @@ -211,6 +216,10 @@ class SearchController < PublicController |
| 211 | 216 | end |
| 212 | 217 | end |
| 213 | 218 | |
| 219 | + def load_search_engine | |
| 220 | + @search_engine = @plugins.first_plugin(:search_engine?) | |
| 221 | + end | |
| 222 | + | |
| 214 | 223 | FILTERS = %w( |
| 215 | 224 | more_recent |
| 216 | 225 | more_active |
| ... | ... | @@ -260,9 +269,7 @@ class SearchController < PublicController |
| 260 | 269 | if map_search? |
| 261 | 270 | MAP_SEARCH_LIMIT |
| 262 | 271 | elsif !multiple_search? |
| 263 | - if [:people, :communities].include? @asset | |
| 264 | - BLOCKS_SEARCH_LIMIT | |
| 265 | - elsif @asset == :enterprises and @empty_query | |
| 272 | + if [:people, :communities, :enterprises].include? @asset | |
| 266 | 273 | BLOCKS_SEARCH_LIMIT |
| 267 | 274 | else |
| 268 | 275 | LIST_SEARCH_LIMIT |
| ... | ... | @@ -273,41 +280,12 @@ class SearchController < PublicController |
| 273 | 280 | end |
| 274 | 281 | |
| 275 | 282 | def paginate_options(page = params[:page]) |
| 276 | - page = 1 if multiple_search? or params[:display] == 'map' | |
| 283 | + page = 1 if multiple_search? or @display == 'map' | |
| 277 | 284 | { :per_page => limit, :page => page } |
| 278 | 285 | end |
| 279 | 286 | |
| 280 | - def full_text_search(filters = [], options = {}) | |
| 281 | - paginate_options = paginate_options(params[:page]) | |
| 282 | - asset_class = asset_class(@asset) | |
| 283 | - solr_options = options | |
| 284 | - pg_options = paginate_options(params[:page]) | |
| 285 | - | |
| 286 | - if !multiple_search? | |
| 287 | - if !@results_only and asset_class.respond_to? :facets | |
| 288 | - solr_options.merge! asset_class.facets_find_options(params[:facet]) | |
| 289 | - solr_options[:all_facets] = true | |
| 290 | - end | |
| 291 | - solr_options[:filter_queries] ||= [] | |
| 292 | - solr_options[:filter_queries] += filters | |
| 293 | - solr_options[:filter_queries] << "environment_id:#{environment.id}" | |
| 294 | - solr_options[:filter_queries] << asset_class.facet_category_query.call(@category) if @category | |
| 295 | - | |
| 296 | - solr_options[:boost_functions] ||= [] | |
| 297 | - params[:order_by] = nil if params[:order_by] == 'none' | |
| 298 | - if params[:order_by] | |
| 299 | - order = SortOptions[@asset][params[:order_by].to_sym] | |
| 300 | - raise "Unknown order by" if order.nil? | |
| 301 | - order[:solr_opts].each do |opt, value| | |
| 302 | - solr_options[opt] = value.is_a?(Proc) ? instance_eval(&value) : value | |
| 303 | - end | |
| 304 | - end | |
| 305 | - end | |
| 306 | - | |
| 307 | - ret = asset_class.find_by_contents(@query, paginate_options, solr_options) | |
| 308 | - @results[@asset] = ret[:results] | |
| 309 | - @facets = ret[:facets] | |
| 310 | - @all_facets = ret[:all_facets] | |
| 287 | + def full_text_search(options = {}) | |
| 288 | + @results[@asset] = @plugins.first(:full_text_search, @asset, @query, @category, paginate_options(params[:page])) | |
| 311 | 289 | end |
| 312 | 290 | |
| 313 | 291 | private | ... | ... |
app/helpers/search_helper.rb
| ... | ... | @@ -2,7 +2,7 @@ module SearchHelper |
| 2 | 2 | |
| 3 | 3 | MAP_SEARCH_LIMIT = 2000 |
| 4 | 4 | LIST_SEARCH_LIMIT = 20 |
| 5 | - BLOCKS_SEARCH_LIMIT = 18 | |
| 5 | + BLOCKS_SEARCH_LIMIT = 24 | |
| 6 | 6 | MULTIPLE_SEARCH_LIMIT = 8 |
| 7 | 7 | DistFilt = 200 |
| 8 | 8 | DistBoost = 50 |
| ... | ... | @@ -50,7 +50,7 @@ module SearchHelper |
| 50 | 50 | end |
| 51 | 51 | |
| 52 | 52 | def map_search? |
| 53 | - !@empty_query and !multiple_search? and params[:display] == 'map' | |
| 53 | + !multiple_search? and params[:display] == 'map' | |
| 54 | 54 | end |
| 55 | 55 | |
| 56 | 56 | def search_page_title(title, category = nil) |
| ... | ... | @@ -66,8 +66,12 @@ module SearchHelper |
| 66 | 66 | :align => 'center', :class => 'search-category-context') if category |
| 67 | 67 | end |
| 68 | 68 | |
| 69 | - def display_results(map_capable = false) | |
| 70 | - if map_capable and map_search? | |
| 69 | + def map_capable?(asset) | |
| 70 | + [:enterprises, :products].include?(asset) | |
| 71 | + end | |
| 72 | + | |
| 73 | + def display_results(asset) | |
| 74 | + if map_capable?(asset) and map_search? | |
| 71 | 75 | partial = 'google_maps' |
| 72 | 76 | klass = 'map' |
| 73 | 77 | else |
| ... | ... | @@ -78,12 +82,6 @@ module SearchHelper |
| 78 | 82 | content_tag('div', render(:partial => partial), :class => "map-or-list-search-results #{klass}") |
| 79 | 83 | end |
| 80 | 84 | |
| 81 | - def display_map_list_button | |
| 82 | - button(:search, params[:display] == 'map' ? _('Display in list') : _('Display in map'), | |
| 83 | - params.merge(:display => (params[:display] == 'map' ? 'list' : 'map')), | |
| 84 | - :class => "map-toggle-button" ) | |
| 85 | - end | |
| 86 | - | |
| 87 | 85 | def city_with_state(city) |
| 88 | 86 | if city and city.kind_of?(City) |
| 89 | 87 | s = city.parent |
| ... | ... | @@ -97,17 +95,6 @@ module SearchHelper |
| 97 | 95 | end |
| 98 | 96 | end |
| 99 | 97 | |
| 100 | - def facets_menu(asset, _facets) | |
| 101 | - @asset_class = asset_class(asset) | |
| 102 | - @facets = _facets | |
| 103 | - render(:partial => 'facets_menu') | |
| 104 | - end | |
| 105 | - | |
| 106 | - def facets_unselect_menu(asset) | |
| 107 | - @asset_class = asset_class(asset) | |
| 108 | - render(:partial => 'facets_unselect_menu') | |
| 109 | - end | |
| 110 | - | |
| 111 | 98 | def facet_javascript(input_id, facet, array) |
| 112 | 99 | array = [] if array.nil? |
| 113 | 100 | hintText = _('Type in an option') |
| ... | ... | @@ -117,94 +104,6 @@ module SearchHelper |
| 117 | 104 | #{jquery_token_input_messages_json(hintText)}});") |
| 118 | 105 | end |
| 119 | 106 | |
| 120 | - def facet_link_html(facet, params, value, label, count) | |
| 121 | - params = params ? params.dup : {} | |
| 122 | - has_extra = label.kind_of?(Array) | |
| 123 | - link_label = has_extra ? label[0] : label | |
| 124 | - id = facet[:solr_field].to_s | |
| 125 | - params[:facet] ||= {} | |
| 126 | - params[:facet][id] ||= {} | |
| 127 | - params[:page] = {} if params[:page] | |
| 128 | - | |
| 129 | - selected = facet[:label_id].nil? ? params[:facet][id] == value : params[:facet][id][facet[:label_id]].to_a.include?(value) | |
| 130 | - | |
| 131 | - if count > 0 | |
| 132 | - url = params.merge(:facet => params[:facet].merge( | |
| 133 | - id => facet[:label_id].nil? ? value : params[:facet][id].merge( facet[:label_id] => params[:facet][id][facet[:label_id]].to_a | [value] ) | |
| 134 | - )) | |
| 135 | - else | |
| 136 | - # preserve others filters and change this filter | |
| 137 | - url = params.merge(:facet => params[:facet].merge( | |
| 138 | - id => facet[:label_id].nil? ? value : { facet[:label_id] => value } | |
| 139 | - )) | |
| 140 | - end | |
| 141 | - | |
| 142 | - content_tag 'div', link_to(link_label, url, :class => 'facet-result-link-label') + | |
| 143 | - content_tag('span', (has_extra ? label[1] : ''), :class => 'facet-result-extra-label') + | |
| 144 | - (count > 0 ? content_tag('span', " (#{count})", :class => 'facet-result-count') : ''), | |
| 145 | - :class => 'facet-menu-item' + (selected ? ' facet-result-link-selected' : '') | |
| 146 | - end | |
| 147 | - | |
| 148 | - def facet_selecteds_html_for(environment, klass, params) | |
| 149 | - def name_with_extra(klass, facet, value) | |
| 150 | - name = klass.facet_result_name(facet, value) | |
| 151 | - name = name[0] + name[1] if name.kind_of?(Array) | |
| 152 | - name | |
| 153 | - end | |
| 154 | - | |
| 155 | - ret = [] | |
| 156 | - params = params.dup | |
| 157 | - params[:facet].each do |id, value| | |
| 158 | - facet = klass.facet_by_id(id.to_sym) | |
| 159 | - next unless facet | |
| 160 | - if value.kind_of?(Hash) | |
| 161 | - label_hash = facet[:label].call(environment) | |
| 162 | - value.each do |label_id, value| | |
| 163 | - facet[:label_id] = label_id | |
| 164 | - facet[:label] = label_hash[label_id] | |
| 165 | - value.to_a.each do |value| | |
| 166 | - ret << [facet[:label], name_with_extra(klass, facet, value), | |
| 167 | - params.merge(:facet => params[:facet].merge(id => params[:facet][id].merge(label_id => params[:facet][id][label_id].to_a.reject{ |v| v == value })))] | |
| 168 | - end | |
| 169 | - end | |
| 170 | - else | |
| 171 | - ret << [klass.facet_label(facet), name_with_extra(klass, facet, value), | |
| 172 | - params.merge(:facet => params[:facet].reject{ |k,v| k == id })] | |
| 173 | - end | |
| 174 | - end | |
| 175 | - | |
| 176 | - ret.map do |label, name, url| | |
| 177 | - content_tag('div', content_tag('span', label, :class => 'facet-selected-label') + | |
| 178 | - content_tag('span', name, :class => 'facet-selected-name') + | |
| 179 | - link_to('', url, :class => 'facet-selected-remove', :title => 'remove facet'), :class => 'facet-selected') | |
| 180 | - end.join | |
| 181 | - end | |
| 182 | - | |
| 183 | - def order_by(asset) | |
| 184 | - options = SortOptions[asset].map do |name, options| | |
| 185 | - next if options[:if] and ! instance_eval(&options[:if]) | |
| 186 | - [_(options[:label]), name.to_s] | |
| 187 | - end.compact | |
| 188 | - | |
| 189 | - content_tag('div', _('Sort results by ') + | |
| 190 | - select_tag(asset.to_s + '[order]', options_for_select(options, params[:order_by] || 'none'), | |
| 191 | - {:onchange => "window.location = jQuery.param.querystring(window.location.href, { 'order_by' : this.options[this.selectedIndex].value})"}), | |
| 192 | - :class => "search-ordering") | |
| 193 | - end | |
| 194 | - | |
| 195 | - def label_total_found(asset, total_found) | |
| 196 | - labels = { | |
| 197 | - :products => _("%s products offers found"), | |
| 198 | - :articles => _("%s articles found"), | |
| 199 | - :events => _("%s events found"), | |
| 200 | - :people => _("%s people found"), | |
| 201 | - :enterprises => _("%s enterprises found"), | |
| 202 | - :communities => _("%s communities found"), | |
| 203 | - } | |
| 204 | - content_tag('span', labels[asset] % total_found, | |
| 205 | - :class => "total-pages-found") if labels[asset] | |
| 206 | - end | |
| 207 | - | |
| 208 | 107 | def asset_class(asset) |
| 209 | 108 | asset.to_s.singularize.camelize.constantize |
| 210 | 109 | end |
| ... | ... | @@ -213,4 +112,19 @@ module SearchHelper |
| 213 | 112 | asset_class(asset).table_name |
| 214 | 113 | end |
| 215 | 114 | |
| 115 | + def display_filter(asset, display, float = 'right') | |
| 116 | + if map_capable?(asset) | |
| 117 | + list_link = display == 'list' ? _('List') : link_to(_('List'), params.merge(:display => 'list')) | |
| 118 | + map_link = display == 'map' ? _('Map') : link_to(_('Map'), params.merge(:display => 'map')) | |
| 119 | + content_tag('div', | |
| 120 | + content_tag('strong', _('Display')) + ': ' + | |
| 121 | + list_link + | |
| 122 | + ' | ' + | |
| 123 | + map_link, | |
| 124 | + :id => 'search-display-filter', | |
| 125 | + :style => "float: #{float}" | |
| 126 | + ) | |
| 127 | + end | |
| 128 | + end | |
| 129 | + | |
| 216 | 130 | end | ... | ... |
app/views/search/_display_results.rhtml
| 1 | 1 | <div id="search-results" class="<%= !multiple_search? ? 'only-one-result-box' : 'multiple-results-boxes' %>"> |
| 2 | 2 | <% @order.each do |name| %> |
| 3 | 3 | <% results = @results[name] %> |
| 4 | - <% empty = results.nil? || results.empty? %> | |
| 5 | 4 | |
| 6 | - <div class="search-results-<%= name %> search-results-box <%= "search-results-empty" if empty %>"> | |
| 7 | - <% if not empty %> | |
| 5 | + <div class="search-results-<%= name %> search-results-box <%= "search-results-empty" if results.blank? %>"> | |
| 6 | + <% if !results.blank? %> | |
| 8 | 7 | <% partial = partial_for_class(results.first.class.class_name.constantize) %> |
| 9 | 8 | |
| 10 | 9 | <% if multiple_search? %> | ... | ... |
app/views/search/_facets_menu.rhtml
| ... | ... | @@ -1,36 +0,0 @@ |
| 1 | -<% less_options_limit = 8 %> | |
| 2 | - | |
| 3 | -<div id="facets-menu"> | |
| 4 | - <% @asset_class.map_facets_for(environment).each do |facet| %> | |
| 5 | - | |
| 6 | - <div id="facet-menu-<%= facet[:id].to_s %>" class="facet-menu"> | |
| 7 | - <div class="facet-menu-label"> | |
| 8 | - <%= @asset_class.facet_label(facet) %> | |
| 9 | - </div> | |
| 10 | - | |
| 11 | - <% results = @asset_class.map_facet_results(facet, params[:facet], @facets, @all_facets, :limit => less_options_limit) %> | |
| 12 | - <% facet_count = results.total_entries %> | |
| 13 | - | |
| 14 | - <% if facet_count > 0 %> | |
| 15 | - <div class="facet-menu-options facet-menu-more-options" style="display: none"> | |
| 16 | - </div> | |
| 17 | - | |
| 18 | - <div class="facet-menu-options facet-menu-less-options"> | |
| 19 | - <% results.each do |id, label, count| %> | |
| 20 | - <%= facet_link_html(facet, params, id, label, count) %><br /> | |
| 21 | - <% end %> | |
| 22 | - </div> <br /> | |
| 23 | - | |
| 24 | - <% if facet_count > less_options_limit %> | |
| 25 | - <%= link_to_function _("Options"), | |
| 26 | - "facet_options_toggle('#{facet[:id].to_s}', '#{url_for(params.merge(:action => 'facets_browse', :facet_id => facet[:id], :asset => @asset, :escape => false))}'); " + | |
| 27 | - "jQuery(this).toggleClass('facet-less-options')", :class => "facet-options-toggle" %> | |
| 28 | - <br /> | |
| 29 | - <% end %> | |
| 30 | - | |
| 31 | - <% else %> | |
| 32 | - <span class="facet-any-result-found"><%= _("No filter available") %></span> | |
| 33 | - <% end %> | |
| 34 | - </div> | |
| 35 | - <% end %> | |
| 36 | -</div> |
app/views/search/_profile.rhtml
| 1 | 1 | <li class="search-profile-item"> |
| 2 | -<% if @empty_query or multiple_search? or !profile.enterprise? %> | |
| 2 | +<% if @empty_query || multiple_search? || !profile.enterprise? || !@search_engine %> | |
| 3 | 3 | <%= profile_image_link profile, :portrait, 'div', |
| 4 | 4 | @filter == 'more_recent' ? profile.send(@filter + '_label') + show_date(profile.created_at) : profile.send(@filter + '_label') %> |
| 5 | 5 | <% else %> | ... | ... |
app/views/search/_results_header.rhtml
| 1 | 1 | <div class="search-results-header <%= "search-no-results" if @results[@asset].nil? or @results[@asset].length == 0 %>"> |
| 2 | - <% if !@empty_query %> | |
| 3 | - <div class="search-results-header-information"> | |
| 4 | - <% if @results[@asset].total_entries > 0 %> | |
| 5 | - <%= label_total_found(@asset, @results[@asset].total_entries) %> | |
| 6 | - <% if params[:display] != 'map' %> | |
| 7 | - <span class="current-page"><%= _("Showing page %s of %s") % [@results[@asset].current_page, @results[@asset].total_pages] %></span> | |
| 8 | - <% end %> | |
| 9 | - <% end %> | |
| 10 | - </div> | |
| 11 | - | |
| 12 | - <div class="search-results-header-facets-order-by"> | |
| 13 | - <%= facets_unselect_menu(@asset) %> | |
| 14 | - <%= order_by(@asset) if params[:display] != 'map' %> | |
| 15 | - </div> | |
| 16 | - <% else %> | |
| 17 | - <div id='search-filter-title'><%= @filter_title if @filter_title %></div> | |
| 18 | - <% end %> | |
| 19 | - | |
| 2 | + <div id='search-filter-title'><%= @filter_title if @filter_title %></div> | |
| 3 | + <%= display_filter(@asset, params[:display]) if map_capable?(@asset) %> | |
| 20 | 4 | <div style="clear: both"></div> |
| 21 | 5 | </div> | ... | ... |
app/views/search/articles.rhtml
| ... | ... | @@ -1,17 +0,0 @@ |
| 1 | -<%= search_page_title( @titles[:articles], @category ) %> | |
| 2 | - | |
| 3 | -<div id="search-column-left"> | |
| 4 | - <% if !@empty_query %> | |
| 5 | - <%= facets_menu(:articles, @facets) %> | |
| 6 | - <% end %> | |
| 7 | -</div> | |
| 8 | - | |
| 9 | -<div id="search-column-right"> | |
| 10 | - <%= render :partial => 'search_form', :locals => { :hint => _('Type the title, author or content desired') } %> | |
| 11 | - <%= render :partial => 'results_header' %> | |
| 12 | - | |
| 13 | - <%= display_results %> | |
| 14 | - <%= pagination_links @results[:articles] %> | |
| 15 | -</div> | |
| 16 | - | |
| 17 | -<div style="clear: both"></div> |
app/views/search/communities.rhtml
| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | -<%= search_page_title( @titles[:communities], @category ) %> | |
| 2 | - | |
| 3 | -<div id='search-column-left'> | |
| 4 | - <% if logged_in? %> | |
| 5 | - <% button_bar do %> | |
| 6 | - <%# FIXME shouldn't the user create the community in the current environment instead of going to its home environment? %> | |
| 7 | - <%= button(:add, __('New community'), user.url.merge(:controller => 'memberships', :action => 'new_community', :profile => user.identifier)) %> | |
| 8 | - <% end %> | |
| 9 | - <% end %> | |
| 10 | - | |
| 11 | - <% if !@empty_query %> | |
| 12 | - <%= facets_menu(:communities, @facets) %> | |
| 13 | - <% end %> | |
| 14 | -</div> | |
| 15 | - | |
| 16 | -<div id='search-column-right'> | |
| 17 | - <%= render :partial => 'search_form', :locals => { :hint => _("Type words about the community you're looking for") } %> | |
| 18 | - <%= render :partial => 'results_header' %> | |
| 19 | - | |
| 20 | - <%= display_results %> | |
| 21 | - <%= pagination_links @results.values.first %> | |
| 22 | -</div> | |
| 23 | - | |
| 24 | -<div style="clear: both"></div> | |
| 25 | - |
app/views/search/contents.rhtml
app/views/search/enterprises.rhtml
| ... | ... | @@ -1,28 +0,0 @@ |
| 1 | -<%= search_page_title( @titles[:enterprises], @category ) %> | |
| 2 | - | |
| 3 | -<div id="search-column-left"> | |
| 4 | - <% if logged_in? && environment.enabled?('enterprise_registration') %> | |
| 5 | - <% button_bar do %> | |
| 6 | - <%= button(:add, __('New enterprise'), {:controller => 'enterprise_registration'}) %> | |
| 7 | - <% end %> | |
| 8 | - <% end %> | |
| 9 | - | |
| 10 | - <% if !@empty_query %> | |
| 11 | - <% button_bar do %> | |
| 12 | - <%= display_map_list_button %> | |
| 13 | - <% end %> | |
| 14 | - <%= facets_menu(:enterprises, @facets) %> | |
| 15 | - <% end %> | |
| 16 | -</div> | |
| 17 | - | |
| 18 | -<div id="search-column-right"> | |
| 19 | - <%= render :partial => 'search_form', :locals => { :hint => _("Type words about the enterprise you're looking for") } %> | |
| 20 | - <%= render :partial => 'results_header' %> | |
| 21 | - | |
| 22 | - <%= display_results(true) %> | |
| 23 | - <% if params[:display] != 'map' %> | |
| 24 | - <%= pagination_links @results[:enterprises] %> | |
| 25 | - <% end %> | |
| 26 | -</div> | |
| 27 | - | |
| 28 | -<div style="clear: both"></div> |
| ... | ... | @@ -0,0 +1 @@ |
| 1 | +<%= render :partial => 'events/agenda' %> | ... | ... |
app/views/search/events.rhtml
app/views/search/index.rhtml
| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 7 | <%= search_page_title(_('Search Results'), @category) %> |
| 8 | 8 | <%= render :partial => 'search_form', :locals => { :hint => '' } %> |
| 9 | 9 | <%= category_context(@category, params) %> |
| 10 | - <%= display_results %> | |
| 10 | + <%= display_results(@asset) %> | |
| 11 | 11 | |
| 12 | 12 | <div id="category-childs"> |
| 13 | 13 | <% if @category %> | ... | ... |
app/views/search/people.rhtml
| ... | ... | @@ -1,19 +0,0 @@ |
| 1 | -<%= search_page_title( @titles[:people], @category ) %> | |
| 2 | - | |
| 3 | -<div id='search-column-left'> | |
| 4 | - <% if !@empty_query %> | |
| 5 | - <%= facets_menu(:people, @facets) %> | |
| 6 | - <% end %> | |
| 7 | -</div> | |
| 8 | - | |
| 9 | -<div id='search-column-right'> | |
| 10 | - <%= render :partial => 'search_form', :locals => { :hint => _("Type words about the person you're looking for") } %> | |
| 11 | - <%= render :partial => 'results_header' %> | |
| 12 | - | |
| 13 | - <%= display_results %> | |
| 14 | - <% if params[:display] != 'map' %> | |
| 15 | - <%= pagination_links @results.values.first %> | |
| 16 | - <% end %> | |
| 17 | -</div> | |
| 18 | - | |
| 19 | -<div style="clear: both"></div> |
app/views/search/products.rhtml
| ... | ... | @@ -1,26 +0,0 @@ |
| 1 | -<%= search_page_title( @titles[:products], @category ) %> | |
| 2 | - | |
| 3 | -<div id="search-column-left"> | |
| 4 | - <% if !@empty_query %> | |
| 5 | - <% button_bar do %> | |
| 6 | - <%= display_map_list_button %> | |
| 7 | -<% end %> | |
| 8 | - <%= facets_menu(:products, @facets) %> | |
| 9 | -<% end %> | |
| 10 | -</div> | |
| 11 | - | |
| 12 | -<div id="search-column-right"> | |
| 13 | - <%= render :partial => 'search_form', :locals => { :hint => _('Type the product, service, city or qualifier desired') } %> | |
| 14 | - <%= render :partial => 'results_header' %> | |
| 15 | - | |
| 16 | - <%= display_results(true) %> | |
| 17 | - <% if !@one_page and params[:display] != 'map' %> | |
| 18 | - <%= pagination_links @results[:products] %> | |
| 19 | -<% end %> | |
| 20 | -</div> | |
| 21 | - | |
| 22 | -<% javascript_tag do %> | |
| 23 | - jQuery('.search-product-price-details').altBeautify(); | |
| 24 | -<% end %> | |
| 25 | - | |
| 26 | -<div style="clear: both"></div> |
| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | +<%= search_page_title( @titles[@asset], @category ) %> | |
| 2 | + | |
| 3 | +<%= render :partial => 'results_header' %> | |
| 4 | + | |
| 5 | +<%= display_results(@asset) %> | |
| 6 | +<% if params[:display] != 'map' %> | |
| 7 | + <%= pagination_links @results[@asset] %> | |
| 8 | +<% end %> | |
| 9 | + | |
| 10 | +<div style="clear: both"></div> | |
| 11 | + | |
| 12 | +<% if @asset == :product %> | |
| 13 | + <% javascript_tag do %> | |
| 14 | + jQuery('.search-product-price-details').altBeautify(); | |
| 15 | + <% end %> | |
| 16 | +<% end %> | ... | ... |
lib/noosfero/plugin.rb
| ... | ... | @@ -351,6 +351,17 @@ class Noosfero::Plugin |
| 351 | 351 | nil |
| 352 | 352 | end |
| 353 | 353 | |
| 354 | + # -> Specifies plugin that works as a search engine | |
| 355 | + # returns = true/false | |
| 356 | + def search_engine? | |
| 357 | + false | |
| 358 | + end | |
| 359 | + | |
| 360 | + # -> Realizes a full text search | |
| 361 | + # returns = whatever the plugin needs to render the view | |
| 362 | + def full_text_search(asset, query, category, paginate_options) | |
| 363 | + end | |
| 364 | + | |
| 354 | 365 | def method_missing(method, *args, &block) |
| 355 | 366 | # This is a generic hotspot for all controllers on Noosfero. |
| 356 | 367 | # If any plugin wants to define filters to run on any controller, the name of | ... | ... |
plugins/solr/lib/solr_plugin.rb
| 1 | +require_dependency 'solr_plugin/search_helper' | |
| 2 | + | |
| 1 | 3 | class SolrPlugin < Noosfero::Plugin |
| 2 | 4 | |
| 5 | + include SolrPlugin::SearchHelper | |
| 6 | + | |
| 3 | 7 | def self.plugin_name |
| 4 | 8 | "Solr" |
| 5 | 9 | end |
| ... | ... | @@ -8,6 +12,16 @@ class SolrPlugin < Noosfero::Plugin |
| 8 | 12 | _("Uses Solr as search engine.") |
| 9 | 13 | end |
| 10 | 14 | |
| 15 | + def search_engine? | |
| 16 | + true | |
| 17 | + end | |
| 18 | + | |
| 19 | + def full_text_search(asset, query, category, paginate_options) | |
| 20 | + asset_class = asset_class(asset) | |
| 21 | + solr_options = solr_options(asset, category) | |
| 22 | + asset_class.find_by_contents(query, paginate_options, solr_options) | |
| 23 | + end | |
| 24 | + | |
| 11 | 25 | end |
| 12 | 26 | |
| 13 | 27 | Dir[File.join(SolrPlugin.root_path, 'lib', 'ext', '*.rb')].each {|file| require_dependency file } | ... | ... |
| ... | ... | @@ -0,0 +1,113 @@ |
| 1 | +class SolrPlugin < Noosfero::Plugin | |
| 2 | + module ResultsHelper | |
| 3 | + def set_results_variables | |
| 4 | + if @results[@asset].kind_of?(Hash) | |
| 5 | + ret = @results[@asset] | |
| 6 | + @results[@asset] = ret[:results] | |
| 7 | + @facets = ret[:facets] | |
| 8 | + @all_facets = ret[:all_facets] | |
| 9 | + end | |
| 10 | + end | |
| 11 | + | |
| 12 | + def order_by(asset) | |
| 13 | + options = SolrPlugin::SortOptions[asset].map do |name, options| | |
| 14 | + next if options[:if] && !instance_eval(&options[:if]) | |
| 15 | + [_(options[:label]), name.to_s] | |
| 16 | + end.compact | |
| 17 | + | |
| 18 | + content_tag('div', _('Sort results by ') + | |
| 19 | + select_tag(asset.to_s + '[order]', options_for_select(options, params[:order_by] || 'none'), | |
| 20 | + {:onchange => "window.location = jQuery.param.querystring(window.location.href, { 'order_by' : this.options[this.selectedIndex].value})"} | |
| 21 | + ), | |
| 22 | + :class => "search-ordering" | |
| 23 | + ) | |
| 24 | + end | |
| 25 | + | |
| 26 | + def label_total_found(asset, total_found) | |
| 27 | + labels = { | |
| 28 | + :products => _("%s products offers found"), | |
| 29 | + :articles => _("%s articles found"), | |
| 30 | + :events => _("%s events found"), | |
| 31 | + :people => _("%s people found"), | |
| 32 | + :enterprises => _("%s enterprises found"), | |
| 33 | + :communities => _("%s communities found"), | |
| 34 | + } | |
| 35 | + content_tag('span', labels[asset] % total_found, | |
| 36 | + :class => "total-pages-found") if labels[asset] | |
| 37 | + end | |
| 38 | + | |
| 39 | + def facets_menu(asset, _facets) | |
| 40 | + @asset_class = asset_class(asset) | |
| 41 | + @facets = _facets | |
| 42 | + render(:partial => 'facets_menu') | |
| 43 | + end | |
| 44 | + | |
| 45 | + def facets_unselect_menu(asset) | |
| 46 | + @asset_class = asset_class(asset) | |
| 47 | + render(:partial => 'facets_unselect_menu') | |
| 48 | + end | |
| 49 | + | |
| 50 | + def facet_selecteds_html_for(environment, klass, params) | |
| 51 | + def name_with_extra(klass, facet, value) | |
| 52 | + name = klass.facet_result_name(facet, value) | |
| 53 | + name = name[0] + name[1] if name.kind_of?(Array) | |
| 54 | + name | |
| 55 | + end | |
| 56 | + | |
| 57 | + ret = [] | |
| 58 | + params = params.dup | |
| 59 | + params[:facet].each do |id, value| | |
| 60 | + facet = klass.facet_by_id(id.to_sym) | |
| 61 | + next unless facet | |
| 62 | + if value.kind_of?(Hash) | |
| 63 | + label_hash = facet[:label].call(environment) | |
| 64 | + value.each do |label_id, value| | |
| 65 | + facet[:label_id] = label_id | |
| 66 | + facet[:label] = label_hash[label_id] | |
| 67 | + value.to_a.each do |value| | |
| 68 | + ret << [facet[:label], name_with_extra(klass, facet, value), | |
| 69 | + params.merge(:facet => params[:facet].merge(id => params[:facet][id].merge(label_id => params[:facet][id][label_id].to_a.reject{ |v| v == value })))] | |
| 70 | + end | |
| 71 | + end | |
| 72 | + else | |
| 73 | + ret << [klass.facet_label(facet), name_with_extra(klass, facet, value), | |
| 74 | + params.merge(:facet => params[:facet].reject{ |k,v| k == id })] | |
| 75 | + end | |
| 76 | + end | |
| 77 | + | |
| 78 | + ret.map do |label, name, url| | |
| 79 | + content_tag('div', content_tag('span', label, :class => 'facet-selected-label') + | |
| 80 | + content_tag('span', name, :class => 'facet-selected-name') + | |
| 81 | + link_to('', url, :class => 'facet-selected-remove', :title => 'remove facet'), :class => 'facet-selected') | |
| 82 | + end.join | |
| 83 | + end | |
| 84 | + | |
| 85 | + def facet_link_html(facet, params, value, label, count) | |
| 86 | + params = params ? params.dup : {} | |
| 87 | + has_extra = label.kind_of?(Array) | |
| 88 | + link_label = has_extra ? label[0] : label | |
| 89 | + id = facet[:solr_field].to_s | |
| 90 | + params[:facet] ||= {} | |
| 91 | + params[:facet][id] ||= {} | |
| 92 | + params[:page] = {} if params[:page] | |
| 93 | + | |
| 94 | + selected = facet[:label_id].nil? ? params[:facet][id] == value : params[:facet][id][facet[:label_id]].to_a.include?(value) | |
| 95 | + | |
| 96 | + if count > 0 | |
| 97 | + url = params.merge(:facet => params[:facet].merge( | |
| 98 | + id => facet[:label_id].nil? ? value : params[:facet][id].merge( facet[:label_id] => params[:facet][id][facet[:label_id]].to_a | [value] ) | |
| 99 | + )) | |
| 100 | + else | |
| 101 | + # preserve others filters and change this filter | |
| 102 | + url = params.merge(:facet => params[:facet].merge( | |
| 103 | + id => facet[:label_id].nil? ? value : { facet[:label_id] => value } | |
| 104 | + )) | |
| 105 | + end | |
| 106 | + | |
| 107 | + content_tag 'div', link_to(link_label, url, :class => 'facet-result-link-label') + | |
| 108 | + content_tag('span', (has_extra ? label[1] : ''), :class => 'facet-result-extra-label') + | |
| 109 | + (count > 0 ? content_tag('span', " (#{count})", :class => 'facet-result-count') : ''), | |
| 110 | + :class => 'facet-menu-item' + (selected ? ' facet-result-link-selected' : '') | |
| 111 | + end | |
| 112 | + end | |
| 113 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,83 @@ |
| 1 | +class SolrPlugin < Noosfero::Plugin | |
| 2 | + | |
| 3 | + SortOptions = { | |
| 4 | + :products => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | |
| 5 | + :more_recent, {:label => _('More recent'), :solr_opts => {:sort => 'updated_at desc, score desc'}}, | |
| 6 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | |
| 7 | + :closest, {:label => _('Closest to me'), :if => proc{ logged_in? && (profile=current_user.person).lat && profile.lng }, | |
| 8 | + :solr_opts => {:sort => "geodist() asc", | |
| 9 | + :latitude => proc{ current_user.person.lat }, :longitude => proc{ current_user.person.lng }}}, | |
| 10 | + ], | |
| 11 | + :events => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | |
| 12 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | |
| 13 | + ], | |
| 14 | + :articles => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | |
| 15 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | |
| 16 | + :more_recent, {:label => _('More recent'), :solr_opts => {:sort => 'updated_at desc, score desc'}}, | |
| 17 | + ], | |
| 18 | + :enterprises => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | |
| 19 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | |
| 20 | + ], | |
| 21 | + :people => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | |
| 22 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | |
| 23 | + ], | |
| 24 | + :communities => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')}, | |
| 25 | + :name, {:label => _('Name'), :solr_opts => {:sort => 'solr_plugin_name_sortable asc'}}, | |
| 26 | + ], | |
| 27 | + } | |
| 28 | + | |
| 29 | + module SearchHelper | |
| 30 | + def asset_class(asset) | |
| 31 | + asset.to_s.singularize.camelize.constantize | |
| 32 | + end | |
| 33 | + | |
| 34 | + def asset_table(asset) | |
| 35 | + asset_class(asset).table_name | |
| 36 | + end | |
| 37 | + | |
| 38 | + def multiple_search? | |
| 39 | + ['index', 'category_index'].include?(context.params[:action]) | |
| 40 | + end | |
| 41 | + | |
| 42 | + def filters(asset) | |
| 43 | + case asset | |
| 44 | + when :products | |
| 45 | + ['solr_plugin_public:true'] | |
| 46 | + when :events | |
| 47 | + [] | |
| 48 | + else | |
| 49 | + ['solr_plugin_public:true'] | |
| 50 | + end | |
| 51 | + end | |
| 52 | + | |
| 53 | + def results_only? | |
| 54 | + context.params[:action] == 'index' | |
| 55 | + end | |
| 56 | + | |
| 57 | + def solr_options(asset, category) | |
| 58 | + asset_class = asset_class(asset) | |
| 59 | + solr_options = {} | |
| 60 | + if !multiple_search? | |
| 61 | + if !results_only? and asset_class.respond_to? :facets | |
| 62 | + solr_options.merge! asset_class.facets_find_options(context.params[:facet]) | |
| 63 | + solr_options[:all_facets] = true | |
| 64 | + end | |
| 65 | + solr_options[:filter_queries] ||= [] | |
| 66 | + solr_options[:filter_queries] += filters(asset) | |
| 67 | + solr_options[:filter_queries] << "environment_id:#{context.environment.id}" | |
| 68 | + solr_options[:filter_queries] << asset_class.facet_category_query.call(category) if category | |
| 69 | + | |
| 70 | + solr_options[:boost_functions] ||= [] | |
| 71 | + context.params[:order_by] = nil if context.params[:order_by] == 'none' | |
| 72 | + if context.params[:order_by] | |
| 73 | + order = SolrPlugin::SortOptions[asset][context.params[:order_by].to_sym] | |
| 74 | + raise "Unknown order by" if order.nil? | |
| 75 | + order[:solr_opts].each do |opt, value| | |
| 76 | + solr_options[opt] = value.is_a?(Proc) ? instance_eval(&value) : value | |
| 77 | + end | |
| 78 | + end | |
| 79 | + end | |
| 80 | + solr_options | |
| 81 | + end | |
| 82 | + end | |
| 83 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,115 @@ |
| 1 | +require 'test_helper' | |
| 2 | + | |
| 3 | +class ArticleTest < ActiveSupport::TestCase | |
| 4 | + def setup | |
| 5 | + @environment = Environment.default | |
| 6 | + @environment.enable_plugin(SolrPlugin) | |
| 7 | + @profile = create_user('testing').person | |
| 8 | + end | |
| 9 | + | |
| 10 | + attr_accessor :environment, :profile | |
| 11 | + | |
| 12 | + should 'act as faceted' do | |
| 13 | + person = fast_create(Person) | |
| 14 | + cat = Category.create!(:name => 'hardcore', :environment_id => Environment.default.id) | |
| 15 | + a = Article.create!(:name => 'black flag review', :profile_id => person.id) | |
| 16 | + a.add_category(cat, true) | |
| 17 | + a.save! | |
| 18 | + assert_equal Article.type_name, Article.facet_by_id(:solr_plugin_f_type)[:proc].call(a.send(:solr_plugin_f_type)) | |
| 19 | + assert_equal Person.type_name, Article.facet_by_id(:solr_plugin_f_profile_type)[:proc].call(a.send(:solr_plugin_f_profile_type)) | |
| 20 | + assert_equal a.published_at, a.send(:solr_plugin_f_published_at) | |
| 21 | + assert_equal ['hardcore'], a.send(:solr_plugin_f_category) | |
| 22 | + assert_equal "solr_plugin_category_filter:\"#{cat.id}\"", Article.facet_category_query.call(cat) | |
| 23 | + end | |
| 24 | + | |
| 25 | + should 'act as searchable' do | |
| 26 | + TestSolr.enable | |
| 27 | + person = fast_create(Person, :name => "Hiro", :address => 'U-Stor-It @ Inglewood, California', | |
| 28 | + :nickname => 'Protagonist') | |
| 29 | + person2 = fast_create(Person, :name => "Raven") | |
| 30 | + category = fast_create(Category, :name => "science fiction", :acronym => "sf", :abbreviation => "sci-fi") | |
| 31 | + a = Article.create!(:name => 'a searchable article about bananas', :profile_id => person.id, | |
| 32 | + :body => 'the body talks about mosquitos', :abstract => 'and the abstract is about beer', | |
| 33 | + :filename => 'not_a_virus.exe') | |
| 34 | + a.add_category(category) | |
| 35 | + c = a.comments.build(:title => 'snow crash', :author => person2, :body => 'wanna try some?') | |
| 36 | + c.save! | |
| 37 | + | |
| 38 | + # fields | |
| 39 | + assert_includes Article.find_by_contents('bananas')[:results].docs, a | |
| 40 | + assert_includes Article.find_by_contents('mosquitos')[:results].docs, a | |
| 41 | + assert_includes Article.find_by_contents('beer')[:results].docs, a | |
| 42 | + assert_includes Article.find_by_contents('not_a_virus.exe')[:results].docs, a | |
| 43 | + # filters | |
| 44 | + assert_includes Article.find_by_contents('bananas', {}, {:filter_queries => ["solr_plugin_public:true"]})[:results].docs, a | |
| 45 | + assert_not_includes Article.find_by_contents('bananas', {}, {:filter_queries => ["solr_plugin_public:false"]})[:results].docs, a | |
| 46 | + assert_includes Article.find_by_contents('bananas', {}, {:filter_queries => ["environment_id:\"#{Environment.default.id}\""]})[:results].docs, a | |
| 47 | + assert_includes Article.find_by_contents('bananas', {}, {:filter_queries => ["profile_id:\"#{person.id}\""]})[:results].docs, a | |
| 48 | + # includes | |
| 49 | + assert_includes Article.find_by_contents('Hiro')[:results].docs, a | |
| 50 | + assert_includes Article.find_by_contents("person-#{person.id}")[:results].docs, a | |
| 51 | + assert_includes Article.find_by_contents("California")[:results].docs, a | |
| 52 | + assert_includes Article.find_by_contents("Protagonist")[:results].docs, a | |
| 53 | +# FIXME: After merging with AI1826, searching on comments is not working | |
| 54 | +# assert_includes Article.find_by_contents("snow")[:results].docs, a | |
| 55 | +# assert_includes Article.find_by_contents("try some")[:results].docs, a | |
| 56 | +# assert_includes Article.find_by_contents("Raven")[:results].docs, a | |
| 57 | +# | |
| 58 | +# FIXME: After merging with AI1826, searching on categories is not working | |
| 59 | +# assert_includes Article.find_by_contents("science")[:results].docs, a | |
| 60 | +# assert_includes Article.find_by_contents(category.slug)[:results].docs, a | |
| 61 | +# assert_includes Article.find_by_contents("sf")[:results].docs, a | |
| 62 | +# assert_includes Article.find_by_contents("sci-fi")[:results].docs, a | |
| 63 | + end | |
| 64 | + | |
| 65 | + should 'boost name matches' do | |
| 66 | + TestSolr.enable | |
| 67 | + person = fast_create(Person) | |
| 68 | + in_body = Article.create!(:name => 'something', :profile_id => person.id, :body => 'bananas in the body!') | |
| 69 | + in_name = Article.create!(:name => 'bananas in the name!', :profile_id => person.id) | |
| 70 | + assert_equal [in_name, in_body], Article.find_by_contents('bananas')[:results].docs | |
| 71 | + end | |
| 72 | + | |
| 73 | + should 'boost if profile is enabled' do | |
| 74 | + TestSolr.enable | |
| 75 | + person2 = fast_create(Person, :enabled => false) | |
| 76 | + art_profile_disabled = Article.create!(:name => 'profile disabled', :profile_id => person2.id) | |
| 77 | + person1 = fast_create(Person, :enabled => true) | |
| 78 | + art_profile_enabled = Article.create!(:name => 'profile enabled', :profile_id => person1.id) | |
| 79 | + assert_equal [art_profile_enabled, art_profile_disabled], Article.find_by_contents('profile')[:results].docs | |
| 80 | + end | |
| 81 | + | |
| 82 | + should 'index comments body together with article' do | |
| 83 | + TestSolr.enable | |
| 84 | + owner = create_user('testuser').person | |
| 85 | + art = fast_create(TinyMceArticle, :profile_id => owner.id, :name => 'ytest') | |
| 86 | + c1 = Comment.create(:title => 'test comment', :body => 'anything', :author => owner, :source => art); c1.save! | |
| 87 | + | |
| 88 | + assert_includes Article.find_by_contents('anything')[:results], art | |
| 89 | + end | |
| 90 | + | |
| 91 | + should 'index by schema name when database is postgresql' do | |
| 92 | + TestSolr.enable | |
| 93 | + uses_postgresql 'schema_one' | |
| 94 | + art1 = Article.create!(:name => 'some thing', :profile_id => @profile.id) | |
| 95 | + assert_equal [art1], Article.find_by_contents('thing')[:results].docs | |
| 96 | + uses_postgresql 'schema_two' | |
| 97 | + art2 = Article.create!(:name => 'another thing', :profile_id => @profile.id) | |
| 98 | + assert_not_includes Article.find_by_contents('thing')[:results], art1 | |
| 99 | + assert_includes Article.find_by_contents('thing')[:results], art2 | |
| 100 | + uses_postgresql 'schema_one' | |
| 101 | + assert_includes Article.find_by_contents('thing')[:results], art1 | |
| 102 | + assert_not_includes Article.find_by_contents('thing')[:results], art2 | |
| 103 | + uses_sqlite | |
| 104 | + end | |
| 105 | + | |
| 106 | + should 'not index by schema name when database is not postgresql' do | |
| 107 | + TestSolr.enable | |
| 108 | + uses_sqlite | |
| 109 | + art1 = Article.create!(:name => 'some thing', :profile_id => @profile.id) | |
| 110 | + assert_equal [art1], Article.find_by_contents('thing')[:results].docs | |
| 111 | + art2 = Article.create!(:name => 'another thing', :profile_id => @profile.id) | |
| 112 | + assert_includes Article.find_by_contents('thing')[:results], art1 | |
| 113 | + assert_includes Article.find_by_contents('thing')[:results], art2 | |
| 114 | + end | |
| 115 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | +require 'test_helper' | |
| 2 | + | |
| 3 | +class EnvironmentTest < ActiveSupport::TestCase | |
| 4 | + def setup | |
| 5 | + @environment = Environment.default | |
| 6 | + @environment.enable_plugin(SolrPlugin) | |
| 7 | + end | |
| 8 | + | |
| 9 | + attr_accessor :environment | |
| 10 | + | |
| 11 | + should 'find by contents from articles' do | |
| 12 | + TestSolr.enable | |
| 13 | + env = fast_create(Environment) | |
| 14 | + env.enable_plugin(SolrPlugin) | |
| 15 | + assert_nothing_raised do | |
| 16 | + env.articles.find_by_contents('')[:results] | |
| 17 | + end | |
| 18 | + end | |
| 19 | + | |
| 20 | + should 'return more than 10 enterprises by contents' do | |
| 21 | + TestSolr.enable | |
| 22 | + Enterprise.destroy_all | |
| 23 | + ('1'..'20').each do |n| | |
| 24 | + Enterprise.create!(:name => 'test ' + n, :identifier => 'test_' + n) | |
| 25 | + end | |
| 26 | + | |
| 27 | + assert_equal 20, environment.enterprises.find_by_contents('test')[:results].total_entries | |
| 28 | + end | |
| 29 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | +require 'test_helper' | |
| 2 | + | |
| 3 | +class EventTest < ActiveSupport::TestCase | |
| 4 | + def setup | |
| 5 | + @environment = Environment.default | |
| 6 | + @environment.enable_plugin(SolrPlugin) | |
| 7 | + @profile = create_user('testing').person | |
| 8 | + end | |
| 9 | + | |
| 10 | + attr_accessor :environment, :profile | |
| 11 | + | |
| 12 | + should 'be indexed by title' do | |
| 13 | + TestSolr.enable | |
| 14 | + e = Event.create!(:name => 'my surprisingly nice event', :start_date => Date.new(2008, 06, 06), :profile => profile) | |
| 15 | + assert_includes Event.find_by_contents('surprisingly')[:results], e | |
| 16 | + end | |
| 17 | + | |
| 18 | + should 'be indexed by body' do | |
| 19 | + TestSolr.enable | |
| 20 | + e = Event.create!(:name => 'bli', :start_date => Date.new(2008, 06, 06), :profile => profile, :body => 'my surprisingly long description about my freaking nice event') | |
| 21 | + assert_includes Event.find_by_contents('surprisingly')[:results], e | |
| 22 | + end | |
| 23 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | +require 'test_helper' | |
| 2 | + | |
| 3 | +class TextArticleTest < ActiveSupport::TestCase | |
| 4 | + def setup | |
| 5 | + @environment = Environment.default | |
| 6 | + @environment.enable_plugin(SolrPlugin) | |
| 7 | + end | |
| 8 | + | |
| 9 | + attr_accessor :environment | |
| 10 | + | |
| 11 | + should 'found TextileArticle by TextArticle indexes' do | |
| 12 | + TestSolr.enable | |
| 13 | + person = create_user('testuser').person | |
| 14 | + article = TextileArticle.create!(:name => 'found article test', :profile => person) | |
| 15 | + assert_equal TextileArticle.find_by_contents('found')[:results].docs, TextArticle.find_by_contents('found')[:results].docs | |
| 16 | + end | |
| 17 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | +require 'test_helper' | |
| 2 | + | |
| 3 | +class TinyMceArticleTest < ActiveSupport::TestCase | |
| 4 | + def setup | |
| 5 | + @environment = Environment.default | |
| 6 | + @environment.enable_plugin(SolrPlugin) | |
| 7 | + @profile = create_user('testing').person | |
| 8 | + end | |
| 9 | + | |
| 10 | + attr_accessor :environment, :profile | |
| 11 | + | |
| 12 | + should 'be found when searching for articles by query' do | |
| 13 | + TestSolr.enable | |
| 14 | + tma = TinyMceArticle.create!(:name => 'test tinymce article', :body => '---', :profile => profile) | |
| 15 | + assert_includes TinyMceArticle.find_by_contents('article')[:results], tma | |
| 16 | + assert_includes Article.find_by_contents('article')[:results], tma | |
| 17 | + end | |
| 18 | +end | ... | ... |
No preview for this file type
No preview for this file type
| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | +<% if logged_in? %> | |
| 2 | + <% button_bar do %> | |
| 3 | + <%# FIXME shouldn't the user create the community in the current environment instead of going to its home environment? %> | |
| 4 | + <%= button(:add, __('New community'), user.url.merge(:controller => 'memberships', :action => 'new_community', :profile => user.identifier)) if @asset == :communities %> | |
| 5 | + <%= button(:add, __('New enterprise'), {:controller => 'enterprise_registration'}) if @asset == :enterprises && environment.enabled?('enterprise_registration') %> | |
| 6 | + <% end %> | |
| 7 | +<% end %> | |
| 8 | +<% if !@empty_query %> | |
| 9 | + <%= facets_menu(@asset, @facets) %> | |
| 10 | +<% end %> | ... | ... |
| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | +<% less_options_limit = 8 %> | |
| 2 | + | |
| 3 | +<div id="facets-menu"> | |
| 4 | + <% @asset_class.map_facets_for(environment).each do |facet| %> | |
| 5 | + | |
| 6 | + <div id="facet-menu-<%= facet[:id].to_s %>" class="facet-menu"> | |
| 7 | + <div class="facet-menu-label"> | |
| 8 | + <%= @asset_class.facet_label(facet) %> | |
| 9 | + </div> | |
| 10 | + | |
| 11 | + <% results = @asset_class.map_facet_results(facet, params[:facet], @facets, @all_facets, :limit => less_options_limit) %> | |
| 12 | + <% facet_count = results.total_entries %> | |
| 13 | + | |
| 14 | + <% if facet_count > 0 %> | |
| 15 | + <div class="facet-menu-options facet-menu-more-options" style="display: none"> | |
| 16 | + </div> | |
| 17 | + | |
| 18 | + <div class="facet-menu-options facet-menu-less-options"> | |
| 19 | + <% results.each do |id, label, count| %> | |
| 20 | + <%= facet_link_html(facet, params, id, label, count) %><br /> | |
| 21 | + <% end %> | |
| 22 | + </div> <br /> | |
| 23 | + | |
| 24 | + <% if facet_count > less_options_limit %> | |
| 25 | + <%= link_to_function _("Options"), | |
| 26 | + "facet_options_toggle('#{facet[:id].to_s}', '#{url_for(params.merge(:action => 'facets_browse', :facet_id => facet[:id], :asset => @asset, :escape => false))}'); " + | |
| 27 | + "jQuery(this).toggleClass('facet-less-options')", :class => "facet-options-toggle" %> | |
| 28 | + <br /> | |
| 29 | + <% end %> | |
| 30 | + | |
| 31 | + <% else %> | |
| 32 | + <span class="facet-any-result-found"><%= _("No filter available") %></span> | |
| 33 | + <% end %> | |
| 34 | + </div> | |
| 35 | + <% end %> | |
| 36 | +</div> | ... | ... |
| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | +<%= render :partial => 'search_form', :locals => { :hint => _("Type words about the %s you're looking for") % @asset.to_s.singularize } %> | |
| 2 | +<%= render :partial => 'results_header' %> | |
| 3 | + | |
| 4 | +<%= display_results(@asset) %> | |
| 5 | +<% if params[:display] != 'map' %> | |
| 6 | + <%= pagination_links @results[@asset] %> | |
| 7 | +<% end %> | ... | ... |
| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | +<div class="search-results-header <%= "search-no-results" if @results[@asset].nil? or @results[@asset].length == 0 %>"> | |
| 2 | + <% if !@empty_query %> | |
| 3 | + <div class="search-results-header-information"> | |
| 4 | + <% if @results[@asset].total_entries > 0 %> | |
| 5 | + <%= label_total_found(@asset, @results[@asset].total_entries) %> | |
| 6 | + <% if params[:display] != 'map' %> | |
| 7 | + <span class="current-page"><%= _("Showing page %s of %s") % [@results[@asset].current_page, @results[@asset].total_pages] %></span> | |
| 8 | + <% end %> | |
| 9 | + <% end %> | |
| 10 | + </div> | |
| 11 | + | |
| 12 | + <div class="search-results-header-facets-order-by"> | |
| 13 | + <%= facets_unselect_menu(@asset) %> | |
| 14 | + <%= order_by(@asset) if params[:display] != 'map' %> | |
| 15 | + </div> | |
| 16 | + <% else %> | |
| 17 | + <div id='search-filter-title'><%= @filter_title if @filter_title %></div> | |
| 18 | + <% end %> | |
| 19 | + <% float = !@empty_query && params[:display] == 'list' ? 'left' : 'right' %> | |
| 20 | + <%= display_filter(@asset, params[:display], float) if map_capable?(@asset) %> | |
| 21 | + <div style="clear: both"></div> | |
| 22 | +</div> | ... | ... |
| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | +<% extend SolrPlugin::ResultsHelper %> | |
| 2 | +<% set_results_variables %> | |
| 3 | + | |
| 4 | +<%= search_page_title( @titles[@asset], @category ) %> | |
| 5 | + | |
| 6 | +<% if !@empty_query %> | |
| 7 | + <div id='search-column-left'> | |
| 8 | + <%= render :partial => 'facets' %> | |
| 9 | + </div> | |
| 10 | + | |
| 11 | + <div id='search-column-right'> | |
| 12 | + <%= render :partial => 'results' %> | |
| 13 | + </div> | |
| 14 | +<% else %> | |
| 15 | + <%= render :partial => 'results' %> | |
| 16 | +<% end %> | |
| 17 | + | |
| 18 | +<div style="clear: both"></div> | |
| 19 | + | |
| 20 | +<% if @asset == :products %> | |
| 21 | + <% javascript_tag do %> | |
| 22 | + jQuery('.search-product-price-details').altBeautify(); | |
| 23 | + <% end %> | |
| 24 | +<% end %> | ... | ... |
public/stylesheets/search.css
| ... | ... | @@ -647,6 +647,7 @@ li.search-product-item hr { |
| 647 | 647 | font-weight: bold; |
| 648 | 648 | font-size: 130%; |
| 649 | 649 | line-height: 35px; |
| 650 | + float: left; | |
| 650 | 651 | } |
| 651 | 652 | .search-results-header.search-no-results { |
| 652 | 653 | border-bottom: 0px; |
| ... | ... | @@ -665,6 +666,9 @@ li.search-product-item hr { |
| 665 | 666 | color: #ff0000 |
| 666 | 667 | } |
| 667 | 668 | |
| 669 | +#search-display-filter { | |
| 670 | + margin-top: 20px; | |
| 671 | +} | |
| 668 | 672 | |
| 669 | 673 | /* Search field and button */ |
| 670 | 674 | ... | ... |