diff --git a/Gemfile.lock b/Gemfile.lock index a6437663e..c33459f75 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -199,7 +199,7 @@ GEM terminal-table (>= 1.5.1) initialjs-rails (0.2.0.5) railties (>= 3.1, < 6.0) - invisible_captcha (0.9.2) + invisible_captcha (0.9.3) rails (>= 3.2.0) jquery-fileupload-rails (0.4.7) actionpack (>= 3.1) @@ -251,7 +251,7 @@ GEM mime-types-data (3.2016.0521) mimemagic (0.3.2) mini_portile2 (2.2.0) - minitest (5.10.2) + minitest (5.10.3) mixlib-cli (1.7.0) mixlib-config (2.2.4) multi_json (1.12.1) @@ -368,7 +368,7 @@ GEM rspec-mocks (3.6.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.6.0) - rspec-rails (3.6.0) + rspec-rails (3.6.1) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) @@ -398,7 +398,7 @@ GEM sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - savon (2.11.1) + savon (2.11.2) akami (~> 1.2) builder (>= 2.1.2) gyoku (~> 1.2) @@ -430,7 +430,7 @@ GEM babel-source (>= 5.8.11) babel-transpiler sprockets (>= 3.0.0) - sprockets-rails (3.2.0) + sprockets-rails (3.2.1) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) @@ -565,6 +565,5 @@ DEPENDENCIES web-console (~> 3.3.0) whenever (~> 0.9.7) - BUNDLED WITH 1.15.3 diff --git a/app/assets/images/help/help_icon_budgets.png b/app/assets/images/help/help_icon_budgets.png index f8a909d7e..fc5e3022f 100644 Binary files a/app/assets/images/help/help_icon_budgets.png and b/app/assets/images/help/help_icon_budgets.png differ diff --git a/app/assets/images/help/help_icon_debates.png b/app/assets/images/help/help_icon_debates.png index c8d59e4c1..afc729671 100644 Binary files a/app/assets/images/help/help_icon_debates.png and b/app/assets/images/help/help_icon_debates.png differ diff --git a/app/assets/images/help/help_icon_legislation_processes.png b/app/assets/images/help/help_icon_legislation_processes.png index 9dd93ad8c..00872c247 100644 Binary files a/app/assets/images/help/help_icon_legislation_processes.png and b/app/assets/images/help/help_icon_legislation_processes.png differ diff --git a/app/assets/images/help/help_icon_polls.png b/app/assets/images/help/help_icon_polls.png index 503f8642d..b7f7cf479 100644 Binary files a/app/assets/images/help/help_icon_polls.png and b/app/assets/images/help/help_icon_polls.png differ diff --git a/app/assets/images/help/help_icon_proposals.png b/app/assets/images/help/help_icon_proposals.png index 05861d042..e41db1cf8 100644 Binary files a/app/assets/images/help/help_icon_proposals.png and b/app/assets/images/help/help_icon_proposals.png differ diff --git a/app/assets/images/logo_header.png b/app/assets/images/logo_header.png index 9bce3cef8..c178ec781 100644 Binary files a/app/assets/images/logo_header.png and b/app/assets/images/logo_header.png differ diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index 1683c2231..e10c0327f 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -894,17 +894,10 @@ } } -.help-link { - margin-left: $line-height; - position: relative; +.help-header { - &::before { - color: $link; - content: '\4e'; - font-family: 'icons'; - position: absolute; - left: -24px; - top: -2px; + h1 { + font-size: rem-calc(24); } } diff --git a/app/controllers/admin/poll/officer_assignments_controller.rb b/app/controllers/admin/poll/officer_assignments_controller.rb index 1f2a7ca2c..45c9a225a 100644 --- a/app/controllers/admin/poll/officer_assignments_controller.rb +++ b/app/controllers/admin/poll/officer_assignments_controller.rb @@ -32,35 +32,6 @@ class Admin::Poll::OfficerAssignmentsController < Admin::BaseController 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 def officer_assignment_params diff --git a/app/controllers/admin/poll/shifts_controller.rb b/app/controllers/admin/poll/shifts_controller.rb new file mode 100644 index 000000000..8a808a7a9 --- /dev/null +++ b/app/controllers/admin/poll/shifts_controller.rb @@ -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 \ No newline at end of file diff --git a/app/helpers/shifts_helper.rb b/app/helpers/shifts_helper.rb new file mode 100644 index 000000000..37f22a3e2 --- /dev/null +++ b/app/helpers/shifts_helper.rb @@ -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 diff --git a/app/models/poll.rb b/app/models/poll.rb index 6d033f514..4ba313963 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -35,6 +35,10 @@ class Poll < ActiveRecord::Base ends_at < timestamp end + def self.current_or_incoming + current + incoming + end + def answerable_by?(user) user.present? && user.level_two_or_three_verified? && diff --git a/app/models/poll/booth.rb b/app/models/poll/booth.rb index c7fb63efc..9edbcbaf0 100644 --- a/app/models/poll/booth.rb +++ b/app/models/poll/booth.rb @@ -2,6 +2,7 @@ class Poll class Booth < ActiveRecord::Base has_many :booth_assignments, class_name: "Poll::BoothAssignment" has_many :polls, through: :booth_assignments + has_many :shifts validates :name, presence: true, uniqueness: true diff --git a/app/models/poll/shift.rb b/app/models/poll/shift.rb new file mode 100644 index 000000000..8ee646ea4 --- /dev/null +++ b/app/models/poll/shift.rb @@ -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 \ No newline at end of file diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index 62638f3b7..b42e717b4 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -73,9 +73,13 @@ <%= link_to t('admin.menu.poll_officers'), admin_officers_path %> -
  • > +
  • > <%= link_to t('admin.menu.poll_booths'), admin_booths_path %>
  • + +
  • > + <%= link_to t('admin.menu.poll_shifts'), admin_booths_path %> +
  • <% end %> diff --git a/app/views/admin/poll/booths/_booth.html.erb b/app/views/admin/poll/booths/_booth.html.erb index 5732400a8..80b1ef38f 100644 --- a/app/views/admin/poll/booths/_booth.html.erb +++ b/app/views/admin/poll/booths/_booth.html.erb @@ -6,6 +6,9 @@ <%= booth.location %> + <%= link_to t("admin.booths.booth.shifts"), + new_admin_booth_shift_path(booth), + class: "button hollow" %> <%= link_to t("admin.actions.edit"), edit_admin_booth_path(booth), class: "button hollow" %> diff --git a/app/views/admin/poll/booths/index.html.erb b/app/views/admin/poll/booths/index.html.erb index 9618aec59..0dbb62cdf 100644 --- a/app/views/admin/poll/booths/index.html.erb +++ b/app/views/admin/poll/booths/index.html.erb @@ -16,6 +16,7 @@ <%= t("admin.booths.index.name") %> <%= t("admin.booths.index.location") %>   +   <% @booths.each do |booth| %> diff --git a/app/views/admin/poll/officer_assignments/by_officer.html.erb b/app/views/admin/poll/officer_assignments/by_officer.html.erb index 6e505040e..8cc6c0437 100644 --- a/app/views/admin/poll/officer_assignments/by_officer.html.erb +++ b/app/views/admin/poll/officer_assignments/by_officer.html.erb @@ -5,35 +5,6 @@

    <%= @officer.name %> - <%= @officer.email %>

    -<%= form_tag(admin_poll_officer_assignments_path(@poll), {id: "officer_assignment_form"}) do %> -
    - <%= t("admin.poll_officer_assignments.by_officer.new_assignment") %> -
    - - <%= 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 } %> -
    - -
    - - <%= select_tag :booth_id, - poll_booths_select_options(@poll), - { prompt: t("admin.poll_officer_assignments.by_officer.select_booth"), - label: false } %> -
    - -
    - <%= 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" %> -
    -
    -<% end %> - - <% if @officer_assignments.empty? %>
    <%= t("admin.poll_officer_assignments.by_officer.no_assignments") %> @@ -45,7 +16,6 @@ <%= t("admin.poll_officer_assignments.by_officer.date") %> <%= t("admin.poll_officer_assignments.by_officer.booth") %> - <%= t("admin.poll_officer_assignments.by_officer.assignment") %> @@ -53,12 +23,6 @@ <%= officer_assignment.final? ? t('polls.final_date') : l(officer_assignment.date.to_date) %> <%= booth_name_with_location(officer_assignment.booth_assignment.booth) %> - - <%= 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" %> - <% end %> @@ -93,6 +57,3 @@ <% end %> - - - diff --git a/app/views/admin/poll/shifts/_shifts.html.erb b/app/views/admin/poll/shifts/_shifts.html.erb new file mode 100644 index 000000000..800c6944b --- /dev/null +++ b/app/views/admin/poll/shifts/_shifts.html.erb @@ -0,0 +1,24 @@ +

    <%= t("admin.poll_shifts.new.assignments") %>

    + + + + + + + + + + <% @shifts.each do |shift| %> + + + + + + <% end %> + +
    <%= t("admin.poll_shifts.new.date") %><%= t("admin.poll_shifts.new.officer") %><%= t("admin.poll_shifts.new.assignment") %>
    <%= l(shift.date.to_date, format: :long) %><%= shift.officer.name %> + <%= link_to t("admin.poll_shifts.new.remove_assignment"), + admin_booth_shift_path(@booth, shift), + method: :delete, + class: "button hollow alert" %> +
    diff --git a/app/views/admin/poll/shifts/new.html.erb b/app/views/admin/poll/shifts/new.html.erb new file mode 100644 index 000000000..c997dc35f --- /dev/null +++ b/app/views/admin/poll/shifts/new.html.erb @@ -0,0 +1,46 @@ +<%= back_link_to admin_booths_path %> + +

    <%= @booth.name %>

    + +<%= form_for @shift, as: :shift, url: admin_booth_shifts_path do |f| %> + <%= render "shared/errors", resource: @shift %> + +
    + + <%= t("admin.poll_shifts.new.new_assignment") %> + + +
    + + <%= f.select :date, + shift_dates_select_options(@polls), + prompt: t("admin.poll_shifts.new.select_date"), + label: false %> +
    + +
    + + <%= f.select :officer_id, + officer_select_options(@officers), + prompt: t("admin.poll_shifts.new.select_officer"), + label: false %> +
    + + <%= f.hidden_field :booth_id, value: @booth.id %> + +
    + <%= f.submit t("admin.poll_shifts.new.add_assignment"), + class: "button expanded hollow margin-top" %> +
    +
    +<% end %> + +
    + <% if @shifts.empty? %> +
    + <%= t("admin.poll_shifts.new.no_assignments") %> +
    + <% else %> + <%= render "shifts" %> + <% end %> +
    \ No newline at end of file diff --git a/app/views/shared/_section_header.html.erb b/app/views/shared/_section_header.html.erb index 29688b487..ca0476bb9 100644 --- a/app/views/shared/_section_header.html.erb +++ b/app/views/shared/_section_header.html.erb @@ -1,10 +1,12 @@ -
    +
    <%= image_tag "help/help_icon_#{image}.png", alt: t("#{i18n_namespace}.icon_alt"), class: "align-top" %>

    <%= t("#{i18n_namespace}.title") %>

    -

    <%= t("#{i18n_namespace}.description") %>

    - <%= link_to t("#{i18n_namespace}.help"), "#section_help", class: "help-link" %> +

    + <%= t("#{i18n_namespace}.description") %>
    + <%= link_to t("#{i18n_namespace}.help"), "#section_help" %> +

    diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 7b77ab8d0..c91719104 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -403,6 +403,7 @@ en: poll_officers: Poll officers polls: Polls poll_booths: Booths location + poll_shifts: Manage shifts officials: Officials organizations: Organisations settings: Configuration settings @@ -481,11 +482,6 @@ en: search: Search user_not_found: User not found 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: officers_title: "List of officers" no_officers: "There are no officers assigned to this poll." @@ -494,18 +490,27 @@ en: add_officer_assignments: "Add shifts as officer" edit_officer_assignments: "Edit officing shifts" by_officer: - new_assignment: "New shift" date: "Date" 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" no_assignments: "This user has no officing shifts in this poll." final_recounts: "Final recounts" 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: flash: destroy: "Booth not assigned anymore" @@ -618,6 +623,8 @@ en: submit_button: "Update booth" show: location: "Location" + booth: + shifts: "Manage shifts" officials: edit: destroy: Remove 'Official' status diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 0e6ae8dfa..58fd31aa1 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -414,6 +414,7 @@ es: poll_officers: Presidentes de mesa polls: Votaciones poll_booths: Ubicación de urnas + poll_shifts: Asignar turnos officials: Cargos públicos organizations: Organizaciones settings: Configuración global @@ -481,11 +482,6 @@ es: search: Buscar user_not_found: Usuario no encontrado 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: officers_title: "Listado de presidentes de mesa asignados" 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" edit_officer_assignments: "Editar turnos" by_officer: - new_assignment: "Nuevo turno" date: "Fecha" 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" no_assignments: "No tiene turnos como presidente de mesa en esta votación." final_recounts: "Recuentos finales" 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: flash: destroy: "Urna desasignada" @@ -618,6 +623,8 @@ es: submit_button: "Actualizar urna" show: location: "Ubicación" + booth: + shifts: "Asignar turnos" officials: edit: destroy: Eliminar condición de 'Cargo Público' diff --git a/config/routes.rb b/config/routes.rb index 00985071a..eaf6b98f4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -286,7 +286,10 @@ Rails.application.routes.draw do get :search, on: :collection end - resources :booths + resources :booths do + resources :shifts + end + resources :questions end diff --git a/db/migrate/20170724190805_create_poll_shifts.rb b/db/migrate/20170724190805_create_poll_shifts.rb new file mode 100644 index 000000000..8bb6eafd7 --- /dev/null +++ b/db/migrate/20170724190805_create_poll_shifts.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index 043e0db7e..b87332817 100644 --- a/db/schema.rb +++ b/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", ["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| t.string "document_number" t.string "document_type" diff --git a/spec/factories.rb b/spec/factories.rb index 2817dfa2d..226723fe3 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -449,6 +449,11 @@ FactoryGirl.define do starts_at { 1.month.ago } ends_at { 1.month.from_now } + trait :current do + starts_at { 2.days.ago } + ends_at { 2.days.from_now } + end + trait :incoming do starts_at { 2.days.from_now } ends_at { 1.month.from_now } @@ -492,6 +497,12 @@ FactoryGirl.define do 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 association :officer_assignment, factory: [:poll_officer_assignment, :final] association :booth_assignment, factory: :poll_booth_assignment diff --git a/spec/features/admin/poll/officer_assignments_spec.rb b/spec/features/admin/poll/officer_assignments_spec.rb deleted file mode 100644 index 08cbd3f99..000000000 --- a/spec/features/admin/poll/officer_assignments_spec.rb +++ /dev/null @@ -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 diff --git a/spec/features/admin/poll/shifts_spec.rb b/spec/features/admin/poll/shifts_spec.rb new file mode 100644 index 000000000..fd9b9f4ca --- /dev/null +++ b/spec/features/admin/poll/shifts_spec.rb @@ -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 diff --git a/spec/models/poll/poll_spec.rb b/spec/models/poll/poll_spec.rb index 61f9fce52..2eb78841b 100644 --- a/spec/models/poll/poll_spec.rb +++ b/spec/models/poll/poll_spec.rb @@ -62,6 +62,20 @@ describe :poll do 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 it "returns true if Poll::Voter with document exists" do poll = create(:poll) diff --git a/spec/models/poll/shift_spec.rb b/spec/models/poll/shift_spec.rb new file mode 100644 index 000000000..e70b5f9a0 --- /dev/null +++ b/spec/models/poll/shift_spec.rb @@ -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