diff --git a/app/assets/javascripts/advanced_search.js.coffee b/app/assets/javascripts/advanced_search.js.coffee new file mode 100644 index 000000000..8bff7f996 --- /dev/null +++ b/app/assets/javascripts/advanced_search.js.coffee @@ -0,0 +1,29 @@ +App.AdvancedSearch = + + advanced_search_terms: -> + $('#js-advanced-search').data('advanced-search-terms') + + toggle_form: (event) -> + event.preventDefault(); + $('#js-advanced-search').slideToggle() + + toggle_date_options: -> + if $('#js-advanced-search-date-min').val() == 'custom' + $('#js-custom-date').show() + $('#js-custom-date input').prop 'disabled', false + else + $('#js-custom-date').hide() + $('#js-custom-date input').prop 'disabled', true + + initialize: -> + if App.AdvancedSearch.advanced_search_terms() + $('#js-advanced-search').show() + App.AdvancedSearch.toggle_date_options() + + $('#js-advanced-search-title').on + click: (event) -> + App.AdvancedSearch.toggle_form(event) + + $('#js-advanced-search-date-min').on + change: -> + App.AdvancedSearch.toggle_date_options() \ No newline at end of file diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e7d288088..24f164bb2 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -35,6 +35,7 @@ //= require users //= require votes //= require annotatable +//= require advanced_search var initialize_modules = function() { @@ -48,6 +49,7 @@ var initialize_modules = function() { App.PreventDoubleSubmission.initialize(); App.IeAlert.initialize(); App.Annotatable.initialize(); + App.AdvancedSearch.initialize(); }; $(function(){ diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index d7cf4d4d1..749c009b0 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -230,6 +230,10 @@ a { } } +.small { + font-size: $small-font-size; +} + // 02. Header // - - - - - - - - - - - - - - - - - - - - - - - - - @@ -515,7 +519,7 @@ header { background: white; border-bottom: 1px solid $border; clear: both; - margin: $line-height 0 $line-height/2; + margin-bottom: $line-height/2; a { color: $text; @@ -1033,6 +1037,42 @@ img.avatar, img.admin-avatar, img.moderator-avatar, img.initialjs-avatar { } } +.search-results { + + h2 { + margin-bottom: 0; + } +} + +.advanced-search { + float: left; + margin: $line-height 0; + + @media (min-width: $small-breakpoint) { + float: right; + margin-bottom: 0; + margin-top: rem-calc(28); + position: absolute; + right: 15px; + z-index: 2; + } +} + +.advanced-search-form { + margin-top: $line-height; + + select { + height: $line-height*2; + } + + @media (max-width: $medium-breakpoint) { + + .column { + padding: 0; + } + } +} + // 10. Officials levels // - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/controllers/concerns/commentable_actions.rb b/app/controllers/concerns/commentable_actions.rb index e04b275d1..a517edc84 100644 --- a/app/controllers/concerns/commentable_actions.rb +++ b/app/controllers/concerns/commentable_actions.rb @@ -4,11 +4,13 @@ module CommentableActions def index @resources = @search_terms.present? ? resource_model.search(@search_terms) : resource_model.all + @resources = @advanced_search_terms.present? ? @resources.filter(@advanced_search_terms) : @resources + @resources = @resources.tagged_with(@tag_filter) if @tag_filter @resources = @resources.page(params[:page]).for_render.send("sort_by_#{@current_order}") index_customization if index_customization.present? - @tag_cloud = tag_cloud + @tag_cloud = tag_cloud set_resource_votes(@resources) set_resources_instance end @@ -81,6 +83,47 @@ module CommentableActions @search_terms = params[:search] if params[:search].present? end + def parse_advanced_search_terms + @advanced_search_terms = params[:advanced_search] if params[:advanced_search].present? + parse_search_date + end + + def parse_search_date + return unless search_by_date? + params[:advanced_search][:date_range] = search_date_range + end + + def search_by_date? + params[:advanced_search] && params[:advanced_search][:date_min].present? + end + + def search_start_date + case params[:advanced_search][:date_min] + when '1' + 24.hours.ago + when '2' + 1.week.ago + when '3' + 1.month.ago + when '4' + 1.year.ago + else + Date.parse(params[:advanced_search][:date_min]) rescue nil + end + end + + def method_name + + end + + def search_finish_date + params[:advanced_search][:date_max].try(:to_date) || Date.today + end + + def search_date_range + search_start_date.beginning_of_day..search_finish_date.end_of_day + end + def set_search_order if params[:search].present? && params[:order].blank? params[:order] = 'relevance' diff --git a/app/controllers/debates_controller.rb b/app/controllers/debates_controller.rb index 824118c8d..12c60a810 100644 --- a/app/controllers/debates_controller.rb +++ b/app/controllers/debates_controller.rb @@ -3,6 +3,7 @@ class DebatesController < ApplicationController include FlagActions before_action :parse_search_terms, only: :index + before_action :parse_advanced_search_terms, only: :index before_action :parse_tag_filter, only: :index before_action :set_search_order, only: :index before_action :authenticate_user!, except: [:index, :show] diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index 4a5e17af3..c60d7cc43 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -3,6 +3,7 @@ class ProposalsController < ApplicationController include FlagActions before_action :parse_search_terms, only: :index + before_action :parse_advanced_search_terms, only: :index before_action :parse_tag_filter, only: :index before_action :set_search_order, only: :index before_action :authenticate_user!, except: [:index, :show] @@ -14,7 +15,7 @@ class ProposalsController < ApplicationController respond_to :html, :js def index_customization - @featured_proposals = Proposal.all.sort_by_confidence_score.limit(3) if (@search_terms.blank? && @tag_filter.blank?) + @featured_proposals = Proposal.all.sort_by_confidence_score.limit(3) if (!@advanced_search_terms && @search_terms.blank? && @tag_filter.blank?) if @featured_proposals.present? set_featured_proposal_votes(@featured_proposals) @resources = @resources.where('proposals.id NOT IN (?)', @featured_proposals.map(&:id)) @@ -44,4 +45,5 @@ class ProposalsController < ApplicationController def set_featured_proposal_votes(proposals) @featured_proposals_votes = current_user ? current_user.proposal_votes(proposals) : {} end + end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb new file mode 100644 index 000000000..3d30ce101 --- /dev/null +++ b/app/helpers/search_helper.rb @@ -0,0 +1,31 @@ +module SearchHelper + + def official_level_search_options + options_for_select([ + [t("shared.advanced_search.author_type_1"), 1], + [t("shared.advanced_search.author_type_2"), 2], + [t("shared.advanced_search.author_type_3"), 3], + [t("shared.advanced_search.author_type_4"), 4], + [t("shared.advanced_search.author_type_5"), 5]], + params[:advanced_search].try(:[], :official_level)) + end + + def date_range_options + options_for_select([ + [t("shared.advanced_search.date_1"), 1], + [t("shared.advanced_search.date_2"), 2], + [t("shared.advanced_search.date_3"), 3], + [t("shared.advanced_search.date_4"), 4], + [t("shared.advanced_search.date_5"), 'custom']], + selected_date_range) + end + + def selected_date_range + custom_date_range? ? 'custom' : params[:advanced_search].try(:[], :date_min) + end + + def custom_date_range? + params[:advanced_search].try(:[], :date_max).present? + end + +end \ No newline at end of file diff --git a/app/models/concerns/filterable.rb b/app/models/concerns/filterable.rb new file mode 100644 index 000000000..68e844782 --- /dev/null +++ b/app/models/concerns/filterable.rb @@ -0,0 +1,28 @@ +module Filterable + extend ActiveSupport::Concern + + included do + scope :by_official_level, -> (official_level) { where(users: { official_level: official_level }).joins(:author) } + scope :by_date_range, -> (date_range) { where(created_at: date_range) } + end + + class_methods do + + def filter(params) + resources = self.all + params.each do |filter, value| + if allowed_filter?(filter, value) + resources = resources.send("by_#{filter}", value) + end + end + resources + end + + def allowed_filter?(filter, value) + return if value.blank? + ['official_level', 'date_range'].include?(filter) + end + + end + +end \ No newline at end of file diff --git a/app/models/debate.rb b/app/models/debate.rb index 670f28e87..6e8392443 100644 --- a/app/models/debate.rb +++ b/app/models/debate.rb @@ -6,6 +6,7 @@ class Debate < ActiveRecord::Base include Measurable include Sanitizable include PgSearch + include Filterable apply_simple_captcha acts_as_votable diff --git a/app/models/proposal.rb b/app/models/proposal.rb index 179f97a79..2d052cfad 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -6,6 +6,7 @@ class Proposal < ActiveRecord::Base include Sanitizable include PgSearch include SearchCache + include Filterable apply_simple_captcha acts_as_votable @@ -68,9 +69,14 @@ class Proposal < ActiveRecord::Base description => 'D' } tag_list.each{ |tag| values[tag] = 'D' } + values[author.username] = 'D' values end + def self.search(terms) + self.pg_search(terms) + end + def description super.try :html_safe end @@ -124,10 +130,6 @@ class Proposal < ActiveRecord::Base self.tags.each{ |t| t.increment_custom_counter_for('Proposal') } end - def self.search(terms) - self.pg_search(terms) - end - def self.votes_needed_for_success Setting['votes_for_proposal_success'].to_i end diff --git a/app/views/debates/index.html.erb b/app/views/debates/index.html.erb index 3d714828f..f1c12e1b7 100644 --- a/app/views/debates/index.html.erb +++ b/app/views/debates/index.html.erb @@ -1,6 +1,6 @@ <% provide :title do %><%= t('debates.index.title') %><% end %> <% content_for :header_addon do %> - <%= render "shared/search_form_header", + <%= render "shared/search_form", search_path: debates_path(page: 1), i18n_namespace: "debates.index.search_form" %> <% end %> @@ -9,14 +9,16 @@
-
- <% if @search_terms %> -

