Allow admins to select proposals and users to list them
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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"]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
9
app/views/admin/proposals/_form.html.erb
Normal file
9
app/views/admin/proposals/_form.html.erb
Normal 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 %>
|
||||||
1
app/views/admin/proposals/_select_proposal.html.erb
Normal file
1
app/views/admin/proposals/_select_proposal.html.erb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<%= link_to_toggle_proposal_selection(proposal) %>
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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 %>
|
||||||
|
|||||||
1
app/views/admin/proposals/toggle_selection.js.erb
Normal file
1
app/views/admin/proposals/toggle_selection.js.erb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
$("#<%= dom_id(@proposal) %> .js-select").html('<%= j render("select_proposal", proposal: @proposal) %>');
|
||||||
@@ -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,6 +62,7 @@
|
|||||||
</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? %>
|
||||||
@@ -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>
|
||||||
|
|||||||
8
app/views/proposals/_selected.html.erb
Normal file
8
app/views/proposals/_selected.html.erb
Normal 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 %>
|
||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user