adds officer residence check and user voting
This commit is contained in:
@@ -7,6 +7,6 @@ class Officing::BaseController < ApplicationController
|
|||||||
skip_authorization_check
|
skip_authorization_check
|
||||||
|
|
||||||
def verify_officer
|
def verify_officer
|
||||||
raise CanCan::AccessDenied unless current_user.try(:poll_officer?) || current_user.try(:administrator?)
|
raise CanCan::AccessDenied unless current_user.try(:poll_officer?) || current_user.try(:administrator?)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
21
app/controllers/officing/residence_controller.rb
Normal file
21
app/controllers/officing/residence_controller.rb
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
class Officing::ResidenceController < Officing::BaseController
|
||||||
|
|
||||||
|
def new
|
||||||
|
@residence = Officing::Residence.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@residence = Officing::Residence.new(residence_params)
|
||||||
|
if @residence.save
|
||||||
|
redirect_to new_officing_voter_path(id: @residence.user.id), notice: t("officing.residence.flash.create")
|
||||||
|
else
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def residence_params
|
||||||
|
params.require(:residence).permit(:document_number, :document_type, :date_of_birth)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,6 +1,25 @@
|
|||||||
class Officing::VotersController < Officing::BaseController
|
class Officing::VotersController < Officing::BaseController
|
||||||
|
respond_to :html, :js
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
@user = User.find(params[:id])
|
||||||
|
@polls = Poll.current # fix and use answerable_by(@user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@poll = Poll.find(voter_params[:poll_id])
|
||||||
|
@user = User.find(voter_params[:user_id])
|
||||||
|
@voter = Poll::Voter.new(document_type: @user.document_type,
|
||||||
|
document_number: @user.document_number,
|
||||||
|
user: @user,
|
||||||
|
poll: @poll)
|
||||||
|
@voter.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def voter_params
|
||||||
|
params.require(:voter).permit(:poll_id, :user_id)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
107
app/models/officing/residence.rb
Normal file
107
app/models/officing/residence.rb
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
class Officing::Residence
|
||||||
|
include ActiveModel::Model
|
||||||
|
include ActiveModel::Dates
|
||||||
|
include ActiveModel::Validations::Callbacks
|
||||||
|
|
||||||
|
attr_accessor :user, :officer, :document_number, :document_type, :date_of_birth
|
||||||
|
|
||||||
|
before_validation :call_census_api
|
||||||
|
|
||||||
|
validates_presence_of :document_number
|
||||||
|
validates_presence_of :document_type
|
||||||
|
validates_presence_of :date_of_birth
|
||||||
|
|
||||||
|
validate :allowed_age
|
||||||
|
validate :residence_in_madrid
|
||||||
|
|
||||||
|
def initialize(attrs={})
|
||||||
|
self.date_of_birth = parse_date('date_of_birth', attrs)
|
||||||
|
attrs = remove_date('date_of_birth', attrs)
|
||||||
|
super
|
||||||
|
clean_document_number
|
||||||
|
end
|
||||||
|
|
||||||
|
def save
|
||||||
|
return false unless valid?
|
||||||
|
|
||||||
|
if user_exists?
|
||||||
|
self.user = find_user_by_document
|
||||||
|
else
|
||||||
|
user_params = {
|
||||||
|
document_number: document_number,
|
||||||
|
document_type: document_type,
|
||||||
|
geozone: self.geozone,
|
||||||
|
date_of_birth: date_of_birth.to_datetime,
|
||||||
|
gender: gender,
|
||||||
|
residence_verified_at: Time.current,
|
||||||
|
verified_at: Time.current,
|
||||||
|
erased_at: Time.current,
|
||||||
|
password: random_password,
|
||||||
|
terms_of_service: '1',
|
||||||
|
email: nil
|
||||||
|
}
|
||||||
|
self.user = User.create!(user_params)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_exists?
|
||||||
|
find_user_by_document.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_user_by_document
|
||||||
|
User.where(document_number: document_number,
|
||||||
|
document_type: document_type).first
|
||||||
|
end
|
||||||
|
|
||||||
|
def residence_in_madrid
|
||||||
|
return if errors.any?
|
||||||
|
|
||||||
|
unless residency_valid?
|
||||||
|
errors.add(:residence_in_madrid, false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def allowed_age
|
||||||
|
return if errors[:date_of_birth].any?
|
||||||
|
|
||||||
|
unless allowed_age?
|
||||||
|
errors.add(:date_of_birth, I18n.t('verification.residence.new.error_not_allowed_age'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def allowed_age?
|
||||||
|
self.date_of_birth <= User.minimum_required_age.years.ago
|
||||||
|
end
|
||||||
|
|
||||||
|
def geozone
|
||||||
|
Geozone.where(census_code: district_code).first
|
||||||
|
end
|
||||||
|
|
||||||
|
def district_code
|
||||||
|
@census_api_response.district_code
|
||||||
|
end
|
||||||
|
|
||||||
|
def gender
|
||||||
|
@census_api_response.gender
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def call_census_api
|
||||||
|
@census_api_response = CensusApi.new.call(document_type, document_number)
|
||||||
|
end
|
||||||
|
|
||||||
|
def residency_valid?
|
||||||
|
@census_api_response.valid? &&
|
||||||
|
@census_api_response.date_of_birth == date_of_birth
|
||||||
|
end
|
||||||
|
|
||||||
|
def clean_document_number
|
||||||
|
self.document_number = self.document_number.gsub(/[^a-z0-9]+/i, "").upcase unless self.document_number.blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
def random_password
|
||||||
|
(0...20).map { ('a'..'z').to_a[rand(26)] }.join
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -44,6 +44,10 @@ class Poll < ActiveRecord::Base
|
|||||||
current.joins(:geozones).where('geozone_restricted = ? or geozones.id = ?', false, user.geozone_id)
|
current.joins(:geozones).where('geozone_restricted = ? or geozones.id = ?', false, user.geozone_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def votable_by?(user)
|
||||||
|
!document_has_voted?(user.document_number, user.document_type)
|
||||||
|
end
|
||||||
|
|
||||||
def document_has_voted?(document_number, document_type)
|
def document_has_voted?(document_number, document_type)
|
||||||
voters.where(document_number: document_number, document_type: document_type).exists?
|
voters.where(document_number: document_number, document_type: document_type).exists?
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ class Poll::Answer < ActiveRecord::Base
|
|||||||
scope :by_question, -> (question_id) { where(question_id: question_id) }
|
scope :by_question, -> (question_id) { where(question_id: question_id) }
|
||||||
|
|
||||||
def record_voter_participation
|
def record_voter_participation
|
||||||
Poll::Voter.create_from_user(author, {poll_id: poll_id})
|
Poll::Voter.create!(user: author, poll: poll)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,44 +1,53 @@
|
|||||||
class Poll
|
class Poll
|
||||||
class Voter < ActiveRecord::Base
|
class Voter < ActiveRecord::Base
|
||||||
belongs_to :poll
|
belongs_to :poll
|
||||||
|
belongs_to :user
|
||||||
|
belongs_to :geozone
|
||||||
belongs_to :booth_assignment
|
belongs_to :booth_assignment
|
||||||
|
|
||||||
validates :poll, presence: true
|
validates :poll_id, presence: true
|
||||||
|
validates :user_id, presence: true
|
||||||
|
validates :geozone_id, presence: true
|
||||||
|
validates :gender, presence: true
|
||||||
|
validates :age, presence: true
|
||||||
|
|
||||||
validates :document_number, presence: true, uniqueness: { scope: [:poll_id, :document_type], message: :has_voted }
|
validates :document_number, presence: true, uniqueness: { scope: [:poll_id, :document_type], message: :has_voted }
|
||||||
|
|
||||||
def census_api_response
|
before_validation :set_demographic_info, :set_document_info
|
||||||
@census_api_response ||= CensusApi.new.call(document_type, document_number)
|
|
||||||
|
def set_demographic_info
|
||||||
|
return unless user.present?
|
||||||
|
|
||||||
|
self.gender = user.gender
|
||||||
|
self.age = user.age
|
||||||
|
self.geozone = user.geozone
|
||||||
end
|
end
|
||||||
|
|
||||||
def in_census?
|
def set_document_info
|
||||||
census_api_response.valid?
|
return unless user.present?
|
||||||
end
|
|
||||||
|
|
||||||
def fill_stats_fields
|
self.document_type = user.document_type
|
||||||
if in_census?
|
self.document_number = user.document_number
|
||||||
self.gender = census_api_response.gender
|
|
||||||
self.geozone_id = Geozone.select(:id).where(census_code: census_api_response.district_code).first.try(:id)
|
|
||||||
self.age = voter_age(census_api_response.date_of_birth)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.create_from_user(user, options = {})
|
|
||||||
poll_id = options[:poll_id]
|
|
||||||
booth_assignment_id = options[:booth_assignment_id]
|
|
||||||
|
|
||||||
Voter.create(
|
|
||||||
document_type: user.document_type,
|
|
||||||
document_number: user.document_number,
|
|
||||||
poll_id: poll_id,
|
|
||||||
booth_assignment_id: booth_assignment_id,
|
|
||||||
gender: user.gender,
|
|
||||||
geozone_id: user.geozone_id,
|
|
||||||
age: user.age
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def in_census?
|
||||||
|
census_api_response.valid?
|
||||||
|
end
|
||||||
|
|
||||||
|
def census_api_response
|
||||||
|
@census_api_response ||= CensusApi.new.call(document_type, document_number)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fill_stats_fields
|
||||||
|
if in_census?
|
||||||
|
self.gender = census_api_response.gender
|
||||||
|
self.geozone_id = Geozone.select(:id).where(census_code: census_api_response.district_code).first.try(:id)
|
||||||
|
self.age = voter_age(census_api_response.date_of_birth)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def voter_age(dob)
|
def voter_age(dob)
|
||||||
if dob.blank?
|
if dob.blank?
|
||||||
nil
|
nil
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<ul id="officing_menu">
|
<ul id="officing_menu">
|
||||||
|
|
||||||
<li <%= "class=active" if controller_name == "voters" %>>
|
<li <%= "class=active" if controller_name == "voters" %>>
|
||||||
<%= link_to new_officing_poll_voter_path(Poll.last) do %>
|
<%= link_to new_officing_residence_path do %>
|
||||||
<span class="icon-user"></span>
|
<span class="icon-user"></span>
|
||||||
<%= t("officing.menu.voters") %>
|
<%= t("officing.menu.voters") %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
14
app/views/officing/residence/_errors.html.erb
Normal file
14
app/views/officing/residence/_errors.html.erb
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<% if @residence.errors[:residence_in_madrid].present? %>
|
||||||
|
|
||||||
|
<div id="error_explanation" data-alert class="callout alert" data-closable>
|
||||||
|
<button class="close-button" aria-label="<%= t("application.close") %>" type="button" data-close>
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
<%= t("officing.residence.new.error_verifying_census") %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% else %>
|
||||||
|
<%= render "shared/errors",
|
||||||
|
resource: @residence,
|
||||||
|
message: t("officing.residence.new.form_errors") %>
|
||||||
|
<% end %>
|
||||||
26
app/views/officing/residence/new.html.erb
Normal file
26
app/views/officing/residence/new.html.erb
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<h2><%= t("officing.residence.new.title") %></h2>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 medium-6 column">
|
||||||
|
<%= form_for @residence, as: "residence", url: officing_residence_path do |f| %>
|
||||||
|
<%= render "errors" %>
|
||||||
|
|
||||||
|
<%= f.label t("officing.residence.new.document_type_label") %>
|
||||||
|
<%= f.select :document_type, document_types, prompt: "", label: false %>
|
||||||
|
|
||||||
|
|
||||||
|
<%= f.text_field :document_number,
|
||||||
|
placeholder: t("officing.residence.new.document_number") %>
|
||||||
|
|
||||||
|
<div class="date-of-birth small-12 medium-6 clear">
|
||||||
|
<%= f.label t("verification.residence.new.date_of_birth") %>
|
||||||
|
<%= f.date_select :date_of_birth,
|
||||||
|
prompt: true,
|
||||||
|
start_year: 1900, end_year: 16.years.ago.year,
|
||||||
|
label: false %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="submit" value="<%= t("officing.residence.new.submit") %>" class="button">
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
3
app/views/officing/voters/_already_voted.html.erb
Normal file
3
app/views/officing/voters/_already_voted.html.erb
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<div class="callout warning">
|
||||||
|
<%= t("officing.voters.show.error_already_voted") %>
|
||||||
|
</div>
|
||||||
7
app/views/officing/voters/_can_vote.html.erb
Normal file
7
app/views/officing/voters/_can_vote.html.erb
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<div class="small-12 medium-6 large-4">
|
||||||
|
<%= form_for @user, as: :voter, url: officing_voters_path, method: :post, remote: true do |f| %>
|
||||||
|
<%= f.hidden_field :poll_id, value: poll.id %>
|
||||||
|
<%= f.hidden_field :user_id, value: @user.id %>
|
||||||
|
<%= f.submit t("officing.voters.show.submit"), class: "button success expanded" %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
3
app/views/officing/voters/_voted.html.erb
Normal file
3
app/views/officing/voters/_voted.html.erb
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<div class="callout success">
|
||||||
|
<%= t("officing.voters.show.success") %>
|
||||||
|
</div>
|
||||||
1
app/views/officing/voters/create.js.erb
Normal file
1
app/views/officing/voters/create.js.erb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
$("#<%= dom_id(@poll) %> #actions").html('<%= j render("voted") %>');
|
||||||
@@ -1,20 +1,15 @@
|
|||||||
<h2><%= t("officing.voters.new.title") %></h2>
|
<h2><%= t("officing.voters.new.title") %></h2>
|
||||||
|
|
||||||
<div class="row">
|
<% @polls.each do |poll| %>
|
||||||
<div class="small-12 medium-6 column">
|
<div id="<%= dom_id(poll) %>">
|
||||||
<form>
|
<div><%= poll.name %></div>
|
||||||
|
|
||||||
<label><%= t("officing.voters.new.document_type_label") %></label>
|
<div id="actions">
|
||||||
<select>
|
<% if poll.votable_by?(@user) %>
|
||||||
<option><%= t("officing.voters.new.document_type.spanish_id") %></option>
|
<%= render "can_vote", poll: poll %>
|
||||||
<option><%= t("officing.voters.new.document_type.residence_card") %></option>
|
<% else %>
|
||||||
<option><%= t("officing.voters.new.document_type.passport") %></option>
|
<%= render "already_voted" %>
|
||||||
</select>
|
<% end %>
|
||||||
|
</div>
|
||||||
<label><%= t("officing.voters.new.document_number") %></label>
|
|
||||||
<input type="text" placeholder="<%= t("officing.voters.new.document_number") %>">
|
|
||||||
|
|
||||||
<input type="submit" value="<%= t("officing.voters.new.submit") %>" class="button">
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<% end %>
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<h2><%= t("officing.voters.show.title") %></h2>
|
|
||||||
|
|
||||||
<!-- IF CAN'T VOTE -->
|
|
||||||
|
|
||||||
<div class="callout alert">
|
|
||||||
<%= t("officing.voters.show.error_verifying_census") %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- IF ALREADY VOTED -->
|
|
||||||
|
|
||||||
<div class="callout warning">
|
|
||||||
<%= t("officing.voters.show.error_already_voted") %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- IF CAN VOTE -->
|
|
||||||
|
|
||||||
<div class="callout success">
|
|
||||||
<%= t("officing.voters.show.can_participate") %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="small-12 medium-6 large-4">
|
|
||||||
<form>
|
|
||||||
<input type="submit" value="<%= t("officing.voters.show.submit") %>" class="button success expanded">
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="callout success">
|
|
||||||
<%= t("officing.voters.show.success") %>
|
|
||||||
</div>
|
|
||||||
@@ -29,7 +29,9 @@ en:
|
|||||||
recount_list: "Your recounts"
|
recount_list: "Your recounts"
|
||||||
booth: "Booth"
|
booth: "Booth"
|
||||||
date: "Date"
|
date: "Date"
|
||||||
voters:
|
residence:
|
||||||
|
flash:
|
||||||
|
create: "Document verified with Census"
|
||||||
new:
|
new:
|
||||||
title: Validate document
|
title: Validate document
|
||||||
document_number: Document number
|
document_number: Document number
|
||||||
@@ -39,10 +41,15 @@ en:
|
|||||||
spanish_id: DNI
|
spanish_id: DNI
|
||||||
document_type_label: Document type
|
document_type_label: Document type
|
||||||
submit: Validate document
|
submit: Validate document
|
||||||
|
error_verifying_census: "The Census was unable to verify this document."
|
||||||
|
error_not_allowed_age: You don't have the required age to participate
|
||||||
|
error_verifying_census_offices: Citizen Support Office
|
||||||
|
form_errors: prevented the verification of this document
|
||||||
|
voters:
|
||||||
|
new:
|
||||||
|
title: Polls
|
||||||
show:
|
show:
|
||||||
title: Validate document
|
title: Validate document
|
||||||
error_verifying_census: "The Census was unable to verify the information of this document."
|
error_already_voted: Has already participated in this poll
|
||||||
error_already_voted: "The person associated with the document has already participated in the vote."
|
|
||||||
can_participate: "The person associated with the document can participate in the vote."
|
|
||||||
submit: Validate vote
|
submit: Validate vote
|
||||||
success: "Vote validated correctly."
|
success: Vote validated successfully.
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ es:
|
|||||||
recount_list: "Tus recuentos"
|
recount_list: "Tus recuentos"
|
||||||
booth: "Urna"
|
booth: "Urna"
|
||||||
date: "Fecha"
|
date: "Fecha"
|
||||||
voters:
|
residence:
|
||||||
|
flash:
|
||||||
|
create: "Documento verificado con el Padrón"
|
||||||
new:
|
new:
|
||||||
title: Validar documento
|
title: Validar documento
|
||||||
document_number: Número de documento
|
document_number: Número de documento
|
||||||
@@ -39,10 +41,15 @@ es:
|
|||||||
spanish_id: DNI
|
spanish_id: DNI
|
||||||
document_type_label: Tipo de documento
|
document_type_label: Tipo de documento
|
||||||
submit: Validar documento
|
submit: Validar documento
|
||||||
|
error_not_allowed_age: No tienes la edad mínima para participar
|
||||||
|
error_verifying_census: El Padrón no pudo verificar este documento.
|
||||||
|
form_errors: evitaron verificar este documento
|
||||||
|
voters:
|
||||||
|
new:
|
||||||
|
title: Votaciones
|
||||||
show:
|
show:
|
||||||
title: Validar documento
|
title: Validar documento
|
||||||
error_verifying_census: "El Padrón no pudo verificar la información de este documento."
|
error_already_voted: "Ya ha participado en la votación."
|
||||||
error_already_voted: "La persona asociada al documento ya ha participado en la votación."
|
|
||||||
can_participate: "La persona asociada al documento puede participar en la votación."
|
can_participate: "La persona asociada al documento puede participar en la votación."
|
||||||
submit: Validar voto
|
submit: Validar voto
|
||||||
success: "Voto validado correctamente."
|
success: Voto validado correctamente.
|
||||||
|
|||||||
@@ -333,8 +333,9 @@ Rails.application.routes.draw do
|
|||||||
namespace :officing do
|
namespace :officing do
|
||||||
resources :polls, only: [:index] do
|
resources :polls, only: [:index] do
|
||||||
resources :recounts, only: [:new, :create]
|
resources :recounts, only: [:new, :create]
|
||||||
resources :voters, only: [:new, :show]
|
|
||||||
end
|
end
|
||||||
|
resource :residence, controller: "residence", only: [:new, :create]
|
||||||
|
resources :voters, only: [:new, :create]
|
||||||
root to: "dashboard#index"
|
root to: "dashboard#index"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ Setting.create(key: 'min_age_to_participate', value: '16')
|
|||||||
puts "Creating Geozones"
|
puts "Creating Geozones"
|
||||||
|
|
||||||
Geozone.create(name: "city")
|
Geozone.create(name: "city")
|
||||||
|
Geozone.create(name: "Existent District", census_code: "01")
|
||||||
('A'..'Z').each { |i| Geozone.create(name: "District #{i}", external_code: i.ord, census_code: i.ord) }
|
('A'..'Z').each { |i| Geozone.create(name: "District #{i}", external_code: i.ord, census_code: i.ord) }
|
||||||
|
|
||||||
puts "Creating Users"
|
puts "Creating Users"
|
||||||
@@ -569,3 +570,11 @@ puts "Commenting Poll Questions"
|
|||||||
commentable: question,
|
commentable: question,
|
||||||
body: Faker::Lorem.sentence)
|
body: Faker::Lorem.sentence)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
puts "Creating Poll Voters"
|
||||||
|
|
||||||
|
(1..10).each do
|
||||||
|
poll = Poll.all.sample
|
||||||
|
document_number = Faker::Number.number(10)
|
||||||
|
Poll::Voter.create!(poll: poll, document_number: document_number)
|
||||||
|
end
|
||||||
|
|||||||
5
db/migrate/20170128214244_adds_user_id_to_poll_voters.rb
Normal file
5
db/migrate/20170128214244_adds_user_id_to_poll_voters.rb
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class AddsUserIdToPollVoters < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_reference :poll_voters, :user, index: true
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20170125114952) do
|
ActiveRecord::Schema.define(version: 20170128214244) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@@ -469,11 +469,13 @@ ActiveRecord::Schema.define(version: 20170125114952) do
|
|||||||
t.string "gender"
|
t.string "gender"
|
||||||
t.integer "geozone_id"
|
t.integer "geozone_id"
|
||||||
t.integer "answer_id"
|
t.integer "answer_id"
|
||||||
|
t.integer "user_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "poll_voters", ["document_number"], name: "index_poll_voters_on_document_number", using: :btree
|
add_index "poll_voters", ["document_number"], name: "index_poll_voters_on_document_number", using: :btree
|
||||||
add_index "poll_voters", ["poll_id", "document_number", "document_type"], name: "doc_by_poll", using: :btree
|
add_index "poll_voters", ["poll_id", "document_number", "document_type"], name: "doc_by_poll", using: :btree
|
||||||
add_index "poll_voters", ["poll_id"], name: "index_poll_voters_on_poll_id", using: :btree
|
add_index "poll_voters", ["poll_id"], name: "index_poll_voters_on_poll_id", using: :btree
|
||||||
|
add_index "poll_voters", ["user_id"], name: "index_poll_voters_on_user_id", using: :btree
|
||||||
|
|
||||||
create_table "polls", force: :cascade do |t|
|
create_table "polls", force: :cascade do |t|
|
||||||
t.string "name"
|
t.string "name"
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ FactoryGirl.define do
|
|||||||
sms_confirmation_code "1234"
|
sms_confirmation_code "1234"
|
||||||
document_type "1"
|
document_type "1"
|
||||||
document_number
|
document_number
|
||||||
|
date_of_birth Date.new(1980, 12, 31)
|
||||||
|
gender "female"
|
||||||
|
geozone
|
||||||
end
|
end
|
||||||
|
|
||||||
trait :level_three do
|
trait :level_three do
|
||||||
@@ -37,6 +40,7 @@ FactoryGirl.define do
|
|||||||
trait :with_confirmed_hide do
|
trait :with_confirmed_hide do
|
||||||
confirmed_hide_at Time.current
|
confirmed_hide_at Time.current
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
factory :identity do
|
factory :identity do
|
||||||
@@ -422,6 +426,7 @@ FactoryGirl.define do
|
|||||||
|
|
||||||
factory :poll_voter, class: 'Poll::Voter' do
|
factory :poll_voter, class: 'Poll::Voter' do
|
||||||
poll
|
poll
|
||||||
|
association :user, :level_two
|
||||||
|
|
||||||
trait :from_booth do
|
trait :from_booth do
|
||||||
association :booth_assignment, factory: :poll_booth_assignment
|
association :booth_assignment, factory: :poll_booth_assignment
|
||||||
@@ -451,6 +456,13 @@ FactoryGirl.define do
|
|||||||
answer { question.valid_answers.sample }
|
answer { question.valid_answers.sample }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
factory :officing_residence, class: 'Officing::Residence' do
|
||||||
|
user
|
||||||
|
document_number
|
||||||
|
document_type "1"
|
||||||
|
date_of_birth Date.new(1980, 12, 31)
|
||||||
|
end
|
||||||
|
|
||||||
factory :organization do
|
factory :organization do
|
||||||
user
|
user
|
||||||
responsible_name "Johnny Utah"
|
responsible_name "Johnny Utah"
|
||||||
@@ -507,6 +519,10 @@ FactoryGirl.define do
|
|||||||
sequence(:name) { |n| "District #{n}" }
|
sequence(:name) { |n| "District #{n}" }
|
||||||
sequence(:external_code) { |n| "#{n}" }
|
sequence(:external_code) { |n| "#{n}" }
|
||||||
sequence(:census_code) { |n| "#{n}" }
|
sequence(:census_code) { |n| "#{n}" }
|
||||||
|
|
||||||
|
trait :in_census do
|
||||||
|
census_code "01"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
factory :banner do
|
factory :banner do
|
||||||
|
|||||||
50
spec/features/officing/residence_spec.rb
Normal file
50
spec/features/officing/residence_spec.rb
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
feature 'Residence' do
|
||||||
|
let(:officer) { create(:poll_officer) }
|
||||||
|
|
||||||
|
background do
|
||||||
|
login_as(officer.user)
|
||||||
|
visit officing_root_path
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Verify voter" do
|
||||||
|
within("#side_menu") do
|
||||||
|
click_link "Validate document"
|
||||||
|
end
|
||||||
|
|
||||||
|
fill_in 'residence_document_number', with: "12345678Z"
|
||||||
|
select 'DNI', from: 'residence_document_type'
|
||||||
|
select_date '31-December-1980', from: 'residence_date_of_birth'
|
||||||
|
|
||||||
|
click_button 'Validate document'
|
||||||
|
|
||||||
|
expect(page).to have_content 'Document verified with Census'
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Error on verify" do
|
||||||
|
within("#side_menu") do
|
||||||
|
click_link "Validate document"
|
||||||
|
end
|
||||||
|
|
||||||
|
click_button 'Validate document'
|
||||||
|
expect(page).to have_content /\d errors? prevented the verification of this document/
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Error on Census" do
|
||||||
|
within("#side_menu") do
|
||||||
|
click_link "Validate document"
|
||||||
|
end
|
||||||
|
|
||||||
|
fill_in 'residence_document_number', with: "12345678Z"
|
||||||
|
select 'DNI', from: 'residence_document_type'
|
||||||
|
select '1997', from: 'residence_date_of_birth_1i'
|
||||||
|
select 'January', from: 'residence_date_of_birth_2i'
|
||||||
|
select '1', from: 'residence_date_of_birth_3i'
|
||||||
|
|
||||||
|
click_button 'Validate document'
|
||||||
|
|
||||||
|
expect(page).to have_content 'The Census was unable to verify this document'
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
55
spec/features/officing/voters_spec.rb
Normal file
55
spec/features/officing/voters_spec.rb
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
feature 'Voters' do
|
||||||
|
|
||||||
|
let(:officer) { create(:poll_officer) }
|
||||||
|
|
||||||
|
background do
|
||||||
|
login_as(officer.user)
|
||||||
|
create(:geozone, :in_census)
|
||||||
|
|
||||||
|
#remove once foundation.equalizer js error has been fixed
|
||||||
|
Capybara.current_driver = :poltergeist_no_js_errors
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Can vote", :js do
|
||||||
|
poll = create(:poll)
|
||||||
|
|
||||||
|
visit new_officing_residence_path
|
||||||
|
officing_verify_residence
|
||||||
|
|
||||||
|
expect(page).to have_content "Polls"
|
||||||
|
expect(page).to have_content poll.name
|
||||||
|
|
||||||
|
click_button "Validate vote"
|
||||||
|
|
||||||
|
expect(page).to have_content "Vote validated successfully"
|
||||||
|
expect(page).to_not have_button "Validate vote"
|
||||||
|
|
||||||
|
page.evaluate_script("window.location.reload()")
|
||||||
|
expect(page).to have_content "Has already participated in this poll"
|
||||||
|
expect(page).to_not have_button "Validate vote"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Already voted", :js do
|
||||||
|
poll1 = create(:poll)
|
||||||
|
poll2 = create(:poll)
|
||||||
|
|
||||||
|
user = create(:user, :level_two)
|
||||||
|
voter = create(:poll_voter, poll: poll1, user: user)
|
||||||
|
|
||||||
|
visit new_officing_voter_path(id: voter.user.id)
|
||||||
|
|
||||||
|
within("#poll_#{poll1.id}") do
|
||||||
|
expect(page).to have_content "Has already participated in this poll"
|
||||||
|
expect(page).to_not have_button "Validate vote"
|
||||||
|
end
|
||||||
|
|
||||||
|
within("#poll_#{poll2.id}") do
|
||||||
|
expect(page).to have_button "Validate vote"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#Fix and use answerable_by(user)
|
||||||
|
xscenario "Display only answerable polls"
|
||||||
|
end
|
||||||
@@ -15,6 +15,7 @@ feature 'Poll Questions' do
|
|||||||
context 'Answering' do
|
context 'Answering' do
|
||||||
let(:geozone) { create(:geozone) }
|
let(:geozone) { create(:geozone) }
|
||||||
let(:poll) { create(:poll, geozone_restricted: true, geozone_ids: [geozone.id]) }
|
let(:poll) { create(:poll, geozone_restricted: true, geozone_ids: [geozone.id]) }
|
||||||
|
|
||||||
scenario 'Non-logged in users' do
|
scenario 'Non-logged in users' do
|
||||||
question = create(:poll_question, valid_answers: 'Han Solo, Chewbacca')
|
question = create(:poll_question, valid_answers: 'Han Solo, Chewbacca')
|
||||||
|
|
||||||
|
|||||||
87
spec/models/officing/residence_spec.rb
Normal file
87
spec/models/officing/residence_spec.rb
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe Officing::Residence do
|
||||||
|
|
||||||
|
let!(:geozone) { create(:geozone, census_code: "01") }
|
||||||
|
let(:residence) { build(:officing_residence, document_number: "12345678Z") }
|
||||||
|
|
||||||
|
describe "validations" do
|
||||||
|
|
||||||
|
it "should be valid" do
|
||||||
|
expect(residence).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "dates" do
|
||||||
|
it "should be valid with a valid date of birth" do
|
||||||
|
residence = Officing::Residence.new({"date_of_birth(3i)"=>"1", "date_of_birth(2i)"=>"1", "date_of_birth(1i)"=>"1980"})
|
||||||
|
expect(residence.errors[:date_of_birth].size).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without a date of birth" do
|
||||||
|
residence = Officing::Residence.new({"date_of_birth(3i)"=>"", "date_of_birth(2i)"=>"", "date_of_birth(1i)"=>""})
|
||||||
|
expect(residence).to_not be_valid
|
||||||
|
expect(residence.errors[:date_of_birth]).to include("can't be blank")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should validate user has allowed age" do
|
||||||
|
residence = Officing::Residence.new({"date_of_birth(3i)"=>"1", "date_of_birth(2i)"=>"1", "date_of_birth(1i)"=>"#{5.year.ago.year}"})
|
||||||
|
expect(residence).to_not be_valid
|
||||||
|
expect(residence.errors[:date_of_birth]).to include("You don't have the required age to participate")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "new" do
|
||||||
|
it "should upcase document number" do
|
||||||
|
residence = Officing::Residence.new({document_number: "x1234567z"})
|
||||||
|
expect(residence.document_number).to eq("X1234567Z")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should remove all characters except numbers and letters" do
|
||||||
|
residence = Officing::Residence.new({document_number: " 12.345.678 - B"})
|
||||||
|
expect(residence.document_number).to eq("12345678B")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "save" do
|
||||||
|
|
||||||
|
it "should store document number, document type, geozone, date of birth and gender" do
|
||||||
|
residence.save
|
||||||
|
user = residence.user
|
||||||
|
|
||||||
|
expect(user.document_number).to eq('12345678Z')
|
||||||
|
expect(user.document_type).to eq("1")
|
||||||
|
expect(user.date_of_birth.year).to eq(1980)
|
||||||
|
expect(user.date_of_birth.month).to eq(12)
|
||||||
|
expect(user.date_of_birth.day).to eq(31)
|
||||||
|
expect(user.gender).to eq('male')
|
||||||
|
expect(user.geozone).to eq(geozone)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should find existing user and use demographic information" do
|
||||||
|
geozone = create(:geozone)
|
||||||
|
create(:user, document_number: "12345678Z",
|
||||||
|
document_type: "1",
|
||||||
|
date_of_birth: Date.new(1981, 11, 30),
|
||||||
|
gender: 'female',
|
||||||
|
geozone: geozone)
|
||||||
|
|
||||||
|
residence = build(:officing_residence,
|
||||||
|
document_number: "12345678Z",
|
||||||
|
document_type: "1")
|
||||||
|
|
||||||
|
residence.save
|
||||||
|
user = residence.user
|
||||||
|
|
||||||
|
expect(user.document_number).to eq('12345678Z')
|
||||||
|
expect(user.document_type).to eq("1")
|
||||||
|
expect(user.date_of_birth.year).to eq(1981)
|
||||||
|
expect(user.date_of_birth.month).to eq(11)
|
||||||
|
expect(user.date_of_birth.day).to eq(30)
|
||||||
|
expect(user.gender).to eq('female')
|
||||||
|
expect(user.geozone).to eq(geozone)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -5,9 +5,29 @@ describe :voter do
|
|||||||
let(:poll) { create(:poll) }
|
let(:poll) { create(:poll) }
|
||||||
let(:booth) { create(:poll_booth) }
|
let(:booth) { create(:poll_booth) }
|
||||||
let(:booth_assignment) { create(:poll_booth_assignment, poll: poll, booth: booth) }
|
let(:booth_assignment) { create(:poll_booth_assignment, poll: poll, booth: booth) }
|
||||||
|
let(:voter) { create(:poll_voter) }
|
||||||
|
|
||||||
describe "validations" do
|
describe "validations" do
|
||||||
|
|
||||||
|
it "should be valid" do
|
||||||
|
expect(voter).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without a user" do
|
||||||
|
voter.user = nil
|
||||||
|
expect(voter).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without a poll" do
|
||||||
|
voter.poll = nil
|
||||||
|
expect(voter).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without a geozone" do
|
||||||
|
voter.user.geozone = nil
|
||||||
|
expect(voter).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
it "should be valid if has not voted" do
|
it "should be valid if has not voted" do
|
||||||
voter = build(:poll_voter, :valid_document)
|
voter = build(:poll_voter, :valid_document)
|
||||||
|
|
||||||
@@ -61,4 +81,31 @@ describe :voter do
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "save" do
|
||||||
|
|
||||||
|
it "sets demographic info" do
|
||||||
|
geozone = create(:geozone)
|
||||||
|
user = create(:user,
|
||||||
|
geozone: geozone,
|
||||||
|
date_of_birth: 30.years.ago,
|
||||||
|
gender: "female")
|
||||||
|
|
||||||
|
voter = build(:poll_voter, user: user)
|
||||||
|
voter.save
|
||||||
|
|
||||||
|
expect(voter.geozone).to eq(geozone)
|
||||||
|
expect(voter.age).to eq(30)
|
||||||
|
expect(voter.gender).to eq("female")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets user info" do
|
||||||
|
user = create(:user, document_number: "1234A", document_type: "1")
|
||||||
|
voter = build(:poll_voter, user: user)
|
||||||
|
voter.save
|
||||||
|
|
||||||
|
expect(voter.document_number).to eq("1234A")
|
||||||
|
expect(voter.document_type).to eq("1")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@@ -105,4 +105,9 @@ RSpec.configure do |config|
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Parallel build helper configuration for travis
|
# Parallel build helper configuration for travis
|
||||||
Knapsack::Adapters::RSpecAdapter.bind
|
Knapsack::Adapters::RSpecAdapter.bind
|
||||||
|
|
||||||
|
options = {js_errors: false}
|
||||||
|
Capybara.register_driver :poltergeist_no_js_errors do |app|
|
||||||
|
Capybara::Poltergeist::Driver.new(app, options)
|
||||||
|
end
|
||||||
@@ -141,6 +141,16 @@ module CommonActions
|
|||||||
expect(page).to have_content 'Residence verified'
|
expect(page).to have_content 'Residence verified'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def officing_verify_residence
|
||||||
|
fill_in 'residence_document_number', with: "12345678Z"
|
||||||
|
select 'DNI', from: 'residence_document_type'
|
||||||
|
select_date '31-December-1980', from: 'residence_date_of_birth'
|
||||||
|
|
||||||
|
click_button 'Validate document'
|
||||||
|
|
||||||
|
expect(page).to have_content 'Document verified with Census'
|
||||||
|
end
|
||||||
|
|
||||||
def confirm_phone
|
def confirm_phone
|
||||||
fill_in 'sms_phone', with: "611111111"
|
fill_in 'sms_phone', with: "611111111"
|
||||||
click_button 'Send'
|
click_button 'Send'
|
||||||
|
|||||||
Reference in New Issue
Block a user