Merge pull request #3567 from consul/select_proposals_by_admins

Make proposals to be selected by administrators
This commit is contained in:
Julian Nicolas Herrero
2019-05-31 15:30:39 +02:00
committed by GitHub
34 changed files with 450 additions and 123 deletions

View File

@@ -6,8 +6,22 @@ class Admin::ProposalsController < Admin::BaseController
has_orders %w[created_at] has_orders %w[created_at]
before_action :load_proposal, except: :index
def show def show
@proposal = Proposal.find(params[:id]) end
def update
if @proposal.update(proposal_params)
redirect_to admin_proposal_path(@proposal), notice: t("admin.proposals.update.notice")
else
render :show
end
end
def toggle_selection
@proposal.toggle :selected
@proposal.save!
end end
private private
@@ -15,4 +29,13 @@ class Admin::ProposalsController < Admin::BaseController
def resource_model def resource_model
Proposal Proposal
end end
def load_proposal
@proposal = Proposal.find(params[:id])
end
def proposal_params
params.require(:proposal).permit(:selected)
end
end end

View File

@@ -51,7 +51,9 @@ class ProposalsController < ApplicationController
discard_draft discard_draft
discard_archived discard_archived
load_retired load_retired
load_selected
load_featured load_featured
remove_archived_from_order_links
end end
def vote def vote
@@ -127,7 +129,9 @@ class ProposalsController < ApplicationController
end end
def discard_archived def discard_archived
@resources = @resources.not_archived unless @current_order == "archival_date" unless @current_order == "archival_date" || params[:selected].present?
@resources = @resources.not_archived
end
end end
def load_retired def load_retired
@@ -139,6 +143,14 @@ class ProposalsController < ApplicationController
end end
end end
def load_selected
if params[:selected].present?
@resources = @resources.selected
else
@resources = @resources.not_selected
end
end
def load_featured def load_featured
return unless !@advanced_search_terms && @search_terms.blank? && @tag_filter.blank? && params[:retired].blank? && @current_order != "recommendations" return unless !@advanced_search_terms && @search_terms.blank? && @tag_filter.blank? && params[:retired].blank? && @current_order != "recommendations"
if Setting["feature.featured_proposals"] if Setting["feature.featured_proposals"]
@@ -151,6 +163,10 @@ class ProposalsController < ApplicationController
end end
end end
def remove_archived_from_order_links
@valid_orders.delete("archival_date")
end
def set_view def set_view
@view = (params[:view] == "minimal") ? "minimal" : "default" @view = (params[:view] == "minimal") ? "minimal" : "default"
end end

View File

