Merge pull request #1824 from rockandror/user-recomendations

User recomendations
This commit is contained in:
Raimond Garcia
2017-09-29 19:02:03 +02:00
committed by GitHub
40 changed files with 975 additions and 106 deletions

View File

@@ -411,7 +411,7 @@ $maincontent-shadow: 0 0 10px rgba($black, 0.5);
$orbit-bullet-background: $medium-gray; $orbit-bullet-background: $medium-gray;
$orbit-bullet-background-active: $dark-gray; $orbit-bullet-background-active: $dark-gray;
$orbit-bullet-diameter: 1.2rem; $orbit-bullet-diameter: 0.8rem;
$orbit-bullet-margin: 0.1rem; $orbit-bullet-margin: 0.1rem;
$orbit-bullet-margin-top: 0.8rem; $orbit-bullet-margin-top: 0.8rem;
$orbit-bullet-margin-bottom: 0.8rem; $orbit-bullet-margin-bottom: 0.8rem;

View File

@@ -18,7 +18,8 @@
// 16. Flags // 16. Flags
// 17. Activity // 17. Activity
// 18. Banners // 18. Banners
// 19. Documents // 19. Recommended Section Home
// 20. Documents
// //
// 01. Global styles // 01. Global styles
@@ -341,6 +342,14 @@ a {
background: $brand; background: $brand;
} }
.truncate-horizontal-text {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
-ms-text-overflow: ellipsis;
}
.align-top { .align-top {
vertical-align: top; vertical-align: top;
} }
@@ -612,7 +621,7 @@ header {
text-align: left; text-align: left;
@include breakpoint(medium) { @include breakpoint(medium) {
margin-right: $line-height * 1.5; margin-right: rem-calc(24);
} }
&:hover { &:hover {
@@ -2161,6 +2170,142 @@ table {
} }
} }
// 19. Recommended Section Home
// -----------
.home-page {
.push {
display: none;
}
}
.section-recommended {
padding: $line-height * 2 0;
h2 {
margin-bottom: $line-height * 2;
}
.debates,
.proposals,
.budget-investments {
@include breakpoint(medium) {
margin-bottom: 0;
}
@include breakpoint(small) {
margin-bottom: $line-height;
}
.button.hollow {
margin-top: rem-calc(15);
}
}
.card {
.card-section {
padding: $line-height 0;
max-width: 300px;
margin: 0 auto;
p {
font-size: rem-calc(15);
text-align: left;
}
}
.orbit {
height: 300px;
.orbit-wrapper {
max-height: 250px;
overflow: hidden;
position: relative;
}
.orbit-bullets {
@include orbit-bullets;
width: 100%;
}
}
}
.card .orbit .orbit-wrapper .truncate {
background: image-url('truncate.png');
background-repeat: repeat-x;
bottom: 0;
height: 20px;
position: absolute;
width: 100%;
}
.debates-inner {
border-top: 4px solid $debates;
}
.proposals-inner {
border-top: 4px solid $proposals;
}
.budget-investments-inner {
border-top: 4px solid $budget;
}
.debates-inner,
.proposals-inner,
.budget-investments-inner {
background: #fff;
max-height: 350px;
@include breakpoint(small) {
max-height: 400px;
}
h4 {
margin-top: $line-height;
margin-bottom: 0;
font-size: rem-calc(18);
min-height: 50px;
}
h5 {
font-size: rem-calc(14);
text-align: left;
}
}
.carousel-image {
.card .orbit {
height: 480px;
.orbit-wrapper {
max-height: 450px;
}
}
.debates-inner,
.proposals-inner,
.budget-investments-inner {
max-height: 500px;
@include breakpoint(small) {
max-height: 600px;
}
}
}
.carousel-image .orbit-wrapper img {
display: block;
@include breakpoint(small) {
margin: 0 auto;
}
}
}
// 19. Documents // 19. Documents
.documents-list { .documents-list {
@@ -2218,6 +2363,5 @@ table {
} }
} }
} }
} }

View File