+
+ <% if @search_terms || @advanced_search_terms %> +

<%= page_entries_info @debates %> - <%= t("debates.index.search_results", count: @debates.size, search_term: @search_terms) %> + <% if !@advanced_search_terms %> + <%= t("debates.index.search_results", count: @debates.size, search_term: @search_terms) %> + <% end %>

<% elsif @tag_filter %> -

+

<%= page_entries_info @debates %> <%= t("debates.index.filter_topic", count: @debates.size, topic: @tag_filter) %>

@@ -27,6 +29,8 @@ <%= render "featured_debates_static" %> <% end %> + <%= render "shared/advanced_search", search_path: debates_path(page: 1) %> + <%= render 'shared/order_links', i18n_namespace: "debates.index" %>
diff --git a/app/views/proposals/index.html.erb b/app/views/proposals/index.html.erb index fc20bc3af..3469ecdb9 100644 --- a/app/views/proposals/index.html.erb +++ b/app/views/proposals/index.html.erb @@ -1,6 +1,6 @@ <% provide :title do %><%= t('proposals.index.title') %><% end %> <% content_for :header_addon do %> - <%= render "shared/search_form_header", + <%= render "shared/search_form", search_path: proposals_path(page: 1), i18n_namespace: "proposals.index.search_form" %> <% end %> @@ -9,14 +9,16 @@
-
- <% if @search_terms %> -

