Merge pull request #1824 from rockandror/user-recomendations
User recomendations
This commit is contained in:
@@ -411,7 +411,7 @@ $maincontent-shadow: 0 0 10px rgba($black, 0.5);
|
||||
|
||||
$orbit-bullet-background: $medium-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-top: 0.8rem;
|
||||
$orbit-bullet-margin-bottom: 0.8rem;
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
// 16. Flags
|
||||
// 17. Activity
|
||||
// 18. Banners
|
||||
// 19. Documents
|
||||
// 19. Recommended Section Home
|
||||
// 20. Documents
|
||||
//
|
||||
|
||||
// 01. Global styles
|
||||
@@ -341,6 +342,14 @@ a {
|
||||
background: $brand;
|
||||
}
|
||||
|
||||
.truncate-horizontal-text {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-o-text-overflow: ellipsis;
|
||||
-ms-text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.align-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
@@ -612,7 +621,7 @@ header {
|
||||
text-align: left;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
margin-right: $line-height * 1.5;
|
||||
margin-right: rem-calc(24);
|
||||
}
|
||||
|
||||
&: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
|
||||
.documents-list {
|
||||
|
||||
@@ -2218,6 +2363,5 @@ table {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Table of Contents
|
||||
//
|
||||
// 01. Logo
|
||||
// 02. Orbit bullets
|
||||
//
|
||||
|
||||
// 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 {
|
||||
|
||||
.cached-image {
|
||||
@@ -96,4 +125,5 @@
|
||||
.loading-bar.no-transition {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,17 +4,22 @@ module CommentableActions
|
||||
include Search
|
||||
|
||||
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 = resource_model.all
|
||||
|
||||
@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.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?
|
||||
|
||||
@tag_cloud = tag_cloud
|
||||
@banners = Banner.with_active
|
||||
|
||||
set_resource_votes(@resources)
|
||||
|
||||
set_resources_instance
|
||||
end
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ class DebatesController < ApplicationController
|
||||
|
||||
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
|
||||
|
||||
load_and_authorize_resource
|
||||
|
||||
@@ -11,7 +11,7 @@ class NotificationsController < ApplicationController
|
||||
|
||||
def show
|
||||
@notification = current_user.notifications.find(params[:id])
|
||||
redirect_to url_for(@notification.linkable_resource)
|
||||
redirect_to linkable_resource_path(@notification)
|
||||
end
|
||||
|
||||
def mark_all_as_read
|
||||
@@ -25,4 +25,13 @@ class NotificationsController < ApplicationController
|
||||
@notification.mark_as_read
|
||||
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
|
||||
|
||||
@@ -9,7 +9,7 @@ class ProposalsController < ApplicationController
|
||||
|
||||
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
|
||||
|
||||
load_and_authorize_resource
|
||||
@@ -113,7 +113,7 @@ class ProposalsController < ApplicationController
|
||||
end
|
||||
|
||||
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)
|
||||
if @featured_proposals.present?
|
||||
set_featured_proposal_votes(@featured_proposals)
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
class WelcomeController < ApplicationController
|
||||
skip_authorization_check
|
||||
before_action :set_user_recommendations, only: :index, if: :current_user
|
||||
|
||||
layout "devise", only: [:welcome, :verification]
|
||||
|
||||
def index
|
||||
if current_user
|
||||
redirect_to :proposals
|
||||
end
|
||||
end
|
||||
|
||||
def welcome
|
||||
@@ -16,4 +14,11 @@ class WelcomeController < ApplicationController
|
||||
redirect_to verification_path if signed_in?
|
||||
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
|
||||
|
||||
@@ -4,4 +4,12 @@ module DebatesHelper
|
||||
Debate.all.featured.count > 0
|
||||
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
|
||||
@@ -32,6 +32,14 @@ module ProposalsHelper
|
||||
Proposal::RETIRE_OPTIONS.collect { |option| [ t("proposals.retire_options.#{option}"), option ] }
|
||||
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)
|
||||
author_of?(proposal, current_user)
|
||||
end
|
||||
|
||||
62
app/helpers/welcome_helper.rb
Normal file
62
app/helpers/welcome_helper.rb
Normal 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
|
||||
@@ -4,6 +4,10 @@ module Followable
|
||||
included do
|
||||
has_many :follows, as: :followable, dependent: :destroy
|
||||
has_many :followers, through: :follows, source: :user
|
||||
|
||||
scope :followed_by_user, -> (user){
|
||||
joins(:follows).where("follows.user_id = ?", user.id)
|
||||
}
|
||||
end
|
||||
|
||||
def followed_by?(user)
|
||||
|
||||
@@ -37,14 +37,21 @@ class Debate < 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 :sort_by_recommendations, -> { order(cached_votes_total: :desc) }
|
||||
scope :last_week, -> { where("created_at >= ?", 7.days.ago)}
|
||||
scope :featured, -> { where("featured_at is not null")}
|
||||
scope :public_for_api, -> { all }
|
||||
|
||||
# Ahoy setup
|
||||
visitable # Ahoy will automatically assign visit_id on create
|
||||
|
||||
attr_accessor :link_required
|
||||
|
||||
def self.recommendations(user)
|
||||
tagged_with(user.interests, any: true).
|
||||
where("author_id != ?", user.id)
|
||||
end
|
||||
|
||||
def searchable_values
|
||||
{ title => 'A',
|
||||
author.username => 'B',
|
||||
@@ -135,4 +142,9 @@ class Debate < ActiveRecord::Base
|
||||
featured_at.present?
|
||||
end
|
||||
|
||||
def self.debates_orders(user)
|
||||
orders = %w{hot_score confidence_score created_at relevance}
|
||||
orders << "recommendations" if user.present?
|
||||
orders
|
||||
end
|
||||
end
|
||||
|
||||
@@ -58,14 +58,27 @@ class Proposal < ActiveRecord::Base
|
||||
scope :sort_by_relevance, -> { all }
|
||||
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
||||
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 :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 :retired, -> { where.not(retired_at: nil) }
|
||||
scope :not_retired, -> { where(retired_at: nil) }
|
||||
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 }
|
||||
|
||||
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
|
||||
"#{id}-#{title}".parameterize
|
||||
end
|
||||
@@ -185,6 +198,12 @@ class Proposal < ActiveRecord::Base
|
||||
(voters + followers).uniq
|
||||
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
|
||||
|
||||
def set_responsible_name
|
||||
|
||||
@@ -88,12 +88,12 @@ class User < ActiveRecord::Base
|
||||
end
|
||||
|
||||
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 }
|
||||
end
|
||||
|
||||
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 }
|
||||
end
|
||||
|
||||
|
||||
@@ -54,7 +54,11 @@
|
||||
<%= link_to t("debates.index.start_debate"), new_debate_path, class: 'button expanded' %>
|
||||
</div>
|
||||
|
||||
<% if @debates.any? || current_user.blank? %>
|
||||
<%= render @debates %>
|
||||
<% else %>
|
||||
<%= empty_recommended_debates_message_text(current_user) %>
|
||||
<% end %>
|
||||
<%= paginate @debates %>
|
||||
|
||||
<% unless @search_terms || @advanced_search_terms || @tag_filter %>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
<%= setting['per_page_code_head'].try(:html_safe) %>
|
||||
</head>
|
||||
<body>
|
||||
<body class="<%= yield (:body_class) %>">
|
||||
<%= setting['per_page_code_body'].try(:html_safe) %>
|
||||
|
||||
<h1 class="show-for-sr"><%= setting['org_name'] %></h1>
|
||||
|
||||
@@ -68,7 +68,11 @@
|
||||
<% end %>
|
||||
|
||||
<div id="proposals-list">
|
||||
<% if @proposals.any? || current_user.blank? %>
|
||||
<%= render partial: 'proposals/proposal', collection: @proposals %>
|
||||
<% else %>
|
||||
<%= empty_recommended_proposals_message_text(current_user) %>
|
||||
<% end %>
|
||||
<%= paginate @proposals %>
|
||||
|
||||
<% unless @search_terms || @advanced_search_terms || @tag_filter %>
|
||||
|
||||
31
app/views/welcome/_recommended.html.erb
Normal file
31
app/views/welcome/_recommended.html.erb
Normal 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>
|
||||
42
app/views/welcome/_recommended_carousel.html.erb
Normal file
42
app/views/welcome/_recommended_carousel.html.erb
Normal 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>
|
||||
@@ -1,3 +1,5 @@
|
||||
<% content_for :body_class, "home-page" %>
|
||||
|
||||
<% content_for :canonical do %>
|
||||
<%= render "shared/canonical", href: root_url %>
|
||||
<% end %>
|
||||
@@ -16,37 +18,35 @@
|
||||
</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 %>
|
||||
<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 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 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>
|
||||
<% end %>
|
||||
|
||||
@@ -109,6 +109,10 @@ en:
|
||||
hot_score: most active
|
||||
most_commented: most commented
|
||||
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:
|
||||
button: Search
|
||||
placeholder: Search debates...
|
||||
@@ -348,6 +352,10 @@ en:
|
||||
most_commented: most commented
|
||||
relevance: relevance
|
||||
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_link: "Proposals retired by the author"
|
||||
retired_links:
|
||||
@@ -753,6 +761,16 @@ en:
|
||||
proposal:
|
||||
description: Open space for citizen proposals about the kind of city we want to live in.
|
||||
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:
|
||||
i_dont_have_an_account: I don't have an account
|
||||
i_have_an_account: I already have an account
|
||||
|
||||
@@ -39,6 +39,8 @@ en:
|
||||
spending_proposal_features:
|
||||
voting_allowed: Voting on investment projects
|
||||
legislation: Legislation
|
||||
user:
|
||||
recommendations: Recommendeds
|
||||
community: Community on proposals and investments
|
||||
map: Proposals and budget investments geolocation
|
||||
map_latitude: Latitude
|
||||
|
||||
@@ -109,6 +109,10 @@ es:
|
||||
hot_score: Más activos hoy
|
||||
most_commented: Más comentados
|
||||
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:
|
||||
button: Buscar
|
||||
placeholder: Buscar debates...
|
||||
@@ -348,6 +352,10 @@ es:
|
||||
most_commented: Más comentadas
|
||||
relevance: Más relevantes
|
||||
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_link: "Propuestas retiradas por sus autores"
|
||||
retired_links:
|
||||
@@ -753,6 +761,16 @@ es:
|
||||
proposal:
|
||||
description: Espacio abierto para propuestas ciudadanas sobre el tipo de ciudad en el que queremos vivir.
|
||||
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:
|
||||
i_dont_have_an_account: No tengo cuenta, quiero crear una y verificarla
|
||||
i_have_an_account: Ya tengo una cuenta que quiero verificar
|
||||
|
||||
@@ -39,6 +39,8 @@ es:
|
||||
spending_proposal_features:
|
||||
voting_allowed: Votaciones sobre propuestas de inversión
|
||||
legislation: Legislación
|
||||
user:
|
||||
recommendations: Recomendaciones
|
||||
community: Comunidad en propuestas y proyectos de inversión
|
||||
map: Geolocalización de propuestas y proyectos de inversión
|
||||
map_latitude: Latitud
|
||||
|
||||
@@ -36,6 +36,7 @@ Setting.create(key: 'feature.facebook_login', value: "true")
|
||||
Setting.create(key: 'feature.google_login', value: "true")
|
||||
Setting.create(key: 'feature.signature_sheets', 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.map', value: "true")
|
||||
Setting.create(key: 'per_page_code_head', value: "")
|
||||
|
||||
@@ -79,6 +79,7 @@ Setting['feature.public_stats'] = true
|
||||
Setting['feature.budgets'] = true
|
||||
Setting['feature.signature_sheets'] = true
|
||||
Setting['feature.legislation'] = true
|
||||
Setting['feature.user.recommendations'] = true
|
||||
Setting['feature.community'] = true
|
||||
Setting['feature.map'] = nil
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ feature 'Admin' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -22,7 +22,7 @@ feature 'Admin' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -32,7 +32,7 @@ feature 'Admin' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -42,7 +42,7 @@ feature 'Admin' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -52,7 +52,7 @@ feature 'Admin' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ feature 'Debates' do
|
||||
|
||||
visit 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."
|
||||
end
|
||||
|
||||
@@ -234,7 +234,7 @@ feature 'Debates' do
|
||||
visit 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'
|
||||
end
|
||||
|
||||
@@ -351,6 +351,69 @@ feature 'Debates' do
|
||||
expect(current_url).to include('order=created_at')
|
||||
expect(current_url).to include('page=1')
|
||||
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
|
||||
|
||||
context "Search" do
|
||||
@@ -759,6 +822,32 @@ feature 'Debates' do
|
||||
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
|
||||
featured_debates = create_featured_debates
|
||||
debate = create(:debate, title: "Abcdefghi")
|
||||
|
||||
@@ -3,20 +3,143 @@ require 'rails_helper'
|
||||
feature "Home" do
|
||||
|
||||
feature "For not logged users" do
|
||||
|
||||
scenario 'Welcome message' do
|
||||
visit root_path
|
||||
|
||||
expect(page).to have_content "Love the city, and it will become a city you love"
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
expect(current_path).to eq proposals_path
|
||||
expect(page).not_to have_content "Recommendations that may interest you"
|
||||
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
|
||||
|
||||
feature 'IE alert' do
|
||||
|
||||
@@ -11,7 +11,7 @@ feature 'Moderation' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -25,7 +25,7 @@ feature 'Moderation' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -39,7 +39,7 @@ feature 'Moderation' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -53,7 +53,7 @@ feature 'Moderation' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
|
||||
@@ -15,16 +15,7 @@ feature "Notifications" do
|
||||
let(:legislation_annotation) { create(:legislation_annotation, author: author) }
|
||||
|
||||
scenario "User commented on my debate", :js do
|
||||
login_as user
|
||||
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
|
||||
create(:notification, notifiable: debate, user: author)
|
||||
login_as author
|
||||
visit root_path
|
||||
|
||||
@@ -37,17 +28,7 @@ feature "Notifications" do
|
||||
end
|
||||
|
||||
scenario "User commented on my legislation question", :js do
|
||||
verified_user = create(:user, :level_two)
|
||||
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
|
||||
create(:notification, notifiable: legislation_question, user: administrator)
|
||||
login_as administrator
|
||||
visit root_path
|
||||
|
||||
@@ -82,6 +63,7 @@ feature "Notifications" do
|
||||
logout
|
||||
login_as author
|
||||
visit root_path
|
||||
visit root_path
|
||||
|
||||
find(".icon-notification").click
|
||||
|
||||
@@ -107,8 +89,10 @@ feature "Notifications" do
|
||||
end
|
||||
|
||||
logout
|
||||
|
||||
login_as author
|
||||
visit root_path
|
||||
visit root_path
|
||||
|
||||
find(".icon-notification").click
|
||||
|
||||
@@ -137,6 +121,7 @@ feature "Notifications" do
|
||||
|
||||
login_as author
|
||||
visit root_path
|
||||
visit root_path
|
||||
|
||||
find(".icon-notification").click
|
||||
|
||||
@@ -208,6 +193,7 @@ feature "Notifications" do
|
||||
logout
|
||||
login_as user1
|
||||
visit root_path
|
||||
visit root_path
|
||||
|
||||
find(".icon-notification").click
|
||||
|
||||
@@ -219,6 +205,7 @@ feature "Notifications" do
|
||||
logout
|
||||
login_as user2
|
||||
visit root_path
|
||||
visit root_path
|
||||
|
||||
find(".icon-notification").click
|
||||
|
||||
@@ -230,6 +217,7 @@ feature "Notifications" do
|
||||
logout
|
||||
login_as user3
|
||||
visit root_path
|
||||
visit root_path
|
||||
|
||||
find(".icon-no-notification").click
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ feature 'Poll Officing' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -24,7 +24,7 @@ feature 'Poll Officing' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -37,7 +37,7 @@ feature 'Poll Officing' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -50,7 +50,7 @@ feature 'Poll Officing' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ feature 'Proposal Notifications' do
|
||||
login_as(user)
|
||||
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")
|
||||
end
|
||||
|
||||
|
||||
@@ -556,7 +556,7 @@ feature 'Proposals' do
|
||||
|
||||
visit 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'
|
||||
end
|
||||
|
||||
@@ -571,7 +571,7 @@ feature 'Proposals' do
|
||||
visit 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'
|
||||
Setting["max_votes_for_proposal_edit"] = 1000
|
||||
end
|
||||
@@ -663,6 +663,69 @@ feature 'Proposals' do
|
||||
expect(current_url).to include('order=created_at')
|
||||
expect(current_url).to include('page=1')
|
||||
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
|
||||
|
||||
feature 'Archived proposals' do
|
||||
@@ -1198,6 +1261,32 @@ feature 'Proposals' do
|
||||
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
|
||||
featured_proposals = create_featured_proposals
|
||||
proposal = create(:proposal, title: "Abcdefghi")
|
||||
|
||||
@@ -21,7 +21,7 @@ feature 'Valuation' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -34,7 +34,7 @@ feature 'Valuation' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -47,7 +47,7 @@ feature 'Valuation' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
@@ -60,7 +60,7 @@ feature 'Valuation' do
|
||||
visit 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"
|
||||
end
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ feature "Welcome screen" do
|
||||
|
||||
login_through_form_as(user)
|
||||
|
||||
expect(current_path).to eq(proposals_path)
|
||||
expect(current_path).to eq(root_path)
|
||||
end
|
||||
|
||||
scenario 'is not shown to organizations' do
|
||||
@@ -41,7 +41,7 @@ feature "Welcome screen" do
|
||||
|
||||
login_through_form_as(organization.user)
|
||||
|
||||
expect(current_path).to eq(proposals_path)
|
||||
expect(current_path).to eq(root_path)
|
||||
end
|
||||
|
||||
scenario 'it is not shown to level-2 users' do
|
||||
@@ -49,7 +49,7 @@ feature "Welcome screen" do
|
||||
|
||||
login_through_form_as(user)
|
||||
|
||||
expect(current_path).to eq(proposals_path)
|
||||
expect(current_path).to eq(root_path)
|
||||
end
|
||||
|
||||
scenario 'it is not shown to level-3 users' do
|
||||
@@ -57,7 +57,7 @@ feature "Welcome screen" do
|
||||
|
||||
login_through_form_as(user)
|
||||
|
||||
expect(current_path).to eq(proposals_path)
|
||||
expect(current_path).to eq(root_path)
|
||||
end
|
||||
|
||||
scenario 'is not shown to administrators' do
|
||||
@@ -65,7 +65,7 @@ feature "Welcome screen" do
|
||||
|
||||
login_through_form_as(administrator.user)
|
||||
|
||||
expect(current_path).to eq(proposals_path)
|
||||
expect(current_path).to eq(root_path)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -714,4 +714,53 @@ describe Debate do
|
||||
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
|
||||
|
||||
@@ -891,4 +891,63 @@ describe Proposal do
|
||||
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
|
||||
|
||||
43
spec/views/welcome/index.html.erb_spec.rb
Normal file
43
spec/views/welcome/index.html.erb_spec.rb
Normal 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
|
||||
Reference in New Issue
Block a user