@@ -1,6 +1,7 @@
// Table of Contents // Table of Contents
// //
// 01. Logo // 01. Logo
// 02. Orbit bullets
// //
// 01. Logo // 01. Logo
@@ -31,7 +32,35 @@
} }
} }
// 02. Orbit bullet
// ----------------
@mixin orbit-bullets {
@include disable-mouse-outline;
position: relative;
margin-top: $orbit-bullet-margin-top;
margin-bottom: $orbit-bullet-margin-bottom;
text-align: center;
button {
width: $orbit-bullet-diameter;
height: $orbit-bullet-diameter;
margin: $orbit-bullet-margin;
border-radius: 50%;
background-color: $orbit-bullet-background;
&:hover {
background-color: $orbit-bullet-background-active;
}
&.is-active {
background-color: $orbit-bullet-background-active;
}
}
}
// 02. Direct uploads
// ------------------
@mixin direct-uploads { @mixin direct-uploads {
.cached-image { .cached-image {
@@ -96,4 +125,5 @@
.loading-bar.no-transition { .loading-bar.no-transition {
transition: none; transition: none;
} }
} }

View File

@@ -4,17 +4,22 @@ module CommentableActions
include Search include Search
def index def index
@resources = @search_terms.present? ? resource_model.search(@search_terms) : resource_model.all @resources = resource_model.all
@resources = @advanced_search_terms.present? ? @resources.filter(@advanced_search_terms) : @resources
@resources = @current_order == "recommendations" && current_user.present? ? @resources.recommendations(current_user) : @resources.for_render
@resources = @resources.search(@search_terms) if @search_terms.present?
@resources = @advanced_search_terms.present? ? @resources.filter(@advanced_search_terms) : @resources
@resources = @resources.tagged_with(@tag_filter) if @tag_filter @resources = @resources.tagged_with(@tag_filter) if @tag_filter
@resources = @resources.page(params[:page]).for_render.send("sort_by_#{@current_order}")
@resources = @resources.page(params[:page]).send("sort_by_#{@current_order}")
index_customization if index_customization.present? index_customization if index_customization.present?
@tag_cloud = tag_cloud @tag_cloud = tag_cloud
@banners = Banner.with_active @banners = Banner.with_active
set_resource_votes(@resources) set_resource_votes(@resources)
set_resources_instance set_resources_instance
end end

View File

@@ -10,7 +10,7 @@ class DebatesController < ApplicationController
invisible_captcha only: [:create, :update], honeypot: :subtitle invisible_captcha only: [:create, :update], honeypot: :subtitle
has_orders %w{hot_score confidence_score created_at relevance}, only: :index has_orders ->(c) { Debate.debates_orders(c.current_user) }, only: :index
has_orders %w{most_voted newest oldest}, only: :show has_orders %w{most_voted newest oldest}, only: :show
load_and_authorize_resource load_and_authorize_resource

View File

@@ -11,7 +11,7 @@ class NotificationsController < ApplicationController
def show def show
@notification = current_user.notifications.find(params[:id]) @notification = current_user.notifications.find(params[:id])
redirect_to url_for(@notification.linkable_resource) redirect_to linkable_resource_path(@notification)
end end
def mark_all_as_read def mark_all_as_read
@@ -25,4 +25,13 @@ class NotificationsController < ApplicationController
@notification.mark_as_read @notification.mark_as_read
end end
def linkable_resource_path(notification)
case notification.linkable_resource.class.name
when "Budget::Investment"
budget_investment_path @notification.linkable_resource.budget, @notification.linkable_resource
else
url_for @notification.linkable_resource
end
end
end end

View File

@@ -9,7 +9,7 @@ class ProposalsController < ApplicationController
invisible_captcha only: [:create, :update], honeypot: :subtitle invisible_captcha only: [:create, :update], honeypot: :subtitle
has_orders %w{hot_score confidence_score created_at relevance archival_date}, only: :index has_orders ->(c) { Proposal.proposals_orders(c.current_user) }, only: :index
has_orders %w{most_voted newest oldest}, only: :show has_orders %w{most_voted newest oldest}, only: :show
load_and_authorize_resource load_and_authorize_resource
@@ -113,7 +113,7 @@ class ProposalsController < ApplicationController
end end
def load_featured def load_featured
return unless !@advanced_search_terms && @search_terms.blank? && @tag_filter.blank? && params[:retired].blank? return unless !@advanced_search_terms && @search_terms.blank? && @tag_filter.blank? && params[:retired].blank? && @current_order != "recommendations"
@featured_proposals = Proposal.not_archived.sort_by_confidence_score.limit(3) @featured_proposals = Proposal.not_archived.sort_by_confidence_score.limit(3)
if @featured_proposals.present? if @featured_proposals.present?
set_featured_proposal_votes(@featured_proposals) set_featured_proposal_votes(@featured_proposals)

View File

@@ -1,12 +1,10 @@
class WelcomeController < ApplicationController class WelcomeController < ApplicationController
skip_authorization_check skip_authorization_check
before_action :set_user_recommendations, only: :index, if: :current_user
layout "devise", only: [:welcome, :verification] layout "devise", only: [:welcome, :verification]
def index def index
if current_user
redirect_to :proposals
end
end end
def welcome def welcome
@@ -16,4 +14,11 @@ class WelcomeController < ApplicationController
redirect_to verification_path if signed_in? redirect_to verification_path if signed_in?
end end
private
def set_user_recommendations
@recommended_debates = Debate.recommendations(current_user).sort_by_recommendations.limit(3)
@recommended_proposals = Proposal.recommendations(current_user).sort_by_recommendations.limit(3)
end
end end

View File

@@ -4,4 +4,12 @@ module DebatesHelper
Debate.all.featured.count > 0 Debate.all.featured.count > 0
end end
def empty_recommended_debates_message_text(user)
if user.interests.any?
t('debates.index.recommendations.without_results')
else
t('debates.index.recommendations.without_interests')
end
end
end end

View File

@@ -32,6 +32,14 @@ module ProposalsHelper
Proposal::RETIRE_OPTIONS.collect { |option| [ t("proposals.retire_options.#{option}"), option ] } Proposal::RETIRE_OPTIONS.collect { |option| [ t("proposals.retire_options.#{option}"), option ] }
end end
def empty_recommended_proposals_message_text(user)
if user.interests.any?
t('proposals.index.recommendations.without_results')
else
t('proposals.index.recommendations.without_interests')
end
end
def author_of_proposal?(proposal) def author_of_proposal?(proposal)
author_of?(proposal, current_user) author_of?(proposal, current_user)
end end

View File

@@ -0,0 +1,62 @@
module WelcomeHelper
def active_class(index)
"is-active is-in" if index == 0
end
def slide_display(index)
"display: none;" if index > 0
end
def recommended_path(recommended)
case recommended.class.name
when "Debate"
debate_path(recommended)
when "Proposal"
proposal_path(recommended)
else
'#'
end
end
def render_recommendation_image(recommended, image_default)
image_path = calculate_image_path(recommended, image_default)
image_tag(image_path) if image_path.present?
end
def calculate_image_path(recommended, image_default)
if recommended.try(:image) && recommended.image.present? && recommended.image.attachment.exists?
recommended.image.attachment.send("url", :medium)
elsif image_default.present?
image_default
end
end
def calculate_carousel_size(debates, proposals, apply_offset)
offset = calculate_offset(debates, proposals, apply_offset)
centered = calculate_centered(debates, proposals)
"#{offset if offset} #{centered if centered}"
end
def calculate_centered(debates, proposals)
if (debates.blank? && proposals.any?) ||
(debates.any? && proposals.blank?)
centered = "medium-centered large-centered"
end
end
def calculate_offset(debates, proposals, apply_offset)
if (debates.any? && proposals.any?)
if apply_offset
offset = "medium-offset-2 large-offset-2"
else
offset = "end"
end
end
end
def highlight_background
(feature?("user.recommendations") && current_user) ? "highlight" : ""
end
end

View File

@@ -4,6 +4,10 @@ module Followable
included do included do
has_many :follows, as: :followable, dependent: :destroy has_many :follows, as: :followable, dependent: :destroy
has_many :followers, through: :follows, source: :user has_many :followers, through: :follows, source: :user
scope :followed_by_user, -> (user){
joins(:follows).where("follows.user_id = ?", user.id)
}
end end
def followed_by?(user) def followed_by?(user)

View File

@@ -37,14 +37,21 @@ class Debate < ActiveRecord::Base
scope :sort_by_random, -> { reorder("RANDOM()") } scope :sort_by_random, -> { reorder("RANDOM()") }
scope :sort_by_relevance, -> { all } scope :sort_by_relevance, -> { all }
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) } scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
scope :sort_by_recommendations, -> { order(cached_votes_total: :desc) }
scope :last_week, -> { where("created_at >= ?", 7.days.ago)} scope :last_week, -> { where("created_at >= ?", 7.days.ago)}
scope :featured, -> { where("featured_at is not null")} scope :featured, -> { where("featured_at is not null")}
scope :public_for_api, -> { all } scope :public_for_api, -> { all }
# Ahoy setup # Ahoy setup
visitable # Ahoy will automatically assign visit_id on create visitable # Ahoy will automatically assign visit_id on create
attr_accessor :link_required attr_accessor :link_required
def self.recommendations(user)
tagged_with(user.interests, any: true).
where("author_id != ?", user.id)
end
def searchable_values def searchable_values
{ title => 'A', { title => 'A',
author.username => 'B', author.username => 'B',
@@ -135,4 +142,9 @@ class Debate < ActiveRecord::Base
featured_at.present? featured_at.present?
end end
def self.debates_orders(user)
orders = %w{hot_score confidence_score created_at relevance}
orders << "recommendations" if user.present?
orders
end
end end

View File

@@ -58,14 +58,27 @@ class Proposal < ActiveRecord::Base
scope :sort_by_relevance, -> { all } scope :sort_by_relevance, -> { all }
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) } scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
scope :sort_by_archival_date, -> { archived.sort_by_confidence_score } scope :sort_by_archival_date, -> { archived.sort_by_confidence_score }
scope :sort_by_recommendations, -> { order(cached_votes_up: :desc) }
scope :archived, -> { where("proposals.created_at <= ?", Setting["months_to_archive_proposals"].to_i.months.ago) } scope :archived, -> { where("proposals.created_at <= ?", Setting["months_to_archive_proposals"].to_i.months.ago) }
scope :not_archived, -> { where("proposals.created_at > ?", Setting["months_to_archive_proposals"].to_i.months.ago) } scope :not_archived, -> { where("proposals.created_at > ?", Setting["months_to_archive_proposals"].to_i.months.ago) }
scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)} scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)}
scope :retired, -> { where.not(retired_at: nil) } scope :retired, -> { where.not(retired_at: nil) }
scope :not_retired, -> { where(retired_at: nil) } scope :not_retired, -> { where(retired_at: nil) }
scope :successful, -> { where("cached_votes_up >= ?", Proposal.votes_needed_for_success) } scope :successful, -> { where("cached_votes_up >= ?", Proposal.votes_needed_for_success) }
scope :unsuccessful, -> { where("cached_votes_up < ?", Proposal.votes_needed_for_success) }
scope :public_for_api, -> { all } scope :public_for_api, -> { all }
def self.recommendations(user)
tagged_with(user.interests, any: true).
where("author_id != ?", user.id).
unsuccessful.
not_followed_by_user(user)
end
def self.not_followed_by_user(user)
where.not(id: followed_by_user(user).pluck(:id))
end
def to_param def to_param
"#{id}-#{title}".parameterize "#{id}-#{title}".parameterize
end end
@@ -185,6 +198,12 @@ class Proposal < ActiveRecord::Base
(voters + followers).uniq (voters + followers).uniq
end end
def self.proposals_orders(user)
orders = %w{hot_score confidence_score created_at relevance archival_date}
orders << "recommendations" if user.present?
orders
end
protected protected
def set_responsible_name def set_responsible_name

