Merge pull request #3345 from consul/backport-polls-officer-for-voter
Add officing booths
This commit is contained in:
@@ -1,12 +1,46 @@
|
||||
class Officing::BaseController < ApplicationController
|
||||
layout "admin"
|
||||
helper_method :current_booth
|
||||
|
||||
before_action :authenticate_user!
|
||||
before_action :verify_officer
|
||||
|
||||
skip_authorization_check
|
||||
|
||||
def verify_officer
|
||||
raise CanCan::AccessDenied unless current_user.try(:poll_officer?)
|
||||
end
|
||||
private
|
||||
|
||||
def verify_officer
|
||||
raise CanCan::AccessDenied unless current_user.try(:poll_officer?)
|
||||
end
|
||||
|
||||
def load_officer_assignment
|
||||
@officer_assignments ||= current_user.poll_officer.
|
||||
officer_assignments.
|
||||
voting_days.
|
||||
where(date: Time.current.to_date)
|
||||
end
|
||||
|
||||
def verify_officer_assignment
|
||||
if @officer_assignments.blank?
|
||||
redirect_to officing_root_path, notice: t("officing.residence.flash.not_allowed")
|
||||
end
|
||||
end
|
||||
|
||||
def verify_booth
|
||||
return unless current_booth.blank?
|
||||
booths = current_user.poll_officer.todays_booths
|
||||
case booths.count
|
||||
when 0
|
||||
redirect_to officing_root_path
|
||||
when 1
|
||||
session[:booth_id] = booths.first.id
|
||||
else
|
||||
redirect_to new_officing_booth_path
|
||||
end
|
||||
end
|
||||
|
||||
def current_booth
|
||||
Poll::Booth.where(id: session[:booth_id]).first
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
24
app/controllers/officing/booth_controller.rb
Normal file
24
app/controllers/officing/booth_controller.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
class Officing::BoothController < Officing::BaseController
|
||||
before_action :load_officer_assignment
|
||||
before_action :verify_officer_assignment
|
||||
|
||||
def new
|
||||
@booths = current_user.poll_officer.todays_booths
|
||||
end
|
||||
|
||||
def create
|
||||
set_booth(Poll::Booth.find(booth_params[:id]))
|
||||
redirect_to officing_root_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def booth_params
|
||||
params.require(:booth).permit(:id)
|
||||
end
|
||||
|
||||
def set_booth(booth)
|
||||
session[:booth_id] = booth.id
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,4 +1,5 @@
|
||||
class Officing::PollsController < Officing::BaseController
|
||||
before_action :verify_booth
|
||||
|
||||
def index
|
||||
@polls = current_user.poll_officer? ? current_user.poll_officer.voting_days_assigned_polls : []
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
class Officing::ResidenceController < Officing::BaseController
|
||||
|
||||
before_action :load_officer_assignment
|
||||
before_action :validate_officer_assignment, only: :create
|
||||
before_action :verify_officer_assignment
|
||||
before_action :verify_booth
|
||||
|
||||
def new
|
||||
@residence = Officing::Residence.new
|
||||
@@ -22,16 +23,4 @@ class Officing::ResidenceController < Officing::BaseController
|
||||
params.require(:residence).permit(:document_number, :document_type, :year_of_birth)
|
||||
end
|
||||
|
||||
def load_officer_assignment
|
||||
@officer_assignments = current_user.poll_officer.
|
||||
officer_assignments.
|
||||
voting_days.
|
||||
where(date: Date.current)
|
||||
end
|
||||
|
||||
def validate_officer_assignment
|
||||
if @officer_assignments.blank?
|
||||
redirect_to officing_root_path, notice: t("officing.residence.flash.not_allowed")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,6 +7,7 @@ class Officing::ResultsController < Officing::BaseController
|
||||
before_action :load_officer_assignment, only: :create
|
||||
before_action :check_officer_assignment, only: :create
|
||||
before_action :build_results, only: :create
|
||||
before_action :verify_booth
|
||||
|
||||
def new
|
||||
end
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
class Officing::VotersController < Officing::BaseController
|
||||
respond_to :html, :js
|
||||
|
||||
before_action :load_officer_assignment
|
||||
before_action :verify_officer_assignment
|
||||
before_action :verify_booth
|
||||
|
||||
def new
|
||||
@user = User.find(params[:id])
|
||||
booths = current_user.poll_officer.shifts.current.vote_collection.pluck(:booth_id).uniq
|
||||
@@ -15,7 +19,9 @@ class Officing::VotersController < Officing::BaseController
|
||||
user: @user,
|
||||
poll: @poll,
|
||||
origin: "booth",
|
||||
officer: current_user.poll_officer)
|
||||
officer: current_user.poll_officer,
|
||||
booth_assignment: Poll::BoothAssignment.where(poll: @poll, booth: current_booth).first,
|
||||
officer_assignment: officer_assignment(@poll))
|
||||
@voter.save!
|
||||
end
|
||||
|
||||
@@ -25,4 +31,13 @@ class Officing::VotersController < Officing::BaseController
|
||||
params.require(:voter).permit(:poll_id, :user_id)
|
||||
end
|
||||
|
||||
def officer_assignment(poll)
|
||||
Poll::OfficerAssignment.by_officer(current_user.poll_officer)
|
||||
.by_poll(poll)
|
||||
.by_booth(current_booth)
|
||||
.by_date(Date.current)
|
||||
.where(final: false)
|
||||
.first
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -3,7 +3,9 @@ class Users::SessionsController < Devise::SessionsController
|
||||
private
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
if !verifying_via_email? && resource.show_welcome_screen?
|
||||
if current_user.poll_officer?
|
||||
new_officing_booth_path
|
||||
elsif !verifying_via_email? && resource.show_welcome_screen?
|
||||
welcome_path
|
||||
else
|
||||
super
|
||||
|
||||
@@ -5,11 +5,15 @@ module OfficersHelper
|
||||
end
|
||||
|
||||
def vote_collection_shift?
|
||||
current_user.poll_officer.officer_assignments.where(date: Time.current.to_date).any?
|
||||
current_user.poll_officer.officer_assignments.voting_days.where(date: Time.current.to_date).any?
|
||||
end
|
||||
|
||||
def final_recount_shift?
|
||||
current_user.poll_officer.officer_assignments.final.where(date: Time.current.to_date).any?
|
||||
end
|
||||
|
||||
def no_shifts?
|
||||
current_user.poll_officer.officer_assignments.where(date: Time.current.to_date).blank?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -23,5 +23,9 @@ class Poll
|
||||
sort {|x, y| y.ends_at <=> x.ends_at}
|
||||
end
|
||||
|
||||
def todays_booths
|
||||
officer_assignments.by_date(Date.current).map(&:booth).uniq
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,11 +17,20 @@ class Poll
|
||||
scope :by_officer_and_poll, ->(officer_id, poll_id) do
|
||||
where("officer_id = ? AND poll_booth_assignments.poll_id = ?", officer_id, poll_id)
|
||||
end
|
||||
scope :by_officer, ->(officer){ where(officer_id: officer.id) }
|
||||
scope :by_poll, ->(poll){ joins(:booth_assignment).where("poll_booth_assignments.poll_id" => poll.id) }
|
||||
scope :by_booth, ->(booth){ joins(:booth_assignment).where("poll_booth_assignments.booth_id" => booth.id) }
|
||||
scope :by_date, ->(date){ where(date: date) }
|
||||
|
||||
before_create :log_user_data
|
||||
|
||||
def log_user_data
|
||||
self.user_data_log = "#{officer.user_id} - #{officer.user.name_and_email}"
|
||||
end
|
||||
|
||||
def booth
|
||||
booth_assignment.booth
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,11 +12,13 @@ class Poll
|
||||
|
||||
validates :poll_id, presence: true
|
||||
validates :user_id, presence: true
|
||||
validates :booth_assignment_id, presence: true, if: ->(voter) { voter.origin == "booth" }
|
||||
validates :officer_assignment_id, presence: true, if: ->(voter) { voter.origin == "booth" }
|
||||
|
||||
validates :document_number, presence: true, uniqueness: { scope: [:poll_id, :document_type], message: :has_voted }
|
||||
validates :origin, inclusion: { in: VALID_ORIGINS }
|
||||
|
||||
before_validation :set_demographic_info, :set_document_info
|
||||
before_validation :set_demographic_info, :set_document_info, :set_denormalized_booth_assignment_id
|
||||
|
||||
scope :web, -> { where(origin: "web") }
|
||||
scope :booth, -> { where(origin: "booth") }
|
||||
@@ -38,6 +40,10 @@ class Poll
|
||||
|
||||
private
|
||||
|
||||
def set_denormalized_booth_assignment_id
|
||||
self.booth_assignment_id ||= officer_assignment.try(:booth_assignment_id)
|
||||
end
|
||||
|
||||
def in_census?
|
||||
census_api_response.valid?
|
||||
end
|
||||
|
||||
@@ -43,14 +43,14 @@
|
||||
<%= link_to booth_assignment.booth.name, admin_poll_booth_assignment_path(@poll, booth_assignment, anchor: "tab-recounts") %>
|
||||
</strong>
|
||||
</td>
|
||||
<td class="text-center <%= "count-error" if total_recounts.to_i != system_count %>">
|
||||
<td class="text-center <%= "count-error" if total_recounts.to_i != system_count %>" id="<%= dom_id(booth_assignment) %>_recount">
|
||||
<% if total_recounts.present? %>
|
||||
<strong><%= total_recounts %></strong>
|
||||
<% else %>
|
||||
<span>-</span>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<td class="text-center" id="<%= dom_id(booth_assignment) %>_system">
|
||||
<% if system_count.present? %>
|
||||
<strong><%= system_count %></strong>
|
||||
<% else %>
|
||||
|
||||
5
app/views/layouts/_officing_booth.html.erb
Normal file
5
app/views/layouts/_officing_booth.html.erb
Normal file
@@ -0,0 +1,5 @@
|
||||
<% if current_user.poll_officer? %>
|
||||
<div id="officing-booth" class="callout info">
|
||||
<%= t("admin.officing_booth.title", booth: try(:current_booth).try(:location)) %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
<div class="admin-content small-12 medium-9 column" data-equalizer-watch>
|
||||
<%= render "layouts/flash" %>
|
||||
<%= render "layouts/officing_booth" %>
|
||||
<%= yield %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
25
app/views/officing/booth/new.html.erb
Normal file
25
app/views/officing/booth/new.html.erb
Normal file
@@ -0,0 +1,25 @@
|
||||
<div class="row margin-top">
|
||||
<div class="small-12 medium-6 column small-centered">
|
||||
<div class="panel margin-top">
|
||||
<h1 class="text-center">
|
||||
<%= t("officing.booth.new.title") %>
|
||||
</h1>
|
||||
<%= form_for Poll::Booth.new,
|
||||
as: :booth,
|
||||
url: officing_booth_path,
|
||||
method: :post do |f| %>
|
||||
<div class="row">
|
||||
<div class="small-12 column">
|
||||
<%= f.select :id,
|
||||
@booths.collect { |booth| [booth.location, booth.id] },
|
||||
selected: @booths.first,
|
||||
label: false,
|
||||
tabindex: "1" %>
|
||||
|
||||
<%= f.submit(t("devise_views.sessions.new.submit"), class: "button expanded") %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<p><%= t("officing.dashboard.index.info") %></p>
|
||||
|
||||
<% unless final_recount_shift? && vote_collection_shift? %>
|
||||
<% if no_shifts? %>
|
||||
<div class="callout warning">
|
||||
<%= t("officing.dashboard.index.no_shifts") %>
|
||||
</div>
|
||||
|
||||
@@ -1,32 +1,25 @@
|
||||
<h2><%= t("officing.residence.new.title") %></h2>
|
||||
|
||||
<% if @officer_assignments.present? %>
|
||||
<div class="row verification account">
|
||||
<div class="small-12 medium-8 column">
|
||||
<%= form_for @residence, as: "residence", url: officing_residence_path do |f| %>
|
||||
<%= render "errors" %>
|
||||
<div class="row verification account">
|
||||
<div class="small-12 medium-8 column">
|
||||
<%= form_for @residence, as: "residence", url: officing_residence_path do |f| %>
|
||||
<%= render "errors" %>
|
||||
|
||||
<div class="small-12 medium-6">
|
||||
<%= f.select :document_type, document_types, prompt: "" %>
|
||||
<div class="small-12 medium-6">
|
||||
<%= f.select :document_type, document_types, prompt: "" %>
|
||||
|
||||
|
||||
<%= f.text_field :document_number,
|
||||
<%= f.text_field :document_number,
|
||||
placeholder: t("officing.residence.new.document_number"),
|
||||
autocomplete: "off" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="date-of-birth small-12 medium-6">
|
||||
<%= f.text_field :year_of_birth, type: "number", autocomplete: "off" %>
|
||||
</div>
|
||||
<div class="date-of-birth small-12 medium-6">
|
||||
<%= f.text_field :year_of_birth, type: "number", autocomplete: "off" %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-6">
|
||||
<input type="submit" value="<%= t("officing.residence.new.submit") %>" class="button expanded">
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="small-12 medium-6">
|
||||
<input type="submit" value="<%= t("officing.residence.new.submit") %>" class="button expanded">
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="callout primary">
|
||||
<%= t("officing.residence.new.no_assignments") %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
$("#<%= dom_id(@poll) %> #actions").html("<%= j render("voted") %>");
|
||||
$("#<%= dom_id(@poll) %> #can_vote_callout").hide();
|
||||
$("#not_voted").hide();
|
||||
$(".js-vote-collection").removeClass("is-hidden");
|
||||
|
||||
@@ -28,4 +28,8 @@
|
||||
</table>
|
||||
<% end %>
|
||||
|
||||
<%= link_to t("officing.voters.new.not_to_vote"), namespaced_root_path, class: "button" %>
|
||||
<% if Poll.votable_by(@user).any? %>
|
||||
<div id="not_voted">
|
||||
<%= link_to t("officing.voters.new.not_to_vote"), namespaced_root_path, class: "button" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -14,6 +14,8 @@ en:
|
||||
edit: Edit
|
||||
configure: Configure
|
||||
delete: Delete
|
||||
officing_booth:
|
||||
title: "You are officing the booth located at %{booth}. If this is not correct, do not continue and call the help phone number. Thank you."
|
||||
banners:
|
||||
index:
|
||||
title: Banners
|
||||
|
||||
@@ -16,6 +16,9 @@ en:
|
||||
no_polls: You are not officing final recounts in any active poll
|
||||
select_poll: Select poll
|
||||
add_results: Add results
|
||||
booth:
|
||||
new:
|
||||
title: "Choose your booth"
|
||||
results:
|
||||
flash:
|
||||
create: "Results saved"
|
||||
@@ -51,7 +54,6 @@ en:
|
||||
submit: Validate document
|
||||
error_verifying_census: "The Census was unable to verify this document."
|
||||
form_errors: prevented the verification of this document
|
||||
no_assignments: "You don't have officing shifts today"
|
||||
voters:
|
||||
new:
|
||||
title: Polls
|
||||
|
||||
@@ -14,6 +14,8 @@ es:
|
||||
edit: Editar
|
||||
configure: Configurar
|
||||
delete: Borrar
|
||||
officing_booth:
|
||||
title: "Estás ahora mismo en la mesa ubicada en %{booth}. Si esto no es correcto no sigas adelante y llama al teléfono de incidencias. Gracias."
|
||||
banners:
|
||||
index:
|
||||
title: Banners
|
||||
|
||||
@@ -16,6 +16,9 @@ es:
|
||||
no_polls: No tienes permiso para recuento final en ninguna votación reciente
|
||||
select_poll: Selecciona votación
|
||||
add_results: Añadir resultados
|
||||
booth:
|
||||
new:
|
||||
title: "Escoge tu urna"
|
||||
results:
|
||||
flash:
|
||||
create: "Datos guardados"
|
||||
@@ -51,7 +54,6 @@ es:
|
||||
submit: Validar documento
|
||||
error_verifying_census: "El Padrón no pudo verificar este documento."
|
||||
form_errors: evitaron verificar este documento
|
||||
no_assignments: "Hoy no tienes turno de presidente de mesa"
|
||||
voters:
|
||||
new:
|
||||
title: Votaciones
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace :officing do
|
||||
resources :results, only: [:new, :create, :index]
|
||||
end
|
||||
|
||||
resource :booth, controller: "booth", only: [:new, :create]
|
||||
resource :residence, controller: "residence", only: [:new, :create]
|
||||
resources :voters, only: [:new, :create]
|
||||
root to: "dashboard#index"
|
||||
|
||||
@@ -42,24 +42,24 @@ end
|
||||
section "Creating Poll Questions & Answers" do
|
||||
Poll.find_each do |poll|
|
||||
(1..4).to_a.sample.times do
|
||||
title = Faker::Lorem.sentence(3).truncate(60) + "?"
|
||||
question_title = Faker::Lorem.sentence(3).truncate(60) + "?"
|
||||
question = Poll::Question.new(author: User.all.sample,
|
||||
title: title,
|
||||
title: question_title,
|
||||
poll: poll)
|
||||
I18n.available_locales.map do |locale|
|
||||
Globalize.with_locale(locale) do
|
||||
question.title = "#{title} (#{locale})"
|
||||
question.title = "#{question_title} (#{locale})"
|
||||
end
|
||||
end
|
||||
question.save!
|
||||
Faker::Lorem.words((2..4).to_a.sample).each do |title|
|
||||
Faker::Lorem.words((2..4).to_a.sample).each do |answer_title|
|
||||
description = "<p>#{Faker::Lorem.paragraphs.join("</p><p>")}</p>"
|
||||
answer = Poll::Question::Answer.new(question: question,
|
||||
title: title.capitalize,
|
||||
title: answer_title.capitalize,
|
||||
description: description)
|
||||
I18n.available_locales.map do |locale|
|
||||
Globalize.with_locale(locale) do
|
||||
answer.title = "#{title} (#{locale})"
|
||||
answer.title = "#{answer_title} (#{locale})"
|
||||
answer.description = "#{description} (#{locale})"
|
||||
end
|
||||
end
|
||||
@@ -114,12 +114,16 @@ end
|
||||
section "Creating Poll Voters" do
|
||||
|
||||
def vote_poll_on_booth(user, poll)
|
||||
officer = Poll::Officer.all.sample
|
||||
|
||||
Poll::Voter.create!(document_type: user.document_type,
|
||||
document_number: user.document_number,
|
||||
user: user,
|
||||
poll: poll,
|
||||
origin: "booth",
|
||||
officer: Poll::Officer.all.sample)
|
||||
officer: officer,
|
||||
officer_assignment: officer.officer_assignments.sample,
|
||||
booth_assignment: poll.booth_assignments.sample)
|
||||
end
|
||||
|
||||
def vote_poll_on_web(user, poll)
|
||||
@@ -142,11 +146,11 @@ section "Creating Poll Voters" do
|
||||
end
|
||||
|
||||
(Poll.expired + Poll.current + Poll.recounting).uniq.each do |poll|
|
||||
level_two_verified_users = User.level_two_verified
|
||||
verified_users = User.level_two_or_three_verified
|
||||
if poll.geozone_restricted?
|
||||
level_two_verified_users = level_two_verified_users.where(geozone_id: poll.geozone_ids)
|
||||
verified_users = verified_users.where(geozone_id: poll.geozone_ids)
|
||||
end
|
||||
user_groups = level_two_verified_users.in_groups(2)
|
||||
user_groups = verified_users.in_groups(2)
|
||||
user_groups.first.each { |user| vote_poll_on_booth(user, poll) }
|
||||
user_groups.second.compact.each { |user| vote_poll_on_web(user, poll) }
|
||||
end
|
||||
@@ -158,13 +162,23 @@ section "Creating Poll Recounts" do
|
||||
officer_assignment = poll.officer_assignments.first
|
||||
author = Poll::Officer.first.user
|
||||
|
||||
total_amount = white_amount = null_amount = 0
|
||||
|
||||
booth_assignment.voters.count.times do
|
||||
case rand
|
||||
when 0...0.1 then null_amount += 1
|
||||
when 0.1...0.2 then white_amount += 1
|
||||
else total_amount += 1
|
||||
end
|
||||
end
|
||||
|
||||
Poll::Recount.create!(officer_assignment: officer_assignment,
|
||||
booth_assignment: booth_assignment,
|
||||
author: author,
|
||||
date: poll.ends_at,
|
||||
white_amount: rand(0..10),
|
||||
null_amount: rand(0..10),
|
||||
total_amount: rand(100..9999),
|
||||
white_amount: white_amount,
|
||||
null_amount: null_amount,
|
||||
total_amount: total_amount,
|
||||
origin: "booth")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ section "Creating Users" do
|
||||
password_confirmation: password,
|
||||
confirmed_at: Time.current,
|
||||
terms_of_service: "1",
|
||||
gender: ["Male", "Female"].sample,
|
||||
gender: %w[male female].sample,
|
||||
date_of_birth: rand((Time.current - 80.years)..(Time.current - 16.years)),
|
||||
public_activity: (rand(1..100) > 30)
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@ require "rails_helper"
|
||||
|
||||
feature "Budget Poll Officing" do
|
||||
|
||||
scenario "Show sidebar menu if officer has shifts assigned" do
|
||||
scenario "Show sidebar menus if officer has shifts assigned" do
|
||||
poll = create(:poll)
|
||||
booth = create(:poll_booth)
|
||||
booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth)
|
||||
@@ -10,13 +10,21 @@ feature "Budget Poll Officing" do
|
||||
user = create(:user)
|
||||
officer = create(:poll_officer, user: user)
|
||||
|
||||
create(:poll_shift, officer: officer, booth: booth, date: Date.current, task: :vote_collection)
|
||||
|
||||
login_as user
|
||||
visit officing_root_path
|
||||
|
||||
expect(page).not_to have_content("You don't have officing shifts today")
|
||||
expect(page).to have_content("Validate document")
|
||||
expect(page).not_to have_content("Total recounts and results")
|
||||
|
||||
create(:poll_shift, officer: officer, booth: booth, date: Date.current, task: :recount_scrutiny)
|
||||
|
||||
officer_assignment = create(:poll_officer_assignment,
|
||||
booth_assignment: booth_assignment,
|
||||
officer: officer)
|
||||
|
||||
login_as user
|
||||
visit officing_root_path
|
||||
|
||||
expect(page).not_to have_content("You don't have officing shifts today")
|
||||
@@ -24,7 +32,7 @@ feature "Budget Poll Officing" do
|
||||
expect(page).to have_content("Total recounts and results")
|
||||
end
|
||||
|
||||
scenario "Do not show sidebar menu if officer has no shifts assigned" do
|
||||
scenario "Do not show sidebar menus if officer has no shifts assigned" do
|
||||
user = create(:user)
|
||||
officer = create(:poll_officer, user: user)
|
||||
|
||||
|
||||
87
spec/features/officing/booth_spec.rb
Normal file
87
spec/features/officing/booth_spec.rb
Normal file
@@ -0,0 +1,87 @@
|
||||
require "rails_helper"
|
||||
|
||||
feature "Booth", :with_frozen_time do
|
||||
|
||||
scenario "Officer with no booth assignments today" do
|
||||
officer = create(:poll_officer)
|
||||
|
||||
login_through_form_as_officer(officer.user)
|
||||
|
||||
expect(page).to have_content "You don't have officing shifts today"
|
||||
end
|
||||
|
||||
scenario "Officer with booth assignments another day" do
|
||||
officer = create(:poll_officer)
|
||||
create(:poll_officer_assignment, officer: officer, date: Date.current + 1.day)
|
||||
|
||||
login_through_form_as_officer(officer.user)
|
||||
|
||||
expect(page).to have_content "You don't have officing shifts today"
|
||||
end
|
||||
|
||||
scenario "Officer with single booth assignment today" do
|
||||
officer = create(:poll_officer)
|
||||
poll = create(:poll)
|
||||
|
||||
booth = create(:poll_booth)
|
||||
|
||||
booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth)
|
||||
create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment, date: Date.current)
|
||||
|
||||
login_through_form_as_officer(officer.user)
|
||||
|
||||
within("#officing-booth") do
|
||||
expect(page).to have_content "You are officing the booth located at #{booth.location}."
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Officer with multiple booth assignments today" do
|
||||
officer = create(:poll_officer)
|
||||
poll = create(:poll)
|
||||
|
||||
booth1 = create(:poll_booth)
|
||||
booth2 = create(:poll_booth)
|
||||
|
||||
ba1 = create(:poll_booth_assignment, poll: poll, booth: booth1)
|
||||
ba2 = create(:poll_booth_assignment, poll: poll, booth: booth2)
|
||||
|
||||
create(:poll_officer_assignment, officer: officer, booth_assignment: ba1, date: Date.current)
|
||||
create(:poll_officer_assignment, officer: officer, booth_assignment: ba2, date: Date.current)
|
||||
|
||||
login_through_form_as_officer(officer.user)
|
||||
|
||||
expect(page).to have_content "Choose your booth"
|
||||
|
||||
select booth2.location, from: "booth_id"
|
||||
click_button "Enter"
|
||||
|
||||
within("#officing-booth") do
|
||||
expect(page).to have_content "You are officing the booth located at #{booth2.location}."
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Display single booth for any number of polls" do
|
||||
officer = create(:poll_officer)
|
||||
|
||||
booth1 = create(:poll_booth)
|
||||
booth2 = create(:poll_booth)
|
||||
|
||||
poll1 = create(:poll)
|
||||
poll2 = create(:poll)
|
||||
|
||||
ba1 = create(:poll_booth_assignment, poll: poll1, booth: booth1)
|
||||
ba2 = create(:poll_booth_assignment, poll: poll2, booth: booth2)
|
||||
ba3 = create(:poll_booth_assignment, poll: poll2, booth: booth2)
|
||||
|
||||
create(:poll_officer_assignment, officer: officer, booth_assignment: ba1, date: Date.current)
|
||||
create(:poll_officer_assignment, officer: officer, booth_assignment: ba2, date: Date.current)
|
||||
create(:poll_officer_assignment, officer: officer, booth_assignment: ba3, date: Date.current)
|
||||
|
||||
login_through_form_as_officer(officer.user)
|
||||
|
||||
expect(page).to have_content "Choose your booth"
|
||||
|
||||
expect(page).to have_select("booth_id", options: [booth1.location, booth2.location])
|
||||
end
|
||||
|
||||
end
|
||||
@@ -25,7 +25,7 @@ feature "Residence", :with_frozen_time do
|
||||
|
||||
background do
|
||||
create(:poll_officer_assignment, officer: officer)
|
||||
login_as(officer.user)
|
||||
login_through_form_as_officer(officer.user)
|
||||
visit officing_root_path
|
||||
end
|
||||
|
||||
@@ -93,4 +93,27 @@ feature "Residence", :with_frozen_time do
|
||||
|
||||
end
|
||||
|
||||
scenario "Verify booth", :js do
|
||||
booth = create(:poll_booth)
|
||||
poll = create(:poll)
|
||||
|
||||
ba = create(:poll_booth_assignment, poll: poll, booth: booth)
|
||||
create(:poll_officer_assignment, officer: officer, booth_assignment: ba)
|
||||
create(:poll_shift, officer: officer, booth: booth, date: Date.current)
|
||||
|
||||
login_as(officer.user)
|
||||
|
||||
visit new_officing_residence_path
|
||||
within("#officing-booth") do
|
||||
expect(page).to have_content "You are officing the booth located at #{booth.location}."
|
||||
end
|
||||
|
||||
officing_verify_residence
|
||||
|
||||
expect(page).to have_content poll.name
|
||||
click_button "Confirm vote"
|
||||
|
||||
expect(page).to have_content "Vote introduced!"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ feature "Officing Results", :with_frozen_time do
|
||||
background do
|
||||
@poll_officer = create(:poll_officer)
|
||||
@officer_assignment = create(:poll_officer_assignment, :final, officer: @poll_officer)
|
||||
create(:poll_shift, officer: @poll_officer, booth: @officer_assignment.booth, date: Date.current)
|
||||
@poll = @officer_assignment.booth_assignment.poll
|
||||
@poll.update(ends_at: 1.day.ago)
|
||||
@question_1 = create(:poll_question, poll: @poll)
|
||||
@@ -15,6 +16,7 @@ feature "Officing Results", :with_frozen_time do
|
||||
create(:poll_question_answer, title: "Tomorrow", question: @question_2)
|
||||
|
||||
login_as(@poll_officer.user)
|
||||
set_officing_booth(@officer_assignment.booth)
|
||||
end
|
||||
|
||||
scenario "Only polls where user is officer for results are accessible" do
|
||||
@@ -30,6 +32,7 @@ feature "Officing Results", :with_frozen_time do
|
||||
click_link "Polling officers"
|
||||
|
||||
expect(page).to have_content("Poll officing")
|
||||
|
||||
within("#side_menu") do
|
||||
click_link "Total recounts and results"
|
||||
end
|
||||
|
||||
@@ -12,9 +12,12 @@ feature "Voters" do
|
||||
create(:poll_shift, officer: officer, booth: booth, date: Date.current, task: :vote_collection)
|
||||
booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth)
|
||||
create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment)
|
||||
set_officing_booth(booth)
|
||||
end
|
||||
|
||||
scenario "Can vote", :js do
|
||||
create(:poll_officer_assignment, officer: officer)
|
||||
|
||||
visit new_officing_residence_path
|
||||
officing_verify_residence
|
||||
|
||||
@@ -57,6 +60,10 @@ feature "Voters" do
|
||||
user = create(:user, residence_verified_at: Time.current, document_type: "1", document_number: "12345678Z")
|
||||
expect(user).not_to be_level_two_verified
|
||||
|
||||
visit root_path
|
||||
click_link "Sign out"
|
||||
login_through_form_as_officer(officer.user)
|
||||
|
||||
visit new_officing_residence_path
|
||||
officing_verify_residence
|
||||
|
||||
@@ -83,6 +90,7 @@ feature "Voters" do
|
||||
booth_assignment = create(:poll_booth_assignment, poll: poll_geozone_restricted_out, booth: booth)
|
||||
create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment)
|
||||
|
||||
set_officing_booth(second_booth)
|
||||
visit new_officing_residence_path
|
||||
officing_verify_residence
|
||||
|
||||
@@ -93,4 +101,44 @@ feature "Voters" do
|
||||
expect(page).to have_content poll_geozone_restricted_in.name
|
||||
expect(page).not_to have_content poll_geozone_restricted_out.name
|
||||
end
|
||||
|
||||
scenario "Store officer and booth information", :js do
|
||||
create(:user, :in_census, id: rand(9999999))
|
||||
poll1 = create(:poll, name: "¿Quieres que XYZ sea aprobado?")
|
||||
poll2 = create(:poll, name: "Pregunta de votación de prueba")
|
||||
|
||||
second_booth = create(:poll_booth)
|
||||
|
||||
ba1 = create(:poll_booth_assignment, poll: poll1, booth: second_booth )
|
||||
ba2 = create(:poll_booth_assignment, poll: poll2, booth: second_booth )
|
||||
create(:poll_shift, officer: officer, booth: second_booth, date: Date.current, task: :vote_collection)
|
||||
|
||||
validate_officer
|
||||
visit new_officing_residence_path
|
||||
set_officing_booth(second_booth)
|
||||
officing_verify_residence
|
||||
|
||||
within("#poll_#{poll1.id}") do
|
||||
click_button "Confirm vote"
|
||||
|
||||
expect(page).to have_content "Vote introduced!"
|
||||
end
|
||||
|
||||
within("#poll_#{poll2.id}") do
|
||||
click_button "Confirm vote"
|
||||
|
||||
expect(page).to have_content "Vote introduced!"
|
||||
end
|
||||
|
||||
expect(Poll::Voter.count).to eq(2)
|
||||
|
||||
voter1 = Poll::Voter.first
|
||||
|
||||
expect(voter1.booth_assignment).to eq(ba1)
|
||||
expect(voter1.officer_assignment).to eq(ba1.officer_assignments.first)
|
||||
|
||||
voter2 = Poll::Voter.last
|
||||
expect(voter2.booth_assignment).to eq(ba2)
|
||||
expect(voter2.officer_assignment).to eq(ba2.officer_assignments.first)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -97,6 +97,7 @@ feature "Poll Officing" do
|
||||
end
|
||||
|
||||
scenario "Poll officer access links" do
|
||||
create(:poll)
|
||||
create(:poll_officer, user: user)
|
||||
login_as(user)
|
||||
visit root_path
|
||||
|
||||
@@ -8,6 +8,7 @@ feature "Voter" do
|
||||
let(:question) { create(:poll_question, poll: poll) }
|
||||
let(:booth) { create(:poll_booth) }
|
||||
let(:officer) { create(:poll_officer) }
|
||||
let(:admin) { create(:administrator) }
|
||||
let!(:answer_yes) { create(:poll_question_answer, question: question, title: "Yes") }
|
||||
let!(:answer_no) { create(:poll_question_answer, question: question, title: "No") }
|
||||
|
||||
@@ -71,6 +72,56 @@ feature "Voter" do
|
||||
|
||||
expect(Poll::Voter.count).to eq(1)
|
||||
expect(Poll::Voter.first.origin).to eq("booth")
|
||||
|
||||
visit root_path
|
||||
click_link "Sign out"
|
||||
login_as(admin.user)
|
||||
visit admin_poll_recounts_path(poll)
|
||||
|
||||
within("#total_system") do
|
||||
expect(page).to have_content "1"
|
||||
end
|
||||
|
||||
within("#poll_booth_assignment_#{Poll::BoothAssignment.where(poll: poll, booth: booth).first.id}_recounts") do
|
||||
expect(page).to have_content "1"
|
||||
end
|
||||
end
|
||||
|
||||
context "The person has decided not to vote at this time" do
|
||||
let!(:user) { create(:user, :in_census) }
|
||||
|
||||
scenario "Show not to vote at this time button" do
|
||||
login_through_form_as_officer(officer.user)
|
||||
|
||||
visit new_officing_residence_path
|
||||
officing_verify_residence
|
||||
|
||||
expect(page).to have_content poll.name
|
||||
expect(page).to have_button "Confirm vote"
|
||||
expect(page).to have_content "Can vote"
|
||||
expect(page).to have_link "The person has decided not to vote at this time"
|
||||
end
|
||||
|
||||
scenario "Hides not to vote at this time button if already voted", :js do
|
||||
login_through_form_as_officer(officer.user)
|
||||
|
||||
visit new_officing_residence_path
|
||||
officing_verify_residence
|
||||
|
||||
within("#poll_#{poll.id}") do
|
||||
click_button("Confirm vote")
|
||||
expect(page).not_to have_button("Confirm vote")
|
||||
expect(page).to have_content "Vote introduced!"
|
||||
expect(page).not_to have_content "The person has decided not to vote at this time"
|
||||
end
|
||||
|
||||
visit new_officing_residence_path
|
||||
officing_verify_residence
|
||||
|
||||
expect(page).to have_content "Has already participated in this poll"
|
||||
expect(page).not_to have_content "The person has decided not to vote at this time"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "Trying to vote the same poll in booth and web" do
|
||||
@@ -107,6 +158,19 @@ feature "Voter" do
|
||||
expect(page).not_to have_link(answer_yes.title)
|
||||
expect(page).to have_content "You have already participated in a physical booth. You can not participate again."
|
||||
expect(Poll::Voter.count).to eq(1)
|
||||
|
||||
visit root_path
|
||||
click_link "Sign out"
|
||||
login_as(admin.user)
|
||||
visit admin_poll_recounts_path(poll)
|
||||
|
||||
within("#total_system") do
|
||||
expect(page).to have_content "1"
|
||||
end
|
||||
|
||||
within("#poll_booth_assignment_#{Poll::BoothAssignment.where(poll: poll, booth: booth).first.id}_recounts") do
|
||||
expect(page).to have_content "1"
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Trying to vote in web again", :js do
|
||||
@@ -162,6 +226,19 @@ feature "Voter" do
|
||||
expect(page).not_to have_link(answer_yes.title)
|
||||
expect(page).to have_content "You have already participated in a physical booth. You can not participate again."
|
||||
expect(Poll::Voter.count).to eq(1)
|
||||
|
||||
visit root_path
|
||||
click_link "Sign out"
|
||||
login_as(admin.user)
|
||||
visit admin_poll_recounts_path(poll)
|
||||
|
||||
within("#total_system") do
|
||||
expect(page).to have_content "1"
|
||||
end
|
||||
|
||||
within("#poll_booth_assignment_#{Poll::BoothAssignment.where(poll: poll, booth: booth).first.id}_recounts") do
|
||||
expect(page).to have_content "1"
|
||||
end
|
||||
end
|
||||
|
||||
context "Side menu" do
|
||||
|
||||
@@ -121,4 +121,21 @@ describe Poll::Officer do
|
||||
expect(assigned_polls.last).to eq(poll_3)
|
||||
end
|
||||
end
|
||||
|
||||
describe "todays_booths" do
|
||||
let(:officer) { create(:poll_officer) }
|
||||
|
||||
it "returns booths for the application's time zone date", :with_different_time_zone do
|
||||
assignment_with_local_time_zone = create(:poll_officer_assignment,
|
||||
date: Date.today,
|
||||
officer: officer)
|
||||
|
||||
assignment_with_application_time_zone = create(:poll_officer_assignment,
|
||||
date: Date.current,
|
||||
officer: officer)
|
||||
|
||||
expect(officer.todays_booths).to include(assignment_with_application_time_zone.booth)
|
||||
expect(officer.todays_booths).not_to include(assignment_with_local_time_zone.booth)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@ describe Poll::Voter do
|
||||
let(:booth) { create(:poll_booth) }
|
||||
let(:booth_assignment) { create(:poll_booth_assignment, poll: poll, booth: booth) }
|
||||
let(:voter) { create(:poll_voter) }
|
||||
let(:officer_assignment) { create(:poll_officer_assignment) }
|
||||
|
||||
describe "validations" do
|
||||
|
||||
@@ -97,6 +98,7 @@ describe Poll::Voter do
|
||||
|
||||
it "is valid with a booth origin" do
|
||||
voter.origin = "booth"
|
||||
voter.officer_assignment = officer_assignment
|
||||
expect(voter).to be_valid
|
||||
end
|
||||
|
||||
@@ -104,7 +106,27 @@ describe Poll::Voter do
|
||||
voter.origin = "web"
|
||||
expect(voter).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
context "assignments" do
|
||||
it "should not be valid without a booth_assignment_id when origin is booth" do
|
||||
voter.origin = "booth"
|
||||
voter.booth_assignment_id = nil
|
||||
expect(voter).not_to be_valid
|
||||
end
|
||||
|
||||
it "should not be valid without an officer_assignment_id when origin is booth" do
|
||||
voter.origin = "booth"
|
||||
voter.officer_assignment_id = nil
|
||||
expect(voter).not_to be_valid
|
||||
end
|
||||
|
||||
it "should be valid without assignments when origin is web" do
|
||||
voter.origin = "web"
|
||||
voter.booth_assignment_id = nil
|
||||
voter.officer_assignment_id = nil
|
||||
expect(voter).to be_valid
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -21,4 +21,15 @@ module CommonActions
|
||||
check "user_terms_of_service"
|
||||
end
|
||||
|
||||
def validate_officer
|
||||
allow_any_instance_of(Officing::BaseController).
|
||||
to receive(:verify_officer_assignment).and_return(true)
|
||||
end
|
||||
|
||||
def set_officing_booth(booth=nil)
|
||||
booth = create(:poll_booth) if booth.blank?
|
||||
|
||||
allow_any_instance_of(Officing::BaseController).
|
||||
to receive(:current_booth).and_return(booth)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user