diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss
index 4b4e3ec9c..fbe9c4f2b 100644
--- a/app/assets/stylesheets/participation.scss
+++ b/app/assets/stylesheets/participation.scss
@@ -794,6 +794,13 @@
}
}
+.proposals-summary {
+
+ .panel {
+ min-height: 0;
+ }
+}
+
// 05. Featured
// - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb
index 224b16bb9..8da777581 100644
--- a/app/controllers/proposals_controller.rb
+++ b/app/controllers/proposals_controller.rb
@@ -6,9 +6,9 @@ class ProposalsController < ApplicationController
before_action :parse_advanced_search_terms, only: :index
before_action :parse_tag_filter, only: :index
before_action :set_search_order, only: :index
- before_action :load_categories, only: [:index, :new, :edit, :map]
- before_action :load_geozones, only: [:edit, :map]
- before_action :authenticate_user!, except: [:index, :show, :map]
+ before_action :load_categories, only: [:index, :new, :edit, :map, :summary]
+ before_action :load_geozones, only: [:edit, :map, :summary]
+ before_action :authenticate_user!, except: [:index, :show, :map, :summary]
has_orders %w{hot_score confidence_score created_at relevance}, only: :index
has_orders %w{most_voted newest oldest}, only: :show
@@ -35,6 +35,11 @@ class ProposalsController < ApplicationController
set_featured_proposal_votes(@proposal)
end
+ def summary
+ @proposals = Proposal.for_summary
+ @tag_cloud = tag_cloud
+ end
+
private
def proposal_params
diff --git a/app/models/abilities/everyone.rb b/app/models/abilities/everyone.rb
index 4de272b8c..21e142c05 100644
--- a/app/models/abilities/everyone.rb
+++ b/app/models/abilities/everyone.rb
@@ -4,7 +4,7 @@ module Abilities
def initialize(user)
can [:read, :map], Debate
- can [:read, :map], Proposal
+ can [:read, :map, :summary], Proposal
can :read, Comment
can :read, SpendingProposal
can :read, Legislation
diff --git a/app/models/proposal.rb b/app/models/proposal.rb
index 8100d79fc..a485061ac 100644
--- a/app/models/proposal.rb
+++ b/app/models/proposal.rb
@@ -41,7 +41,8 @@ class Proposal < ActiveRecord::Base
scope :sort_by_random, -> { reorder("RANDOM()") }
scope :sort_by_relevance , -> { all }
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
- scope :last_week, -> { where("created_at >= ?", 7.days.ago)}
+ scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)}
+ scope :in_categories, -> { where("lower(tags.name) IN (?)", ActsAsTaggableOn::Tag.category_names) }
def searchable_values
{ title => 'A',
@@ -60,13 +61,24 @@ class Proposal < ActiveRecord::Base
end
def self.search_by_code(terms)
- if code_match = /\A#{Setting["proposal_code_prefix"]}-\d\d\d\d-\d\d-(\d*)\z/.match(terms)
- results = where(id: code_match[1])
- end
-
+ matched_code = self.match_code(terms)
+ results = where(id: matched_code[1]) if matched_code
return results if (results.present? && results.first.code == terms)
end
+ def self.match_code(terms)
+ /\A#{Setting["proposal_code_prefix"]}-\d\d\d\d-\d\d-(\d*)\z/.match(terms)
+ end
+
+ def self.for_summary
+ last_week.
+ sort_by_confidence_score.
+ in_categories.
+ joins(:tags).
+ select('proposals.*, tags.name as tag_name').
+ group_by(&:tag_name)
+ end
+
def description
super.try :html_safe
end
diff --git a/app/models/tag_cloud.rb b/app/models/tag_cloud.rb
index 086d88c48..54c745ce8 100644
--- a/app/models/tag_cloud.rb
+++ b/app/models/tag_cloud.rb
@@ -16,7 +16,7 @@ class TagCloud
end
def category_names
- ActsAsTaggableOn::Tag.where("kind = 'category'").map {|tag| tag.name.downcase }
+ ActsAsTaggableOn::Tag.category_names
end
def geozone_names
diff --git a/app/views/proposals/_popular.html.erb b/app/views/proposals/_popular.html.erb
new file mode 100644
index 000000000..f8e3c61ac
--- /dev/null
+++ b/app/views/proposals/_popular.html.erb
@@ -0,0 +1,4 @@
+
+
+
+<%= link_to t("proposals.index.top_link"), "/proposals/summary", class: "small" %>
diff --git a/app/views/proposals/index.html.erb b/app/views/proposals/index.html.erb
index 71cdb54a5..e1308a17e 100644
--- a/app/views/proposals/index.html.erb
+++ b/app/views/proposals/index.html.erb
@@ -56,6 +56,7 @@
<%= render "shared/tag_cloud", taggable: 'proposal' %>
<%= render 'categories' %>
<%= render 'geozones' %>
+ <%= render 'popular' %>
diff --git a/app/views/proposals/summary.html.erb b/app/views/proposals/summary.html.erb
new file mode 100644
index 000000000..6743601f0
--- /dev/null
+++ b/app/views/proposals/summary.html.erb
@@ -0,0 +1,58 @@
+
+
+
+
+ <%= link_to :back, class: 'back left' do %>
+
+ <%= t("proposals.show.back_link") %>
+ <% end %>
+
+ <% @proposals.each do |group_name, proposals| %>
+
+
<%= group_name %>
+
+ <% proposals[0..2].each do |proposal| %>
+
+
+
+
+
+
<%= link_to proposal.title, namespaced_proposal_path(proposal) %>
+
+
+ <% if proposal.author.hidden? || proposal.author.erased? %>
+ <%= t("proposals.show.author_deleted") %>
+ <% else %>
+ <%= proposal.author.name %>
+ <% if proposal.author.official? %>
+
+ <%= proposal.author.official_position %>
+
+ <% end %>
+ <% end %>
+
+
+
+ <%= link_to proposal.description, namespaced_proposal_path(proposal) %>
+
+
+
+
+
+
+
+ <% end %>
+
+ <% end %>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/initializers/acts_as_taggable_on.rb b/config/initializers/acts_as_taggable_on.rb
index 829b43725..c9e38683c 100644
--- a/config/initializers/acts_as_taggable_on.rb
+++ b/config/initializers/acts_as_taggable_on.rb
@@ -34,6 +34,10 @@ module ActsAsTaggableOn
update(custom_counter_field_name_for(taggable_type) => visible_taggables.count)
end
+ def self.category_names
+ Tag.where("kind = 'category'").map {|tag| tag.name.downcase }
+ end
+
private
def custom_counter_field_name_for(taggable_type)
"#{taggable_type.underscore.pluralize}_count"
diff --git a/config/locales/en.yml b/config/locales/en.yml
index e4dcf33a3..0cdaa227c 100755
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -108,7 +108,7 @@ en:
select_order: Order by
start_debate: Start a debate
title: Debates
- share_debate: "Share a link"
+ share_debate: "Share a link"
new:
back_link: Go back
form:
@@ -142,7 +142,7 @@ en:
debate_link: "Link"
new:
start_new: "Share a link"
- recommendations_title: "Recommendations for sharing a link"
+ recommendations_title: "Recommendations for sharing a link"
form:
submit_button: "Share link"
create:
@@ -301,6 +301,8 @@ en:
select_order_long: 'You are viewing proposals according to:'
start_proposal: Create a proposal
title: Proposals
+ top: Weekly selection
+ top_link: See the best proposals
new:
back_link: Go back
form:
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 4502475ec..59bfdc0df 100755
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -143,7 +143,7 @@ es:
debate_link: "Enlace"
new:
start_new: "Compartir un enlace"
- recommendations_title: "Recomendaciones para compartir un enlace"
+ recommendations_title: "Recomendaciones para compartir un enlace"
form:
submit_button: "Comparte un enlace"
create:
@@ -302,6 +302,8 @@ es:
select_order_long: Estas viendo las propuestas
start_proposal: Crea una propuesta
title: Propuestas ciudadanas
+ top: Selección semanal
+ top_link: Ver las mejores propuestas
new:
back_link: Volver
form:
diff --git a/config/routes.rb b/config/routes.rb
index 8b2e6d280..c9e4023ad 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -43,9 +43,9 @@ Rails.application.routes.draw do
get :suggest
end
end
-
+
get 'debate_links/new' => 'debate_links#new'
- post 'debate_links' => 'debate_links#create'
+ post 'debate_links' => 'debate_links#create'
resources :proposals do
member do
@@ -57,6 +57,7 @@ Rails.application.routes.draw do
collection do
get :map
get :suggest
+ get :summary
end
end
diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb
index 4d1de0af1..c8e9234dc 100644
--- a/spec/features/proposals_spec.rb
+++ b/spec/features/proposals_spec.rb
@@ -1162,4 +1162,70 @@ feature 'Proposals' do
end
end
end
+
+ context "Summary" do
+
+ scenario "Displays proposals grouped by category" do
+ create(:tag, kind: 'category', name: 'Culture')
+ create(:tag, kind: 'category', name: 'Social Services')
+
+ 3.times { create(:proposal, tag_list: 'Culture') }
+ 3.times { create(:proposal, tag_list: 'Social Services') }
+
+ create(:proposal, tag_list: 'Random')
+
+ visit proposals_path
+ click_link "See the best proposals"
+
+ within("#culture") do
+ expect(page).to have_content("Culture")
+ expect(page).to have_css(".proposal", count: 3)
+ end
+
+ within("#social-services") do
+ expect(page).to have_content("Social Services")
+ expect(page).to have_css(".proposal", count: 3)
+ end
+ end
+
+ scenario "Displays a maximum of 3 proposals per category" do
+ create(:tag, kind: 'category', name: 'Culture')
+ 4.times { create(:proposal, tag_list: 'Culture') }
+
+ visit summary_proposals_path
+
+ expect(page).to have_css(".proposal", count: 3)
+ end
+
+ scenario "Orders proposals by votes" do
+ create(:tag, kind: 'category', name: 'Culture')
+ create(:proposal, title: 'Best', tag_list: 'Culture').update_column(:confidence_score, 10)
+ create(:proposal, title: 'Worst', tag_list: 'Culture').update_column(:confidence_score, 2)
+ create(:proposal, title: 'Medium', tag_list: 'Culture').update_column(:confidence_score, 5)
+
+ visit summary_proposals_path
+
+ expect('Best').to appear_before('Medium')
+ expect('Medium').to appear_before('Worst')
+ end
+
+ scenario "Displays proposals from last week" do
+ create(:tag, kind: 'category', name: 'Culture')
+ proposal1 = create(:proposal, tag_list: 'Culture', created_at: 1.day.ago)
+ proposal2 = create(:proposal, tag_list: 'Culture', created_at: 5.days.ago)
+ proposal3 = create(:proposal, tag_list: 'Culture', created_at: 8.days.ago)
+
+ visit summary_proposals_path
+
+ 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
+
end
diff --git a/spec/models/proposal_spec.rb b/spec/models/proposal_spec.rb
index 8a61afcaf..0f9b2f362 100644
--- a/spec/models/proposal_spec.rb
+++ b/spec/models/proposal_spec.rb
@@ -633,12 +633,64 @@ describe Proposal do
describe "#last_week" do
it "should return proposals created this week" do
proposal = create(:proposal)
- expect(Proposal.last_week.all).to include (proposal)
+ expect(Proposal.last_week).to include(proposal)
end
- it "should not show proposals created more than a week ago" do
+ it "should not return proposals created more than a week ago" do
proposal = create(:proposal, created_at: 8.days.ago)
- expect(Proposal.last_week.all).to_not include (proposal)
+ expect(Proposal.last_week).to_not include(proposal)
+ end
+ end
+
+ describe "for_summary" do
+ it "should return proposals tagged with a category" do
+ create(:tag, kind: 'category', name: 'Culture')
+ proposal = create(:proposal, tag_list: 'Culture')
+
+ expect(Proposal.for_summary.values.flatten).to include(proposal)
+ end
+
+ it "should not return proposals tagged without a category" do
+ create(:tag, kind: 'category', name: 'Culture')
+ proposal = create(:proposal, tag_list: 'Parks')
+
+ expect(Proposal.for_summary.values.flatten).to_not include(proposal)
+ end
+
+ it "should return proposals created this week" do
+ create(:tag, kind: 'category', name: 'Culture')
+ proposal = create(:proposal, tag_list: 'Culture')
+ expect(Proposal.for_summary.values.flatten).to include(proposal)
+ end
+
+ it "should not return proposals created more than a week ago" do
+ create(:tag, kind: 'category', name: 'Culture')
+ proposal = create(:proposal, tag_list: 'Culture', created_at: 8.days.ago)
+ expect(Proposal.for_summary.values.flatten).to_not include(proposal)
+ end
+
+ it "should order by votes" do
+ create(:tag, kind: 'category', name: 'Culture')
+ create(:proposal, tag_list: 'Culture').update_column(:confidence_score, 2)
+ create(:proposal, tag_list: 'Culture').update_column(:confidence_score, 10)
+ create(:proposal, tag_list: 'Culture').update_column(:confidence_score, 5)
+
+ results = Proposal.for_summary.values.flatten
+
+ expect(results.first.confidence_score).to be(10)
+ expect(results.second.confidence_score).to be(5)
+ expect(results.third.confidence_score).to be(2)
+ end
+
+ it "should return proposals grouped by tag" do
+ create(:tag, kind: 'category', name: 'Culture')
+ create(:tag, kind: 'category', name: 'Health')
+
+ proposal1 = create(:proposal, tag_list: 'Culture')
+ proposal2 = create(:proposal, tag_list: 'Culture')
+ proposal3 = create(:proposal, tag_list: 'Health')
+
+ expect(Proposal.for_summary).to include('Culture' => [proposal2, proposal1], 'Health' => [proposal3])
end
end