View File

@@ -88,12 +88,12 @@ class User < ActiveRecord::Base
end end
def debate_votes(debates) def debate_votes(debates)
voted = votes.for_debates(debates) voted = votes.for_debates(Array(debates).map(&:id))
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value } voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
end end
def proposal_votes(proposals) def proposal_votes(proposals)
voted = votes.for_proposals(proposals) voted = votes.for_proposals(Array(proposals).map(&:id))
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value } voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
end end

View File

@@ -54,7 +54,11 @@
<%= link_to t("debates.index.start_debate"), new_debate_path, class: 'button expanded' %> <%= link_to t("debates.index.start_debate"), new_debate_path, class: 'button expanded' %>
</div> </div>
<% if @debates.any? || current_user.blank? %>
<%= render @debates %> <%= render @debates %>
<% else %>
<%= empty_recommended_debates_message_text(current_user) %>
<% end %>
<%= paginate @debates %> <%= paginate @debates %>
<% unless @search_terms || @advanced_search_terms || @tag_filter %> <% unless @search_terms || @advanced_search_terms || @tag_filter %>

View File

@@ -23,7 +23,7 @@
<%= setting['per_page_code_head'].try(:html_safe) %> <%= setting['per_page_code_head'].try(:html_safe) %>
</head> </head>
<body> <body class="<%= yield (:body_class) %>">
<%= setting['per_page_code_body'].try(:html_safe) %> <%= setting['per_page_code_body'].try(:html_safe) %>
<h1 class="show-for-sr"><%= setting['org_name'] %></h1> <h1 class="show-for-sr"><%= setting['org_name'] %></h1>

View File

@@ -68,7 +68,11 @@
<% end %> <% end %>
<div id="proposals-list"> <div id="proposals-list">
<% if @proposals.any? || current_user.blank? %>
<%= render partial: 'proposals/proposal', collection: @proposals %> <%= render partial: 'proposals/proposal', collection: @proposals %>
<% else %>
<%= empty_recommended_proposals_message_text(current_user) %>
<% end %>
<%= paginate @proposals %> <%= paginate @proposals %>
<% unless @search_terms || @advanced_search_terms || @tag_filter %> <% unless @search_terms || @advanced_search_terms || @tag_filter %>

View File

@@ -0,0 +1,31 @@
<div class="small-12 column section-recommended padding">
<div class="row">
<h2 class="text-center"><%= t("welcome.recommended.title") %></h2>
<div class="small-12 column carousel-image">
<% if recommended_debates.any? %>
<% carousel_size = calculate_carousel_size(recommended_debates, recommended_proposals, true) %>
<%= render "recommended_carousel", recommendeds: recommended_debates,
key: "debates",
image_field: nil,
image_version: nil,
image_default: nil,
carousel_size: carousel_size,
btn_text_link: t("welcome.recommended.debates.btn_text_link"),
btn_path_link: debates_path(order: "recommendations") %>
<% end %>
<% if recommended_proposals.any? %>
<% carousel_size = calculate_carousel_size(recommended_debates, recommended_proposals, false) %>
<%= render "recommended_carousel", recommendeds: recommended_proposals,
key: "proposals",
image_field: :attachment,
image_version: :thumb,
image_default: nil,
carousel_size: carousel_size,
btn_text_link: t("welcome.recommended.proposals.btn_text_link"),
btn_path_link: proposals_path(order: "recommendations") %>
<% end %>
</div>
</div>
</div>

View File

