diff --git a/app/controllers/admin/poll/booth_assignments_controller.rb b/app/controllers/admin/poll/booth_assignments_controller.rb index 7998f29a2..5b9ea9d7b 100644 --- a/app/controllers/admin/poll/booth_assignments_controller.rb +++ b/app/controllers/admin/poll/booth_assignments_controller.rb @@ -23,18 +23,24 @@ class Admin::Poll::BoothAssignmentsController < Admin::Poll::BaseController end def create - @booth_assignment = ::Poll::BoothAssignment.new(poll_id: booth_assignment_params[:poll_id], - booth_id: booth_assignment_params[:booth_id]) + @poll = Poll.find(booth_assignment_params[:poll_id]) + @booth = Poll::Booth.find(booth_assignment_params[:booth_id]) + @booth_assignment = ::Poll::BoothAssignment.new(poll: @poll, + booth: @booth) if @booth_assignment.save notice = t("admin.poll_booth_assignments.flash.create") else notice = t("admin.poll_booth_assignments.flash.error_create") end - redirect_to admin_poll_booth_assignments_path(@booth_assignment.poll_id), notice: notice + respond_to do |format| + format.js { render layout: false } + end end def destroy + @poll = Poll.find(booth_assignment_params[:poll_id]) + @booth = Poll::Booth.find(booth_assignment_params[:booth_id]) @booth_assignment = ::Poll::BoothAssignment.find(params[:id]) if @booth_assignment.destroy @@ -42,7 +48,14 @@ class Admin::Poll::BoothAssignmentsController < Admin::Poll::BaseController else notice = t("admin.poll_booth_assignments.flash.error_destroy") end - redirect_to admin_poll_booth_assignments_path(@booth_assignment.poll_id), notice: notice + respond_to do |format| + format.js { render layout: false } + end + end + + def manage + @booths = ::Poll::Booth.all + @poll = Poll.find(params[:poll_id]) end private diff --git a/app/controllers/admin/poll/polls_controller.rb b/app/controllers/admin/poll/polls_controller.rb index 5103275fb..8ba6e934e 100644 --- a/app/controllers/admin/poll/polls_controller.rb +++ b/app/controllers/admin/poll/polls_controller.rb @@ -47,6 +47,10 @@ class Admin::Poll::PollsController < Admin::Poll::BaseController redirect_to admin_poll_path(@poll), notice: notice end + def booth_assignments + @polls = Poll.current_or_incoming + end + private def load_geozones diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index 1bc8d5e0c..704f9be24 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -56,10 +56,10 @@ module Abilities can [:index, :create, :edit, :update, :destroy], Geozone - can [:read, :create, :update, :destroy, :add_question, :search_booths, :search_officers], Poll + can [:read, :create, :update, :destroy, :add_question, :search_booths, :search_officers, :booth_assignments], Poll can [:read, :create, :update, :destroy, :available], Poll::Booth can [:search, :create, :index, :destroy], ::Poll::Officer - can [:create, :destroy], ::Poll::BoothAssignment + can [:create, :destroy, :manage], ::Poll::BoothAssignment can [:create, :destroy], ::Poll::OfficerAssignment can [:read, :create, :update], Poll::Question can :destroy, Poll::Question # , comments_count: 0, votes_up: 0 diff --git a/app/models/poll/booth.rb b/app/models/poll/booth.rb index 04f9d3dea..07e7d2456 100644 --- a/app/models/poll/booth.rb +++ b/app/models/poll/booth.rb @@ -15,5 +15,8 @@ class Poll where(polls: { id: Poll.current_or_incoming }).includes(:polls) end + def assignment_on_poll(poll) + booth_assignments.where(poll: poll).first + end end -end \ No newline at end of file +end diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index f2af2c116..0518aa0e3 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -60,7 +60,8 @@ <%= t("admin.menu.title_polls") %> <% end %> diff --git a/app/views/admin/poll/booth_assignments/_booth_assignment.html.erb b/app/views/admin/poll/booth_assignments/_booth_assignment.html.erb new file mode 100644 index 000000000..d78f7be8b --- /dev/null +++ b/app/views/admin/poll/booth_assignments/_booth_assignment.html.erb @@ -0,0 +1,31 @@ + + <%= link_to booth.name, admin_booth_path(booth) %> + + + <%= booth.location || t("admin.booths.index.no_location") %> + +<% if booth_assignment.present? %> + + <%= t("admin.booth_assignments.manage.status.assigned") %> + + + <%= link_to t("admin.booth_assignments.manage.actions.unassign"), + admin_poll_booth_assignment_path(@poll, booth_assignment, booth_id: booth.id), + method: :delete, + remote: true, + title: t("admin.booth_assignments.manage.actions.unassign"), + class: "button hollow alert" %> + +<% else %> + + <%= t("admin.booth_assignments.manage.status.unassigned") %> + + + <%= link_to t("admin.booth_assignments.manage.actions.assign"), + admin_poll_booth_assignments_path(@poll, booth_id: booth.id), + method: :post, + remote: true, + title: t("admin.booth_assignments.manage.actions.assign"), + class: "button" %> + +<% end %> diff --git a/app/views/admin/poll/booth_assignments/_search_booths_results.html.erb b/app/views/admin/poll/booth_assignments/_search_booths_results.html.erb index 3fa7fc080..cebde154c 100644 --- a/app/views/admin/poll/booth_assignments/_search_booths_results.html.erb +++ b/app/views/admin/poll/booth_assignments/_search_booths_results.html.erb @@ -12,7 +12,6 @@ <%= t("admin.poll_booth_assignments.index.table_name") %> <%= t("admin.poll_booth_assignments.index.table_location") %> - <%= t("admin.poll_booth_assignments.index.table_assignment") %> @@ -24,14 +23,6 @@ <%= booth.location %> - - <% unless @poll.booth_ids.include?(booth.id) %> - <%= link_to t("admin.poll_booth_assignments.index.add_booth"), - admin_poll_booth_assignments_path(@poll, booth_id: booth.id), - method: :post, - class: "button hollow" %> - <% end %> - <% end %> diff --git a/app/views/admin/poll/booth_assignments/create.js.erb b/app/views/admin/poll/booth_assignments/create.js.erb new file mode 100644 index 000000000..8b278f7b3 --- /dev/null +++ b/app/views/admin/poll/booth_assignments/create.js.erb @@ -0,0 +1 @@ +$("#<%= dom_id(@booth) %>").html('<%= j render("booth_assignment", booth: @booth, booth_assignment: @booth.assignment_on_poll(@poll)) %>'); diff --git a/app/views/admin/poll/booth_assignments/destroy.js.erb b/app/views/admin/poll/booth_assignments/destroy.js.erb new file mode 100644 index 000000000..8b278f7b3 --- /dev/null +++ b/app/views/admin/poll/booth_assignments/destroy.js.erb @@ -0,0 +1 @@ +$("#<%= dom_id(@booth) %>").html('<%= j render("booth_assignment", booth: @booth, booth_assignment: @booth.assignment_on_poll(@poll)) %>'); diff --git a/app/views/admin/poll/booth_assignments/index.html.erb b/app/views/admin/poll/booth_assignments/index.html.erb index f14e59ef1..75cbe889f 100644 --- a/app/views/admin/poll/booth_assignments/index.html.erb +++ b/app/views/admin/poll/booth_assignments/index.html.erb @@ -1,10 +1,15 @@ <%= render "/admin/poll/polls/poll_header" %> +
<%= render "/admin/poll/polls/subnav" %> <%= render "search_booths" %>

