diff --git a/app/controllers/admin/spending_proposals_controller.rb b/app/controllers/admin/spending_proposals_controller.rb new file mode 100644 index 000000000..dae595716 --- /dev/null +++ b/app/controllers/admin/spending_proposals_controller.rb @@ -0,0 +1,26 @@ +class Admin::SpendingProposalsController < Admin::BaseController + has_filters %w{unresolved accepted rejected}, only: :index + + before_action :load_spending_proposal, except: [:index] + + def index + @spending_proposals = SpendingProposal.send(@current_filter).order(created_at: :desc).page(params[:page]) + end + + def accept + @spending_proposal.accept + redirect_to request.query_parameters.merge(action: :index) + end + + def reject + @spending_proposal.reject + redirect_to request.query_parameters.merge(action: :index) + end + + private + + def load_spending_proposal + @spending_proposal = SpendingProposal.find(params[:id]) + end + +end \ No newline at end of file diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index 5f45e96c8..b27a8a73b 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -32,6 +32,13 @@ <% end %> +
  • > + <%= link_to admin_spending_proposals_path do %> + + <%= t("admin.menu.spending_proposals") %> + <% end %> +
  • +
  • > <%= link_to admin_users_path do %> diff --git a/app/views/admin/spending_proposals/index.html.erb b/app/views/admin/spending_proposals/index.html.erb new file mode 100644 index 000000000..cf55594d0 --- /dev/null +++ b/app/views/admin/spending_proposals/index.html.erb @@ -0,0 +1,33 @@ +

    <%= t("admin.spending_proposals.index.title") %>

    + +<%= render 'shared/filter_subnav', i18n_namespace: "admin.spending_proposals.index" %> + +

    <%= page_entries_info @spending_proposals %>

    + + + <% @spending_proposals.each do |spending_proposal| %> + + + + + <% end %> +
    + <%= spending_proposal.title %> + + <% unless spending_proposal.accepted? %> + <%= link_to t("admin.spending_proposals.actions.accept"), + accept_admin_spending_proposal_path(spending_proposal, request.query_parameters), + method: :put, + data: { confirm: t("admin.actions.confirm") }, + class: "button radius tiny success no-margin" %> + <% end %> + <% unless spending_proposal.rejected? %> + <%= link_to t("admin.spending_proposals.actions.reject"), + reject_admin_spending_proposal_path(spending_proposal, request.query_parameters), + method: :put, + data: { confirm: t("admin.actions.confirm") }, + class: "button radius tiny warning right" %> + <% end %> +
    + +<%= paginate @spending_proposals %> diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 6b815cd31..9941114f8 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -109,6 +109,7 @@ ignore_unused: - 'admin.comments.index.filter*' - 'admin.debates.index.filter*' - 'admin.proposals.index.filter*' + - 'admin.spending_proposals.index.filter*' - 'admin.organizations.index.filter*' - 'admin.users.index.filter*' - 'admin.activity.show.filter*' diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index 276e3ca96..6b421a6b1 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -16,6 +16,7 @@ en: hidden_debates: "Hidden debates" hidden_comments: "Hidden comments" hidden_users: "Hidden users" + spending_proposals: "Spending proposals" incomplete_verifications: "Incomplete verifications" organizations: "Organisations" officials: "Officials" @@ -91,6 +92,17 @@ en: all: "All" with_confirmed_hide: "Confirmed" without_confirmed_hide: "Pending" + spending_proposals: + actions: + accept: Accept + reject: Reject + index: + title: "Spending proposals for participatory budgeting" + filter: "Filter" + filters: + unresolved: "Unresolved" + accepted: "Accepted" + rejected: "Rejected" users: index: title: "Hidden users" diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index b124d60e3..9f7099996 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -16,6 +16,7 @@ es: hidden_debates: "Debates ocultos" hidden_comments: "Comentarios ocultos" hidden_users: "Usuarios bloqueados" + spending_proposals: "Propuestas de gasto" incomplete_verifications: "Verificaciones incompletas" organizations: "Organizaciones" officials: "Cargos públicos" @@ -91,6 +92,17 @@ es: all: "Todas" with_confirmed_hide: "Confirmadas" without_confirmed_hide: "Pendientes" + spending_proposals: + actions: + accept: Aceptar + reject: Rechazar + index: + title: "Propuestas de gasto para presupuestos participativos" + filter: "Filtro" + filters: + unresolved: "Sin resolver" + accepted: "Aceptadas" + rejected: "Rechazadas" users: index: title: "Usuarios bloqueados" diff --git a/config/routes.rb b/config/routes.rb index fa4edc5a1..c2b776dec 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -122,6 +122,13 @@ Rails.application.routes.draw do end end + resources :spending_proposals, only: :index do + member do + put :accept + put :reject + end + end + resources :comments, only: :index do member do put :restore diff --git a/spec/features/admin/spending_proposals_spec.rb b/spec/features/admin/spending_proposals_spec.rb new file mode 100644 index 000000000..f684bf386 --- /dev/null +++ b/spec/features/admin/spending_proposals_spec.rb @@ -0,0 +1,100 @@ +require 'rails_helper' + +feature 'Admin spending proposals' do + + background do + admin = create(:administrator) + login_as(admin.user) + end + + scenario 'Index shows spending proposals' do + spending_proposal = create(:spending_proposal) + visit admin_spending_proposals_path + + expect(page).to have_content(spending_proposal.title) + end + + scenario 'Accept' do + spending_proposal = create(:spending_proposal) + visit admin_spending_proposals_path + + click_link 'Accept' + + expect(page).to_not have_content(spending_proposal.title) + + click_link 'Accepted' + expect(page).to have_content(spending_proposal.title) + + expect(spending_proposal.reload).to be_accepted + end + + scenario 'Reject' do + spending_proposal = create(:spending_proposal) + visit admin_spending_proposals_path + + click_link 'Reject' + + expect(page).to_not have_content(spending_proposal.title) + + click_link('Rejected') + expect(page).to have_content(spending_proposal.title) + + expect(spending_proposal.reload).to be_rejected + end + + scenario "Current filter is properly highlighted" do + visit admin_spending_proposals_path + expect(page).to_not have_link('Unresolved') + expect(page).to have_link('Accepted') + expect(page).to have_link('Rejected') + + visit admin_spending_proposals_path(filter: 'unresolved') + expect(page).to_not have_link('Unresolved') + expect(page).to have_link('Accepted') + expect(page).to have_link('Rejected') + + visit admin_spending_proposals_path(filter: 'accepted') + expect(page).to have_link('Unresolved') + expect(page).to_not have_link('Accepted') + expect(page).to have_link('Rejected') + + visit admin_spending_proposals_path(filter: 'rejected') + expect(page).to have_link('Accepted') + expect(page).to have_link('Unresolved') + expect(page).to_not have_link('Rejected') + end + + scenario "Filtering proposals" do + create(:spending_proposal, title: "Recent spending proposal") + create(:spending_proposal, title: "Good spending proposal", resolution: "accepted") + create(:spending_proposal, title: "Bad spending proposal", resolution: "rejected") + + visit admin_spending_proposals_path(filter: 'unresolved') + expect(page).to have_content('Recent spending proposal') + expect(page).to_not have_content('Good spending proposal') + expect(page).to_not have_content('Bad spending proposal') + + visit admin_spending_proposals_path(filter: 'accepted') + expect(page).to have_content('Good spending proposal') + expect(page).to_not have_content('Recent spending proposal') + expect(page).to_not have_content('Bad spending proposal') + + visit admin_spending_proposals_path(filter: 'rejected') + expect(page).to have_content('Bad spending proposal') + expect(page).to_not have_content('Good spending proposal') + expect(page).to_not have_content('Recent spending proposal') + end + + scenario "Action links remember the pagination setting and the filter" do + per_page = Kaminari.config.default_per_page + (per_page + 2).times { create(:spending_proposal, resolution: "accepted") } + + visit admin_spending_proposals_path(filter: 'accepted', page: 2) + + click_on('Reject', match: :first, exact: true) + + expect(current_url).to include('filter=accepted') + expect(current_url).to include('page=2') + end + +end