@@ -0,0 +1,42 @@
<div class="small-12 medium-4 large-4 <%= carousel_size %> column text-center <%= key %> ">
<div class="card small-centered <%= key %>-inner">
<h4><%= t("welcome.recommended.#{key.underscore}.title") %></h4>
<div class="orbit" role="region" data-orbit data-use-m-u-i="false">
<div class="orbit-wrapper">
<ul class="orbit-container no-bullet" tabindex="0" >
<% recommendeds.each_with_index do |recommended, index| %>
<li class="orbit-slide <%= active_class(index) %>" data-slide="<%= index %>" style="position: relative; <%= slide_display(index) %>" aria-live="polite">
<div class="card">
<%= render_recommendation_image(recommended, image_default) %>
<div class="card-section">
<%= link_to recommended_path(recommended) do %>
<h5 class="truncate-horizontal-text"><%= recommended.title %></h5>
<% end %>
<p><%= recommended.description %></p>
</div>
</div>
</li>
<% end %>
</ul>
<div class="truncate"></div>
</div>
<nav class="orbit-bullets">
<% recommendeds.each_with_index do |recommended, index| %>
<button data-slide="<%= index %>" class="<%= active_class(index) %>">
<span class="show-for-sr">Second slide details.</span>
</button>
<% end %>
</nav>
</div>
</div>
<%= link_to btn_text_link, btn_path_link, class: 'button hollow expanded' %>
</div>

View File

@@ -1,3 +1,5 @@
<% content_for :body_class, "home-page" %>
<% content_for :canonical do %> <% content_for :canonical do %>
<%= render "shared/canonical", href: root_url %> <%= render "shared/canonical", href: root_url %>
<% end %> <% end %>
@@ -16,37 +18,35 @@
</div> </div>
</div> </div>
<% if feature?("user.recommendations") && (@recommended_debates.present? || @recommended_proposals.present?) %>
<%= render "recommended",
recommended_debates: @recommended_debates,
recommended_proposals: @recommended_proposals %>
<% end %>
<% cache [locale_and_user_status, @featured_debates, @featured_proposals, 'featured'] do %> <% cache [locale_and_user_status, @featured_debates, @featured_proposals, 'featured'] do %>
<main> <main>
<div class="row">
<div class="small-12 medium-6 column">
<p>
<span class="lead"><strong><%= t("welcome.debates.title") %></strong></span><br>
<%= t("welcome.debates.description") %>
</p>
<div class="small-12 column text-center <%= highlight_background %>">
<div class="row margin padding">
<div class="small-12 medium-3 column">
<h2><%= t("welcome.debates.title") %></h2>
<p><%= t("welcome.debates.description") %></p>
</div>
<div class="small-12 medium-3 column">
<h2><%= t("welcome.proposal.title") %></h2>
<p><%= t("welcome.proposal.description") %></p>
</div>
<div class="small-12 medium-3 column">
<h2><%= t("welcome.decide.title") %></h2>
<p><%= t("welcome.decide.description") %></p>
</div>
<div class="small-12 medium-3 column">
<h2><%= t("welcome.do.title") %></h2>
<p><%= t("welcome.do.description") %></p>
</div> </div>
<div class="small-12 medium-6 column">
<p>
<span class="lead"><strong><%= t("welcome.proposal.title") %></strong></span><br>
<%= t("welcome.proposal.description") %>
</p>
</div> </div>
</div> </div>
<div class="row margin-top">
<div class="small-12 medium-6 column">
<p>
<span class="lead"><strong><%= t("welcome.decide.title") %></strong></span><br>
<%= t("welcome.decide.description") %>
</p>
</div>
<div class="small-12 medium-6 column">
<p>
<span class="lead"><strong><%= t("welcome.do.title") %></strong></span><br>
<%= t("welcome.do.description") %>
</p>
</div>
</div>
</main> </main>
<% end %> <% end %>

View File

@@ -109,6 +109,10 @@ en:
hot_score: most active hot_score: most active
most_commented: most commented most_commented: most commented
relevance: relevance relevance: relevance
recommendations: recommendations
recommendations:
without_results: There are not debates related to your interests
without_interests: Follow proposals so we can give you recommendations
search_form: search_form:
button: Search button: Search
placeholder: Search debates... placeholder: Search debates...
@@ -348,6 +352,10 @@ en:
most_commented: most commented most_commented: most commented
relevance: relevance relevance: relevance
archival_date: Archived archival_date: Archived
recommendations: recommendations
recommendations:
without_results: There are not proposals related to your interests
without_interests: Follow proposals so we can give you recommendations
retired_proposals: Retired proposals retired_proposals: Retired proposals
retired_proposals_link: "Proposals retired by the author" retired_proposals_link: "Proposals retired by the author"
retired_links: retired_links:
@@ -753,6 +761,16 @@ en:
proposal: proposal:
description: Open space for citizen proposals about the kind of city we want to live in. description: Open space for citizen proposals about the kind of city we want to live in.
title: You propose title: You propose
recommended:
title: Recommendations that may interest you
debates:
title: Recommended debates
btn_text_link: All recommended debates
proposals:
title: Recommended proposals
btn_text_link: All recommended proposals
budget_investments:
title: Recommended investments
verification: verification:
i_dont_have_an_account: I don't have an account i_dont_have_an_account: I don't have an account
i_have_an_account: I already have an account i_have_an_account: I already have an account

View File

@@ -39,6 +39,8 @@ en:
spending_proposal_features: spending_proposal_features:
voting_allowed: Voting on investment projects voting_allowed: Voting on investment projects
legislation: Legislation legislation: Legislation
user:
recommendations: Recommendeds
community: Community on proposals and investments community: Community on proposals and investments
map: Proposals and budget investments geolocation map: Proposals and budget investments geolocation
map_latitude: Latitude map_latitude: Latitude

View File

@@ -109,6 +109,10 @@ es:
hot_score: Más activos hoy hot_score: Más activos hoy
most_commented: Más comentados most_commented: Más comentados
relevance: Más relevantes relevance: Más relevantes
recommendations: Recomendaciones
recommendations:
without_results: No existen debates relacionados con tus intereses
without_interests: Sigue propuestas para que podamos darte recomendaciones
search_form: search_form:
button: Buscar button: Buscar
placeholder: Buscar debates... placeholder: Buscar debates...
@@ -348,6 +352,10 @@ es:
most_commented: Más comentadas most_commented: Más comentadas
relevance: Más relevantes relevance: Más relevantes
archival_date: Archivadas archival_date: Archivadas
recommendations: Recomendaciones
recommendations:
without_results: No existen propuestas relacionadas con tus intereses
without_interests: Sigue propuestas para que podamos darte recomendaciones
retired_proposals: Propuestas retiradas retired_proposals: Propuestas retiradas
retired_proposals_link: "Propuestas retiradas por sus autores" retired_proposals_link: "Propuestas retiradas por sus autores"
retired_links: retired_links:
@@ -753,6 +761,16 @@ es:
proposal: proposal:
description: Espacio abierto para propuestas ciudadanas sobre el tipo de ciudad en el que queremos vivir. description: Espacio abierto para propuestas ciudadanas sobre el tipo de ciudad en el que queremos vivir.
title: Propones title: Propones
recommended:
title: Recomendaciones que te pueden interesar
debates:
title: Debates recomendados
btn_text_link: Todos los debates recomendados
proposals:
title: Propuestas recomendadas
btn_text_link: Todas las propuestas recomendadas
budget_investments:
title: Presupuestos recomendados
verification: verification:
i_dont_have_an_account: No tengo cuenta, quiero crear una y verificarla i_dont_have_an_account: No tengo cuenta, quiero crear una y verificarla
i_have_an_account: Ya tengo una cuenta que quiero verificar i_have_an_account: Ya tengo una cuenta que quiero verificar