+
+ <% if @search_terms || @advanced_search_terms %> +

<%= page_entries_info @proposals %> - <%= t("proposals.index.search_results", count: @proposals.size, search_term: @search_terms) %> + <% if !@advanced_search_terms %> + <%= t("proposals.index.search_results", count: @proposals.size, search_term: @search_terms) %> + <% end %>

<% elsif @tag_filter %> -

+

<%= page_entries_info @proposals %> <%= t("proposals.index.filter_topic", count: @proposals.size, topic: @tag_filter) %>

@@ -36,6 +38,8 @@
<% end %> + <%= render "shared/advanced_search", search_path: proposals_path(page: 1)%> + <%= render 'shared/order_links', i18n_namespace: "proposals.index" %>
diff --git a/app/views/shared/_advanced_search.html.erb b/app/views/shared/_advanced_search.html.erb new file mode 100644 index 000000000..2f0233b53 --- /dev/null +++ b/app/views/shared/_advanced_search.html.erb @@ -0,0 +1,47 @@ +<%= link_to t("shared.advanced_search.title"), "#", id: 'js-advanced-search-title', class: "advanced-search small" %> + +
+ <%= form_tag search_path, method: :get do %> + + <% end %> +
\ No newline at end of file diff --git a/app/views/shared/_search_form.html.erb b/app/views/shared/_search_form.html.erb index 1c0344993..1a5edd4a9 100644 --- a/app/views/shared/_search_form.html.erb +++ b/app/views/shared/_search_form.html.erb @@ -1,27 +1,22 @@ -<% # Params: - # - # search_path: for example debates_path - # i18n_namespace: for example "debates.index.search_form" -%> - -
- -

<%= t("#{i18n_namespace}.title") %>