<%= t("admin.poll_booth_assignments.index.booths_title") %>

+ <%= link_to t("admin.booth_assignments.manage_assignments"), + manage_admin_poll_booth_assignments_path(@poll), + class: "button hollow float-right" %> + <% if @booth_assignments.empty? %>
<%= t("admin.poll_booth_assignments.index.no_booths") %> @@ -14,7 +19,6 @@ <%= t("admin.poll_booth_assignments.index.table_name") %> <%= t("admin.poll_booth_assignments.index.table_location") %> - <%= t("admin.poll_booth_assignments.index.table_assignment") %> <% @booth_assignments.each do |booth_assignment| %> @@ -25,13 +29,7 @@ - <%= booth_assignment.booth.location %> - - - <%= link_to t("admin.poll_booth_assignments.index.remove_booth"), - admin_poll_booth_assignment_path(@poll, booth_assignment), - method: :delete, - class: "button hollow alert" %> + <%= booth_assignment.booth.location || t("admin.booths.index.no_location") %> <% end %> diff --git a/app/views/admin/poll/booth_assignments/manage.html.erb b/app/views/admin/poll/booth_assignments/manage.html.erb new file mode 100644 index 000000000..a24fac478 --- /dev/null +++ b/app/views/admin/poll/booth_assignments/manage.html.erb @@ -0,0 +1,28 @@ +<%= link_to booth_assignments_admin_polls_path do %> + <%= t("shared.back") %> +<% end %> +
+ +

<%= t("admin.booth_assignments.manage.assignments_list", poll: @poll.name) %>