View File

@@ -39,6 +39,8 @@ es:
spending_proposal_features: spending_proposal_features:
voting_allowed: Votaciones sobre propuestas de inversión voting_allowed: Votaciones sobre propuestas de inversión
legislation: Legislación legislation: Legislación
user:
recommendations: Recomendaciones
community: Comunidad en propuestas y proyectos de inversión community: Comunidad en propuestas y proyectos de inversión
map: Geolocalización de propuestas y proyectos de inversión map: Geolocalización de propuestas y proyectos de inversión
map_latitude: Latitud map_latitude: Latitud

View File

@@ -36,6 +36,7 @@ Setting.create(key: 'feature.facebook_login', value: "true")
Setting.create(key: 'feature.google_login', value: "true") Setting.create(key: 'feature.google_login', value: "true")
Setting.create(key: 'feature.signature_sheets', value: "true") Setting.create(key: 'feature.signature_sheets', value: "true")
Setting.create(key: 'feature.legislation', value: "true") Setting.create(key: 'feature.legislation', value: "true")
Setting.create(key: 'feature.user.recommendations', value: "true")
Setting.create(key: 'feature.community', value: "true") Setting.create(key: 'feature.community', value: "true")
Setting.create(key: 'feature.map', value: "true") Setting.create(key: 'feature.map', value: "true")
Setting.create(key: 'per_page_code_head', value: "") Setting.create(key: 'per_page_code_head', value: "")

View File

@@ -79,6 +79,7 @@ Setting['feature.public_stats'] = true
Setting['feature.budgets'] = true Setting['feature.budgets'] = true
Setting['feature.signature_sheets'] = true Setting['feature.signature_sheets'] = true
Setting['feature.legislation'] = true Setting['feature.legislation'] = true
Setting['feature.user.recommendations'] = true
Setting['feature.community'] = true Setting['feature.community'] = true
Setting['feature.map'] = nil Setting['feature.map'] = nil

View File