-
+
+ <%= form_tag search_path, method: :get do %> -
-
- -
- " class="search-form"> -
-
- "> -
- +
+
+
+ + " class="search-form" value="<%= params[:search] %>"> +
+
+
+
<% end %> +
diff --git a/app/views/shared/_search_form_header.html.erb b/app/views/shared/_search_form_header.html.erb deleted file mode 100644 index ddbc9db3f..000000000 --- a/app/views/shared/_search_form_header.html.erb +++ /dev/null @@ -1,28 +0,0 @@ -<% # Params: - # - # i18n_namespace: for example "debates.index.search_form" - # search_path: for example debates_path -%> - -
-
- - <%= form_tag search_path, method: :get do %> -
-
-
- - " class="search-form"> -
-
- -
-
-
- <% end %> - -
-
diff --git a/config/locales/en.yml b/config/locales/en.yml index 06c2be639..0e31c1261 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -327,6 +327,27 @@ en: form: submit_button: Save changes shared: + advanced_search: + author_type: 'By author category' + author_type_blank: 'Select a category' + author_type_1: 'Public employee' + author_type_2: 'Municipal Organization' + author_type_3: 'General director' + author_type_4: 'City councillor' + author_type_5: 'Mayoress' + date: 'By date' + date_range_blank: 'Choose a date' + date_1: 'Last 24 hours' + date_2: 'Last week' + date_3: 'Last month' + date_4: 'Last year' + date_5: 'Customized' + from: 'From' + general: 'With the text' + general_placeholder: 'Write the text' + search: 'Filter' + title: 'Advanced search' + to: 'To' author_info: author_deleted: User deleted check: Select diff --git a/config/locales/es.yml b/config/locales/es.yml index 3a7ab7669..cbd7c5789 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -327,6 +327,27 @@ es: form: submit_button: Guardar cambios shared: + advanced_search: + author_type: 'Por categoría de autor' + author_type_blank: 'Elige una categoría' + author_type_1: 'Empleado público' + author_type_2: 'Organización Municipal' + author_type_3: 'Director general' + author_type_4: 'Concejal' + author_type_5: 'Alcaldesa' + date: 'Por fecha' + date_range_blank: 'Elige una fecha' + date_1: 'Últimas 24 horas' + date_2: 'Última semana' + date_3: 'Último mes' + date_4: 'Último año' + date_5: 'Personalizada' + from: 'Desde' + general: 'Con el texto' + general_placeholder: 'Escribe el texto' + search: 'Filtrar' + title: 'Búsqueda avanzada' + to: 'Hasta' author_info: author_deleted: Usuario eliminado check: Seleccionar diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index db3e721b4..5dc1b6d8f 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -453,80 +453,404 @@ feature 'Debates' do end end - scenario 'Debate index search' do - debate1 = create(:debate, title: "Show me what you got") - debate2 = create(:debate, title: "Get Schwifty") - debate3 = create(:debate) - debate4 = create(:debate, description: "Schwifty in here") - debate5 = create(:debate, tag_list: 'schwifty') - debate6 = create(:debate, tag_list: ['awesome foreign schwifty', 'major']) + context "Search" do - visit debates_path - fill_in "search", with: "Schwifty" - click_button "Search" + context "Basic search" do - within("#debates") do - expect(page).to have_css('.debate', count: 4) + scenario 'Search by text' do + debate1 = create(:debate, title: "Get Schwifty") + debate2 = create(:debate, title: "Schwifty Hello") + debate3 = create(:debate, title: "Do not show me") - expect(page).to have_content(debate2.title) - expect(page).to have_content(debate4.title) - expect(page).to have_content(debate5.title) - expect(page).to have_content(debate6.title) + visit debates_path + + within "#search_form" do + fill_in "search", with: "Schwifty" + click_button "Search" + end + + within("#debates") do + expect(page).to have_css('.debate', count: 2) + + expect(page).to have_content(debate1.title) + expect(page).to have_content(debate2.title) + expect(page).to_not have_content(debate3.title) + end + end + + scenario "Maintain search criteria" do + visit debates_path + + within "#search_form" do + fill_in "search", with: "Schwifty" + click_button "Search" + end + + expect(page).to have_selector("input[name='search'][value='Schwifty']") + end - expect(page).to_not have_content(debate1.title) - expect(page).to_not have_content(debate3.title) end - end - pending "Order by relevance by default", :js do - debate1 = create(:debate, title: "Show you got", cached_votes_up: 10) - debate2 = create(:debate, title: "Show what you got", cached_votes_up: 1) - debate3 = create(:debate, title: "Show you got", cached_votes_up: 100) + context "Advanced search" do - visit debates_path - fill_in "search", with: "Show what you got" - click_button "Search" + scenario "Search by text", :js do + debate1 = create(:debate, title: "Get Schwifty") + debate2 = create(:debate, title: "Schwifty Hello") + debate3 = create(:debate, title: "Do not show me") - expect(page).to have_selector('a.active', text: "relevance") + visit debates_path - within("#debates") do - expect(all(".debate")[0].text).to match "Show what you got" - expect(all(".debate")[1].text).to match "Show you got" - expect(all(".debate")[2].text).to match "Show you got" + click_link "Advanced search" + fill_in "Write the text", with: "Schwifty" + click_button "Filter" + + within("#debates") do + expect(page).to have_css('.debate', count: 2) + + expect(page).to have_content(debate1.title) + expect(page).to have_content(debate2.title) + expect(page).to_not have_content(debate3.title) + end + end + + context "Search by author type" do + + scenario "Public employee", :js do + ana = create :user, official_level: 1 + john = create :user, official_level: 2 + + debate1 = create(:debate, author: ana) + debate2 = create(:debate, author: ana) + debate3 = create(:debate, author: john) + + visit debates_path + + click_link "Advanced search" + select "Public employee", from: "advanced_search_official_level" + click_button "Filter" + + within("#debates") do + expect(page).to have_css('.debate', count: 2) + + expect(page).to have_content(debate1.title) + expect(page).to have_content(debate2.title) + expect(page).to_not have_content(debate3.title) + end + end + + scenario "Municipal Organization", :js do + ana = create :user, official_level: 2 + john = create :user, official_level: 3 + + debate1 = create(:debate, author: ana) + debate2 = create(:debate, author: ana) + debate3 = create(:debate, author: john) + + visit debates_path + + click_link "Advanced search" + select "Municipal Organization", from: "advanced_search_official_level" + click_button "Filter" + + within("#debates") do + expect(page).to have_css('.debate', count: 2) + + expect(page).to have_content(debate1.title) + expect(page).to have_content(debate2.title) + expect(page).to_not have_content(debate3.title) + end + end + + scenario "General director", :js do + ana = create :user, official_level: 3 + john = create :user, official_level: 4 + + debate1 = create(:debate, author: ana) + debate2 = create(:debate, author: ana) + debate3 = create(:debate, author: john) + + visit debates_path + + click_link "Advanced search" + select "General director", from: "advanced_search_official_level" + click_button "Filter" + + within("#debates") do + expect(page).to have_css('.debate', count: 2) + + expect(page).to have_content(debate1.title) + expect(page).to have_content(debate2.title) + expect(page).to_not have_content(debate3.title) + end + end + + scenario "City councillor", :js do + ana = create :user, official_level: 4 + john = create :user, official_level: 5 + + debate1 = create(:debate, author: ana) + debate2 = create(:debate, author: ana) + debate3 = create(:debate, author: john) + + visit debates_path + + click_link "Advanced search" + select "City councillor", from: "advanced_search_official_level" + click_button "Filter" + + within("#debates") do + expect(page).to have_css('.debate', count: 2) + + expect(page).to have_content(debate1.title) + expect(page).to have_content(debate2.title) + expect(page).to_not have_content(debate3.title) + end + end + + scenario "Mayoress", :js do + ana = create :user, official_level: 5 + john = create :user, official_level: 4 + + debate1 = create(:debate, author: ana) + debate2 = create(:debate, author: ana) + debate3 = create(:debate, author: john) + + visit debates_path + + click_link "Advanced search" + select "Mayoress", from: "advanced_search_official_level" + click_button "Filter" + + within("#debates") do + expect(page).to have_css('.debate', count: 2) + + expect(page).to have_content(debate1.title) + expect(page).to have_content(debate2.title) + expect(page).to_not have_content(debate3.title) + end + end + + end + + context "Search by date" do + + context "Predefined date ranges" do + + scenario "Last day", :js do + debate1 = create(:debate, created_at: 1.minute.ago) + debate2 = create(:debate, created_at: 1.hour.ago) + debate3 = create(:debate, created_at: 2.days.ago) + + visit debates_path + + click_link "Advanced search" + select "Last 24 hours", from: "js-advanced-search-date-min" + click_button "Filter" + + within("#debates") do + expect(page).to have_css('.debate', count: 2) + + expect(page).to have_content(debate1.title) + expect(page).to have_content(debate2.title) + expect(page).to_not have_content(debate3.title) + end + end + + scenario "Last week", :js do + debate1 = create(:debate, created_at: 1.day.ago) + debate2 = create(:debate, created_at: 5.days.ago) + debate3 = create(:debate, created_at: 8.days.ago) + + visit debates_path + + click_link "Advanced search" + select "Last week", from: "js-advanced-search-date-min" + click_button "Filter" + + within("#debates") do + expect(page).to have_css('.debate', count: 2) + + expect(page).to have_content(debate1.title) + expect(page).to have_content(debate2.title) + expect(page).to_not have_content(debate3.title) + end + end + + scenario "Last month", :js do + debate1 = create(:debate, created_at: 10.days.ago) + debate2 = create(:debate, created_at: 20.days.ago) + debate3 = create(:debate, created_at: 33.days.ago) + + visit debates_path + + click_link "Advanced search" + select "Last month", from: "js-advanced-search-date-min" + click_button "Filter" + + within("#debates") do + expect(page).to have_css('.debate', count: 2) + + expect(page).to have_content(debate1.title) + expect(page).to have_content(debate2.title) + expect(page).to_not have_content(debate3.title) + end + end + + scenario "Last year", :js do + debate1 = create(:debate, created_at: 300.days.ago) + debate2 = create(:debate, created_at: 350.days.ago) + debate3 = create(:debate, created_at: 370.days.ago) + + visit debates_path + + click_link "Advanced search" + select "Last year", from: "js-advanced-search-date-min" + click_button "Filter" + + within("#debates") do + expect(page).to have_css('.debate', count: 2) + + expect(page).to have_content(debate1.title) + expect(page).to have_content(debate2.title) + expect(page).to_not have_content(debate3.title) + end + end + + end + + scenario "Search by custom date range", :js do + debate1 = create(:debate, created_at: 2.days.ago) + debate2 = create(:debate, created_at: 3.days.ago) + debate3 = create(:debate, created_at: 9.days.ago) + + visit debates_path + + click_link "Advanced search" + select "Customized", from: "js-advanced-search-date-min" + fill_in "advanced_search_date_min", with: 7.days.ago + fill_in "advanced_search_date_max", with: 1.days.ago + click_button "Filter" + + within("#debates") do + expect(page).to have_css('.debate', count: 2) + + expect(page).to have_content(debate1.title) + expect(page).to have_content(debate2.title) + expect(page).to_not have_content(debate3.title) + end + end + + scenario "Search by multiple filters", :js do + ana = create :user, official_level: 1 + john = create :user, official_level: 1 + + debate1 = create(:debate, title: "Get Schwifty", author: ana, created_at: 1.minute.ago) + debate2 = create(:debate, title: "Hello Schwifty", author: john, created_at: 2.days.ago) + debate3 = create(:debate, title: "Save the forest") + + visit debates_path + + click_link "Advanced search" + fill_in "Write the text", with: "Schwifty" + select "Public employee", from: "advanced_search_official_level" + select "Last 24 hours", from: "js-advanced-search-date-min" + + click_button "Filter" + + within("#debates") do + expect(page).to have_css('.debate', count: 1) + expect(page).to have_content(debate1.title) + end + end + + scenario "Maintain advanced search criteria", :js do + visit debates_path + click_link "Advanced search" + + fill_in "Write the text", with: "Schwifty" + select "Public employee", from: "advanced_search_official_level" + select "Last 24 hours", from: "js-advanced-search-date-min" + + click_button "Filter" + + within "#js-advanced-search" do + expect(page).to have_selector("input[name='search'][value='Schwifty']") + expect(page).to have_select('advanced_search[official_level]', selected: 'Public employee') + expect(page).to have_select('advanced_search[date_min]', selected: 'Last 24 hours') + end + end + + scenario "Maintain custom date search criteria", :js do + visit debates_path + click_link "Advanced search" + + select "Customized", from: "js-advanced-search-date-min" + fill_in "advanced_search_date_min", with: 7.days.ago + fill_in "advanced_search_date_max", with: 1.days.ago + click_button "Filter" + + within "#js-advanced-search" do + expect(page).to have_select('advanced_search[date_min]', selected: 'Customized') + expect(page).to have_selector("input[name='advanced_search[date_min]'][value*='#{7.days.ago.strftime('%Y-%m-%d')}']") + expect(page).to have_selector("input[name='advanced_search[date_max]'][value*='#{1.day.ago.strftime('%Y-%m-%d')}']") + end + end + + end end - end - pending "Reorder results maintaing search", :js do - debate1 = create(:debate, title: "Show you got", cached_votes_up: 10, created_at: 1.week.ago) - debate2 = create(:debate, title: "Show what you got", cached_votes_up: 1, created_at: 1.month.ago) - debate3 = create(:debate, title: "Show you got", cached_votes_up: 100, created_at: Time.now) - debate4 = create(:debate, title: "Do not display", cached_votes_up: 1, created_at: 1.week.ago) + pending "Order by relevance by default", :js do + debate1 = create(:debate, title: "Show you got", cached_votes_up: 10) + debate2 = create(:debate, title: "Show what you got", cached_votes_up: 1) + debate3 = create(:debate, title: "Show you got", cached_votes_up: 100) - visit debates_path - fill_in "search", with: "Show what you got" - click_button "Search" + visit debates_path + fill_in "search", with: "Show what you got" + click_button "Search" - click_link "newest" - expect(page).to have_selector('a.active', text: "Newest") + expect(page).to have_selector("a.active", text: "relevance") - within("#debates") do - expect(all(".debate")[0].text).to match "Show you got" - expect(all(".debate")[1].text).to match "Show you got" - expect(all(".debate")[2].text).to match "Show what you got" - expect(page).to_not have_content "Do not display" + within("#debates") do + expect(all(".debate")[0].text).to match "Show what you got" + expect(all(".debate")[1].text).to match "Show you got" + expect(all(".debate")[2].text).to match "Show you got" + end end - end - scenario 'Index search does not show featured debates' do - featured_debates = create_featured_debates - debate = create(:debate, title: "Abcdefghi") + pending "Reorder results maintaing search", :js do + debate1 = create(:debate, title: "Show you got", cached_votes_up: 10, created_at: 1.week.ago) + debate2 = create(:debate, title: "Show what you got", cached_votes_up: 1, created_at: 1.month.ago) + debate3 = create(:debate, title: "Show you got", cached_votes_up: 100, created_at: Time.now) + debate4 = create(:debate, title: "Do not display", cached_votes_up: 1, created_at: 1.week.ago) - visit debates_path - fill_in "search", with: debate.title - click_button "Search" + visit debates_path + fill_in "search", with: "Show what you got" + click_button "Search" + click_link 'newest' + expect(page).to have_selector("a.active", text: "newest") + + within("#debates") do + expect(all(".debate")[0].text).to match "Show you got" + expect(all(".debate")[1].text).to match "Show you got" + expect(all(".debate")[2].text).to match "Show what you got" + expect(page).to_not have_content "Do not display" + end + end + + scenario 'After a search do not show featured debates' do + featured_debates = create_featured_debates + debate = create(:debate, title: "Abcdefghi") + + visit debates_path + within "#search_form" do + fill_in "search", with: debate.title + click_button "Search" + end + + expect(page).to_not have_selector('#debates .debate-featured') + expect(page).to_not have_selector('#featured-debates') + end - expect(page).to_not have_selector('#debates .debate-featured') - expect(page).to_not have_selector('#featured-debates') end scenario 'Index tag does not show featured debates' do diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index 2350f427d..0ef313704 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -516,79 +516,404 @@ feature 'Proposals' do end end - scenario 'Proposal index search' do - proposal1 = create(:proposal, title: "Show me what you got") - proposal2 = create(:proposal, title: "Get Schwifty") - proposal3 = create(:proposal) - proposal4 = create(:proposal, description: "Schwifty in here") - proposal5 = create(:proposal, question: "Schwifty in here") + context "Search" do - visit proposals_path - fill_in "search", with: "Schwifty" - click_button "Search" + context "Basic search" do - expect(current_path).to eq(proposals_path) + scenario 'Search by text' do + proposal1 = create(:proposal, title: "Get Schwifty") + proposal2 = create(:proposal, title: "Schwifty Hello") + proposal3 = create(:proposal, title: "Do not show me") - within("#proposals") do - expect(page).to have_css('.proposal', count: 3) + visit proposals_path - expect(page).to have_content(proposal2.title) - expect(page).to have_content(proposal4.title) - expect(page).to have_content(proposal5.title) + within "#search_form" do + fill_in "search", with: "Schwifty" + click_button "Search" + end + + within("#proposals") do + expect(page).to have_css('.proposal', count: 2) + + expect(page).to have_content(proposal1.title) + expect(page).to have_content(proposal2.title) + expect(page).to_not have_content(proposal3.title) + end + end + + scenario "Maintain search criteria" do + visit proposals_path + + within "#search_form" do + fill_in "search", with: "Schwifty" + click_button "Search" + end + + expect(page).to have_selector("input[name='search'][value='Schwifty']") + end - expect(page).to_not have_content(proposal1.title) - expect(page).to_not have_content(proposal3.title) end - end - scenario "Order by relevance by default", :js do - proposal1 = create(:proposal, title: "Show you got", cached_votes_up: 10) - proposal2 = create(:proposal, title: "Show what you got", cached_votes_up: 1) - proposal3 = create(:proposal, title: "Show you got", cached_votes_up: 100) + context "Advanced search" do - visit proposals_path - fill_in "search", with: "Show what you got" - click_button "Search" + scenario "Search by text", :js do + proposal1 = create(:proposal, title: "Get Schwifty") + proposal2 = create(:proposal, title: "Schwifty Hello") + proposal3 = create(:proposal, title: "Do not show me") - expect(page).to have_selector("a.active", text: "relevance") + visit proposals_path - within("#proposals") do - expect(all(".proposal")[0].text).to match "Show what you got" - expect(all(".proposal")[1].text).to match "Show you got" - expect(all(".proposal")[2].text).to match "Show you got" + click_link "Advanced search" + fill_in "Write the text", with: "Schwifty" + click_button "Filter" + + within("#proposals") do + expect(page).to have_css('.proposal', count: 2) + + expect(page).to have_content(proposal1.title) + expect(page).to have_content(proposal2.title) + expect(page).to_not have_content(proposal3.title) + end + end + + context "Search by author type" do + + scenario "Public employee", :js do + ana = create :user, official_level: 1 + john = create :user, official_level: 2 + + proposal1 = create(:proposal, author: ana) + proposal2 = create(:proposal, author: ana) + proposal3 = create(:proposal, author: john) + + visit proposals_path + + click_link "Advanced search" + select "Public employee", from: "advanced_search_official_level" + click_button "Filter" + + within("#proposals") do + expect(page).to have_css('.proposal', count: 2) + + expect(page).to have_content(proposal1.title) + expect(page).to have_content(proposal2.title) + expect(page).to_not have_content(proposal3.title) + end + end + + scenario "Municipal Organization", :js do + ana = create :user, official_level: 2 + john = create :user, official_level: 3 + + proposal1 = create(:proposal, author: ana) + proposal2 = create(:proposal, author: ana) + proposal3 = create(:proposal, author: john) + + visit proposals_path + + click_link "Advanced search" + select "Municipal Organization", from: "advanced_search_official_level" + click_button "Filter" + + within("#proposals") do + expect(page).to have_css('.proposal', count: 2) + + expect(page).to have_content(proposal1.title) + expect(page).to have_content(proposal2.title) + expect(page).to_not have_content(proposal3.title) + end + end + + scenario "General director", :js do + ana = create :user, official_level: 3 + john = create :user, official_level: 4 + + proposal1 = create(:proposal, author: ana) + proposal2 = create(:proposal, author: ana) + proposal3 = create(:proposal, author: john) + + visit proposals_path + + click_link "Advanced search" + select "General director", from: "advanced_search_official_level" + click_button "Filter" + + within("#proposals") do + expect(page).to have_css('.proposal', count: 2) + + expect(page).to have_content(proposal1.title) + expect(page).to have_content(proposal2.title) + expect(page).to_not have_content(proposal3.title) + end + end + + scenario "City councillor", :js do + ana = create :user, official_level: 4 + john = create :user, official_level: 5 + + proposal1 = create(:proposal, author: ana) + proposal2 = create(:proposal, author: ana) + proposal3 = create(:proposal, author: john) + + visit proposals_path + + click_link "Advanced search" + select "City councillor", from: "advanced_search_official_level" + click_button "Filter" + + within("#proposals") do + expect(page).to have_css('.proposal', count: 2) + + expect(page).to have_content(proposal1.title) + expect(page).to have_content(proposal2.title) + expect(page).to_not have_content(proposal3.title) + end + end + + scenario "Mayoress", :js do + ana = create :user, official_level: 5 + john = create :user, official_level: 4 + + proposal1 = create(:proposal, author: ana) + proposal2 = create(:proposal, author: ana) + proposal3 = create(:proposal, author: john) + + visit proposals_path + + click_link "Advanced search" + select "Mayoress", from: "advanced_search_official_level" + click_button "Filter" + + within("#proposals") do + expect(page).to have_css('.proposal', count: 2) + + expect(page).to have_content(proposal1.title) + expect(page).to have_content(proposal2.title) + expect(page).to_not have_content(proposal3.title) + end + end + + end + + context "Search by date" do + + context "Predefined date ranges" do + + scenario "Last day", :js do + proposal1 = create(:proposal, created_at: 1.minute.ago) + proposal2 = create(:proposal, created_at: 1.hour.ago) + proposal3 = create(:proposal, created_at: 2.days.ago) + + visit proposals_path + + click_link "Advanced search" + select "Last 24 hours", from: "js-advanced-search-date-min" + click_button "Filter" + + within("#proposals") do + expect(page).to have_css('.proposal', count: 2) + + expect(page).to have_content(proposal1.title) + expect(page).to have_content(proposal2.title) + expect(page).to_not have_content(proposal3.title) + end + end + + scenario "Last week", :js do + proposal1 = create(:proposal, created_at: 1.day.ago) + proposal2 = create(:proposal, created_at: 5.days.ago) + proposal3 = create(:proposal, created_at: 8.days.ago) + + visit proposals_path + + click_link "Advanced search" + select "Last week", from: "js-advanced-search-date-min" + click_button "Filter" + + within("#proposals") do + expect(page).to have_css('.proposal', count: 2) + + expect(page).to have_content(proposal1.title) + expect(page).to have_content(proposal2.title) + expect(page).to_not have_content(proposal3.title) + end + end + + scenario "Last month", :js do + proposal1 = create(:proposal, created_at: 10.days.ago) + proposal2 = create(:proposal, created_at: 20.days.ago) + proposal3 = create(:proposal, created_at: 33.days.ago) + + visit proposals_path + + click_link "Advanced search" + select "Last month", from: "js-advanced-search-date-min" + click_button "Filter" + + within("#proposals") do + expect(page).to have_css('.proposal', count: 2) + + expect(page).to have_content(proposal1.title) + expect(page).to have_content(proposal2.title) + expect(page).to_not have_content(proposal3.title) + end + end + + scenario "Last year", :js do + proposal1 = create(:proposal, created_at: 300.days.ago) + proposal2 = create(:proposal, created_at: 350.days.ago) + proposal3 = create(:proposal, created_at: 370.days.ago) + + visit proposals_path + + click_link "Advanced search" + select "Last year", from: "js-advanced-search-date-min" + click_button "Filter" + + within("#proposals") do + expect(page).to have_css('.proposal', count: 2) + + expect(page).to have_content(proposal1.title) + expect(page).to have_content(proposal2.title) + expect(page).to_not have_content(proposal3.title) + end + end + + end + + scenario "Search by custom date range", :js do + proposal1 = create(:proposal, created_at: 2.days.ago) + proposal2 = create(:proposal, created_at: 3.days.ago) + proposal3 = create(:proposal, created_at: 9.days.ago) + + visit proposals_path + + click_link "Advanced search" + select "Customized", from: "js-advanced-search-date-min" + fill_in "advanced_search_date_min", with: 7.days.ago + fill_in "advanced_search_date_max", with: 1.days.ago + click_button "Filter" + + within("#proposals") do + expect(page).to have_css('.proposal', count: 2) + + expect(page).to have_content(proposal1.title) + expect(page).to have_content(proposal2.title) + expect(page).to_not have_content(proposal3.title) + end + end + + scenario "Search by multiple filters", :js do + ana = create :user, official_level: 1 + john = create :user, official_level: 1 + + proposal1 = create(:proposal, title: "Get Schwifty", author: ana, created_at: 1.minute.ago) + proposal2 = create(:proposal, title: "Hello Schwifty", author: john, created_at: 2.days.ago) + proposal3 = create(:proposal, title: "Save the forest") + + visit proposals_path + + click_link "Advanced search" + fill_in "Write the text", with: "Schwifty" + select "Public employee", from: "advanced_search_official_level" + select "Last 24 hours", from: "js-advanced-search-date-min" + + click_button "Filter" + + within("#proposals") do + expect(page).to have_css('.proposal', count: 1) + expect(page).to have_content(proposal1.title) + end + end + + scenario "Maintain advanced search criteria", :js do + visit proposals_path + click_link "Advanced search" + + fill_in "Write the text", with: "Schwifty" + select "Public employee", from: "advanced_search_official_level" + select "Last 24 hours", from: "js-advanced-search-date-min" + + click_button "Filter" + + within "#js-advanced-search" do + expect(page).to have_selector("input[name='search'][value='Schwifty']") + expect(page).to have_select('advanced_search[official_level]', selected: 'Public employee') + expect(page).to have_select('advanced_search[date_min]', selected: 'Last 24 hours') + end + end + + scenario "Maintain custom date search criteria", :js do + visit proposals_path + click_link "Advanced search" + + select "Customized", from: "js-advanced-search-date-min" + fill_in "advanced_search_date_min", with: 7.days.ago.to_date + fill_in "advanced_search_date_max", with: 1.days.ago.to_date + click_button "Filter" + + within "#js-advanced-search" do + expect(page).to have_select('advanced_search[date_min]', selected: 'Customized') + expect(page).to have_selector("input[name='advanced_search[date_min]'][value*='#{7.days.ago.strftime('%Y-%m-%d')}']") + expect(page).to have_selector("input[name='advanced_search[date_max]'][value*='#{1.day.ago.strftime('%Y-%m-%d')}']") + end + end + + end end - end - scenario "Reorder results maintaing search", :js do - proposal1 = create(:proposal, title: "Show you got", cached_votes_up: 10, created_at: 1.week.ago) - proposal2 = create(:proposal, title: "Show what you got", cached_votes_up: 1, created_at: 1.month.ago) - proposal3 = create(:proposal, title: "Show you got", cached_votes_up: 100, created_at: Time.now) - proposal4 = create(:proposal, title: "Do not display", cached_votes_up: 1, created_at: 1.week.ago) + scenario "Order by relevance by default", :js do + proposal1 = create(:proposal, title: "Show you got", cached_votes_up: 10) + proposal2 = create(:proposal, title: "Show what you got", cached_votes_up: 1) + proposal3 = create(:proposal, title: "Show you got", cached_votes_up: 100) - visit proposals_path - fill_in "search", with: "Show what you got" - click_button "Search" - click_link 'newest' - expect(page).to have_selector("a.active", text: "newest") + visit proposals_path + fill_in "search", with: "Show what you got" + click_button "Search" - within("#proposals") do - expect(all(".proposal")[0].text).to match "Show you got" - expect(all(".proposal")[1].text).to match "Show you got" - expect(all(".proposal")[2].text).to match "Show what you got" - expect(page).to_not have_content "Do not display" + expect(page).to have_selector("a.active", text: "relevance") + + within("#proposals") do + expect(all(".proposal")[0].text).to match "Show what you got" + expect(all(".proposal")[1].text).to match "Show you got" + expect(all(".proposal")[2].text).to match "Show you got" + end end - end - scenario 'Index search does not show featured proposals' do - featured_proposals = create_featured_proposals - proposal = create(:proposal, title: "Abcdefghi") + scenario "Reorder results maintaing search", :js do + proposal1 = create(:proposal, title: "Show you got", cached_votes_up: 10, created_at: 1.week.ago) + proposal2 = create(:proposal, title: "Show what you got", cached_votes_up: 1, created_at: 1.month.ago) + proposal3 = create(:proposal, title: "Show you got", cached_votes_up: 100, created_at: Time.now) + proposal4 = create(:proposal, title: "Do not display", cached_votes_up: 1, created_at: 1.week.ago) - visit proposals_path - fill_in "search", with: proposal.title - click_button "Search" + visit proposals_path + fill_in "search", with: "Show what you got" + click_button "Search" + click_link 'newest' + expect(page).to have_selector("a.active", text: "newest") + + within("#proposals") do + expect(all(".proposal")[0].text).to match "Show you got" + expect(all(".proposal")[1].text).to match "Show you got" + expect(all(".proposal")[2].text).to match "Show what you got" + expect(page).to_not have_content "Do not display" + end + end + + scenario 'After a search do not show featured proposals' do + featured_proposals = create_featured_proposals + proposal = create(:proposal, title: "Abcdefghi") + + visit proposals_path + within "#search_form" do + fill_in "search", with: proposal.title + click_button "Search" + end + + expect(page).to_not have_selector('#proposals .proposal-featured') + expect(page).to_not have_selector('#featured-proposals') + end - expect(page).to_not have_selector('#proposals .proposal-featured') - expect(page).to_not have_selector('#featured-proposals') end scenario 'Index tag does not show featured proposals' do diff --git a/spec/models/debate_spec.rb b/spec/models/debate_spec.rb index 83129485b..cc21e89e7 100644 --- a/spec/models/debate_spec.rb +++ b/spec/models/debate_spec.rb @@ -445,6 +445,13 @@ describe Debate do expect(results).to eq([debate]) end + xit "searches by author name" do + author = create(:user, username: 'Danny Trejo') + debate = create(:debate, author: author) + results = Debate.search('Danny') + expect(results).to eq([debate]) + end + end context "stemming" do diff --git a/spec/models/proposal_spec.rb b/spec/models/proposal_spec.rb index 4bb198f1c..2aade4657 100644 --- a/spec/models/proposal_spec.rb +++ b/spec/models/proposal_spec.rb @@ -395,6 +395,13 @@ describe Proposal do expect(results).to eq([proposal]) end + it "searches by author name" do + author = create(:user, username: 'Danny Trejo') + proposal = create(:proposal, author: author) + results = Proposal.search('Danny') + expect(results).to eq([proposal]) + end + end context "stemming" do