+ +<% if @booths.empty? %> +
+ <%= t("admin.booths.index.no_booths") %> +
+<% else %> + + + + + + + + + <% @booths.each do |booth| %> + + <%= render partial: "booth_assignment", locals: { booth: booth, booth_assignment: booth.assignment_on_poll(@poll) } %> + + <% end %> + +
<%= t("admin.booths.index.name") %><%= t("admin.booths.index.location") %><%= t("admin.booth_assignments.manage.status.assign_status") %><%= t("admin.actions.actions") %>
+<% end %> diff --git a/app/views/admin/poll/polls/booth_assignments.html.erb b/app/views/admin/poll/polls/booth_assignments.html.erb new file mode 100644 index 000000000..ad5dc6211 --- /dev/null +++ b/app/views/admin/poll/polls/booth_assignments.html.erb @@ -0,0 +1,32 @@ +

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

+ +<% if @polls.any? %> + + + + + + + + <% @polls.each do |poll| %> + + + + + + <% end %> + +
<%= t("admin.polls.index.name") %><%= t("admin.polls.index.dates") %><%= t("admin.actions.actions") %>
+ <%= link_to poll.name, admin_poll_path(poll) %> + + <%= l poll.starts_at.to_date %> - <%= l poll.ends_at.to_date %> + + <%= link_to t("admin.booth_assignments.manage_assignments"), + manage_admin_poll_booth_assignments_path(poll), + class: "button hollow" %> +
+<% else %> +
+ <%= t("admin.polls.index.no_polls") %> +
+<% end %> diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 38abe6f56..aa0fc0f8a 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -409,6 +409,7 @@ en: poll_officers: Poll officers polls: Polls poll_booths: Booths location + poll_booth_assignments: Booths Assignments poll_shifts: Manage shifts officials: Officials organizations: Organisations @@ -524,6 +525,17 @@ en: date_missing: "A date must be selected" vote_collection: Collect Votes recount_scrutiny: Recount & Scrutiny + booth_assignments: + manage_assignments: Manage assignments + manage: + assignments_list: "Assignments for poll '%{poll}'" + status: + assign_status: Assignment + assigned: Assigned + unassigned: Unassigned + actions: + assign: Assign booth + unassign: Unassign booth poll_booth_assignments: flash: destroy: "Booth not assigned anymore" @@ -547,9 +559,6 @@ en: no_booths: "There are no booths assigned to this poll." table_name: "Name" table_location: "Location" - table_assignment: "Assignment" - remove_booth: "Remove booth from poll" - add_booth: "Assign booth" polls: index: title: "List of polls" @@ -666,6 +675,7 @@ en: add_booth: "Add booth" name: "Name" location: "Location" + no_location: "No Location" new: title: "New booth" name: "Name" diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 3336cdc5b..2ff4449ec 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -420,6 +420,7 @@ es: poll_officers: Presidentes de mesa polls: Votaciones poll_booths: Ubicación de urnas + poll_booth_assignments: Asignación de urnas poll_shifts: Asignar turnos officials: Cargos públicos organizations: Organizaciones @@ -524,6 +525,17 @@ es: date_missing: "Debe seleccionarse una fecha" vote_collection: Recoger Votos recount_scrutiny: Recuento & Escrutinio + booth_assignments: + manage_assignments: Gestionar asignaciones + manage: + assignments_list: "Asignaciones para la votación '%{poll}'" + status: + assign_status: Asignación + assigned: Asignada + unassigned: No asignada + actions: + assign: Assign booth + unassign: Unassign booth poll_booth_assignments: flash: destroy: "Urna desasignada" @@ -547,9 +559,6 @@ es: no_booths: "No hay urnas asignadas a esta votación." table_name: "Nombre" table_location: "Ubicación" - table_assignment: "Asignación" - remove_booth: "Desasignar urna" - add_booth: "Asignar urna" polls: index: title: "Listado de votaciones" @@ -668,6 +677,7 @@ es: add_booth: "Añadir urna" name: "Nombre" location: "Ubicación" + no_location: "Sin Ubicación" new: title: "Nueva urna" name: "Nombre" diff --git a/config/routes.rb b/config/routes.rb index ae4f7280c..6f94594a3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -111,7 +111,7 @@ Rails.application.routes.draw do resources :annotations do get :search, on: :collection end - + resources :polls, only: [:show, :index] do resources :questions, controller: 'polls/questions', shallow: true do post :answer, on: :member @@ -273,10 +273,12 @@ Rails.application.routes.draw do scope module: :poll do resources :polls do + get :booth_assignments, on: :collection patch :add_question, on: :member resources :booth_assignments, only: [:index, :show, :create, :destroy] do get :search_booths, on: :collection + get :manage, on: :collection end resources :officer_assignments, only: [:index, :create, :destroy] do diff --git a/spec/features/admin/poll/booth_assigments_spec.rb b/spec/features/admin/poll/booth_assigments_spec.rb index 5813e2dac..cceec1a3e 100644 --- a/spec/features/admin/poll/booth_assigments_spec.rb +++ b/spec/features/admin/poll/booth_assigments_spec.rb @@ -7,66 +7,109 @@ feature 'Admin booths assignments' do login_as(admin.user) end - scenario 'Assign booth to poll', :js do - poll = create(:poll) - booth = create(:poll_booth) + feature 'Admin Booth Assignment management' do - visit admin_poll_path(poll) - within('#poll-resources') do - click_link 'Booths (0)' + let!(:poll) { create(:poll) } + let!(:booth) { create(:poll_booth) } + + scenario 'List Polls and Booths to manage', :js do + second_poll = create(:poll) + second_booth = create(:poll_booth) + + visit booth_assignments_admin_polls_path + + expect(page).to have_content(poll.name) + expect(page).to have_content(second_poll.name) + + within("#poll_#{second_poll.id}") do + click_link 'Manage assignments' + end + + expect(page).to have_content "Assignments for poll '#{second_poll.name}'" + + expect(page).to have_content(booth.name) + expect(page).to have_content(second_booth.name) end - expect(page).to have_content 'There are no booths assigned to this poll.' + scenario 'Assign booth to poll', :js do + visit admin_poll_path(poll) + within('#poll-resources') do + click_link 'Booths (0)' + end - fill_in 'search-booths', with: booth.name - click_button 'Search' - expect(page).to have_content(booth.name) + expect(page).to have_content 'There are no booths assigned to this poll.' + expect(page).to_not have_content booth.name - within('#search-booths-results') do - click_link 'Assign booth' + fill_in 'search-booths', with: booth.name + click_button 'Search' + expect(page).to have_content(booth.name) + + visit manage_admin_poll_booth_assignments_path(poll) + + expect(page).to have_content "Assignments for poll '#{poll.name}'" + + within("#poll_booth_#{booth.id}") do + expect(page).to have_content(booth.name) + expect(page).to have_content "Unassigned" + + click_link 'Assign booth' + + expect(page).not_to have_content "Unassigned" + expect(page).to have_content "Assigned" + expect(page).to have_link "Unassign booth" + end + + visit admin_poll_path(poll) + within('#poll-resources') do + click_link 'Booths (1)' + end + + expect(page).to_not have_content 'There are no booths assigned to this poll.' + expect(page).to have_content booth.name end - expect(page).to have_content 'Booth assigned' + scenario 'Unassign booth from poll', :js do + assignment = create(:poll_booth_assignment, poll: poll, booth: booth) - visit admin_poll_path(poll) - within('#poll-resources') do - click_link 'Booths (1)' + visit admin_poll_path(poll) + within('#poll-resources') do + click_link 'Booths (1)' + end + + expect(page).not_to have_content 'There are no booths assigned to this poll.' + expect(page).to have_content booth.name + + fill_in 'search-booths', with: booth.name + click_button 'Search' + expect(page).to have_content(booth.name) + + visit manage_admin_poll_booth_assignments_path(poll) + + expect(page).to have_content "Assignments for poll '#{poll.name}'" + + within("#poll_booth_#{booth.id}") do + expect(page).to have_content(booth.name) + expect(page).to have_content "Assigned" + + click_link 'Unassign booth' + + expect(page).to have_content "Unassigned" + expect(page).not_to have_content "Assigned" + expect(page).to have_link "Assign booth" + end + + visit admin_poll_path(poll) + within('#poll-resources') do + click_link 'Booths (0)' + end + + expect(page).to have_content 'There are no booths assigned to this poll.' + expect(page).not_to have_content booth.name end - - expect(page).to_not have_content 'There are no booths assigned to this poll.' - expect(page).to have_content booth.name - end - - scenario 'Remove booth from poll', :js do - poll = create(:poll) - booth = create(:poll_booth) - assignment = create(:poll_booth_assignment, poll: poll, booth: booth) - - visit admin_poll_path(poll) - within('#poll-resources') do - click_link 'Booths (1)' - end - - expect(page).to_not have_content 'There are no booths assigned to this poll.' - expect(page).to have_content booth.name - - within("#poll_booth_assignment_#{assignment.id}") do - click_link 'Remove booth from poll' - end - - expect(page).to have_content 'Booth not assigned anymore' - - visit admin_poll_path(poll) - within('#poll-resources') do - click_link 'Booths (0)' - end - - expect(page).to have_content 'There are no booths assigned to this poll.' - expect(page).to_not have_content booth.name end feature 'Show' do - scenario 'Lists all assigned poll oficers' do + scenario 'Lists all assigned poll officers' do poll = create(:poll) booth = create(:poll_booth) booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth)