Merge branch 'master' into community
11
Gemfile.lock
@@ -199,7 +199,7 @@ GEM
|
|||||||
terminal-table (>= 1.5.1)
|
terminal-table (>= 1.5.1)
|
||||||
initialjs-rails (0.2.0.5)
|
initialjs-rails (0.2.0.5)
|
||||||
railties (>= 3.1, < 6.0)
|
railties (>= 3.1, < 6.0)
|
||||||
invisible_captcha (0.9.2)
|
invisible_captcha (0.9.3)
|
||||||
rails (>= 3.2.0)
|
rails (>= 3.2.0)
|
||||||
jquery-fileupload-rails (0.4.7)
|
jquery-fileupload-rails (0.4.7)
|
||||||
actionpack (>= 3.1)
|
actionpack (>= 3.1)
|
||||||
@@ -251,7 +251,7 @@ GEM
|
|||||||
mime-types-data (3.2016.0521)
|
mime-types-data (3.2016.0521)
|
||||||
mimemagic (0.3.2)
|
mimemagic (0.3.2)
|
||||||
mini_portile2 (2.2.0)
|
mini_portile2 (2.2.0)
|
||||||
minitest (5.10.2)
|
minitest (5.10.3)
|
||||||
mixlib-cli (1.7.0)
|
mixlib-cli (1.7.0)
|
||||||
mixlib-config (2.2.4)
|
mixlib-config (2.2.4)
|
||||||
multi_json (1.12.1)
|
multi_json (1.12.1)
|
||||||
@@ -368,7 +368,7 @@ GEM
|
|||||||
rspec-mocks (3.6.0)
|
rspec-mocks (3.6.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.6.0)
|
rspec-support (~> 3.6.0)
|
||||||
rspec-rails (3.6.0)
|
rspec-rails (3.6.1)
|
||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
railties (>= 3.0)
|
railties (>= 3.0)
|
||||||
@@ -398,7 +398,7 @@ GEM
|
|||||||
sprockets (>= 2.8, < 4.0)
|
sprockets (>= 2.8, < 4.0)
|
||||||
sprockets-rails (>= 2.0, < 4.0)
|
sprockets-rails (>= 2.0, < 4.0)
|
||||||
tilt (>= 1.1, < 3)
|
tilt (>= 1.1, < 3)
|
||||||
savon (2.11.1)
|
savon (2.11.2)
|
||||||
akami (~> 1.2)
|
akami (~> 1.2)
|
||||||
builder (>= 2.1.2)
|
builder (>= 2.1.2)
|
||||||
gyoku (~> 1.2)
|
gyoku (~> 1.2)
|
||||||
@@ -430,7 +430,7 @@ GEM
|
|||||||
babel-source (>= 5.8.11)
|
babel-source (>= 5.8.11)
|
||||||
babel-transpiler
|
babel-transpiler
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
sprockets-rails (3.2.0)
|
sprockets-rails (3.2.1)
|
||||||
actionpack (>= 4.0)
|
actionpack (>= 4.0)
|
||||||
activesupport (>= 4.0)
|
activesupport (>= 4.0)
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
@@ -565,6 +565,5 @@ DEPENDENCIES
|
|||||||
web-console (~> 3.3.0)
|
web-console (~> 3.3.0)
|
||||||
whenever (~> 0.9.7)
|
whenever (~> 0.9.7)
|
||||||
|
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.15.3
|
1.15.3
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -894,17 +894,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.help-link {
|
.help-header {
|
||||||
margin-left: $line-height;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&::before {
|
h1 {
|
||||||
color: $link;
|
font-size: rem-calc(24);
|
||||||
content: '\4e';
|
|
||||||
font-family: 'icons';
|
|
||||||
position: absolute;
|
|
||||||
left: -24px;
|
|
||||||
top: -2px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,35 +32,6 @@ class Admin::Poll::OfficerAssignmentsController < Admin::BaseController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
|
||||||
@officer_assignment = ::Poll::OfficerAssignment.new(booth_assignment: @booth_assignment,
|
|
||||||
officer_id: create_params[:officer_id],
|
|
||||||
date: create_params[:date])
|
|
||||||
@officer_assignment.final = true if @officer_assignment.date > @booth_assignment.poll.ends_at.to_date
|
|
||||||
|
|
||||||
if @officer_assignment.save
|
|
||||||
notice = t("admin.poll_officer_assignments.flash.create")
|
|
||||||
else
|
|
||||||
notice = t("admin.poll_officer_assignments.flash.error_create")
|
|
||||||
end
|
|
||||||
|
|
||||||
redirect_params = { poll_id: create_params[:poll_id], officer_id: create_params[:officer_id] }
|
|
||||||
redirect_to by_officer_admin_poll_officer_assignments_path(redirect_params), notice: notice
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy
|
|
||||||
@officer_assignment = ::Poll::OfficerAssignment.includes(:booth_assignment).find(params[:id])
|
|
||||||
|
|
||||||
if @officer_assignment.destroy
|
|
||||||
notice = t("admin.poll_officer_assignments.flash.destroy")
|
|
||||||
else
|
|
||||||
notice = t("admin.poll_officer_assignments.flash.error_destroy")
|
|
||||||
end
|
|
||||||
|
|
||||||
redirect_params = { poll_id: @officer_assignment.poll_id, officer_id: @officer_assignment.officer_id }
|
|
||||||
redirect_to by_officer_admin_poll_officer_assignments_path(redirect_params), notice: notice
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def officer_assignment_params
|
def officer_assignment_params
|
||||||
|
|||||||
53
app/controllers/admin/poll/shifts_controller.rb
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
class Admin::Poll::ShiftsController < Admin::BaseController
|
||||||
|
|
||||||
|
before_action :load_booth
|
||||||
|
before_action :load_polls
|
||||||
|
|
||||||
|
def new
|
||||||
|
load_officers
|
||||||
|
load_shifts
|
||||||
|
@shift = ::Poll::Shift.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@shift = ::Poll::Shift.new(shift_params)
|
||||||
|
if @shift.save
|
||||||
|
notice = t("admin.poll_shifts.flash.create")
|
||||||
|
redirect_to new_admin_booth_shift_path(@shift.booth), notice: notice
|
||||||
|
else
|
||||||
|
load_officers
|
||||||
|
load_shifts
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@shift = Poll::Shift.find(params[:id])
|
||||||
|
@shift.destroy
|
||||||
|
notice = t("admin.poll_shifts.flash.destroy")
|
||||||
|
redirect_to new_admin_booth_shift_path(@booth), notice: notice
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_booth
|
||||||
|
@booth = ::Poll::Booth.find(params[:booth_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_polls
|
||||||
|
@polls = ::Poll.current_or_incoming
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_officers
|
||||||
|
@officers = ::Poll::Officer.all
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_shifts
|
||||||
|
@shifts = @booth.shifts
|
||||||
|
end
|
||||||
|
|
||||||
|
def shift_params
|
||||||
|
params.require(:shift).permit(:booth_id, :officer_id, :date)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
23
app/helpers/shifts_helper.rb
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
module ShiftsHelper
|
||||||
|
|
||||||
|
def shift_dates_select_options(polls)
|
||||||
|
options = []
|
||||||
|
(start_date(polls)..end_date(polls)).each do |date|
|
||||||
|
options << [l(date, format: :long), l(date)]
|
||||||
|
end
|
||||||
|
options_for_select(options, params[:date])
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_date(polls)
|
||||||
|
polls.map(&:starts_at).min.to_date
|
||||||
|
end
|
||||||
|
|
||||||
|
def end_date(polls)
|
||||||
|
polls.map(&:ends_at).max.to_date
|
||||||
|
end
|
||||||
|
|
||||||
|
def officer_select_options(officers)
|
||||||
|
officers.collect { |officer| [officer.name, officer.id] }
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -35,6 +35,10 @@ class Poll < ActiveRecord::Base
|
|||||||
ends_at < timestamp
|
ends_at < timestamp
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.current_or_incoming
|
||||||
|
current + incoming
|
||||||
|
end
|
||||||
|
|
||||||
def answerable_by?(user)
|
def answerable_by?(user)
|
||||||
user.present? &&
|
user.present? &&
|
||||||
user.level_two_or_three_verified? &&
|
user.level_two_or_three_verified? &&
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ class Poll
|
|||||||
class Booth < ActiveRecord::Base
|
class Booth < ActiveRecord::Base
|
||||||
has_many :booth_assignments, class_name: "Poll::BoothAssignment"
|
has_many :booth_assignments, class_name: "Poll::BoothAssignment"
|
||||||
has_many :polls, through: :booth_assignments
|
has_many :polls, through: :booth_assignments
|
||||||
|
has_many :shifts
|
||||||
|
|
||||||
validates :name, presence: true, uniqueness: true
|
validates :name, presence: true, uniqueness: true
|
||||||
|
|
||||||
|
|||||||
22
app/models/poll/shift.rb
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
class Poll
|
||||||
|
class Shift < ActiveRecord::Base
|
||||||
|
belongs_to :booth
|
||||||
|
belongs_to :officer
|
||||||
|
|
||||||
|
validates :booth_id, presence: true
|
||||||
|
validates :officer_id, presence: true
|
||||||
|
validates :date, presence: true
|
||||||
|
validates :date, uniqueness: { scope: [:officer_id, :booth_id] }
|
||||||
|
|
||||||
|
after_create :create_officer_assignments
|
||||||
|
|
||||||
|
def create_officer_assignments
|
||||||
|
booth.booth_assignments.each do |booth_assignment|
|
||||||
|
attrs = { officer_id: officer_id,
|
||||||
|
date: date,
|
||||||
|
booth_assignment_id: booth_assignment.id }
|
||||||
|
Poll::OfficerAssignment.create!(attrs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -73,9 +73,13 @@
|
|||||||
<%= link_to t('admin.menu.poll_officers'), admin_officers_path %>
|
<%= link_to t('admin.menu.poll_officers'), admin_officers_path %>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li <%= "class=active" if controller_name == "booths" %>>
|
<li <%# "class=active" if controller_name == "booths" %>>
|
||||||
<%= link_to t('admin.menu.poll_booths'), admin_booths_path %>
|
<%= link_to t('admin.menu.poll_booths'), admin_booths_path %>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li <%= "class=active" if controller_name == "booths" %>>
|
||||||
|
<%= link_to t('admin.menu.poll_shifts'), admin_booths_path %>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
<%= booth.location %>
|
<%= booth.location %>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
|
<%= link_to t("admin.booths.booth.shifts"),
|
||||||
|
new_admin_booth_shift_path(booth),
|
||||||
|
class: "button hollow" %>
|
||||||
<%= link_to t("admin.actions.edit"),
|
<%= link_to t("admin.actions.edit"),
|
||||||
edit_admin_booth_path(booth),
|
edit_admin_booth_path(booth),
|
||||||
class: "button hollow" %>
|
class: "button hollow" %>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
<th><%= t("admin.booths.index.name") %></th>
|
<th><%= t("admin.booths.index.name") %></th>
|
||||||
<th><%= t("admin.booths.index.location") %></th>
|
<th><%= t("admin.booths.index.location") %></th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
|
<th> </th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<% @booths.each do |booth| %>
|
<% @booths.each do |booth| %>
|
||||||
|
|||||||
@@ -5,35 +5,6 @@
|
|||||||
|
|
||||||
<h2><%= @officer.name %> - <%= @officer.email %></h2>
|
<h2><%= @officer.name %> - <%= @officer.email %></h2>
|
||||||
|
|
||||||
<%= form_tag(admin_poll_officer_assignments_path(@poll), {id: "officer_assignment_form"}) do %>
|
|
||||||
<fieldset class="fieldset">
|
|
||||||
<legend><%= t("admin.poll_officer_assignments.by_officer.new_assignment") %></legend>
|
|
||||||
<div class="small-12 medium-4 column">
|
|
||||||
<label><%= t("admin.poll_officer_assignments.by_officer.date") %></label>
|
|
||||||
<%= select_tag :date,
|
|
||||||
poll_dates_select_options(@poll) + poll_final_recount_option(@poll),
|
|
||||||
{ prompt: t("admin.poll_officer_assignments.by_officer.select_date"),
|
|
||||||
label: false } %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="small-12 medium-4 column">
|
|
||||||
<label><%= t("admin.poll_officer_assignments.by_officer.booth") %></label>
|
|
||||||
<%= select_tag :booth_id,
|
|
||||||
poll_booths_select_options(@poll),
|
|
||||||
{ prompt: t("admin.poll_officer_assignments.by_officer.select_booth"),
|
|
||||||
label: false } %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="small-12 medium-4 column">
|
|
||||||
<%= hidden_field_tag :officer_id, @officer.id %>
|
|
||||||
<%= hidden_field_tag :poll_id, @poll.id %>
|
|
||||||
<%= submit_tag t("admin.poll_officer_assignments.by_officer.add_assignment"),
|
|
||||||
class: "button expanded hollow margin-top" %>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
|
|
||||||
<% if @officer_assignments.empty? %>
|
<% if @officer_assignments.empty? %>
|
||||||
<div class="callout primary margin-top">
|
<div class="callout primary margin-top">
|
||||||
<%= t("admin.poll_officer_assignments.by_officer.no_assignments") %>
|
<%= t("admin.poll_officer_assignments.by_officer.no_assignments") %>
|
||||||
@@ -45,7 +16,6 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th><%= t("admin.poll_officer_assignments.by_officer.date") %></th>
|
<th><%= t("admin.poll_officer_assignments.by_officer.date") %></th>
|
||||||
<th><%= t("admin.poll_officer_assignments.by_officer.booth") %></th>
|
<th><%= t("admin.poll_officer_assignments.by_officer.booth") %></th>
|
||||||
<th class="text-right"><%= t("admin.poll_officer_assignments.by_officer.assignment") %></th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -53,12 +23,6 @@
|
|||||||
<tr id="<%= dom_id officer_assignment %>">
|
<tr id="<%= dom_id officer_assignment %>">
|
||||||
<td><%= officer_assignment.final? ? t('polls.final_date') : l(officer_assignment.date.to_date) %></td>
|
<td><%= officer_assignment.final? ? t('polls.final_date') : l(officer_assignment.date.to_date) %></td>
|
||||||
<td><%= booth_name_with_location(officer_assignment.booth_assignment.booth) %></td>
|
<td><%= booth_name_with_location(officer_assignment.booth_assignment.booth) %></td>
|
||||||
<td class="text-right">
|
|
||||||
<%= link_to t("admin.poll_officer_assignments.by_officer.remove_assignment"),
|
|
||||||
admin_poll_officer_assignment_path(@poll, officer_assignment),
|
|
||||||
method: :delete,
|
|
||||||
class: "button hollow alert" %>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -93,6 +57,3 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
24
app/views/admin/poll/shifts/_shifts.html.erb
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<h3><%= t("admin.poll_shifts.new.assignments") %></h3>
|
||||||
|
<table class="fixed">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><%= t("admin.poll_shifts.new.date") %></th>
|
||||||
|
<th><%= t("admin.poll_shifts.new.officer") %></th>
|
||||||
|
<th class="text-right"><%= t("admin.poll_shifts.new.assignment") %></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% @shifts.each do |shift| %>
|
||||||
|
<tr id="shift_<%= shift.id %>" class="shift">
|
||||||
|
<td><%= l(shift.date.to_date, format: :long) %></td>
|
||||||
|
<td><%= shift.officer.name %></td>
|
||||||
|
<td class="text-right">
|
||||||
|
<%= link_to t("admin.poll_shifts.new.remove_assignment"),
|
||||||
|
admin_booth_shift_path(@booth, shift),
|
||||||
|
method: :delete,
|
||||||
|
class: "button hollow alert" %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
46
app/views/admin/poll/shifts/new.html.erb
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<%= back_link_to admin_booths_path %>
|
||||||
|
|
||||||
|
<h2><%= @booth.name %></h2>
|
||||||
|
|
||||||
|
<%= form_for @shift, as: :shift, url: admin_booth_shifts_path do |f| %>
|
||||||
|
<%= render "shared/errors", resource: @shift %>
|
||||||
|
|
||||||
|
<fieldset class="fieldset">
|
||||||
|
<legend>
|
||||||
|
<%= t("admin.poll_shifts.new.new_assignment") %>
|
||||||
|
</legend>
|
||||||
|
|
||||||
|
<div class="small-12 medium-4 column">
|
||||||
|
<label><%= t("admin.poll_shifts.new.date") %></label>
|
||||||
|
<%= f.select :date,
|
||||||
|
shift_dates_select_options(@polls),
|
||||||
|
prompt: t("admin.poll_shifts.new.select_date"),
|
||||||
|
label: false %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="small-12 medium-4 column">
|
||||||
|
<label><%= t("admin.poll_shifts.new.officer") %></label>
|
||||||
|
<%= f.select :officer_id,
|
||||||
|
officer_select_options(@officers),
|
||||||
|
prompt: t("admin.poll_shifts.new.select_officer"),
|
||||||
|
label: false %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= f.hidden_field :booth_id, value: @booth.id %>
|
||||||
|
|
||||||
|
<div class="small-12 medium-4 column">
|
||||||
|
<%= f.submit t("admin.poll_shifts.new.add_assignment"),
|
||||||
|
class: "button expanded hollow margin-top" %>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div id="shifts">
|
||||||
|
<% if @shifts.empty? %>
|
||||||
|
<div class="callout primary margin-top">
|
||||||
|
<%= t("admin.poll_shifts.new.no_assignments") %>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<%= render "shifts" %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
<div class="highlight jumbo">
|
<div class="highlight jumbo help-header">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="small-12 medium-9 column" data-magellan>
|
<div class="small-12 medium-9 column" data-magellan>
|
||||||
<%= image_tag "help/help_icon_#{image}.png", alt: t("#{i18n_namespace}.icon_alt"), class: "align-top" %>
|
<%= image_tag "help/help_icon_#{image}.png", alt: t("#{i18n_namespace}.icon_alt"), class: "align-top" %>
|
||||||
<h1 class="inline-block"><%= t("#{i18n_namespace}.title") %></h1>
|
<h1 class="inline-block"><%= t("#{i18n_namespace}.title") %></h1>
|
||||||
<p class="lead"><%= t("#{i18n_namespace}.description") %></p>
|
<p>
|
||||||
<%= link_to t("#{i18n_namespace}.help"), "#section_help", class: "help-link" %>
|
<%= t("#{i18n_namespace}.description") %><br>
|
||||||
|
<%= link_to t("#{i18n_namespace}.help"), "#section_help" %>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -403,6 +403,7 @@ en:
|
|||||||
poll_officers: Poll officers
|
poll_officers: Poll officers
|
||||||
polls: Polls
|
polls: Polls
|
||||||
poll_booths: Booths location
|
poll_booths: Booths location
|
||||||
|
poll_shifts: Manage shifts
|
||||||
officials: Officials
|
officials: Officials
|
||||||
organizations: Organisations
|
organizations: Organisations
|
||||||
settings: Configuration settings
|
settings: Configuration settings
|
||||||
@@ -481,11 +482,6 @@ en:
|
|||||||
search: Search
|
search: Search
|
||||||
user_not_found: User not found
|
user_not_found: User not found
|
||||||
poll_officer_assignments:
|
poll_officer_assignments:
|
||||||
flash:
|
|
||||||
destroy: "Officing shift removed"
|
|
||||||
create: "Officing shift added"
|
|
||||||
error_destroy: "An error ocurred when removing officer assignment"
|
|
||||||
error_create: "An error ocurred when adding officer assignment"
|
|
||||||
index:
|
index:
|
||||||
officers_title: "List of officers"
|
officers_title: "List of officers"
|
||||||
no_officers: "There are no officers assigned to this poll."
|
no_officers: "There are no officers assigned to this poll."
|
||||||
@@ -494,18 +490,27 @@ en:
|
|||||||
add_officer_assignments: "Add shifts as officer"
|
add_officer_assignments: "Add shifts as officer"
|
||||||
edit_officer_assignments: "Edit officing shifts"
|
edit_officer_assignments: "Edit officing shifts"
|
||||||
by_officer:
|
by_officer:
|
||||||
new_assignment: "New shift"
|
|
||||||
date: "Date"
|
date: "Date"
|
||||||
booth: "Booth"
|
booth: "Booth"
|
||||||
assignment: "Assignment"
|
|
||||||
select_date: "Select day"
|
|
||||||
select_booth: "Select booth"
|
|
||||||
add_assignment: "Add shift"
|
|
||||||
remove_assignment: "Remove"
|
|
||||||
assignments: "Officing shifts in this poll"
|
assignments: "Officing shifts in this poll"
|
||||||
no_assignments: "This user has no officing shifts in this poll."
|
no_assignments: "This user has no officing shifts in this poll."
|
||||||
final_recounts: "Final recounts"
|
final_recounts: "Final recounts"
|
||||||
final_recount: "Final recount (by officer)"
|
final_recount: "Final recount (by officer)"
|
||||||
|
poll_shifts:
|
||||||
|
new:
|
||||||
|
new_assignment: "New shift"
|
||||||
|
date: "Date"
|
||||||
|
officer: "Officer"
|
||||||
|
assignment: "Assignment"
|
||||||
|
select_date: "Select day"
|
||||||
|
select_officer: "Select officer"
|
||||||
|
add_assignment: "Add shift"
|
||||||
|
remove_assignment: "Remove"
|
||||||
|
assignments: "Shifts in this booth"
|
||||||
|
no_assignments: "This booth has no shifts"
|
||||||
|
flash:
|
||||||
|
create: "Shift added"
|
||||||
|
destroy: "Shift removed"
|
||||||
poll_booth_assignments:
|
poll_booth_assignments:
|
||||||
flash:
|
flash:
|
||||||
destroy: "Booth not assigned anymore"
|
destroy: "Booth not assigned anymore"
|
||||||
@@ -618,6 +623,8 @@ en:
|
|||||||
submit_button: "Update booth"
|
submit_button: "Update booth"
|
||||||
show:
|
show:
|
||||||
location: "Location"
|
location: "Location"
|
||||||
|
booth:
|
||||||
|
shifts: "Manage shifts"
|
||||||
officials:
|
officials:
|
||||||
edit:
|
edit:
|
||||||
destroy: Remove 'Official' status
|
destroy: Remove 'Official' status
|
||||||
|
|||||||
@@ -414,6 +414,7 @@ es:
|
|||||||
poll_officers: Presidentes de mesa
|
poll_officers: Presidentes de mesa
|
||||||
polls: Votaciones
|
polls: Votaciones
|
||||||
poll_booths: Ubicación de urnas
|
poll_booths: Ubicación de urnas
|
||||||
|
poll_shifts: Asignar turnos
|
||||||
officials: Cargos públicos
|
officials: Cargos públicos
|
||||||
organizations: Organizaciones
|
organizations: Organizaciones
|
||||||
settings: Configuración global
|
settings: Configuración global
|
||||||
@@ -481,11 +482,6 @@ es:
|
|||||||
search: Buscar
|
search: Buscar
|
||||||
user_not_found: Usuario no encontrado
|
user_not_found: Usuario no encontrado
|
||||||
poll_officer_assignments:
|
poll_officer_assignments:
|
||||||
flash:
|
|
||||||
destroy: "Eliminado turno de presidente de mesa"
|
|
||||||
create: "Añadido turno de presidente de mesa"
|
|
||||||
error_destroy: "Se ha producido un error al eliminar el turno"
|
|
||||||
error_create: "Se ha producido un error al intentar crear el turno"
|
|
||||||
index:
|
index:
|
||||||
officers_title: "Listado de presidentes de mesa asignados"
|
officers_title: "Listado de presidentes de mesa asignados"
|
||||||
no_officers: "No hay presidentes de mesa asignados a esta votación."
|
no_officers: "No hay presidentes de mesa asignados a esta votación."
|
||||||
@@ -494,18 +490,27 @@ es:
|
|||||||
add_officer_assignments: "Añadir turnos como presidente de mesa"
|
add_officer_assignments: "Añadir turnos como presidente de mesa"
|
||||||
edit_officer_assignments: "Editar turnos"
|
edit_officer_assignments: "Editar turnos"
|
||||||
by_officer:
|
by_officer:
|
||||||
new_assignment: "Nuevo turno"
|
|
||||||
date: "Fecha"
|
date: "Fecha"
|
||||||
booth: "Urna"
|
booth: "Urna"
|
||||||
assignment: "Asignación"
|
|
||||||
select_date: "Seleccionar día"
|
|
||||||
select_booth: "Seleccionar urna"
|
|
||||||
add_assignment: "Añadir turno"
|
|
||||||
remove_assignment: "Eliminar turno"
|
|
||||||
assignments: "Turnos como presidente de mesa en esta votación"
|
assignments: "Turnos como presidente de mesa en esta votación"
|
||||||
no_assignments: "No tiene turnos como presidente de mesa en esta votación."
|
no_assignments: "No tiene turnos como presidente de mesa en esta votación."
|
||||||
final_recounts: "Recuentos finales"
|
final_recounts: "Recuentos finales"
|
||||||
final_recount: "Recuento final (presidente de mesa)"
|
final_recount: "Recuento final (presidente de mesa)"
|
||||||
|
poll_shifts:
|
||||||
|
new:
|
||||||
|
new_assignment: "Nuevo turno"
|
||||||
|
date: "Fecha"
|
||||||
|
officer: "Presidente de mesa"
|
||||||
|
assignment: "Asignación"
|
||||||
|
select_date: "Seleccionar día"
|
||||||
|
select_officer: "Seleccionar presidente de mesa"
|
||||||
|
add_assignment: "Añadir turno"
|
||||||
|
remove_assignment: "Eliminar turno"
|
||||||
|
assignments: "Turnos en esta urna"
|
||||||
|
no_assignments: "Esta urna no tiene turnos asignados"
|
||||||
|
flash:
|
||||||
|
create: "Añadido turno de presidente de mesa"
|
||||||
|
destroy: "Eliminado turno de presidente de mesa"
|
||||||
poll_booth_assignments:
|
poll_booth_assignments:
|
||||||
flash:
|
flash:
|
||||||
destroy: "Urna desasignada"
|
destroy: "Urna desasignada"
|
||||||
@@ -618,6 +623,8 @@ es:
|
|||||||
submit_button: "Actualizar urna"
|
submit_button: "Actualizar urna"
|
||||||
show:
|
show:
|
||||||
location: "Ubicación"
|
location: "Ubicación"
|
||||||
|
booth:
|
||||||
|
shifts: "Asignar turnos"
|
||||||
officials:
|
officials:
|
||||||
edit:
|
edit:
|
||||||
destroy: Eliminar condición de 'Cargo Público'
|
destroy: Eliminar condición de 'Cargo Público'
|
||||||
|
|||||||
@@ -286,7 +286,10 @@ Rails.application.routes.draw do
|
|||||||
get :search, on: :collection
|
get :search, on: :collection
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :booths
|
resources :booths do
|
||||||
|
resources :shifts
|
||||||
|
end
|
||||||
|
|
||||||
resources :questions
|
resources :questions
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
15
db/migrate/20170724190805_create_poll_shifts.rb
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
class CreatePollShifts < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :poll_shifts do |t|
|
||||||
|
t.integer :booth_id
|
||||||
|
t.integer :officer_id
|
||||||
|
t.date :date
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :poll_shifts, :booth_id
|
||||||
|
add_index :poll_shifts, :officer_id
|
||||||
|
add_index :poll_shifts, [:booth_id, :officer_id]
|
||||||
|
end
|
||||||
|
end
|
||||||
12
db/schema.rb
@@ -676,6 +676,18 @@ ActiveRecord::Schema.define(version: 20170822144743) do
|
|||||||
add_index "poll_questions", ["proposal_id"], name: "index_poll_questions_on_proposal_id", using: :btree
|
add_index "poll_questions", ["proposal_id"], name: "index_poll_questions_on_proposal_id", using: :btree
|
||||||
add_index "poll_questions", ["tsv"], name: "index_poll_questions_on_tsv", using: :gin
|
add_index "poll_questions", ["tsv"], name: "index_poll_questions_on_tsv", using: :gin
|
||||||
|
|
||||||
|
create_table "poll_shifts", force: :cascade do |t|
|
||||||
|
t.integer "booth_id"
|
||||||
|
t.integer "officer_id"
|
||||||
|
t.date "date"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index "poll_shifts", ["booth_id", "officer_id"], name: "index_poll_shifts_on_booth_id_and_officer_id", using: :btree
|
||||||
|
add_index "poll_shifts", ["booth_id"], name: "index_poll_shifts_on_booth_id", using: :btree
|
||||||
|
add_index "poll_shifts", ["officer_id"], name: "index_poll_shifts_on_officer_id", using: :btree
|
||||||
|
|
||||||
create_table "poll_voters", force: :cascade do |t|
|
create_table "poll_voters", force: :cascade do |t|
|
||||||
t.string "document_number"
|
t.string "document_number"
|
||||||
t.string "document_type"
|
t.string "document_type"
|
||||||
|
|||||||
@@ -449,6 +449,11 @@ FactoryGirl.define do
|
|||||||
starts_at { 1.month.ago }
|
starts_at { 1.month.ago }
|
||||||
ends_at { 1.month.from_now }
|
ends_at { 1.month.from_now }
|
||||||
|
|
||||||
|
trait :current do
|
||||||
|
starts_at { 2.days.ago }
|
||||||
|
ends_at { 2.days.from_now }
|
||||||
|
end
|
||||||
|
|
||||||
trait :incoming do
|
trait :incoming do
|
||||||
starts_at { 2.days.from_now }
|
starts_at { 2.days.from_now }
|
||||||
ends_at { 1.month.from_now }
|
ends_at { 1.month.from_now }
|
||||||
@@ -492,6 +497,12 @@ FactoryGirl.define do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
factory :poll_shift, class: 'Poll::Shift' do
|
||||||
|
association :booth, factory: :poll_booth
|
||||||
|
association :officer, factory: :poll_officer
|
||||||
|
date Date.current
|
||||||
|
end
|
||||||
|
|
||||||
factory :poll_final_recount, class: 'Poll::FinalRecount' do
|
factory :poll_final_recount, class: 'Poll::FinalRecount' do
|
||||||
association :officer_assignment, factory: [:poll_officer_assignment, :final]
|
association :officer_assignment, factory: [:poll_officer_assignment, :final]
|
||||||
association :booth_assignment, factory: :poll_booth_assignment
|
association :booth_assignment, factory: :poll_booth_assignment
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
feature 'Admin officer assignments in poll' do
|
|
||||||
|
|
||||||
background do
|
|
||||||
admin = create(:administrator)
|
|
||||||
login_as(admin.user)
|
|
||||||
end
|
|
||||||
|
|
||||||
scenario 'Assign officer to poll', :js do
|
|
||||||
booth_assignment = create(:poll_booth_assignment)
|
|
||||||
officer = create(:poll_officer)
|
|
||||||
|
|
||||||
visit admin_poll_path(booth_assignment.poll)
|
|
||||||
within('#poll-resources') do
|
|
||||||
click_link 'Officers (0)'
|
|
||||||
end
|
|
||||||
|
|
||||||
expect(page).to have_content 'There are no officers assigned to this poll'
|
|
||||||
|
|
||||||
fill_in 'search-officers', with: officer.name
|
|
||||||
click_button 'Search'
|
|
||||||
|
|
||||||
within('#search-officers-results') do
|
|
||||||
click_link 'Add shifts as officer'
|
|
||||||
end
|
|
||||||
|
|
||||||
expect(page).to have_content 'This user has no officing shifts in this poll'
|
|
||||||
expect(page).to have_content officer.name
|
|
||||||
expect(page).to have_content booth_assignment.poll.name
|
|
||||||
|
|
||||||
within('#officer_assignment_form') do
|
|
||||||
select I18n.l(booth_assignment.poll.ends_at.to_date, format: :long), from: 'date'
|
|
||||||
select "#{booth_assignment.booth.name} (#{booth_assignment.booth.location})", from: 'booth_id'
|
|
||||||
click_button 'Add shift'
|
|
||||||
end
|
|
||||||
|
|
||||||
expect(page).to have_content 'Officing shift added'
|
|
||||||
expect(page).to_not have_content 'This user has no officing shifts in this poll'
|
|
||||||
|
|
||||||
visit admin_poll_path(booth_assignment.poll)
|
|
||||||
within('#poll-resources') do
|
|
||||||
click_link 'Officers (1)'
|
|
||||||
end
|
|
||||||
|
|
||||||
expect(page).to_not have_content 'There are no officers in this poll'
|
|
||||||
expect(page).to have_content officer.name
|
|
||||||
expect(page).to have_content officer.email
|
|
||||||
end
|
|
||||||
|
|
||||||
scenario 'Remove officer assignment from poll' do
|
|
||||||
officer_assignment = create(:poll_officer_assignment)
|
|
||||||
poll = officer_assignment.booth_assignment.poll
|
|
||||||
booth = officer_assignment.booth_assignment.booth
|
|
||||||
officer = officer_assignment.officer
|
|
||||||
|
|
||||||
visit by_officer_admin_poll_officer_assignments_path(poll, officer_id: officer.id)
|
|
||||||
|
|
||||||
expect(page).to_not have_content 'This user has no officing shifts in this poll'
|
|
||||||
within("#poll_officer_assignment_#{officer_assignment.id}") do
|
|
||||||
expect(page).to have_content booth.name
|
|
||||||
click_link 'Remove'
|
|
||||||
end
|
|
||||||
|
|
||||||
expect(page).to have_content 'Officing shift removed'
|
|
||||||
expect(page).to have_content 'This user has no officing shifts in this poll'
|
|
||||||
end
|
|
||||||
|
|
||||||
scenario 'Index view shows recounts info for officer' do
|
|
||||||
booth_assignment = create(:poll_booth_assignment)
|
|
||||||
poll = booth_assignment.poll
|
|
||||||
officer = create(:poll_officer)
|
|
||||||
create(:poll_officer_assignment,
|
|
||||||
booth_assignment: booth_assignment,
|
|
||||||
officer: officer,
|
|
||||||
date: poll.starts_at)
|
|
||||||
final_officer_assignment = create(:poll_officer_assignment, :final,
|
|
||||||
booth_assignment: booth_assignment,
|
|
||||||
officer: officer,
|
|
||||||
date: poll.ends_at + 1.day)
|
|
||||||
create(:poll_final_recount,
|
|
||||||
booth_assignment: booth_assignment,
|
|
||||||
officer_assignment: final_officer_assignment,
|
|
||||||
date: poll.ends_at,
|
|
||||||
count: 9876)
|
|
||||||
|
|
||||||
visit by_officer_admin_poll_officer_assignments_path(poll, officer_id: officer.id)
|
|
||||||
|
|
||||||
within('#final_recount_list') { expect(page).to have_content('9876') }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
88
spec/features/admin/poll/shifts_spec.rb
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
feature 'Admin shifts' do
|
||||||
|
|
||||||
|
background do
|
||||||
|
admin = create(:administrator)
|
||||||
|
login_as(admin.user)
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Show" do
|
||||||
|
poll = create(:poll)
|
||||||
|
officer = create(:poll_officer)
|
||||||
|
|
||||||
|
booth1 = create(:poll_booth)
|
||||||
|
booth2 = create(:poll_booth)
|
||||||
|
|
||||||
|
shift1 = create(:poll_shift, officer: officer, booth: booth1, date: Date.today)
|
||||||
|
shift2 = create(:poll_shift, officer: officer, booth: booth2, date: Date.tomorrow)
|
||||||
|
|
||||||
|
visit new_admin_booth_shift_path(booth1)
|
||||||
|
|
||||||
|
expect(page).to have_css(".shift", count: 1)
|
||||||
|
expect(page).to have_content I18n.l(Date.today, format: :long)
|
||||||
|
expect(page).to have_content officer.name
|
||||||
|
|
||||||
|
visit new_admin_booth_shift_path(booth2)
|
||||||
|
|
||||||
|
expect(page).to have_css(".shift", count: 1)
|
||||||
|
expect(page).to have_content I18n.l(Date.tomorrow, format: :long)
|
||||||
|
expect(page).to have_content officer.name
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Create" do
|
||||||
|
poll = create(:poll)
|
||||||
|
booth = create(:poll_booth)
|
||||||
|
officer = create(:poll_officer)
|
||||||
|
|
||||||
|
visit admin_booths_path
|
||||||
|
|
||||||
|
within("#booth_#{booth.id}") do
|
||||||
|
click_link "Manage shifts"
|
||||||
|
end
|
||||||
|
|
||||||
|
select I18n.l(poll.starts_at.to_date, format: :long), from: 'shift_date'
|
||||||
|
select officer.name, from: 'shift_officer_id'
|
||||||
|
click_button "Add shift"
|
||||||
|
|
||||||
|
expect(page).to have_content "Shift added"
|
||||||
|
|
||||||
|
within("#shifts") do
|
||||||
|
expect(page).to have_css(".shift", count: 1)
|
||||||
|
expect(page).to have_content(I18n.l(poll.starts_at.to_date, format: :long))
|
||||||
|
expect(page).to have_content(officer.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Destroy" do
|
||||||
|
poll = create(:poll)
|
||||||
|
booth = create(:poll_booth)
|
||||||
|
officer = create(:poll_officer)
|
||||||
|
|
||||||
|
shift = create(:poll_shift, officer: officer, booth: booth)
|
||||||
|
|
||||||
|
visit admin_booths_path
|
||||||
|
|
||||||
|
within("#booth_#{booth.id}") do
|
||||||
|
click_link "Manage shifts"
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(page).to have_css(".shift", count: 1)
|
||||||
|
within("#shift_#{shift.id}") do
|
||||||
|
click_link "Remove"
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(page).to have_content "Shift removed"
|
||||||
|
expect(page).to have_css(".shift", count: 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Empty" do
|
||||||
|
poll = create(:poll)
|
||||||
|
booth = create(:poll_booth)
|
||||||
|
|
||||||
|
visit new_admin_booth_shift_path(booth)
|
||||||
|
|
||||||
|
expect(page).to have_content "This booth has no shifts"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -62,6 +62,20 @@ describe :poll do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#current_or_incoming" do
|
||||||
|
it "returns current or incoming polls" do
|
||||||
|
current = create(:poll, :current)
|
||||||
|
incoming = create(:poll, :incoming)
|
||||||
|
expired = create(:poll, :expired)
|
||||||
|
|
||||||
|
current_or_incoming = Poll.current_or_incoming
|
||||||
|
|
||||||
|
expect(current_or_incoming).to include(current)
|
||||||
|
expect(current_or_incoming).to include(incoming)
|
||||||
|
expect(current_or_incoming).to_not include(expired)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#document_has_voted?" do
|
describe "#document_has_voted?" do
|
||||||
it "returns true if Poll::Voter with document exists" do
|
it "returns true if Poll::Voter with document exists" do
|
||||||
poll = create(:poll)
|
poll = create(:poll)
|
||||||
|
|||||||
61
spec/models/poll/shift_spec.rb
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe :shift do
|
||||||
|
let(:shift) { build(:poll_shift) }
|
||||||
|
|
||||||
|
describe "validations" do
|
||||||
|
|
||||||
|
it "should be valid" do
|
||||||
|
expect(shift).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without a booth" do
|
||||||
|
shift.booth = nil
|
||||||
|
expect(shift).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without an officer" do
|
||||||
|
shift.officer = nil
|
||||||
|
expect(shift).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without a date" do
|
||||||
|
shift.date = nil
|
||||||
|
expect(shift).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "officer_assignments" do
|
||||||
|
|
||||||
|
it "should create corresponding officer_assignments" do
|
||||||
|
poll1 = create(:poll)
|
||||||
|
poll2 = create(:poll)
|
||||||
|
poll3 = create(:poll)
|
||||||
|
|
||||||
|
booth = create(:poll_booth)
|
||||||
|
officer = create(:poll_officer)
|
||||||
|
|
||||||
|
booth_assignment1 = create(:poll_booth_assignment, poll: poll1, booth: booth)
|
||||||
|
booth_assignment2 = create(:poll_booth_assignment, poll: poll2, booth: booth)
|
||||||
|
|
||||||
|
shift = create(:poll_shift, booth: booth, officer: officer, date: Date.current)
|
||||||
|
|
||||||
|
officer_assignments = Poll::OfficerAssignment.all
|
||||||
|
expect(officer_assignments.count).to eq(2)
|
||||||
|
|
||||||
|
oa1 = officer_assignments.first
|
||||||
|
oa2 = officer_assignments.second
|
||||||
|
|
||||||
|
expect(oa1.officer).to eq(officer)
|
||||||
|
expect(oa1.date).to eq(Date.current)
|
||||||
|
expect(oa1.booth_assignment).to eq(booth_assignment1)
|
||||||
|
|
||||||
|
expect(oa2.officer).to eq(officer)
|
||||||
|
expect(oa2.date).to eq(Date.current)
|
||||||
|
expect(oa2.booth_assignment).to eq(booth_assignment2)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||