Allow admins to select proposals and users to list them

This commit is contained in:
Julian Herrero
2019-04-16 12:39:21 +02:00
parent 9948804e21
commit ad5f7a06e1
20 changed files with 216 additions and 24 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,6 +51,7 @@ class ProposalsController < ApplicationController
discard_draft discard_draft
discard_archived discard_archived
load_retired load_retired
load_selected
load_featured load_featured
end end
@@ -139,6 +140,10 @@ class ProposalsController < ApplicationController
end end
end end
def load_selected
@resources = @resources.selected if params[:selected].present?
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"]

View File

@@ -64,4 +64,39 @@ 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
link_to button_text,
toggle_selection_admin_proposal_path(proposal),
remote: true,
method: :patch,
class: html_class
end
def css_for_proposal_info_row
if feature?(:allow_images)
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
end end

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

@@ -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 %>">
<% else %> <% else %>
<div class="row"> <div class="row">
<div class="small-12 medium-9 column"> <div class="<%= css_for_proposal_info_row %>">
<% 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,24 +62,27 @@
</div> </div>
</div> </div>
<div id="<%= dom_id(proposal) %>_votes" <% if show_proposal_votes? %>
class="small-12 medium-3 column supports-container"> <div id="<%= dom_id(proposal) %>_votes"
<% if proposal.successful? %> class="small-12 medium-3 column supports-container">
<div class="padding text-center"> <% if proposal.successful? %>
<p> <div class="padding text-center">
<%= t("proposals.proposal.successful") %> <p>
</p> <%= t("proposals.proposal.successful") %>
</div> </p>
<% elsif proposal.archived? %> </div>
<div class="padding text-center"> <% elsif proposal.archived? %>
<strong><%= t("proposals.proposal.supports", count: proposal.total_votes) %></strong> <div class="padding text-center">
<p><%= t("proposals.proposal.archived") %></p> <strong><%= t("proposals.proposal.supports", count: proposal.total_votes) %></strong>
</div> <p><%= t("proposals.proposal.archived") %></p>
<% else %> </div>
<%= render "votes", <% else %>
{ proposal: proposal, vote_url: vote_proposal_path(proposal, value: "yes") } %> <%= render "votes",
<% end %> { proposal: proposal, vote_url: vote_proposal_path(proposal, value: "yes") } %>
</div> <% end %>
</div>
<% end %>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,8 @@
<% if params[:selected].blank? %>
<div class="sidebar-divider"></div>
<h2 class="sidebar-title"><%= t("proposals.index.selected_proposals") %></h2>
<p>
<%= link_to t("proposals.index.selected_proposals"), proposals_path(selected: "all"), class: "small" %>
</p>
<% end %>

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>
@@ -69,7 +77,10 @@
</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 %>
<%= render "shared/order_links", i18n_namespace: "proposals.index" %> <%= render "shared/order_links", i18n_namespace: "proposals.index" %>
@@ -118,6 +129,7 @@
<%= render "popular" %> <%= render "popular" %>
<% end %> <% end %>
<%= render "retired" %> <%= render "retired" %>
<%= render "selected" %>
</aside> </aside>
</div> </div>

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

@@ -1239,10 +1239,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,7 @@ 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
retired_links: retired_links:
all: All all: All
duplicated: Duplicated duplicated: Duplicated

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

@@ -1239,9 +1239,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,7 @@ 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
retired_links: retired_links:
all: Todas all: Todas
duplicated: Duplicadas duplicated: Duplicadas

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

@@ -10,6 +10,7 @@ feature "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 @@ feature "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 @@ feature "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

@@ -118,6 +118,25 @@ feature "Proposals" do
end end
end end
context "Index" do
scenario "Lists selected proposals" do
selected_proposal = create(:proposal, :selected)
unselected_proposal = create(:proposal)
visit proposals_path
expect(page).to have_selector("#proposals .proposal", count: 2)
expect(page).to have_content selected_proposal.title
expect(page).to have_content unselected_proposal.title
click_link "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 unselected_proposal.title
end
end
scenario "Show" do scenario "Show" do
proposal = create(:proposal) proposal = create(:proposal)