@@ -11,22 +11,6 @@ module LegislationHelper
t("proposals.index.start_proposal") t("proposals.index.start_proposal")
end end
def link_to_toggle_legislation_proposal_selection(proposal)
if proposal.selected?
button_text = t("admin.legislation.proposals.index.selected")
html_class = "button expanded"
else
button_text = t("admin.legislation.proposals.index.select")
html_class = "button hollow expanded"
end
link_to button_text,
toggle_selection_admin_legislation_process_proposal_path(proposal.process, proposal),
remote: true,
method: :patch,
class: html_class
end
def legislation_process_tabs(process) def legislation_process_tabs(process)
{ {
"info" => edit_admin_legislation_process_path(process), "info" => edit_admin_legislation_process_path(process),

View File

@@ -64,4 +64,50 @@ module ProposalsHelper
proposals_current_view == "default" ? "minimal" : "default" proposals_current_view == "default" ? "minimal" : "default"
end end
def link_to_toggle_proposal_selection(proposal)
if proposal.selected?
button_text = t("admin.proposals.index.selected")
html_class = "button expanded"
else
button_text = t("admin.proposals.index.select")
html_class = "button hollow expanded"
end
case proposal.class.to_s
when "Proposal"
path = toggle_selection_admin_proposal_path(proposal)
when "Legislation::Proposal"
path = toggle_selection_admin_legislation_process_proposal_path(proposal.process, proposal)
end
link_to button_text, path, remote: true, method: :patch, class: html_class
end
def css_for_proposal_info_row(proposal)
if proposal.image.present?
if params[:selected].present?
"small-12 medium-9 column"
else
"small-12 medium-6 large-7 column"
end
else
if params[:selected].present?
"small-12 column"
else
"small-12 medium-9 column"
end
end
end
def show_proposal_votes?
params[:selected].blank?
end
def show_featured_proposals?
params[:selected].blank? && @featured_proposals.present?
end
def show_recommended_proposals?
params[:selected].blank? && feature?("user.recommendations") && @recommended_proposals.present?
end
end end

View File

@@ -74,6 +74,8 @@ class Proposal < ApplicationRecord
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 :unsuccessful, -> { where("cached_votes_up < ?", Proposal.votes_needed_for_success) }
scope :public_for_api, -> { all } scope :public_for_api, -> { all }
scope :selected, -> { where(selected: true) }
scope :not_selected, -> { where(selected: false) }
scope :not_supported_by_user, ->(user) { where.not(id: user.find_voted_items(votable_type: "Proposal").compact.map(&:id)) } scope :not_supported_by_user, ->(user) { where.not(id: user.find_voted_items(votable_type: "Proposal").compact.map(&:id)) }
scope :published, -> { where.not(published_at: nil) } scope :published, -> { where.not(published_at: nil) }
scope :draft, -> { where(published_at: nil) } scope :draft, -> { where(published_at: nil) }

View File

@@ -9,7 +9,7 @@
<th class="text-center"><%= t("admin.legislation.proposals.index.id") %></th> <th class="text-center"><%= t("admin.legislation.proposals.index.id") %></th>
<th><%= t("admin.legislation.proposals.index.title") %></th> <th><%= t("admin.legislation.proposals.index.title") %></th>
<th class="text-center"><%= t("admin.legislation.proposals.index.supports") %></th> <th class="text-center"><%= t("admin.legislation.proposals.index.supports") %></th>
<th><%= t("admin.legislation.proposals.index.selected") %></th> <th><%= t("admin.proposals.index.selected") %></th>
</tr> </tr>
</thead> </thead>

View File

@@ -1 +1 @@
<%= link_to_toggle_legislation_proposal_selection(proposal) %> <%= link_to_toggle_proposal_selection(proposal) %>

View File

@@ -0,0 +1,9 @@
<%= form_for [:admin, @proposal] do |f| %>
<%= render "shared/errors", resource: @proposal %>
<%= f.check_box :selected %>
<%= f.submit t("admin.proposals.form.update"), class: "button success" %>
<% end %>

View File

@@ -0,0 +1 @@
<%= link_to_toggle_proposal_selection(proposal) %>

View File

@@ -16,6 +16,7 @@
<th><%= t("admin.proposals.index.title") %></th> <th><%= t("admin.proposals.index.title") %></th>
<th><%= t("admin.proposals.index.author") %></th> <th><%= t("admin.proposals.index.author") %></th>
<th><%= t("admin.proposals.index.milestones") %></th> <th><%= t("admin.proposals.index.milestones") %></th>
<th><%= t("admin.proposals.index.selected") %></th>
</tr> </tr>
</thead> </thead>
@@ -26,6 +27,7 @@
<td><%= link_to proposal.title, admin_proposal_path(proposal) %></td> <td><%= link_to proposal.title, admin_proposal_path(proposal) %></td>
<td><%= proposal.author.username %></td> <td><%= proposal.author.username %></td>
<td><%= proposal.milestones.count %></td> <td><%= proposal.milestones.count %></td>
<td class="js-select"><%= render "select_proposal", proposal: proposal %></td>
</tr> </tr>
<% end %> <% end %>
</tbody> </tbody>

View File

@@ -26,4 +26,10 @@
<%= render "proposals/info", proposal: @proposal %> <%= render "proposals/info", proposal: @proposal %>
</div> </div>
<div class="small-12 column">
<hr>
<%= render "form" %>
<hr>
</div>
<%= render "admin/milestones/milestones", milestoneable: @proposal %> <%= render "admin/milestones/milestones", milestoneable: @proposal %>

View File

@@ -0,0 +1 @@
$("#<%= dom_id(@proposal) %> .js-select").html('<%= j render("select_proposal", proposal: @proposal) %>');

View File

@@ -1,6 +0,0 @@
<div class="sidebar-divider"></div>
<h2 class="sidebar-title"><%= t("proposals.index.top") %></h2>
<p>
<%= link_to t("proposals.index.top_link_proposals"), summary_proposals_path, class: "small" %><br>
</p>

View File

@@ -12,10 +12,10 @@
alt: proposal.image.title.unicode_normalize %> alt: proposal.image.title.unicode_normalize %>
</div> </div>
<div class="small-12 medium-6 large-7 column"> <div class="<%= css_for_proposal_info_row(proposal) %>">
<% else %> <% else %>
<div class="row"> <div class="row">
<div class="small-12 medium-9 column"> <div class="<%= css_for_proposal_info_row(proposal) %>">
<% end %> <% end %>
<div class="proposal-content"> <div class="proposal-content">
<% cache [locale_and_user_status(proposal), "index", proposal, proposal.author] do %> <% cache [locale_and_user_status(proposal), "index", proposal, proposal.author] do %>
@@ -62,13 +62,14 @@
</div> </div>
</div> </div>
<% if show_proposal_votes? %>
<div id="<%= dom_id(proposal) %>_votes" <div id="<%= dom_id(proposal) %>_votes"
class="small-12 medium-3 column supports-container"> class="small-12 medium-3 column supports-container">
<% if proposal.successful? %> <% if proposal.successful? %>
<div class="padding text-center"> <div class="padding">
<p> <div class="supports text-center">
<%= t("proposals.proposal.successful") %> <%= render "proposals/supports", proposal: proposal %>
</p> </div>
</div> </div>
<% elsif proposal.archived? %> <% elsif proposal.archived? %>
<div class="padding text-center"> <div class="padding text-center">
@@ -80,6 +81,8 @@
{ proposal: proposal, vote_url: vote_proposal_path(proposal, value: "yes") } %> { proposal: proposal, vote_url: vote_proposal_path(proposal, value: "yes") } %>
<% end %> <% end %>
</div> </div>
<% end %>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,16 @@
<div class="sidebar-divider"></div>
<h2 class="sidebar-title"><%= t("proposals.index.proposals_lists") %></h2>
<p>
<%= link_to t("proposals.index.top_link_proposals"),
summary_proposals_path,
class: "small" %>
<br>
<%= link_to t("proposals.index.archived_proposals"),
proposals_path(order: "archival_date"),
class: "small" %>
<br>
<%= link_to t("proposals.index.retired_proposals_link"),
proposals_path(retired: "all"),
class: "small" %>
</p>

View File

@@ -1,9 +1,7 @@
<div class="sidebar-divider"></div> <% if params[:retired].present? %>
<h2 class="sidebar-title"><%= t("proposals.index.retired_proposals") %></h2> <div class="sidebar-divider"></div>
<h2 class="sidebar-title"><%= t("proposals.index.retired_proposals") %></h2>
<% if params[:retired].blank? %>
<p><%= link_to t("proposals.index.retired_proposals_link"), proposals_path(retired: "all"), class: "small" %></p>
<% else %>
<div class="sidebar-links"> <div class="sidebar-links">
<%= link_to t("proposals.index.retired_links.all"), proposals_path(retired: "all") %> <%= link_to t("proposals.index.retired_links.all"), proposals_path(retired: "all") %>
<% Proposal::RETIRE_OPTIONS.each do |option| %> <% Proposal::RETIRE_OPTIONS.each do |option| %>

View File

@@ -0,0 +1,16 @@
<div class="progress small-12 round">
<span class="meter" style="width: <%= progress_bar_percentage(proposal) %>%;"></span>
<span class="percentage">
<%= supports_percentage(proposal) %>&nbsp;/&nbsp;<%= t("proposals.proposal.total_percent") %>
</span>
</div>
<span class="total-supports">
<%= t("proposals.proposal.supports", count: proposal.total_votes) %>&nbsp;
<span>
<abbr title="<%= t("proposals.proposal.reason_for_supports_necessary") %>">
<%= t("proposals.proposal.supports_necessary",
number: number_with_delimiter(Proposal.votes_needed_for_success)) %>
</abbr>
</span>
</span>

View File

@@ -1,20 +1,5 @@
<div class="supports text-center"> <div class="supports text-center">
<div class="progress small-12 round"> <%= render "proposals/supports", proposal: proposal %>
<span class="meter" style="width: <%= progress_bar_percentage(proposal) %>%;"></span>
<span class="percentage">
<%= supports_percentage(proposal) %>&nbsp;/&nbsp;<%= t("proposals.proposal.total_percent") %>
</span>
</div>
<span class="total-supports">
<%= t("proposals.proposal.supports", count: proposal.total_votes) %>&nbsp;
<span>
<abbr>
<%= t("proposals.proposal.supports_necessary",
number: number_with_delimiter(Proposal.votes_needed_for_success)) %>
</abbr>
</span>
</span>
<div class="in-favor"> <div class="in-favor">
<% if voted_for?(@proposal_votes, proposal) %> <% if voted_for?(@proposal_votes, proposal) %>

View File

@@ -9,7 +9,13 @@
<% end %> <% end %>
<main> <main>
<% if @search_terms || @advanced_search_terms || @tag_filter || params[:retired].present? %> <% if [
@search_terms,
@advanced_search_terms,
@tag_filter,
params[:retired].present?,
params[:selected].present?
].any? %>
<div class="highlight no-margin-top padding margin-bottom"> <div class="highlight no-margin-top padding margin-bottom">
<div class="row"> <div class="row">
<div class="small-12 column"> <div class="small-12 column">
@@ -29,6 +35,8 @@
</p> </p>
<% elsif params[:retired].present? %> <% elsif params[:retired].present? %>
<h2><%= t("proposals.index.retired_proposals") %></h2> <h2><%= t("proposals.index.retired_proposals") %></h2>
<% elsif params[:selected].present? %>
<h2><%= t("proposals.index.selected_proposals") %></h2>
<% end %> <% end %>
</div> </div>
</div> </div>
@@ -37,7 +45,7 @@
<%= render "shared/section_header", i18n_namespace: "proposals.index.section_header", image: "proposals" %> <%= render "shared/section_header", i18n_namespace: "proposals.index.section_header", image: "proposals" %>
<% end %> <% end %>
<% if feature?("user.recommendations") && @recommended_proposals.present? %> <% if show_recommended_proposals? %>
<%= render "shared/recommended_index", recommended: @recommended_proposals, <%= render "shared/recommended_index", recommended: @recommended_proposals,
disable_recommendations_path: recommendations_disable_proposals_path, disable_recommendations_path: recommendations_disable_proposals_path,
namespace: "proposals" %> namespace: "proposals" %>
@@ -50,7 +58,7 @@
<%= render "shared/banner" %> <%= render "shared/banner" %>
<% end %> <% end %>
<% if @featured_proposals.present? %> <% if show_featured_proposals? %>
<div id="featured-proposals" class="row featured-proposals"> <div id="featured-proposals" class="row featured-proposals">
<div class="small-12 column"> <div class="small-12 column">
<h2> <h2>
@@ -69,9 +77,14 @@
</div> </div>
</div> </div>
<%= render("shared/advanced_search", search_path: proposals_path(page: 1)) unless params[:retired].present? %> <% unless params[:retired].present? || params[:selected].present? %>
<%= render "shared/advanced_search",
search_path: proposals_path(page: 1) %>
<% end %>
<% unless params[:selected].present? %>
<%= render "shared/order_links", i18n_namespace: "proposals.index" %> <%= render "shared/order_links", i18n_namespace: "proposals.index" %>
<% end %>
<% if @proposals.any? %> <% if @proposals.any? %>
<div class="show-for-small-only"> <div class="show-for-small-only">
@@ -111,13 +124,21 @@
<%= link_to t("proposals.index.start_proposal"), <%= link_to t("proposals.index.start_proposal"),
new_proposal_path, new_proposal_path,
class: "button expanded" %> class: "button expanded" %>
<div class="sidebar-divider"></div>
<h2 class="sidebar-title"><%= t("proposals.index.selected_proposals") %></h2>
<br>
<p class="small">
<%= link_to t("proposals.index.selected_proposals_link"), proposals_path(selected: "all") %>
</p>
<% if params[:retired].blank? %> <% if params[:retired].blank? %>
<%= render "categories" %> <%= render "categories" %>
<%= render "shared/tag_cloud", taggable: "proposal" %> <%= render "shared/tag_cloud", taggable: "proposal" %>
<%= render "geozones" %> <%= render "geozones" %>
<%= render "popular" %>
<% end %> <% end %>
<%= render "retired" %> <%= render "retired" %>
<%= render "proposals_lists" %>
</aside> </aside>
</div> </div>

View File

@@ -62,6 +62,11 @@
</div> </div>
<% end %> <% end %>
<% if @proposal.selected? %>
<div class="callout success">
<strong><%= t("proposals.proposal.selected") %></strong>
</div>
<% else %>
<div id="proposal_sticky" data-sticky-container> <div id="proposal_sticky" data-sticky-container>
<div class="sticky fixed-mobile-content" <div class="sticky fixed-mobile-content"
data-sticky data-sticky
@@ -77,12 +82,12 @@
<div id="<%= dom_id(@proposal) %>_votes"> <div id="<%= dom_id(@proposal) %>_votes">
<% if @proposal.draft? %> <% if @proposal.draft? %>
<div class="callout primary"> <div class="callout primary">
<p class=text-center><strong><%= t('.draft') %></strong></p> <p class=text-center><strong><%= t(".draft") %></strong></p>
</div> </div>
<% elsif @proposal.successful? %> <% elsif @proposal.successful? %>
<p> <div class="supports text-center">
<%= t("proposals.proposal.successful") %> <%= render "supports", proposal: @proposal %>
</p> </div>
<% elsif @proposal.archived? %> <% elsif @proposal.archived? %>
<div class="padding text-center"> <div class="padding text-center">
<p> <p>
@@ -100,6 +105,7 @@
</div> </div>
<div id="sticky_stop"></div> <div id="sticky_stop"></div>
<% end %>
<%= render "proposals/social_share", proposal: @proposal, share_title: t("proposals.show.share") %> <%= render "proposals/social_share", proposal: @proposal, share_title: t("proposals.show.share") %>

View File

@@ -187,6 +187,7 @@ en:
title: "Title" title: "Title"
question: "Question" question: "Question"
description: "Description" description: "Description"
selected: "Mark as selected"
terms_of_service: "Terms of service" terms_of_service: "Terms of service"
user: user:
login: "Email or username" login: "Email or username"

View File

@@ -556,8 +556,6 @@ en:
id: Id id: Id
title: Title title: Title
supports: Total supports supports: Total supports
select: Select
selected: Selected
form: form:
custom_categories: Categories custom_categories: Categories
custom_categories_description: Categories that users can select creating the proposal. Max 160 characteres. custom_categories_description: Categories that users can select creating the proposal. Max 160 characteres.
@@ -1239,10 +1237,16 @@ en:
title: Proposals title: Proposals
id: ID id: ID
author: Author author: Author
select: Select
selected: Selected
milestones: Milestones milestones: Milestones
no_proposals: There are no proposals. no_proposals: There are no proposals.
show: show:
create_question: Add this proposal to a poll to be voted create_question: Add this proposal to a poll to be voted
form:
update: Update proposal
update:
notice: Proposal updated successfully
hidden_proposals: hidden_proposals:
index: index:
filter: Filter filter: Filter

View File

@@ -376,6 +376,10 @@ en:
error: "An error has occured. Please go to 'My account' page to manually disable recommendations for proposals" error: "An error has occured. Please go to 'My account' page to manually disable recommendations for proposals"
retired_proposals: Retired proposals retired_proposals: Retired proposals
retired_proposals_link: "Proposals retired by the author" retired_proposals_link: "Proposals retired by the author"
selected_proposals: Selected proposals
selected_proposals_link: View selected proposals
archived_proposals: Archived proposals
proposals_lists: Proposals lists
retired_links: retired_links:
all: All all: All
duplicated: Duplicated duplicated: Duplicated
@@ -437,9 +441,11 @@ en:
other: "%{count} votes" other: "%{count} votes"
zero: No votes zero: No votes
supports_necessary: "%{number} supports needed" supports_necessary: "%{number} supports needed"
reason_for_supports_necessary: ""
total_percent: 100% total_percent: 100%
archived: "This proposal has been archived and can't collect supports." archived: "This proposal has been archived and can't collect supports."
successful: "This proposal has reached the required supports." successful: "This proposal has reached the required supports."
selected: "Selected proposal"
show: show:
author_deleted: User deleted author_deleted: User deleted
code: "Proposal code:" code: "Proposal code:"

View File

@@ -187,6 +187,7 @@ es:
title: "Título" title: "Título"
question: "Pregunta" question: "Pregunta"
description: "Descripción" description: "Descripción"
selected: "Marcar como seleccionada"
terms_of_service: "Términos de servicio" terms_of_service: "Términos de servicio"
user: user:
login: "Email o nombre de usuario" login: "Email o nombre de usuario"

View File

@@ -555,8 +555,6 @@ es:
back: Volver back: Volver
id: Id id: Id
supports: Apoyos totales supports: Apoyos totales
select: Seleccionar
selected: Seleccionada
form: form:
custom_categories: Categorías custom_categories: Categorías
custom_categories_description: Categorías que el usuario puede seleccionar al crear la propuesta. Máximo 160 caracteres. custom_categories_description: Categorías que el usuario puede seleccionar al crear la propuesta. Máximo 160 caracteres.
@@ -1239,9 +1237,15 @@ es:
id: ID id: ID
author: Autor author: Autor
milestones: Hitos milestones: Hitos
select: Seleccionar
selected: Seleccionada
no_proposals: No hay propuestas. no_proposals: No hay propuestas.
show: show:
create_question: Añadir esta propuesta a una votación para ser votada create_question: Añadir esta propuesta a una votación para ser votada
form:
update: Actualizar propuesta ciudadana
update:
notice: Propuesta actualizada correctamente
hidden_proposals: hidden_proposals:
index: index:
filter: Filtro filter: Filtro

View File

@@ -376,6 +376,10 @@ es:
error: "Ha ocurrido un error. Por favor dirígete al apartado 'Mi cuenta' para desactivar las recomendaciones manualmente" error: "Ha ocurrido un error. Por favor dirígete al apartado 'Mi cuenta' para desactivar las recomendaciones manualmente"
retired_proposals: Propuestas retiradas retired_proposals: Propuestas retiradas
retired_proposals_link: "Propuestas retiradas por sus autores" retired_proposals_link: "Propuestas retiradas por sus autores"
selected_proposals: Propuestas seleccionadas
selected_proposals_link: Ver propuestas seleccionadas
archived_proposals: Propuestas archivadas
proposals_lists: Listas de propuestas
retired_links: retired_links:
all: Todas all: Todas
duplicated: Duplicadas duplicated: Duplicadas
@@ -437,9 +441,11 @@ es:
one: 1 voto one: 1 voto
other: "%{count} votos" other: "%{count} votos"
supports_necessary: "%{number} apoyos necesarios" supports_necessary: "%{number} apoyos necesarios"
reason_for_supports_necessary: ""
total_percent: 100% total_percent: 100%
archived: "Esta propuesta ha sido archivada y ya no puede recoger apoyos." archived: "Esta propuesta ha sido archivada y ya no puede recoger apoyos."
successful: "Esta propuesta ha alcanzado los apoyos necesarios." successful: "Esta propuesta ha alcanzado los apoyos necesarios."
selected: "Propuesta seleccionada"
show: show:
author_deleted: Usuario eliminado author_deleted: Usuario eliminado
code: "Código de la propuesta:" code: "Código de la propuesta:"

View File

@@ -29,7 +29,8 @@ namespace :admin do
end end
end end
resources :proposals, only: [:index, :show] do resources :proposals, only: [:index, :show, :update] do
member { patch :toggle_selection }
resources :milestones, controller: "proposal_milestones" resources :milestones, controller: "proposal_milestones"
resources :progress_bars, except: :show, controller: "proposal_progress_bars" resources :progress_bars, except: :show, controller: "proposal_progress_bars"
end end

View File

@@ -0,0 +1,5 @@
class AddSelectedToProposal < ActiveRecord::Migration
def change
add_column :proposals, :selected, :bool, default: false, index: true
end
end

View File

@@ -1194,6 +1194,7 @@ ActiveRecord::Schema.define(version: 20190429125842) do
t.text "retired_explanation" t.text "retired_explanation"
t.integer "community_id" t.integer "community_id"
t.datetime "published_at" t.datetime "published_at"
t.boolean "selected", default: false
t.index ["author_id", "hidden_at"], name: "index_proposals_on_author_id_and_hidden_at", using: :btree t.index ["author_id", "hidden_at"], name: "index_proposals_on_author_id_and_hidden_at", using: :btree
t.index ["author_id"], name: "index_proposals_on_author_id", using: :btree t.index ["author_id"], name: "index_proposals_on_author_id", using: :btree
t.index ["cached_votes_up"], name: "index_proposals_on_cached_votes_up", using: :btree t.index ["cached_votes_up"], name: "index_proposals_on_cached_votes_up", using: :btree

View File

@@ -33,6 +33,10 @@ FactoryBot.define do
created_at { 25.months.ago } created_at { 25.months.ago }
end end
trait :selected do
selected true
end
trait :with_hot_score do trait :with_hot_score do
before(:save) { |d| d.calculate_hot_score } before(:save) { |d| d.calculate_hot_score }
end end

View File

@@ -10,6 +10,7 @@ describe "Admin proposals" do
"admin_proposal_path" "admin_proposal_path"
context "Index" do context "Index" do
scenario "Search" do scenario "Search" do
create(:proposal, title: "Make Pluto a planet again") create(:proposal, title: "Make Pluto a planet again")
create(:proposal, title: "Build a monument to honour CONSUL developers") create(:proposal, title: "Build a monument to honour CONSUL developers")
@@ -26,6 +27,29 @@ describe "Admin proposals" do
expect(page).to have_content "Make Pluto a planet again" expect(page).to have_content "Make Pluto a planet again"
expect(page).not_to have_content "Build a monument" expect(page).not_to have_content "Build a monument"
end end
scenario "Select a proposal", :js do
proposal = create(:proposal)
visit admin_proposals_path
within("#proposal_#{proposal.id}") { click_link "Select" }
within("#proposal_#{proposal.id}") { expect(page).to have_link "Selected" }
expect(proposal.reload.selected?).to be true
end
scenario "Unselect a proposal", :js do
proposal = create(:proposal, :selected)
visit admin_proposals_path
within("#proposal_#{proposal.id}") { click_link "Selected" }
within("#proposal_#{proposal.id}") { expect(page).to have_link "Select" }
expect(proposal.reload.selected?).to be false
end
end end
context "Show" do context "Show" do
@@ -55,5 +79,32 @@ describe "Admin proposals" do
expect(page).to have_link "Add this proposal to a poll to be voted" expect(page).to have_link "Add this proposal to a poll to be voted"
end end
end end
scenario "Select a proposal" do
proposal = create(:proposal)
visit admin_proposal_path(proposal)
check "Mark as selected"
click_button "Update proposal"
expect(page).to have_content "Proposal updated successfully"
expect(find_field("Mark as selected")).to be_checked
expect(proposal.reload.selected?).to be true
end
scenario "Unselect a proposal" do
proposal = create(:proposal, :selected)
visit admin_proposal_path(proposal)
uncheck "Mark as selected"
click_button "Update proposal"
expect(page).to have_content "Proposal updated successfully"
expect(find_field("Mark as selected")).not_to be_checked
expect(proposal.reload.selected?).to be false
end
end end
end end

View File

@@ -9,8 +9,8 @@ describe "Proposal ballots" do
visit proposals_path visit proposals_path
successful_proposals.each do |proposal| successful_proposals.each do |proposal|
within("#proposal_#{proposal.id}_votes") do within("#proposal_#{proposal.id}_votes .supports .progress") do
expect(page).to have_content "This proposal has reached the required supports" expect(page).to have_content "100% / 100%"
end end
end end
end end
@@ -20,8 +20,8 @@ describe "Proposal ballots" do
successful_proposals.each do |proposal| successful_proposals.each do |proposal|
visit proposal_path(proposal) visit proposal_path(proposal)
within("#proposal_#{proposal.id}_votes") do within("#proposal_#{proposal.id}_votes .supports .progress") do
expect(page).to have_content "This proposal has reached the required supports" expect(page).to have_content "100% / 100%"
end end
end end
end end

View File

@@ -833,12 +833,12 @@ describe "Proposals" do
describe "Archived proposals" do describe "Archived proposals" do
scenario "show on archived tab" do scenario "show on proposals list" do
create_featured_proposals create_featured_proposals
archived_proposals = create_archived_proposals archived_proposals = create_archived_proposals
visit proposals_path visit proposals_path
click_link "archived" click_link "Archived proposals"
within("#proposals-list") do within("#proposals-list") do
archived_proposals.each do |proposal| archived_proposals.each do |proposal|
@@ -906,7 +906,7 @@ describe "Proposals" do
expect(page).not_to have_content(archived_proposal.title) expect(page).not_to have_content(archived_proposal.title)
end end
click_link "archived" click_link "Archived proposals"
within("#featured-proposals") do within("#featured-proposals") do
expect(page).to have_content(featured_proposal.title) expect(page).to have_content(featured_proposal.title)
@@ -924,7 +924,7 @@ describe "Proposals" do
create(:proposal, :archived, title: "Some votes").update_column(:confidence_score, 25) create(:proposal, :archived, title: "Some votes").update_column(:confidence_score, 25)
visit proposals_path visit proposals_path
click_link "archived" click_link "Archived proposals"
within("#proposals-list") do within("#proposals-list") do
expect(all(".proposal")[0].text).to match "Most voted" expect(all(".proposal")[0].text).to match "Most voted"
@@ -935,6 +935,96 @@ describe "Proposals" do
end end
context "Selected Proposals" do
let!(:selected_proposal) { create(:proposal, :selected) }
let!(:not_selected_proposal) { create(:proposal) }
scenario "do not show in index by default" do
visit proposals_path
expect(page).to have_selector("#proposals .proposal", count: 1)
expect(page).to have_content not_selected_proposal.title
expect(page).not_to have_content selected_proposal.title
end
scenario "show in selected proposals list" do
visit proposals_path
click_link "View selected proposals"
expect(page).to have_selector("#proposals .proposal", count: 1)
expect(page).to have_content selected_proposal.title
expect(page).not_to have_content not_selected_proposal.title
end
scenario "show a selected proposal message in show view" do
visit proposal_path(selected_proposal)
within("aside") { expect(page).not_to have_content "SUPPORTS" }
within("aside") { expect(page).to have_content "Selected proposal" }
end
scenario "do not show featured proposal in selected proposals list" do
Setting["feature.featured_proposals"] = true
create_featured_proposals
visit proposals_path
expect(page).to have_selector("#proposals .proposal-featured")
expect(page).to have_selector("#featured-proposals")
click_link "View selected proposals"
expect(page).not_to have_selector("#proposals .proposal-featured")
expect(page).not_to have_selector("#featured-proposals")
end
scenario "do not show recommented proposal in selected proposals list" do
create(:proposal, title: "Recommended", cached_votes_up: 10, tag_list: "Economy")
user = create(:user)
create(:follow, followable: create(:proposal, tag_list: "Economy"), user: user)
login_as(user)
visit proposals_path
expect(page).to have_css(".recommendation", count: 1)
expect(page).to have_link "Recommended"
expect(page).to have_link "See more recommendations"
click_link "View selected proposals"
expect(page).not_to have_css ".recommendation"
expect(page).not_to have_link "Recommended"
expect(page).not_to have_link "See more recommendations"
end
scenario "do not show order links in selected proposals list" do
visit proposals_path
expect(page).to have_css "ul.submenu"
expect(page).to have_link "most active"
expect(page).to have_link "highest rated"
expect(page).to have_link "newest"
click_link "View selected proposals"
expect(page).not_to have_css "ul.submenu"
expect(page).not_to have_link "most active"
expect(page).not_to have_link "highest rated"
expect(page).not_to have_link "newest"
end
scenario "show archived proposals in selected proposals list" do
archived_proposal = create(:proposal, :selected, :archived)
visit proposals_path
expect(page).not_to have_content archived_proposal.title
click_link "View selected proposals"
expect(page).to have_content archived_proposal.title
end
end
context "Search" do context "Search" do
context "Basic search" do context "Basic search" do
@@ -1754,8 +1844,8 @@ describe "Successful proposals" do
successful_proposals.each do |proposal| successful_proposals.each do |proposal|
within("#proposal_#{proposal.id}_votes") do within("#proposal_#{proposal.id}_votes") do
expect(page).not_to have_css(".supports") expect(page).not_to have_link "Support"
expect(page).to have_content "This proposal has reached the required supports" expect(page).to have_content "100% / 100%"
end end
end end
end end
@@ -1766,8 +1856,8 @@ describe "Successful proposals" do
successful_proposals.each do |proposal| successful_proposals.each do |proposal|
visit proposal_path(proposal) visit proposal_path(proposal)
within("#proposal_#{proposal.id}_votes") do within("#proposal_#{proposal.id}_votes") do
expect(page).not_to have_css(".supports") expect(page).not_to have_link "Support"
expect(page).to have_content "This proposal has reached the required supports" expect(page).to have_content "100% / 100%"
end end
end end
end end

View File

@@ -866,6 +866,30 @@ describe Proposal do
end end
end end
describe "selected" do
let!(:not_selected_proposal) { create(:proposal) }
let!(:selected_proposal) { create(:proposal, :selected) }
it "selected? is true" do
expect(not_selected_proposal.selected?).to be false
expect(selected_proposal.selected?).to be true
end
it "scope selected" do
selected = Proposal.selected
expect(selected.size).to be 1
expect(selected.first).to eq selected_proposal
end
it "scope not_selected" do
not_selected = Proposal.not_selected
expect(not_selected.size).to be 1
expect(not_selected.first).to eq not_selected_proposal
end
end
describe "public_for_api scope" do describe "public_for_api scope" do
it "returns proposals" do it "returns proposals" do
proposal = create(:proposal) proposal = create(:proposal)