@@ -12,7 +12,7 @@ feature 'Admin' do
visit admin_root_path visit admin_root_path
expect(current_path).not_to eq(admin_root_path) expect(current_path).not_to eq(admin_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -22,7 +22,7 @@ feature 'Admin' do
visit admin_root_path visit admin_root_path
expect(current_path).not_to eq(admin_root_path) expect(current_path).not_to eq(admin_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -32,7 +32,7 @@ feature 'Admin' do
visit admin_root_path visit admin_root_path
expect(current_path).not_to eq(admin_root_path) expect(current_path).not_to eq(admin_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -42,7 +42,7 @@ feature 'Admin' do
visit admin_root_path visit admin_root_path
expect(current_path).not_to eq(admin_root_path) expect(current_path).not_to eq(admin_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -52,7 +52,7 @@ feature 'Admin' do
visit admin_root_path visit admin_root_path
expect(current_path).not_to eq(admin_root_path) expect(current_path).not_to eq(admin_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end

View File

@@ -219,7 +219,7 @@ feature 'Debates' do
visit edit_debate_path(debate) visit edit_debate_path(debate)
expect(current_path).not_to eq(edit_debate_path(debate)) expect(current_path).not_to eq(edit_debate_path(debate))
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to carry out the action 'edit' on debate." expect(page).to have_content "You do not have permission to carry out the action 'edit' on debate."
end end
@@ -234,7 +234,7 @@ feature 'Debates' do
visit edit_debate_path(debate) visit edit_debate_path(debate)
expect(current_path).not_to eq(edit_debate_path(debate)) expect(current_path).not_to eq(edit_debate_path(debate))
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content 'You do not have permission to' expect(page).to have_content 'You do not have permission to'
end end
@@ -351,6 +351,69 @@ feature 'Debates' do
expect(current_url).to include('order=created_at') expect(current_url).to include('order=created_at')
expect(current_url).to include('page=1') expect(current_url).to include('page=1')
end end
context 'Recommendations' do
background do
Setting['feature.user.recommendations'] = true
create(:debate, title: 'Best', cached_votes_total: 10, tag_list: "Sport")
create(:debate, title: 'Medium', cached_votes_total: 5, tag_list: "Sport")
create(:debate, title: 'Worst', cached_votes_total: 1, tag_list: "Sport")
end
after do
Setting['feature.user.recommendations'] = nil
end
scenario 'Debates can not ordered by recommendations when there is not an user logged', :js do
visit debates_path
expect(page).not_to have_selector('a', text: 'recommendations')
end
scenario 'Should display text when there are not recommendeds results', :js do
user = create(:user)
proposal = create(:proposal, tag_list: "Distinct_to_sport")
create(:follow, followable: proposal, user: user)
login_as(user)
visit debates_path
click_link 'recommendations'
expect(page).to have_content "There are not debates related to your interests"
end
scenario 'Should display text when user has not related interests', :js do
user = create(:user)
login_as(user)
visit debates_path
click_link 'recommendations'
expect(page).to have_content "Follow proposals so we can give you recommendations"
end
scenario 'Debates are ordered by recommendations when there is a user logged', :js do
proposal = create(:proposal, tag_list: "Sport" )
user = create(:user)
create(:follow, followable: proposal, user: user)
login_as(user)
visit debates_path
click_link 'recommendations'
expect(page).to have_selector('a.active', text: 'recommendations')
within '#debates' do
expect('Best').to appear_before('Medium')
expect('Medium').to appear_before('Worst')
end
expect(current_url).to include('order=recommendations')
expect(current_url).to include('page=1')
end
end
end end
context "Search" do context "Search" do
@@ -759,6 +822,32 @@ feature 'Debates' do
end end
end end
scenario "Reorder by recommendations results maintaing search", :js do
Setting['feature.user.recommendations'] = true
user = create(:user)
login_as(user)
debate1 = create(:debate, title: "Show you got", cached_votes_total: 10, tag_list: "Sport")
debate2 = create(:debate, title: "Show what you got", cached_votes_total: 1, tag_list: "Sport")
debate3 = create(:debate, title: "Do not display with same tag", cached_votes_total: 100, tag_list: "Sport")
debate4 = create(:debate, title: "Do not display", cached_votes_total: 1)
proposal1 = create(:proposal, tag_list: "Sport")
create(:follow, followable: proposal1, user: user)
visit debates_path
fill_in "search", with: "Show you got"
click_button "Search"
click_link 'recommendations'
expect(page).to have_selector("a.active", text: "recommendations")
within("#debates") do
expect(all(".debate")[0].text).to match "Show you got"
expect(all(".debate")[1].text).to match "Show what you got"
expect(page).to_not have_content "Do not display with same tag"
expect(page).to_not have_content "Do not display"
end
Setting['feature.user.recommendations'] = nil
end
scenario 'After a search do not show featured debates' do scenario 'After a search do not show featured debates' do
featured_debates = create_featured_debates featured_debates = create_featured_debates
debate = create(:debate, title: "Abcdefghi") debate = create(:debate, title: "Abcdefghi")

View File

@@ -3,20 +3,143 @@ require 'rails_helper'
feature "Home" do feature "Home" do
feature "For not logged users" do feature "For not logged users" do
scenario 'Welcome message' do scenario 'Welcome message' do
visit root_path visit root_path
expect(page).to have_content "Love the city, and it will become a city you love" expect(page).to have_content "Love the city, and it will become a city you love"
end end
scenario 'Not display recommended section' do
debate = create(:debate)
visit root_path
expect(page).not_to have_content "Recommendations that may interest you"
end
end end
feature "For signed in users" do feature "For signed in users" do
scenario 'Redirect to proposals' do
login_as(create(:user)) before do
# user = create(:user)
# login_as(user)
end
feature "Recommended" do
background do
Setting['feature.user.recommendations'] = true
user = create(:user)
proposal = create(:proposal, tag_list: "Sport" )
create(:follow, followable: proposal, user: user)
login_as(user)
end
after do
Setting['feature.user.recommendations'] = nil
end
scenario 'Display recommended section' do
debate = create(:debate, tag_list: "Sport")
visit root_path
expect(page).to have_content "Recommendations that may interest you"
end
scenario 'Display recommended section when feature flag recommended is active' do
debate = create(:debate, tag_list: "Sport")
visit root_path
expect(page).to have_content "Recommendations that may interest you"
end
scenario 'Not display recommended section when feature flag recommended is not active' do
debate = create(:debate, tag_list: "Sport")
Setting['feature.user.recommendations'] = false
visit root_path visit root_path
expect(current_path).to eq proposals_path expect(page).not_to have_content "Recommendations that may interest you"
end end
scenario 'Display debates' do
debate = create(:debate, tag_list: "Sport")
visit root_path
expect(page).to have_content debate.title
expect(page).to have_content debate.description
end
scenario 'Display all recommended debates link' do
debate = create(:debate, tag_list: "Sport")
visit root_path
expect(page).to have_link("All recommended debates", href: debates_path(order: "recommendations"))
end
scenario 'Display proposal' do
proposal = create(:proposal, tag_list: "Sport")
visit root_path
expect(page).to have_content proposal.title
expect(page).to have_content proposal.description
end
scenario 'Display all recommended proposals link' do
debate = create(:proposal, tag_list: "Sport")
visit root_path
expect(page).to have_link("All recommended proposals", href: proposals_path(order: "recommendations"))
end
scenario 'Display orbit carrousel' do
create_list(:debate, 3, tag_list: "Sport")
visit root_path
expect(page).to have_selector('li[data-slide="0"]')
expect(page).to have_selector('li[data-slide="1"]', visible: false)
expect(page).to have_selector('li[data-slide="2"]', visible: false)
end
scenario 'Display recommended show when click on carousel' do
debate = create(:debate, tag_list: "Sport")
visit root_path
click_on debate.title
expect(current_path).to eq debate_path(debate)
end
scenario 'Do not display recommended section when there are not debates and proposals' do
visit root_path
expect(page).not_to have_content "Recommendations that may interest you"
end
feature 'Carousel size' do
scenario 'Display debates centered when there are no proposals' do
debate = create(:debate, tag_list: "Sport")
visit root_path
expect(page).to have_selector('.medium-centered.large-centered')
end
scenario 'Correct display debates and proposals' do
proposal = create(:proposal, tag_list: "Sport")
debates = create(:debate, tag_list: "Sport")
visit root_path
expect(page).to have_selector('.debates.medium-offset-2.large-offset-2')
expect(page).not_to have_selector('.proposals.medium-offset-2.large-offset-2')
expect(page).not_to have_selector('.debates.end')
expect(page).to have_selector('.proposals.end')
expect(page).not_to have_selector('.medium-centered.large-centered')
end
end
end
end end
feature 'IE alert' do feature 'IE alert' do

View File

@@ -11,7 +11,7 @@ feature 'Moderation' do
visit moderation_root_path visit moderation_root_path
expect(current_path).not_to eq(moderation_root_path) expect(current_path).not_to eq(moderation_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -25,7 +25,7 @@ feature 'Moderation' do
visit moderation_root_path visit moderation_root_path
expect(current_path).not_to eq(moderation_root_path) expect(current_path).not_to eq(moderation_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -39,7 +39,7 @@ feature 'Moderation' do
visit moderation_root_path visit moderation_root_path
expect(current_path).not_to eq(moderation_root_path) expect(current_path).not_to eq(moderation_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -53,7 +53,7 @@ feature 'Moderation' do
visit moderation_root_path visit moderation_root_path
expect(current_path).not_to eq(moderation_root_path) expect(current_path).not_to eq(moderation_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end

View File

@@ -15,16 +15,7 @@ feature "Notifications" do
let(:legislation_annotation) { create(:legislation_annotation, author: author) } let(:legislation_annotation) { create(:legislation_annotation, author: author) }
scenario "User commented on my debate", :js do scenario "User commented on my debate", :js do
login_as user create(:notification, notifiable: debate, user: author)
visit debate_path debate
fill_in "comment-body-debate_#{debate.id}", with: "I commented on your debate"
click_button "Publish comment"
within "#comments" do
expect(page).to have_content "I commented on your debate"
end
logout
login_as author login_as author
visit root_path visit root_path
@@ -37,17 +28,7 @@ feature "Notifications" do
end end
scenario "User commented on my legislation question", :js do scenario "User commented on my legislation question", :js do
verified_user = create(:user, :level_two) create(:notification, notifiable: legislation_question, user: administrator)
login_as verified_user
visit legislation_process_question_path legislation_question.process, legislation_question
fill_in "comment-body-legislation_question_#{legislation_question.id}", with: "I answered your question"
click_button "Publish answer"
within "#comments" do
expect(page).to have_content "I answered your question"
end
logout
login_as administrator login_as administrator
visit root_path visit root_path
@@ -82,6 +63,7 @@ feature "Notifications" do
logout logout
login_as author login_as author
visit root_path visit root_path
visit root_path
find(".icon-notification").click find(".icon-notification").click
@@ -107,8 +89,10 @@ feature "Notifications" do
end end
logout logout
login_as author login_as author
visit root_path visit root_path
visit root_path
find(".icon-notification").click find(".icon-notification").click
@@ -137,6 +121,7 @@ feature "Notifications" do
login_as author login_as author
visit root_path visit root_path
visit root_path
find(".icon-notification").click find(".icon-notification").click
@@ -208,6 +193,7 @@ feature "Notifications" do
logout logout
login_as user1 login_as user1
visit root_path visit root_path
visit root_path
find(".icon-notification").click find(".icon-notification").click
@@ -219,6 +205,7 @@ feature "Notifications" do
logout logout
login_as user2 login_as user2
visit root_path visit root_path
visit root_path
find(".icon-notification").click find(".icon-notification").click
@@ -230,6 +217,7 @@ feature "Notifications" do
logout logout
login_as user3 login_as user3
visit root_path visit root_path
visit root_path
find(".icon-no-notification").click find(".icon-no-notification").click

View File

@@ -11,7 +11,7 @@ feature 'Poll Officing' do
visit officing_root_path visit officing_root_path
expect(current_path).not_to eq(officing_root_path) expect(current_path).not_to eq(officing_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -24,7 +24,7 @@ feature 'Poll Officing' do
visit officing_root_path visit officing_root_path
expect(current_path).not_to eq(officing_root_path) expect(current_path).not_to eq(officing_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -37,7 +37,7 @@ feature 'Poll Officing' do
visit officing_root_path visit officing_root_path
expect(current_path).not_to eq(officing_root_path) expect(current_path).not_to eq(officing_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -50,7 +50,7 @@ feature 'Poll Officing' do
visit officing_root_path visit officing_root_path
expect(current_path).not_to eq(officing_root_path) expect(current_path).not_to eq(officing_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end

View File

@@ -189,7 +189,7 @@ feature 'Proposal Notifications' do
login_as(user) login_as(user)
visit new_proposal_notification_path(proposal_id: proposal.id) visit new_proposal_notification_path(proposal_id: proposal.id)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content("You do not have permission to carry out the action") expect(page).to have_content("You do not have permission to carry out the action")
end end

View File

@@ -556,7 +556,7 @@ feature 'Proposals' do
visit edit_proposal_path(proposal) visit edit_proposal_path(proposal)
expect(current_path).not_to eq(edit_proposal_path(proposal)) expect(current_path).not_to eq(edit_proposal_path(proposal))
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content 'You do not have permission' expect(page).to have_content 'You do not have permission'
end end
@@ -571,7 +571,7 @@ feature 'Proposals' do
visit edit_proposal_path(proposal) visit edit_proposal_path(proposal)
expect(current_path).not_to eq(edit_proposal_path(proposal)) expect(current_path).not_to eq(edit_proposal_path(proposal))
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content 'You do not have permission' expect(page).to have_content 'You do not have permission'
Setting["max_votes_for_proposal_edit"] = 1000 Setting["max_votes_for_proposal_edit"] = 1000
end end
@@ -663,6 +663,69 @@ feature 'Proposals' do
expect(current_url).to include('order=created_at') expect(current_url).to include('order=created_at')
expect(current_url).to include('page=1') expect(current_url).to include('page=1')
end end
context 'Recommendations' do
before do
Setting['feature.user.recommendations'] = true
create(:proposal, title: 'Best', cached_votes_up: 10, tag_list: "Sport")
create(:proposal, title: 'Medium', cached_votes_up: 5, tag_list: "Sport")
create(:proposal, title: 'Worst', cached_votes_up: 1, tag_list: "Sport")
end
after do
Setting['feature.user.recommendations'] = nil
end
scenario 'Proposals can not ordered by recommendations when there is not an user logged', :js do
visit proposals_path
expect(page).not_to have_selector('a', text: 'recommendations')
end
scenario 'Should display text when there are not recommendeds results', :js do
user = create(:user)
proposal = create(:proposal, tag_list: "Distinct_to_sport")
create(:follow, followable: proposal, user: user)
login_as(user)
visit proposals_path
click_link 'recommendations'
expect(page).to have_content "There are not proposals related to your interests"
end
scenario 'Should display text when user has not related interests', :js do
user = create(:user)
login_as(user)
visit proposals_path
click_link 'recommendations'
expect(page).to have_content "Follow proposals so we can give you recommendations"
end
scenario 'Proposals are ordered by recommendations when there is an user logged', :js do
user = create(:user)
proposal = create(:proposal, tag_list: "Sport")
create(:follow, followable: proposal, user: user)
login_as(user)
visit proposals_path
click_link 'recommendations'
expect(page).to have_selector('a.active', text: 'recommendations')
within '#proposals-list' do
expect('Best').to appear_before('Medium')
expect('Medium').to appear_before('Worst')
end
expect(current_url).to include('order=recommendations')
expect(current_url).to include('page=1')
end
end
end end
feature 'Archived proposals' do feature 'Archived proposals' do
@@ -1198,6 +1261,32 @@ feature 'Proposals' do
end end
end end
scenario "Reorder by recommendations results maintaing search", :js do
Setting['feature.user.recommendations'] = true
user = create(:user)
login_as(user)
proposal1 = create(:proposal, title: "Show you got", cached_votes_up: 10, tag_list: "Sport")
proposal2 = create(:proposal, title: "Show what you got", cached_votes_up: 1, tag_list: "Sport")
proposal3 = create(:proposal, title: "Do not display with same tag", cached_votes_up: 100, tag_list: "Sport")
proposal4 = create(:proposal, title: "Do not display", cached_votes_up: 1)
proposal5 = create(:proposal, tag_list: "Sport")
create(:follow, followable: proposal5, user: user)
visit proposals_path
fill_in "search", with: "Show you got"
click_button "Search"
click_link 'recommendations'
expect(page).to have_selector("a.active", text: "recommendations")
within("#proposals") do
expect(all(".proposal")[0].text).to match "Show you got"
expect(all(".proposal")[1].text).to match "Show what you got"
expect(page).to_not have_content "Do not display with same tag"
expect(page).to_not have_content "Do not display"
end
Setting['feature.user.recommendations'] = nil
end
scenario 'After a search do not show featured proposals' do scenario 'After a search do not show featured proposals' do
featured_proposals = create_featured_proposals featured_proposals = create_featured_proposals
proposal = create(:proposal, title: "Abcdefghi") proposal = create(:proposal, title: "Abcdefghi")

View File

@@ -21,7 +21,7 @@ feature 'Valuation' do
visit valuation_root_path visit valuation_root_path
expect(current_path).not_to eq(valuation_root_path) expect(current_path).not_to eq(valuation_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -34,7 +34,7 @@ feature 'Valuation' do
visit valuation_root_path visit valuation_root_path
expect(current_path).not_to eq(valuation_root_path) expect(current_path).not_to eq(valuation_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -47,7 +47,7 @@ feature 'Valuation' do
visit valuation_root_path visit valuation_root_path
expect(current_path).not_to eq(valuation_root_path) expect(current_path).not_to eq(valuation_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
@@ -60,7 +60,7 @@ feature 'Valuation' do
visit valuation_root_path visit valuation_root_path
expect(current_path).not_to eq(valuation_root_path) expect(current_path).not_to eq(valuation_root_path)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end

View File

@@ -33,7 +33,7 @@ feature "Welcome screen" do
login_through_form_as(user) login_through_form_as(user)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
end end
scenario 'is not shown to organizations' do scenario 'is not shown to organizations' do
@@ -41,7 +41,7 @@ feature "Welcome screen" do
login_through_form_as(organization.user) login_through_form_as(organization.user)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
end end
scenario 'it is not shown to level-2 users' do scenario 'it is not shown to level-2 users' do
@@ -49,7 +49,7 @@ feature "Welcome screen" do
login_through_form_as(user) login_through_form_as(user)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
end end
scenario 'it is not shown to level-3 users' do scenario 'it is not shown to level-3 users' do
@@ -57,7 +57,7 @@ feature "Welcome screen" do
login_through_form_as(user) login_through_form_as(user)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
end end
scenario 'is not shown to administrators' do scenario 'is not shown to administrators' do
@@ -65,7 +65,7 @@ feature "Welcome screen" do
login_through_form_as(administrator.user) login_through_form_as(administrator.user)
expect(current_path).to eq(proposals_path) expect(current_path).to eq(root_path)
end end
end end

View File

@@ -714,4 +714,53 @@ describe Debate do
end end
end end
describe "#recommendations" do
let(:user) { create(:user) }
it "Should not return any debates when user has not interests" do
create(:debate)
expect(Debate.recommendations(user).size).to eq 0
end
it "Should return debates ordered by cached_votes_total" do
debate1 = create(:debate, cached_votes_total: 1, tag_list: "Sport" )
debate2 = create(:debate, cached_votes_total: 5, tag_list: "Sport" )
debate3 = create(:debate, cached_votes_total: 10, tag_list: "Sport" )
proposal = create(:proposal, tag_list: "Sport" )
create(:follow, followable: proposal, user: user)
result = Debate.recommendations(user).sort_by_recommendations
expect(result.first).to eq debate3
expect(result.second).to eq debate2
expect(result.third).to eq debate1
end
it "Should return debates related with user interests" do
debate1 = create(:debate, tag_list: "Sport")
debate2 = create(:debate, tag_list: "Politics")
proposal1 = create(:proposal, tag_list: "Sport")
create(:follow, followable: proposal1, user: user)
result = Debate.recommendations(user)
expect(result.size).to eq 1
expect(result).to eq [debate1]
end
it "Should not return debates when user is the author" do
debate1 = create(:debate, author: user, tag_list: "Sport")
debate2 = create(:debate, tag_list: "Sport")
proposal = create(:proposal, tag_list: "Sport" )
create(:follow, followable: proposal, user: user)
result = Debate.recommendations(user)
expect(result.size).to eq 1
expect(result).to eq [debate2]
end
end
end end

View File

@@ -891,4 +891,63 @@ describe Proposal do
end end
end end
describe "#recommendations" do
let(:user) { create(:user) }
it "Should not return any proposals when user has not interests" do
create(:proposal)
expect(Proposal.recommendations(user).size).to eq 0
end
it "Should return proposals ordered by cached_votes_up" do
proposal1 = create(:proposal, cached_votes_up: 1, tag_list: "Sport" )
proposal2 = create(:proposal, cached_votes_up: 5, tag_list: "Sport" )
proposal3 = create(:proposal, cached_votes_up: 10, tag_list: "Sport" )
proposal4 = create(:proposal, tag_list: "Sport" )
create(:follow, followable: proposal4, user: user)
result = Proposal.recommendations(user).sort_by_recommendations
expect(result.first).to eq proposal3
expect(result.second).to eq proposal2
expect(result.third).to eq proposal1
end
it "Should return proposals related with user interests" do
proposal1 = create(:proposal, tag_list: "Sport")
proposal2 = create(:proposal, tag_list: "Sport")
proposal3 = create(:proposal, tag_list: "Politics")
create(:follow, followable: proposal1, user: user)
result = Proposal.recommendations(user)
expect(result.size).to eq 1
expect(result).to eq [proposal2]
end
it "Should not return proposals when user is follower" do
proposal1 = create(:proposal, tag_list: "Sport")
create(:follow, followable: proposal1, user: user)
result = Proposal.recommendations(user)
expect(result.size).to eq 0
end
it "Should not return proposals when user is the author" do
proposal1 = create(:proposal, author: user, tag_list: "Sport")
proposal2 = create(:proposal, tag_list: "Sport")
proposal3 = create(:proposal, tag_list: "Sport")
create(:follow, followable: proposal3, user: user)
result = Proposal.recommendations(user)
expect(result.size).to eq 1
expect(result).to eq [proposal2]
end
end
end end

View File

@@ -0,0 +1,43 @@
require "rails_helper"
RSpec.describe "welcome/index" do
it 'Display images on orbit carrousel when we have defined image_default' do
debate = create(:debate)
render template: "welcome/_recommended_carousel.html.erb",
locals: { key: "debates",
recommendeds: [debate],
image_field: nil,
image_version: nil,
image_default: "https://dummyimage.com/600x400/000/fff",
carousel_size: "medium-6 large-6 medium-centered large-centered",
btn_text_link: t("welcome.recommended.debates.btn_text_link"),
btn_path_link: debates_path(order: "recommendations")}
within 'li[data-slide="0"] .card' do
expect(page).to have_selector("img")
end
end
it 'Not display images on orbit carrousel when we have not defined image_default' do
debate = create(:debate)
render template: "welcome/_recommended_carousel.html.erb",
locals: { key: "debates",
recommendeds: [debate],
image_field: nil,
image_version: nil,
image_default: nil,
carousel_size: "medium-6 large-6 medium-centered large-centered",
btn_text_link: t("welcome.recommended.debates.btn_text_link"),
btn_path_link: debates_path(order: "recommendations")}
within 'li[data-slide="0"] .card' do
expect(page).not_to have_selector("img")
end
end
end