Merge branch 'master' into admin-profiles

This commit is contained in:
decabeza
2017-10-25 18:29:01 +02:00
85 changed files with 1547 additions and 772 deletions

View File

@@ -25,7 +25,7 @@ App.PreventDoubleSubmission =
unless event.target.id == "new_officing_voter" unless event.target.id == "new_officing_voter"
buttons = $(this).find(':button, :submit') buttons = $(this).find(':button, :submit')
App.PreventDoubleSubmission.disable_buttons(buttons) App.PreventDoubleSubmission.disable_buttons(buttons)
).on('ajax:success', -> ).on('ajax:success', (event) ->
unless event.target.id == "new_officing_voter" unless event.target.id == "new_officing_voter"
buttons = $(this).find(':button, :submit') buttons = $(this).find(':button, :submit')
App.PreventDoubleSubmission.reset_buttons(buttons) App.PreventDoubleSubmission.reset_buttons(buttons)

View File

@@ -214,6 +214,8 @@ a {
margin-bottom: $line-height / 2; margin-bottom: $line-height / 2;
li { li {
font-size: $base-font-size;
margin-bottom: 0;
margin-right: $line-height / 2; margin-right: $line-height / 2;
@include breakpoint(medium) { @include breakpoint(medium) {
@@ -316,13 +318,16 @@ a {
} }
.tabs { .tabs {
border: { border-left: 0;
left: 0; border-right: 0;
right: 0; border-top: 0;
top: 0;
};
margin-bottom: $line-height; margin-bottom: $line-height;
.tabs-title {
font-size: $base-font-size;
margin-bottom: 0;
}
.tabs-title > a { .tabs-title > a {
color: $text-medium; color: $text-medium;
margin-bottom: rem-calc(-1); margin-bottom: rem-calc(-1);
@@ -376,6 +381,10 @@ a {
box-shadow: none; box-shadow: none;
} }
.uppercase {
text-transform: uppercase;
}
// 02. Header // 02. Header
// ---------- // ----------

View File

@@ -8,6 +8,7 @@
// 06. Budget // 06. Budget
// 07. Proposals successful // 07. Proposals successful
// 08. Polls // 08. Polls
// 09. Polls results and stats
// //
// 01. Votes and supports // 01. Votes and supports
@@ -1799,3 +1800,59 @@
} }
} }
} }
// 09. Polls results and stats
// ---------------------------
.polls-results-stats {
.sidebar {
border-bottom: 1px solid $border;
margin-bottom: $line-height;
@include breakpoint(medium) {
border-bottom: 0;
border-right: 1px solid $border;
}
.menu {
padding: 0;
li a {
color: $link;
line-height: $line-height;
}
}
}
table {
table-layout: fixed;
caption {
padding: $line-height / 2 0;
text-align: left;
}
th {
text-align: left;
&.win {
background: #009fde;
}
}
td {
&.win {
background: #ccedf8;
font-weight: bold;
}
}
}
.number {
font-size: rem-calc(60);
font-weight: bold;
line-height: rem-calc(60);
}
}

View File

@@ -6,16 +6,10 @@ class Admin::AdministratorsController < Admin::BaseController
end end
def search def search
@user = User.find_by(email: params[:email]) @users = User.search(params[:name_or_email])
.includes(:administrator)
respond_to do |format| .page(params[:page])
if @user .for_render
@administrator = Administrator.find_or_initialize_by(user: @user)
format.js
else
format.js { render "user_not_found" }
end
end
end end
def create def create

View File

@@ -6,16 +6,10 @@ class Admin::ManagersController < Admin::BaseController
end end
def search def search
@user = User.find_by(email: params[:email]) @users = User.search(params[:name_or_email])
.includes(:manager)
respond_to do |format| .page(params[:page])
if @user .for_render
@manager = Manager.find_or_initialize_by(user: @user)
format.js
else
format.js { render "user_not_found" }
end
end
end end
def create def create

View File

@@ -6,16 +6,10 @@ class Admin::ModeratorsController < Admin::BaseController
end end
def search def search
@user = User.find_by(email: params[:email]) @users = User.search(params[:name_or_email])
.includes(:moderator)
respond_to do |format| .page(params[:page])
if @user .for_render
@moderator = Moderator.find_or_initialize_by(user: @user)
format.js
else
format.js { render "user_not_found" }
end
end
end end
def create def create

View File

@@ -23,18 +23,24 @@ class Admin::Poll::BoothAssignmentsController < Admin::Poll::BaseController
end end
def create def create
@booth_assignment = ::Poll::BoothAssignment.new(poll_id: booth_assignment_params[:poll_id], @poll = Poll.find(booth_assignment_params[:poll_id])
booth_id: booth_assignment_params[:booth_id]) @booth = Poll::Booth.find(booth_assignment_params[:booth_id])
@booth_assignment = ::Poll::BoothAssignment.new(poll: @poll,
booth: @booth)
if @booth_assignment.save if @booth_assignment.save
notice = t("admin.poll_booth_assignments.flash.create") notice = t("admin.poll_booth_assignments.flash.create")
else else
notice = t("admin.poll_booth_assignments.flash.error_create") notice = t("admin.poll_booth_assignments.flash.error_create")
end end
redirect_to admin_poll_booth_assignments_path(@booth_assignment.poll_id), notice: notice respond_to do |format|
format.js { render layout: false }
end
end end
def destroy def destroy
@poll = Poll.find(booth_assignment_params[:poll_id])
@booth = Poll::Booth.find(booth_assignment_params[:booth_id])
@booth_assignment = ::Poll::BoothAssignment.find(params[:id]) @booth_assignment = ::Poll::BoothAssignment.find(params[:id])
if @booth_assignment.destroy if @booth_assignment.destroy
@@ -42,7 +48,14 @@ class Admin::Poll::BoothAssignmentsController < Admin::Poll::BaseController
else else
notice = t("admin.poll_booth_assignments.flash.error_destroy") notice = t("admin.poll_booth_assignments.flash.error_destroy")
end end
redirect_to admin_poll_booth_assignments_path(@booth_assignment.poll_id), notice: notice respond_to do |format|
format.js { render layout: false }
end
end
def manage
@booths = ::Poll::Booth.all
@poll = Poll.find(params[:poll_id])
end end
private private

View File

@@ -47,6 +47,10 @@ class Admin::Poll::PollsController < Admin::Poll::BaseController
redirect_to admin_poll_path(@poll), notice: notice redirect_to admin_poll_path(@poll), notice: notice
end end
def booth_assignments
@polls = Poll.current_or_incoming
end
private private
def load_geozones def load_geozones
@@ -54,7 +58,8 @@ class Admin::Poll::PollsController < Admin::Poll::BaseController
end end
def poll_params def poll_params
params.require(:poll).permit(:name, :starts_at, :ends_at, :geozone_restricted, :summary, :description, params.require(:poll).permit(:name, :starts_at, :ends_at, :geozone_restricted,
:summary, :description, :results_enabled, :stats_enabled,
geozone_ids: [], geozone_ids: [],
image_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy]) image_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy])
end end

View File

@@ -6,6 +6,8 @@ class Admin::Poll::ShiftsController < Admin::Poll::BaseController
def new def new
load_shifts load_shifts
@shift = ::Poll::Shift.new @shift = ::Poll::Shift.new
@voting_polls = @booth.polls.current_or_incoming
@recount_polls = @booth.polls.current_or_recounting_or_incoming
end end
def create def create

View File

@@ -6,16 +6,10 @@ class Admin::ValuatorsController < Admin::BaseController
end end
def search def search
@user = User.find_by(email: params[:email]) @users = User.search(params[:name_or_email])
.includes(:valuator)
respond_to do |format| .page(params[:page])
if @user .for_render
@valuator = Valuator.find_or_initialize_by(user: @user)
format.js
else
format.js { render "user_not_found" }
end
end
end end
def create def create

View File

@@ -29,6 +29,8 @@ class NotificationsController < ApplicationController
case notification.linkable_resource.class.name case notification.linkable_resource.class.name
when "Budget::Investment" when "Budget::Investment"
budget_investment_path @notification.linkable_resource.budget, @notification.linkable_resource budget_investment_path @notification.linkable_resource.budget, @notification.linkable_resource
when "Topic"
community_topic_path @notification.linkable_resource.community, @notification.linkable_resource
else else
url_for @notification.linkable_resource url_for @notification.linkable_resource
end end

View File

@@ -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?)
end end
end end

View File

@@ -13,6 +13,9 @@ class Polls::QuestionsController < ApplicationController
answer.touch if answer.persisted? answer.touch if answer.persisted?
answer.save! answer.save!
answer.record_voter_participation(token) answer.record_voter_participation(token)
@question.question_answers.where(question_id: @question).each do |answer|
answer.set_most_voted
end
@answers_by_question_id = { @question.id => params[:answer] } @answers_by_question_id = { @question.id => params[:answer] }
end end

View File

@@ -25,8 +25,13 @@ class PollsController < ApplicationController
@commentable = @poll @commentable = @poll
@comment_tree = CommentTree.new(@commentable, params[:page], @current_order) @comment_tree = CommentTree.new(@commentable, params[:page], @current_order)
end
def stats
@stats = Poll::Stats.new(@poll).generate @stats = Poll::Stats.new(@poll).generate
end end
def results
end
end end

View File

@@ -1,10 +1,12 @@
module ShiftsHelper module ShiftsHelper
def shift_vote_collection_dates(booth, polls) def shift_vote_collection_dates(booth, polls)
return [] if polls.blank?
date_options((start_date(polls)..end_date(polls)), Poll::Shift.tasks[:vote_collection], booth) date_options((start_date(polls)..end_date(polls)), Poll::Shift.tasks[:vote_collection], booth)
end end
def shift_recount_scrutiny_dates(booth, polls) def shift_recount_scrutiny_dates(booth, polls)
return [] if polls.blank?
dates = polls.map(&:ends_at).map(&:to_date).sort.inject([]) do |total, date| dates = polls.map(&:ends_at).map(&:to_date).sort.inject([]) do |total, date|
initial_date = date < Date.current ? Date.current : date initial_date = date < Date.current ? Date.current : date
total << (initial_date..date + Poll::RECOUNT_DURATION).to_a total << (initial_date..date + Poll::RECOUNT_DURATION).to_a

View File

@@ -52,12 +52,8 @@ module UsersHelper
current_user && current_user.manager? current_user && current_user.manager?
end end
def current_poll_officer?
current_user && current_user.poll_officer?
end
def show_admin_menu? def show_admin_menu?
current_administrator? || current_moderator? || current_valuator? || current_manager? || current_poll_officer? current_administrator? || current_moderator? || current_valuator? || current_manager?
end end
def interests_title_text(user) def interests_title_text(user)

View File

@@ -56,10 +56,10 @@ module Abilities
can [:index, :create, :edit, :update, :destroy], Geozone can [:index, :create, :edit, :update, :destroy], Geozone
can [:read, :create, :update, :destroy, :add_question, :search_booths, :search_officers], Poll can [:read, :create, :update, :destroy, :add_question, :search_booths, :search_officers, :booth_assignments, :results, :stats], Poll
can [:read, :create, :update, :destroy, :available], Poll::Booth can [:read, :create, :update, :destroy, :available], Poll::Booth
can [:search, :create, :index, :destroy], ::Poll::Officer can [:search, :create, :index, :destroy], ::Poll::Officer
can [:create, :destroy], ::Poll::BoothAssignment can [:create, :destroy, :manage], ::Poll::BoothAssignment
can [:create, :destroy], ::Poll::OfficerAssignment can [:create, :destroy], ::Poll::OfficerAssignment
can [:read, :create, :update], Poll::Question can [:read, :create, :update], Poll::Question
can :destroy, Poll::Question # , comments_count: 0, votes_up: 0 can :destroy, Poll::Question # , comments_count: 0, votes_up: 0

View File

@@ -7,6 +7,12 @@ module Abilities
can [:read, :map, :summary, :share], Proposal can [:read, :map, :summary, :share], Proposal
can :read, Comment can :read, Comment
can :read, Poll can :read, Poll
can :results, Poll do |poll|
poll.expired? && poll.results_enabled?
end
can :stats, Poll do |poll|
poll.expired? && poll.stats_enabled?
end
can :read, Poll::Question can :read, Poll::Question
can [:read, :welcome], Budget can [:read, :welcome], Budget
can :read, SpendingProposal can :read, SpendingProposal
@@ -23,7 +29,6 @@ module Abilities
can [:read], Legislation::Question can [:read], Legislation::Question
can [:create], Legislation::Answer can [:create], Legislation::Answer
can [:search, :comments, :read, :create, :new_comment], Legislation::Annotation can [:search, :comments, :read, :create, :new_comment], Legislation::Annotation
can :read_stats, Poll
end end
end end
end end

View File

@@ -12,8 +12,11 @@ class Poll
end end
def self.available def self.available
where(polls: { id: Poll.current_or_incoming }).includes(:polls) where(polls: { id: Poll.current_or_recounting_or_incoming }).includes(:polls)
end end
def assignment_on_poll(poll)
booth_assignments.where(poll: poll).first
end
end end
end end

View File

@@ -55,4 +55,8 @@ class Poll::Question < ActiveRecord::Base
where(poll_id: Poll.answerable_by(user).pluck(:id)) where(poll_id: Poll.answerable_by(user).pluck(:id))
end end
def answers_total_votes
question_answers.map { |a| Poll::Answer.where(question_id: self, answer: a.title).count }.sum
end
end end

View File

@@ -31,4 +31,24 @@ class Poll::Question::Answer < ActiveRecord::Base
def self.last_position(question_id) def self.last_position(question_id)
where(question_id: question_id).maximum('given_order') || 0 where(question_id: question_id).maximum('given_order') || 0
end end
def total_votes
Poll::Answer.where(question_id: question, answer: title).count
end
def most_voted?
self.most_voted
end
def total_votes_percentage
question.answers_total_votes == 0 ? 0 : (total_votes * 100) / question.answers_total_votes
end
def set_most_voted
answers = question.question_answers
.map { |a| Poll::Answer.where(question_id: a.question, answer: a.title).count }
is_most_voted = !answers.any?{ |a| a > self.total_votes }
self.update(most_voted: is_most_voted)
end
end end

View File

@@ -18,107 +18,125 @@ class Poll
private private
def total_participants def total_participants
total_participants_web + total_participants_booth stats_cache('total_participants') { total_participants_web + total_participants_booth }
end end
def total_participants_web def total_participants_web
total_web_valid + total_web_white + total_web_null stats_cache('total_participants_web') { total_web_valid + total_web_white + total_web_null }
end end
def total_participants_web_percentage def total_participants_web_percentage
stats_cache('total_participants_web_percentage') {
(total_participants) == 0 ? 0 : total_participants_web * 100 / total_participants (total_participants) == 0 ? 0 : total_participants_web * 100 / total_participants
}
end end
def total_participants_booth def total_participants_booth
voters.where(origin: 'booth').count stats_cache('total_participants_booth') { voters.where(origin: 'booth').count }
end end
def total_participants_booth_percentage def total_participants_booth_percentage
stats_cache('total_participants_booth_percentage') {
(total_participants) == 0 ? 0 : total_participants_booth * 100 / total_participants.to_f (total_participants) == 0 ? 0 : total_participants_booth * 100 / total_participants.to_f
}
end end
def total_web_valid def total_web_valid
voters.where(origin: 'web').count stats_cache('total_web_valid') { voters.where(origin: 'web').count }
end end
def valid_percentage_web def valid_percentage_web
stats_cache('valid_percentage_web') {
(total_valid_votes) == 0 ? 0 : total_web_valid * 100 / total_valid_votes.to_f (total_valid_votes) == 0 ? 0 : total_web_valid * 100 / total_valid_votes.to_f
}
end end
def total_web_white def total_web_white
0 stats_cache('total_web_white') { 0 }
end end
def white_percentage_web def white_percentage_web
0 stats_cache('white_percentage_web') { 0 }
end end
def total_web_null def total_web_null
0 stats_cache('total_web_null') { 0 }
end end
def null_percentage_web def null_percentage_web
0 stats_cache('null_percentage_web') { 0 }
end end
def total_booth_valid def total_booth_valid
recounts.sum(:total_amount) stats_cache('total_booth_valid') { recounts.sum(:total_amount) }
end end
def valid_percentage_booth def valid_percentage_booth
stats_cache('valid_percentage_booth') {
(total_valid_votes) == 0 ? 0 : total_booth_valid * 100 / total_valid_votes.to_f (total_valid_votes) == 0 ? 0 : total_booth_valid * 100 / total_valid_votes.to_f
}
end end
def total_booth_white def total_booth_white
recounts.sum(:white_amount) stats_cache('total_booth_white') { recounts.sum(:white_amount) }
end end
def white_percentage_booth def white_percentage_booth
stats_cache('white_percentage_booth') {
(total_white_votes) == 0 ? 0 : total_booth_white * 100 / total_white_votes.to_f (total_white_votes) == 0 ? 0 : total_booth_white * 100 / total_white_votes.to_f
}
end end
def total_booth_null def total_booth_null
recounts.sum(:null_amount) stats_cache('total_booth_null') { recounts.sum(:null_amount) }
end end
def null_percentage_booth def null_percentage_booth
stats_cache('null_percentage_booth') {
(total_null_votes == 0) ? 0 : total_booth_null * 100 / total_null_votes.to_f (total_null_votes == 0) ? 0 : total_booth_null * 100 / total_null_votes.to_f
}
end end
def total_valid_votes def total_valid_votes
total_web_valid + total_booth_valid stats_cache('total_valid_votes') { total_web_valid + total_booth_valid }
end end
def total_valid_percentage def total_valid_percentage
stats_cache('total_valid_percentage'){
(total_participants) == 0 ? 0 : total_valid_votes * 100 / total_participants.to_f (total_participants) == 0 ? 0 : total_valid_votes * 100 / total_participants.to_f
}
end end
def total_white_votes def total_white_votes
total_web_white + total_booth_white stats_cache('total_white_votes') { total_web_white + total_booth_white }
end end
def total_white_percentage def total_white_percentage
stats_cache('total_white_percentage') {
(total_participants) == 0 ? 0 : total_white_votes * 100 / total_participants.to_f (total_participants) == 0 ? 0 : total_white_votes * 100 / total_participants.to_f
}
end end
def total_null_votes def total_null_votes
total_web_null + total_booth_null stats_cache('total_null_votes') { total_web_null + total_booth_null }
end end
def total_null_percentage def total_null_percentage
stats_cache('total_null_percentage') {
(total_participants) == 0 ? 0 : total_null_votes * 100 / total_participants.to_f (total_participants) == 0 ? 0 : total_null_votes * 100 / total_participants.to_f
}
end end
def voters def voters
@poll.voters stats_cache('voters') { @poll.voters }
end end
def recounts def recounts
@poll.recounts stats_cache('recounts') { @poll.recounts }
end end
def stats_cache(key, &block) def stats_cache(key, &block)
Rails.cache.fetch("polls_stats/#{@poll.id}/#{key}/v7", &block) Rails.cache.fetch("polls_stats/#{@poll.id}/#{key}", &block)
end end
end end

View File

@@ -60,7 +60,8 @@
<strong><%= t("admin.menu.title_polls") %></strong> <strong><%= t("admin.menu.title_polls") %></strong>
</a> </a>
<ul id="polls_menu" <%= "class=is-active" if menu_polls? || controller.class.parent == Admin::Poll::Questions::Answers %>> <ul id="polls_menu" <%= "class=is-active" if menu_polls? || controller.class.parent == Admin::Poll::Questions::Answers %>>
<li <%= "class=active" if ["polls", "officer_assignments", "booth_assignments", "recounts", "results"].include? controller_name %>> <li <%= "class=active" if controller_name == "polls" && action_name != "booth_assignments" ||
(["booth_assignments", "officer_assignments", "recounts", "results"].include? controller_name) %>>
<%= link_to t('admin.menu.polls'), admin_polls_path %> <%= link_to t('admin.menu.polls'), admin_polls_path %>
</li> </li>
@@ -79,6 +80,10 @@
<%= 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 == "polls" && action_name == "booth_assignments") || (controller_name == "booth_assignments" && action_name == "manage") %>>
<%= link_to t('admin.menu.poll_booth_assignments'), booth_assignments_admin_polls_path %>
</li>
<li <%= "class=active" if controller_name == "shifts" || <li <%= "class=active" if controller_name == "shifts" ||
controller_name == "booths" && controller_name == "booths" &&
action_name == "available" %>> action_name == "available" %>>

View File

@@ -1,29 +0,0 @@
<table>
<thead>
<th scope="col"><%= t("admin.administrators.index.name") %></th>
<th scope="col"><%= t("admin.administrators.index.email") %></th>
<th scope="col" class="small-3"><%= t("admin.shared.actions") %></th>
</thead>
<tbody>
<tr>
<td>
<%= administrator.name %>
</td>
<td>
<%= administrator.email %>
</td>
<td>
<% if administrator.persisted? %>
<%= link_to t('admin.administrators.administrator.delete'),
admin_administrator_path(administrator),
method: :delete,
class: "button hollow alert expanded" %>
<% else %>
<%= link_to t('admin.administrators.administrator.add'),{ controller: "admin/administrators", action: :create, user_id: administrator.user_id },
method: :post,
class: "button success expanded" %>
<% end %>
</td>
</tr>
</tbody>
</table>

View File

@@ -1,18 +1,6 @@
<h2><%= t("admin.administrators.index.title") %></h2> <h2><%= t("admin.administrators.index.title") %></h2>
<div class="small-12 medium-6"> <%= render 'admin/shared/user_search', url: search_admin_administrators_path %>
<%= form_tag search_admin_administrators_path, method: :get, remote: true do %>
<div class="input-group">
<%= text_field_tag :email, '', placeholder: t('admin.administrators.search.email_placeholder') %>
<div class="input-group-button">
<%= submit_tag t('admin.administrators.search.search'), class: 'button' %>
</div>
</div>
<% end %>
</div>
<div id="search-result"></div>
<% if @administrators.any? %> <% if @administrators.any? %>
<h3 class="margin"><%= page_entries_info @administrators %></h3> <h3 class="margin"><%= page_entries_info @administrators %></h3>

View File

@@ -0,0 +1,29 @@
<h2><%= t("admin.administrators.search.title") %></h2>
<%= render 'admin/shared/user_search', url: search_admin_administrators_path %>
<h3><%= page_entries_info @users %></h3>
<table id="administrators">
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.email %></td>
<td class="text-right">
<% if user.administrator? && user.administrator.persisted? %>
<%= link_to t('admin.administrators.administrator.delete'),
admin_administrator_path(user),
method: :delete,
class: "button hollow alert" %>
<% else %>
<%= link_to t('admin.administrators.administrator.add'),
{ controller: "admin/administrators",
action: :create,
user_id: user },
method: :post,
class: "button success" %>
<% end %>
</td>
</tr>
<% end %>
</table>

View File

@@ -1 +0,0 @@
$("#search-result").html("<%= j render 'administrator', administrator: @administrator %>");

View File

@@ -1 +0,0 @@
$("#search-result").html("<div class=\"callout alert\"><%= j t('admin.administrators.search.user_not_found') %></div>");

View File

@@ -1,27 +0,0 @@
<table>
<thead>
<th scope="col"><%= t("admin.managers.index.name") %></th>
<th scope="col"><%= t("admin.managers.index.email") %></th>
<th scope="col" class="small-3"><%= t("admin.shared.actions") %></th>
</thead>
<tr>
<td>
<%= manager.name %>
</td>
<td>
<%= manager.email %>
</td>
<td>
<% if manager.persisted? %>
<%= link_to t('admin.managers.manager.delete'),
admin_manager_path(manager),
method: :delete,
class: "button hollow alert expanded"
%>
<% else %>
<%= link_to t('admin.managers.manager.add'),{ controller: "admin/managers", action: :create, user_id: manager.user_id },
method: :post, class: "button success expanded" %>
<% end %>
</td>
</tr>
</table>

View File

@@ -1,17 +1,6 @@
<h2><%= t("admin.managers.index.title") %></h2> <h2><%= t("admin.managers.index.title") %></h2>
<div class="small-12 medium-6"> <%= render 'admin/shared/user_search', url: search_admin_managers_path %>
<%= form_tag search_admin_managers_path, method: :get, remote: true do %>
<div class="input-group">
<%= text_field_tag :email, '', placeholder: t('admin.managers.search.email_placeholder') %>
<div class="input-group-button">
<%= submit_tag t('admin.managers.search.search'), class: 'button' %>
</div>
</div>
<% end %>
</div>
<div id="search-result"></div>
<div id="managers"> <div id="managers">
<% if @managers.any? %> <% if @managers.any? %>
@@ -40,8 +29,12 @@
class: "button hollow alert expanded" class: "button hollow alert expanded"
%> %>
<% else %> <% else %>
<%= link_to t('admin.managers.manager.add'),{ controller: "admin/managers", action: :create, user_id: manager.user_id }, <%= link_to t('admin.managers.manager.add'),
method: :post, class: "button success expanded" %> { controller: "admin/managers",
action: :create,
user_id: manager.user_id },
method: :post,
class: "button success expanded" %>
<% end %> <% end %>
</td> </td>
</tr> </tr>

View File

@@ -0,0 +1,29 @@
<h2><%= t("admin.managers.search.title") %></h2>
<%= render 'admin/shared/user_search', url: search_admin_managers_path %>
<h3><%= page_entries_info @users %></h3>
<table id="managers">
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.email %></td>
<td class="text-right">
<% if user.manager? && user.manager.persisted? %>
<%= link_to t('admin.managers.manager.delete'),
admin_manager_path(user),
method: :delete,
class: "button hollow alert" %>
<% else %>
<%= link_to t('admin.managers.manager.add'),
{ controller: "admin/managers",
action: :create,
user_id: user },
method: :post,
class: "button success" %>
<% end %>
</td>
</tr>
<% end %>
</table>

View File

@@ -1 +0,0 @@
$("#search-result").html("<%= j render 'manager', manager: @manager %>");

View File

@@ -1 +0,0 @@
$("#search-result").html("<div class=\"callout alert\"><%= j t('admin.managers.search.user_not_found') %></div>");

View File

@@ -1,30 +0,0 @@
<table>
<thead>
<th scope="col"><%= t("admin.moderators.index.name") %></th>
<th scope="col" class="small-6"><%= t("admin.moderators.index.email") %></th>
<th scope="col" class="small-3"><%= t("admin.shared.actions") %></th>
</thead>
<tbody>
<tr>
<td>
<%= moderator.name %>
</td>
<td>
<%= moderator.email %>
</td>
<td>
<% if moderator.persisted? %>
<%= link_to t('admin.moderators.moderator.delete'),
admin_moderator_path(moderator),
method: :delete,
class: "button hollow alert expanded" %>
<% else %>
<%= link_to t('admin.moderators.moderator.add'),{ controller: "admin/moderators", action: :create, user_id: moderator.user_id },
method: :post,
class: "button success expanded" %>
<% end %>
</td>
</tr>
</tbody>
</table>

View File

@@ -2,23 +2,11 @@
<h2 class="inline-block"><%= t("admin.moderators.index.title") %></h2> <h2 class="inline-block"><%= t("admin.moderators.index.title") %></h2>
<div class="small-12 medium-6"> <%= render 'admin/shared/user_search', url: search_admin_moderators_path %>
<%= form_tag search_admin_moderators_path, method: :get, remote: true do %>
<div class="input-group">
<%= text_field_tag :email, '', placeholder: t('admin.moderators.search.email_placeholder') %>
<div class="input-group-button">
<%= submit_tag t('admin.moderators.search.search'), class: 'button' %>
</div>
</div>
<% end %>
</div>
<div id="search-result"></div>
<div id="moderators"> <div id="moderators">
<% if @moderators.any? %> <% if @moderators.any? %>
<h3 class="margin"><%= page_entries_info @moderators %></h3>
<h3><%= page_entries_info @moderators %></h3>
<table> <table>
<thead> <thead>

View File

@@ -0,0 +1,29 @@
<h2><%= t("admin.moderators.search.title") %></h2>
<%= render 'admin/shared/user_search', url: search_admin_moderators_path %>
<h3><%= page_entries_info @users %></h3>
<table id="moderators">
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.email %></td>
<td class="text-right">
<% if user.moderator? && user.moderator.persisted? %>
<%= link_to t('admin.moderators.moderator.delete'),
admin_moderator_path(user),
method: :delete,
class: "button hollow alert" %>
<% else %>
<%= link_to t('admin.moderators.moderator.add'),
{ controller: "admin/moderators",
action: :create,
user_id: user },
method: :post,
class: "button success" %>
<% end %>
</td>
</tr>
<% end %>
</table>

View File

@@ -1 +0,0 @@
$("#search-result").html("<%= j render 'moderator', moderator: @moderator %>");

View File

@@ -1 +0,0 @@
$("#search-result").html("<div class=\"callout alert\"><%= j t('admin.moderators.search.user_not_found') %></div>");

View File

@@ -0,0 +1,31 @@
<td>
<%= link_to booth.name, admin_booth_path(booth) %>
</td>
<td>
<%= booth.location || t("admin.booths.index.no_location") %>
</td>
<% if booth_assignment.present? %>
<td>
<span class="verified"><%= t("admin.booth_assignments.manage.status.assigned") %></span>
</td>
<td class="text-right">
<%= link_to t("admin.booth_assignments.manage.actions.unassign"),
admin_poll_booth_assignment_path(@poll, booth_assignment, booth_id: booth.id),
method: :delete,
remote: true,
title: t("admin.booth_assignments.manage.actions.unassign"),
class: "button hollow alert" %>
</td>
<% else %>
<td>
<span class="delete"><%= t("admin.booth_assignments.manage.status.unassigned") %></span>
</td>
<td class="text-right">
<%= link_to t("admin.booth_assignments.manage.actions.assign"),
admin_poll_booth_assignments_path(@poll, booth_id: booth.id),
method: :post,
remote: true,
title: t("admin.booth_assignments.manage.actions.assign"),
class: "button" %>
</td>
<% end %>

View File

@@ -12,7 +12,6 @@
<tr> <tr>
<th><%= t("admin.poll_booth_assignments.index.table_name") %></th> <th><%= t("admin.poll_booth_assignments.index.table_name") %></th>
<th><%= t("admin.poll_booth_assignments.index.table_location") %></th> <th><%= t("admin.poll_booth_assignments.index.table_location") %></th>
<th class="text-center"><%= t("admin.poll_booth_assignments.index.table_assignment") %></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -24,14 +23,6 @@
<td> <td>
<%= booth.location %> <%= booth.location %>
</td> </td>
<td class="text-center">
<% unless @poll.booth_ids.include?(booth.id) %>
<%= link_to t("admin.poll_booth_assignments.index.add_booth"),
admin_poll_booth_assignments_path(@poll, booth_id: booth.id),
method: :post,
class: "button hollow" %>
<% end %>
</td>
</tr> </tr>
<% end %> <% end %>
</tbody> </tbody>

View File

@@ -0,0 +1 @@
$("#<%= dom_id(@booth) %>").html('<%= j render("booth_assignment", booth: @booth, booth_assignment: @booth.assignment_on_poll(@poll)) %>');

View File

@@ -0,0 +1 @@
$("#<%= dom_id(@booth) %>").html('<%= j render("booth_assignment", booth: @booth, booth_assignment: @booth.assignment_on_poll(@poll)) %>');

View File

@@ -1,10 +1,15 @@
<%= render "/admin/poll/polls/poll_header" %> <%= render "/admin/poll/polls/poll_header" %>
<div id="poll-resources"> <div id="poll-resources">
<%= render "/admin/poll/polls/subnav" %> <%= render "/admin/poll/polls/subnav" %>
<%= render "search_booths" %> <%= render "search_booths" %>
<h3><%= t("admin.poll_booth_assignments.index.booths_title") %></h3> <h3><%= t("admin.poll_booth_assignments.index.booths_title") %></h3>
<%= link_to t("admin.booth_assignments.manage_assignments"),
manage_admin_poll_booth_assignments_path(@poll),
class: "button hollow float-right" %>
<% if @booth_assignments.empty? %> <% if @booth_assignments.empty? %>
<div class="callout primary margin-top"> <div class="callout primary margin-top">
<%= t("admin.poll_booth_assignments.index.no_booths") %> <%= t("admin.poll_booth_assignments.index.no_booths") %>
@@ -14,7 +19,6 @@
<thead> <thead>
<th><%= t("admin.poll_booth_assignments.index.table_name") %></th> <th><%= t("admin.poll_booth_assignments.index.table_name") %></th>
<th><%= t("admin.poll_booth_assignments.index.table_location") %></th> <th><%= t("admin.poll_booth_assignments.index.table_location") %></th>
<th class="text-right"><%= t("admin.poll_booth_assignments.index.table_assignment") %></th>
</thead> </thead>
<tbody> <tbody>
<% @booth_assignments.each do |booth_assignment| %> <% @booth_assignments.each do |booth_assignment| %>
@@ -25,13 +29,7 @@
</strong> </strong>
</td> </td>
<td> <td>
<%= booth_assignment.booth.location %> <%= booth_assignment.booth.location || t("admin.booths.index.no_location") %>
</td>
<td class="text-right">
<%= link_to t("admin.poll_booth_assignments.index.remove_booth"),
admin_poll_booth_assignment_path(@poll, booth_assignment),
method: :delete,
class: "button hollow alert" %>
</td> </td>
</tr> </tr>
<% end %> <% end %>

View File

@@ -0,0 +1,28 @@
<%= link_to booth_assignments_admin_polls_path do %>
<span class="icon-angle-left"></span> <%= t("shared.back") %>
<% end %>
<hr>
<h2 class="inline-block"><%= t("admin.booth_assignments.manage.assignments_list", poll: @poll.name) %></h2>
<% if @booths.empty? %>
<div class="callout primary">
<%= t("admin.booths.index.no_booths") %>
</div>
<% else %>
<table>
<thead>
<th><%= t("admin.booths.index.name") %></th>
<th><%= t("admin.booths.index.location") %></th>
<th><%= t("admin.booth_assignments.manage.status.assign_status") %></th>
<th class="text-right"><%= t("admin.actions.actions") %></th>
</thead>
<tbody>
<% @booths.each do |booth| %>
<tr id="<%= dom_id(booth) %>" class="booth">
<%= render partial: "booth_assignment", locals: { booth: booth, booth_assignment: booth.assignment_on_poll(@poll) } %>
</tr>
<% end %>
</tbody>
</table>
<% end %>

View File

@@ -53,6 +53,17 @@
</div> </div>
</div> </div>
<% if controller_name == "polls" && action_name == "edit" %>
<div class="row">
<fieldset class="fieldset">
<legend><%= t('admin.polls.new.show_results_and_stats') %></legend>
<%= f.check_box :results_enabled, checked: @poll.results_enabled?, label: t('admin.polls.new.show_results') %>
<%= f.check_box :stats_enabled, checked: @poll.stats_enabled?, label: t('admin.polls.new.show_stats') %>
<p class="small"><%= t('admin.polls.new.results_and_stats_reminder') %></p>
</fieldset>
</div>
<% end %>
<div class="row"> <div class="row">
<div class="small-12 medium-4 column"> <div class="small-12 medium-4 column">
<%= f.submit t("admin.polls.#{admin_submit_action(@poll)}.submit_button"), <%= f.submit t("admin.polls.#{admin_submit_action(@poll)}.submit_button"),

View File

@@ -0,0 +1,32 @@
<h2 class="inline-block"><%= t("admin.polls.index.title") %></h2>
<% if @polls.any? %>
<table>
<thead>
<th class="medium-6"><%= t("admin.polls.index.name") %></th>
<th><%= t("admin.polls.index.dates") %></th>
<th class="text-right"><%= t("admin.actions.actions") %></th>
</thead>
<tbody>
<% @polls.each do |poll| %>
<tr id="<%= dom_id(poll) %>" class="poll">
<td>
<strong><%= link_to poll.name, admin_poll_path(poll) %></strong>
</td>
<td>
<%= l poll.starts_at.to_date %> - <%= l poll.ends_at.to_date %>
</td>
<td class="text-right">
<%= link_to t("admin.booth_assignments.manage_assignments"),
manage_admin_poll_booth_assignments_path(poll),
class: "button hollow" %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<div class="callout primary">
<%= t("admin.polls.index.no_polls") %>
</div>
<% end %>

View File

@@ -24,12 +24,12 @@
<div class="small-12 medium-3 column"> <div class="small-12 medium-3 column">
<label><%= t("admin.poll_shifts.new.date") %></label> <label><%= t("admin.poll_shifts.new.date") %></label>
<%= select 'shift[date]', 'vote_collection_date', <%= select 'shift[date]', 'vote_collection_date',
options_for_select(shift_vote_collection_dates(@booth, @booth.polls.current_or_incoming)), options_for_select(shift_vote_collection_dates(@booth, @voting_polls)),
{ prompt: t("admin.poll_shifts.new.select_date"), { prompt: @voting_polls.present? ? t("admin.poll_shifts.new.select_date") : t("admin.poll_shifts.new.no_voting_days"),
label: false }, label: false },
class: 'js-shift-vote-collection-dates' %> class: 'js-shift-vote-collection-dates' %>
<%= select 'shift[date]', 'recount_scrutiny_date', <%= select 'shift[date]', 'recount_scrutiny_date',
options_for_select(shift_recount_scrutiny_dates(@booth, @booth.polls.current_or_recounting_or_incoming)), options_for_select(shift_recount_scrutiny_dates(@booth, @recount_polls)),
{ prompt: t("admin.poll_shifts.new.select_date"), { prompt: t("admin.poll_shifts.new.select_date"),
label: false }, label: false },
class: 'js-shift-recount-scrutiny-dates', class: 'js-shift-recount-scrutiny-dates',

View File

@@ -1,3 +1,4 @@
<% if current_user.administrator? %>
<li> <li>
<%= link_to admin_stats_path, title: t("admin.menu.stats") do %> <%= link_to admin_stats_path, title: t("admin.menu.stats") do %>
<span class="icon-stats"></span> <span class="icon-stats"></span>
@@ -8,3 +9,4 @@
<span class="icon-settings"></span> <span class="icon-settings"></span>
<% end %> <% end %>
</li> </li>
<% end %>

View File

@@ -1,34 +0,0 @@
<h3><%= t('admin.valuators.valuator.user_found') %></h3>
<table>
<thead>
<th scope="col"><%= t("admin.valuators.index.name") %></th>
<th scope="col"><%= t("admin.valuators.index.email") %></th>
</thead>
<tbody>
<tr>
<td>
<%= valuator.name %>
</td>
<td>
<%= valuator.email %>
</td>
</tr>
</tbody>
</table>
<% unless @valuator.persisted? %>
<%= form_for @valuator, url: admin_valuators_path do |f| %>
<div class="small-12 medium-8">
<div class="input-group">
<%= f.text_field :description, label: false, placeholder: t('admin.valuators.valuator.description_placeholder') %>
<div class="input-group-button">
<%= f.hidden_field :user_id %>
<%= f.submit t('admin.valuators.valuator.add'), class: "button success" %>
</div>
</div>
</div>
<hr>
<% end %>
<% end %>

View File

@@ -1,17 +1,6 @@
<h2><%= t("admin.valuators.index.title") %></h2> <h2><%= t("admin.valuators.index.title") %></h2>
<div class="small-12 medium-6"> <%= render 'admin/shared/user_search', url: search_admin_valuators_path %>
<%= form_tag search_admin_valuators_path, method: :get, remote: true do %>
<div class="input-group">
<%= text_field_tag :email, '', placeholder: t('admin.valuators.search.email_placeholder') %>
<div class="input-group-button">
<%= submit_tag t('admin.valuators.search.search'), class: 'button' %>
</div>
</div>
<% end %>
</div>
<div id="search-result"></div>
<% if @valuators.any? %> <% if @valuators.any? %>
<h3 class="margin"><%= page_entries_info @valuators %></h3> <h3 class="margin"><%= page_entries_info @valuators %></h3>

View File

@@ -0,0 +1,27 @@
<h2><%= t("admin.valuators.search.title") %></h2>
<%= render 'admin/shared/user_search', url: search_admin_valuators_path %>
<h3><%= page_entries_info @users %></h3>
<table id="valuators">
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.email %></td>
<td class="float-right">
<% if user.valuator? && user.valuator.description.present? %>
<%= user.valuator.description %>
<% else %>
<%= form_for Valuator.new(user: user), url: admin_valuators_path do |f| %>
<%= f.text_field :description,
label: false,
placeholder: t("admin.valuators.valuator.description_placeholder") %>
<%= f.hidden_field :user_id %>
<%= f.submit t("admin.valuators.valuator.add"), class: "button success float-left" %>
<% end %>
<% end %>
</td>
</tr>
<% end %>
</table>

View File

@@ -1 +0,0 @@
$("#search-result").html("<%= j render 'valuator', valuator: @valuator %>");

View File

@@ -1 +0,0 @@
$("#search-result").html("<div class=\"callout alert\"><%= j t('admin.valuators.search.user_not_found') %></div>");

View File

@@ -1,6 +1,6 @@
<div class="row"> <div class="row margin-top">
<div class="small-12 column"> <div class="small-12 column">
<ul class="tabs" data-tabs id="polls-tabs"> <ul class="tabs" data-tabs id="polls_tabs">
<li class="tabs-title is-active"> <li class="tabs-title is-active">
<%= link_to "#tab-comments" do %> <%= link_to "#tab-comments" do %>
<h3> <h3>

View File

@@ -19,11 +19,27 @@
<div class="dates"></div> <div class="dates"></div>
<% if poll.questions.count == 1 %> <% if poll.questions.count == 1 %>
<% poll.questions.each do |question| %> <% poll.questions.each do |question| %>
<h4><%= link_to question.title, poll %></h4> <h4>
<% if poll.results_enabled? %>
<%= link_to question.title, results_poll_path(poll) %>
<% elsif poll.stats_enabled? %>
<%= link_to question.title, stats_poll_path(poll) %>
<% else %>
<%= link_to question.title, poll %>
<% end %>
</h4>
<%= poll_dates(poll) %> <%= poll_dates(poll) %>
<% end %> <% end %>
<% else %> <% else %>
<h4><%= link_to poll.name, poll %></h4> <h4>
<% if poll.results_enabled? %>
<%= link_to poll.name, results_poll_path(poll) %>
<% elsif poll.stats_enabled? %>
<%= link_to poll.name, stats_poll_path(poll) %>
<% else %>
<%= link_to poll.name, poll %>
<% end %>
</h4>
<%= poll_dates(poll) %> <%= poll_dates(poll) %>
<ul class="margin-top"> <ul class="margin-top">
<% poll.questions.each do |question| %> <% poll.questions.each do |question| %>

View File

@@ -0,0 +1,27 @@
<div class="expanded no-margin-top polls-show-header">
<div class="row">
<div class="small-12 medium-9 column padding">
<%= back_link_to polls_path, t("polls.show.back") %>
<h2><%= @poll.name %></h2>
<%= safe_html_with_links simple_format(@poll.summary) %>
<% if @poll.geozones.any? %>
<ul class="no-bullet margin-top tags">
<% @poll.geozones.each do |g| %>
<li class="inline-block"><span><%= g.name %></span></li>
<% end %>
</ul>
<% end %>
</div>
<aside class="small-12 medium-3 column margin-top">
<%= render partial: 'shared/social_share', locals: {
share_title: t("shared.share"),
title: @poll.name,
url: poll_url(@poll)
} %>
</aside>
</div>
</div>

View File

@@ -0,0 +1,36 @@
<% if current_user && current_user.administrator? ||
(@poll.expired? && (@poll.results_enabled? || @poll.stats_enabled?)) %>
<div class="row margin-top">
<div class="small-12 column">
<ul class="menu simple clear">
<% if current_user && current_user.administrator? || @poll.results_enabled? %>
<% if controller_name == "polls" && action_name == "results" %>
<li class="active">
<h2><%= t("polls.show.results_menu") %></h2>
</li>
<% else %>
<li><%= link_to t("polls.show.results_menu"), results_poll_path(@poll) %></li>
<% end %>
<% end %>
<% if current_user && current_user.administrator? || @poll.stats_enabled? %>
<% if controller_name == "polls" && action_name == "stats" %>
<li class="active">
<h2><%= t("polls.show.stats_menu") %></h2>
</li>
<% else %>
<li><%= link_to t("polls.show.stats_menu"), stats_poll_path(@poll) %></li>
<% end %>
<% end %>
<% if controller_name == "polls" && action_name == "show" %>
<li class="active">
<h2><%= t("polls.show.info_menu") %></h2>
</li>
<% else %>
<li><%= link_to t("polls.show.info_menu"), poll_path(@poll) %></li>
<% end %>
</ul>
</div>
</div>
<% end %>

View File

@@ -1,20 +0,0 @@
<div class="row">
<div class="small-12 column">
<ul class="tabs" data-tabs id="polls-tabs">
<li class="tabs-title">
<%= link_to "#tab-stats" do %>
<h3>
<%= t("polls.show.stats_menu") %> <!-- t("polls.show.comments_tab") -->
</h3>
<% end %>
</li>
<li class="tabs-title is-active">
<%= link_to "#tab-information" do %>
<h3>
<%= t("polls.show.info_menu") %>
</h3>
<% end %>
</li>
</ul>
</div>
</div>

View File

@@ -1,126 +0,0 @@
<div class="row margin">
<div class="small-12 medium-9 column">
<%= render "callout" %>
<% if @poll.voted_in_booth?(current_user) %>
<div class="callout warning">
<%= t("polls.show.already_voted_in_booth") %>
</div>
<% else %>
<% if current_user && @poll.voted_in_web?(current_user) %>
<div class="callout warning">
<%= t("polls.show.already_voted_in_web") %>
</div>
<% end %>
<% end %>
<% @questions.each do |question| %>
<%= render 'polls/questions/question', question: question, token: @token %>
<% end %>
<% if poll_voter_token(@poll, current_user).empty? %>
<div class="callout token-message js-token-message" style="display: none">
<%= t('poll_questions.show.voted_token') %>
</div>
<% end %>
<%= link_to t("polls.show.participate_in_other_polls"), polls_path, class: "button hollow" %>
</div>
</div>
<div class="expanded poll-more-info">
<div class="row margin">
<div class="small-12 medium-9 column">
<h3><%= t("polls.show.more_info_title") %></h3>
<%= safe_html_with_links simple_format(@poll.description) %>
</div>
<% if false %>
<aside class="small-12 medium-3 column">
<div class="sidebar-divider"></div>
<h2><%= t("polls.show.documents") %></h2>
</aside>
<% end %>
</div>
</div>
<div class="expanded poll-more-info-answers">
<div class="row padding">
<% @poll_questions_answers.each do |answer| %>
<div class="small-12 medium-6 column end answer <%= cycle('first', '') %>" id="answer_<%= answer.id %>">
<% if answer.description.present? %>
<h3><%= answer.title %></h3>
<% end %>
<% if answer.images.any? %>
<%= render "gallery", answer: answer %>
<% end %>
<% if answer.description.present? %>
<div class="margin-top">
<div id="answer_description_<%= answer.id %>" class="answer-description short" data-toggler="short">
<%= safe_html_with_links simple_format(answer.description) %>
</div>
<div class="margin">
<a id="read_more_<%= answer.id %>"
data-toggle="answer_description_<%= answer.id %> read_more_<%= answer.id %> read_less_<%= answer.id %>"
data-toggler="hide">
<%= t("polls.show.read_more", answer: answer.title) %>
</a>
<a id="read_less_<%= answer.id %>"
data-toggle="answer_description_<%= answer.id %> read_more_<%= answer.id %> read_less_<%= answer.id %>"
data-toggler="hide"
class="hide">
<%= t("polls.show.read_less", answer: answer.title) %>
</a>
</div>
</div>
<% end %>
<% if answer.documents.present? %>
<div class="document-link">
<p>
<span class="icon-document"></span>&nbsp;
<strong><%= t("polls.show.documents") %></strong>
</p>
<% answer.documents.each do |document| %>
<%= link_to document.title,
document.attachment.url,
target: "_blank",
rel: "nofollow" %><br>
<% end %>
</div>
<% end %>
<% if answer.videos.present? %>
<div class="video-link">
<p>
<span class="icon-video"></span>&nbsp;
<strong><%= t("polls.show.videos") %></strong>
</p>
<% answer.videos.each do |video| %>
<%= link_to video.title,
video.url,
target: "_blank",
rel: "nofollow" %><br>
<% end %>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
<div class="tabs-content" data-tabs-content="proposals-tabs" role="tablist">
<%= render "filter_subnav" %>
<div class="tabs-panel is-active" id="tab-comments">
<%= render "comments" %>
</div>
</div>

View File

@@ -0,0 +1,49 @@
<% provide :title do %><%= @poll.name %><% end %>
<div class="polls-results-stats">
<%= render "poll_header" %>
<%= render "poll_subnav" %>
<div class="row margin" data-equalizer data-equalize-on="medium">
<div class="small-12 medium-3 column sidebar" data-equalizer-watch>
<p><strong><%= t("polls.show.results.title") %></strong></p>
<ul class="menu vertical">
<%- @poll.questions.each do |question| %>
<li><%=link_to question.title, "##{question.title.parameterize}" %></li>
<% end %>
</ul>
</div>
<div class="small-12 medium-9 column" data-equalizer-watch>
<%- @poll.questions.each do |question| %>
<table id="question_<%= question.id %>_results_table">
<h3 id="<%= question.title.parameterize %>"><%= question.title %></h3>
<thead>
<tr>
<%- question.question_answers.each do |answer| %>
<th scope="col" <%= answer.most_voted? ? "class=win" : "" %>>
<% if answer.most_voted %>
<span class="show-for-sr"><%= t("polls.show.results.most_voted_answer") %></span>
<% end %>
<%= answer.title %>
</th>
<% end %>
</tr>
</thead>
<tbody>
<tr>
<%- question.question_answers.each do |answer| %>
<td id="answer_<%= answer.id %>_result" <%= answer.most_voted? ? "class=win" : "" %>>
<%= answer.total_votes %>
(<%= answer.total_votes_percentage.round(2) %>%)
</td>
<% end %>
</tr>
</tbody>
</table>
<% end %>
</div>
</div>
</div>

View File

@@ -1,44 +1,134 @@
<% provide :title do %><%= @poll.name %><% end %> <% provide :title do %><%= @poll.name %><% end %>
<div class="polls-show"> <div class="polls-show">
<div class="expanded no-margin-top polls-show-header"> <%= render "poll_header" %>
<div class="row">
<div class="small-12 medium-9 column padding">
<%= back_link_to polls_path, t("polls.show.back") %>
<h2><%= @poll.name %></h2> <%= render "poll_subnav" %>
<%= safe_html_with_links simple_format(@poll.summary) %> <div class="row margin">
<div class="small-12 medium-9 column">
<%= render "callout" %>
<% if @poll.geozones.any? %> <% if @poll.voted_in_booth?(current_user) %>
<ul class="no-bullet margin-top tags"> <div class="callout warning">
<% @poll.geozones.each do |g| %> <%= t("polls.show.already_voted_in_booth") %>
<li class="inline-block"><span><%= g.name %></span></li> </div>
<% else %>
<% if current_user && @poll.voted_in_web?(current_user) && !@poll.expired? %>
<div class="callout warning">
<%= t("polls.show.already_voted_in_web") %>
</div>
<% end %> <% end %>
</ul>
<% end %> <% end %>
<% @questions.each do |question| %>
<%= render 'polls/questions/question', question: question, token: @token %>
<% end %>
<% if poll_voter_token(@poll, current_user).empty? %>
<div class="callout token-message js-token-message" style="display: none">
<%= t('poll_questions.show.voted_token') %>
</div>
<% end %>
<%= link_to t("polls.show.participate_in_other_polls"), polls_path, class: "button hollow" %>
</div>
</div> </div>
<aside class="small-12 medium-3 column margin-top"> <div class="expanded poll-more-info">
<%= render partial: 'shared/social_share', locals: { <div class="row margin">
share_title: t("shared.share"), <div class="small-12 medium-9 column">
title: @poll.name, <h3><%= t("polls.show.more_info_title") %></h3>
url: poll_url <%= safe_html_with_links simple_format(@poll.description) %>
} %> </div>
<% if false %>
<aside class="small-12 medium-3 column">
<div class="sidebar-divider"></div>
<h2><%= t("polls.show.documents") %></h2>
</aside> </aside>
<% end %>
</div> </div>
</div> </div>
<div class="tabs-content" data-tabs-content="polls-tabs" role="tablist"> <div class="expanded poll-more-info-answers">
<%= render "results_subnavigation" %> <div class="row padding">
<div id="tab-stats" class="tabs-panel"> <% @poll_questions_answers.each do |answer| %>
<%= render "polls/stats/show" %> <div class="small-12 medium-6 column end answer <%= cycle('first', '') %>" id="answer_<%= answer.id %>">
<% if answer.description.present? %>
<h3><%= answer.title %></h3>
<% end %>
<% if answer.images.any? %>
<%= render "gallery", answer: answer %>
<% end %>
<% if answer.description.present? %>
<div class="margin-top">
<div id="answer_description_<%= answer.id %>" class="answer-description short" data-toggler="short">
<%= safe_html_with_links simple_format(answer.description) %>
</div>
<div class="margin">
<a id="read_more_<%= answer.id %>"
data-toggle="answer_description_<%= answer.id %> read_more_<%= answer.id %> read_less_<%= answer.id %>"
data-toggler="hide">
<%= t("polls.show.read_more", answer: answer.title) %>
</a>
<a id="read_less_<%= answer.id %>"
data-toggle="answer_description_<%= answer.id %> read_more_<%= answer.id %> read_less_<%= answer.id %>"
data-toggler="hide"
class="hide">
<%= t("polls.show.read_less", answer: answer.title) %>
</a>
</div>
</div>
<% end %>
<% if answer.documents.present? %>
<div class="document-link">
<p>
<span class="icon-document"></span>&nbsp;
<strong><%= t("polls.show.documents") %></strong>
</p>
<% answer.documents.each do |document| %>
<%= link_to document.title,
document.attachment.url,
target: "_blank",
rel: "nofollow" %><br>
<% end %>
</div>
<% end %>
<% if answer.videos.present? %>
<div class="video-link">
<p>
<span class="icon-video"></span>&nbsp;
<strong><%= t("polls.show.videos") %></strong>
</p>
<% answer.videos.each do |video| %>
<%= link_to video.title,
video.url,
target: "_blank",
rel: "nofollow" %><br>
<% end %>
</div>
<% end %>
</div>
<% end %>
</div> </div>
<div id="tab-information" class="tabs-panel is-active">
<%= render "show" %>
</div>
</div>
</div> </div>
<div class="tabs-content" data-tabs-content="polls_tabs" role="tablist">
<%= render "filter_subnav" %>
<div class="tabs-panel is-active" id="tab-comments">
<%= render "comments" %>
</div>
</div>
</div>

View File

@@ -0,0 +1,96 @@
<% provide :title do %><%= @poll.name %><% end %>
<div class="polls-results-stats">
<%= render "poll_header" %>
<%= render "poll_subnav" %>
<div class="row margin" data-equalizer data-equalize-on="medium">
<div class="small-12 medium-3 column sidebar" data-equalizer-watch>
<p><strong><%= t("polls.show.stats.title") %></strong></p>
<ul class="menu vertical margin-top">
<li><a href="#total"><%= t("polls.show.stats.total_participation") %></a></li>
</ul>
</div>
<div class="small-12 medium-9 column" data-equalizer-watch>
<h3 id="total"><%= t("polls.show.stats.total_participation") %></h3>
<p class="margin-top uppercase">
<%= t("polls.show.stats.total_votes") %><br>
<span class="number"><%= @stats[:total_participants] %></span>
</p>
<table>
<thead>
<tr>
<th scope="col"><%= t("polls.show.stats.votes") %></th>
<th scope="col"><%= t("polls.show.stats.web") %></th>
<th scope="col"><%= t("polls.show.stats.booth") %></th>
<th scope="col"><%= t("polls.show.stats.total") %></th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row"><%= t("polls.show.stats.valid") %></th>
<td>
<%= @stats[:total_web_valid] %>
<small><em>(<%= @stats[:valid_percentage_web].round(2) %>%)</em></small>
</td>
<td>
<%= @stats[:total_booth_valid] %>
<small><em>(<%= @stats[:valid_percentage_booth].round(2) %>%)</em></small>
</td>
<td>
<%= @stats[:total_valid_votes] %>
<small><em>(<%= @stats[:total_valid_percentage].round(2) %>%)</em></small>
</td>
</tr>
<tr>
<th scope="row"><%= t("polls.show.stats.white") %></th>
<td>
<%= @stats[:total_web_white] %>
<small><em>(<%= @stats[:white_percentage_web].round(2) %>%)</em></small>
</td>
<td>
<%= @stats[:total_booth_white] %>
<small><em>(<%= @stats[:white_percentage_booth].round(2) %>%)</em></small>
</td>
<td><%= @stats[:total_white_votes] %>
<small><em>(<%= @stats[:total_white_percentage].round(2) %>%)</em></small>
</td>
</tr>
<tr>
<th scope="row"><%= t("polls.show.stats.null_votes") %></th>
<td>
<%= @stats[:total_web_null] %>
<small><em>(<%= @stats[:null_percentage_web].round(2) %>%)</em></small>
</td>
<td>
<%= @stats[:total_booth_null] %>
<small><em>(<%= @stats[:null_percentage_booth].round(2) %>%)</em></small>
</td>
<td>
<%= @stats[:total_null_votes] %>
<small><em>(<%= @stats[:total_null_percentage].round(2) %>%)</em></small>
</td>
</tr>
<tr>
<th scope="row"><%= t("polls.show.stats.total") %></th>
<td>
<%= @stats[:total_participants_web] %>
<small><em>(<%= @stats[:total_participants_web_percentage].round(2) %>%)</em></small>
</td>
<td>
<%= @stats[:total_participants_booth] %>
<small><em>(<%= @stats[:total_participants_booth_percentage].round(2) %>%)</em></small>
</td>
<td><%= @stats[:total_participants_web] + @stats[:total_participants_booth] %></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>

View File

@@ -1,85 +0,0 @@
<div class="row">
<div class="small-12 medium-3 column sidebar">
<p><%= t("polls.show.stats.title") %></p>
<ul class="menu vertical margin-top">
<li><a href="#total"><%= t("polls.show.stats.total_participation") %></a></li>
</ul>
</div>
<div class="small-12 medium-9 column">
<h3 id="total"><%= t("polls.show.stats.total_participation") %></h3>
<p class="stat-number margin-top">
<%= t("polls.show.stats.total_votes") %><br>
<span><%= @stats[:total_participants] %></span>
</p>
<table class="polls-total-stats">
<thead>
<tr>
<th scope="col"><%= t("polls.show.stats.votes") %></th>
<th scope="col"><%= t("polls.show.stats.web") %></th>
<th scope="col"><%= t("polls.show.stats.booth") %></th>
<th scope="col"><%= t("polls.show.stats.total") %></th>
</tr>
</thead>
<tbody>
<tr>
<th><%= t("polls.show.stats.valid") %></th>
<td><%= @stats[:total_web_valid] %> <small><em>
(<%= number_to_percentage(@stats[:valid_percentage_web],
strip_insignificant_zeros: true,
precision: 2) %>)</em></small></td>
<td><%= @stats[:total_booth_valid] %> <small><em>
(<%= number_to_percentage(@stats[:valid_percentage_booth],
strip_insignificant_zeros: true,
precision: 2) %>)</em></small></td>
<td><%= @stats[:total_valid_votes] %> <small><em>
(<%= number_to_percentage(@stats[:total_valid_percentage],
strip_insignificant_zeros: true,
precision: 2) %>)</em></small></td>
</tr>
<tr>
<th><%= t("polls.show.stats.white") %></th>
<td><%= @stats[:total_web_white] %> <small><em>
(<%= number_to_percentage(@stats[:white_percentage_web],
strip_insignificant_zeros: true,
precision: 2) %>)</em></small></td>
<td><%= @stats[:total_booth_white] %> <small><em>
(<%= number_to_percentage(@stats[:white_percentage_booth],
strip_insignificant_zeros: true,
precision: 2) %>)</em></small></td>
<td><%= @stats[:total_white_votes] %> <small><em>
(<%= number_to_percentage(@stats[:total_white_percentage],
strip_insignificant_zeros: true,
precision: 2) %>)</em></small></td>
</tr>
<tr>
<th><%= t("polls.show.stats.null_votes") %></th>
<td><%= @stats[:total_web_null] %> <small><em>
(<%= number_to_percentage(@stats[:null_percentage_web],
strip_insignificant_zeros: true,
precision: 2) %>)</em></small></td>
<td><%= @stats[:total_booth_null] %> <small><em>
(<%= number_to_percentage(@stats[:null_percentage_booth],
strip_insignificant_zeros: true,
precision: 2) %>)</em></small></td>
<td><%= @stats[:total_null_votes] %> <small><em>
(<%= number_to_percentage(@stats[:total_null_percentage],
strip_insignificant_zeros: true,
precision: 2) %>)</em></small></td>
</tr>
<tr>
<th><%= t("polls.show.stats.total") %></th>
<td><%= @stats[:total_participants_web] %> <small><em>
(<%= number_to_percentage(@stats[:total_participants_web_percentage],
strip_insignificant_zeros: true,
precision: 2) %>)</em></small></td>
<td><%= @stats[:total_participants_booth] %> <small><em>
(<%= number_to_percentage(@stats[:total_participants_booth_percentage],
strip_insignificant_zeros: true,
precision: 2) %>)</em></small></td>
<td><%= @stats[:total_participants_web] + @stats[:total_participants_booth] %></td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@@ -26,12 +26,11 @@
<%= link_to t("layouts.header.management"), management_sign_in_path %> <%= link_to t("layouts.header.management"), management_sign_in_path %>
</li> </li>
<% end %> <% end %>
</ul>
<% if current_user.administrator? || current_user.poll_officer? %> </li>
<% end %>
<% if current_user && current_user.poll_officer? %>
<li> <li>
<%= link_to t("layouts.header.officing"), officing_root_path %> <%= link_to t("layouts.header.officing"), officing_root_path %>
</li> </li>
<% end %> <% end %>
</ul>
</li>
<% end %>

View File

@@ -390,9 +390,7 @@ en:
add: Add add: Add
delete: Delete delete: Delete
search: search:
email_placeholder: Search user by email title: 'Managers: User search'
search: Search
user_not_found: User not found
menu: menu:
activity: Moderator activity activity: Moderator activity
admin: Admin menu admin: Admin menu
@@ -413,6 +411,7 @@ en:
poll_officers: Poll officers poll_officers: Poll officers
polls: Polls polls: Polls
poll_booths: Booths location poll_booths: Booths location
poll_booth_assignments: Booths Assignments
poll_shifts: Manage shifts poll_shifts: Manage shifts
officials: Officials officials: Officials
organizations: Organisations organizations: Organisations
@@ -447,6 +446,7 @@ en:
email_placeholder: Search user by email email_placeholder: Search user by email
search: Search search: Search
user_not_found: User not found. user_not_found: User not found.
title: "Administrators: User search"
moderators: moderators:
index: index:
title: Moderators title: Moderators
@@ -457,9 +457,7 @@ en:
add: Add add: Add
delete: Delete delete: Delete
search: search:
email_placeholder: Search user by email title: 'Moderators: User search'
search: Search
user_not_found: User not found
newsletters: newsletters:
index: index:
title: Newsletters title: Newsletters
@@ -474,12 +472,9 @@ en:
no_valuators: There are no valuators. no_valuators: There are no valuators.
valuator: valuator:
description_placeholder: 'Description (optional)' description_placeholder: 'Description (optional)'
user_found: User found
add: Add to valuators add: Add to valuators
search: search:
email_placeholder: Search user by email title: 'Valuators: User search'
search: Search
user_not_found: User not found
summary: summary:
title: Valuator summary for investment projects title: Valuator summary for investment projects
valuator_name: Valuator valuator_name: Valuator
@@ -529,6 +524,7 @@ en:
search_officer_placeholder: Search officer search_officer_placeholder: Search officer
search_officer_text: Search for an officer to assign a new shift search_officer_text: Search for an officer to assign a new shift
select_date: "Select day" select_date: "Select day"
no_voting_days: "Los dias de votación terminaron"
select_task: "Select task" select_task: "Select task"
table_shift: "Shift" table_shift: "Shift"
table_email: "Email" table_email: "Email"
@@ -539,6 +535,17 @@ en:
date_missing: "A date must be selected" date_missing: "A date must be selected"
vote_collection: Collect Votes vote_collection: Collect Votes
recount_scrutiny: Recount & Scrutiny recount_scrutiny: Recount & Scrutiny
booth_assignments:
manage_assignments: Manage assignments
manage:
assignments_list: "Assignments for poll '%{poll}'"
status:
assign_status: Assignment
assigned: Assigned
unassigned: Unassigned
actions:
assign: Assign booth
unassign: Unassign booth
poll_booth_assignments: poll_booth_assignments:
flash: flash:
destroy: "Booth not assigned anymore" destroy: "Booth not assigned anymore"
@@ -562,9 +569,6 @@ en:
no_booths: "There are no booths assigned to this poll." no_booths: "There are no booths assigned to this poll."
table_name: "Name" table_name: "Name"
table_location: "Location" table_location: "Location"
table_assignment: "Assignment"
remove_booth: "Remove booth from poll"
add_booth: "Assign booth"
polls: polls:
index: index:
title: "List of polls" title: "List of polls"
@@ -575,6 +579,10 @@ en:
geozone_restricted: "Restricted to districts" geozone_restricted: "Restricted to districts"
new: new:
title: "New poll" title: "New poll"
show_results_and_stats: "Show results and stats"
show_results: "Show results"
show_stats: "Show stats"
results_and_stats_reminder: "Marking these checkboxes the results and/or stats of this poll will be publicly available and every user will see them."
submit_button: "Create poll" submit_button: "Create poll"
edit: edit:
title: "Edit poll" title: "Edit poll"
@@ -681,6 +689,7 @@ en:
add_booth: "Add booth" add_booth: "Add booth"
name: "Name" name: "Name"
location: "Location" location: "Location"
no_location: "No Location"
new: new:
title: "New booth" title: "New booth"
name: "Name" name: "Name"

View File

@@ -501,6 +501,7 @@ en:
videos: "External video" videos: "External video"
info_menu: "Information" info_menu: "Information"
stats_menu: "Participation statistics" stats_menu: "Participation statistics"
results_menu: "Poll results"
stats: stats:
title: "Participation data" title: "Participation data"
total_participation: "Total participation" total_participation: "Total participation"
@@ -512,6 +513,9 @@ en:
valid: "Valid" valid: "Valid"
white: "White votes" white: "White votes"
null_votes: "Invalid" null_votes: "Invalid"
results:
title: "Questions"
most_voted_answer: "Most voted answer: "
poll_questions: poll_questions:
create_question: "Create question" create_question: "Create question"
show: show:

View File

@@ -394,6 +394,7 @@ es:
email_placeholder: Buscar usuario por email email_placeholder: Buscar usuario por email
search: Buscar search: Buscar
user_not_found: Usuario no encontrado. user_not_found: Usuario no encontrado.
title: "Administradores: Búsqueda de usuarios"
managers: managers:
index: index:
title: Gestores title: Gestores
@@ -404,9 +405,7 @@ es:
add: Añadir como Gestor add: Añadir como Gestor
delete: Borrar delete: Borrar
search: search:
email_placeholder: Buscar usuario por email title: 'Gestores: Búsqueda de usuarios'
search: Buscar
user_not_found: Usuario no encontrado
menu: menu:
activity: Actividad de moderadores activity: Actividad de moderadores
admin: Menú de administración admin: Menú de administración
@@ -427,6 +426,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_booth_assignments: Asignación de urnas
poll_shifts: Asignar turnos poll_shifts: Asignar turnos
officials: Cargos públicos officials: Cargos públicos
organizations: Organizaciones organizations: Organizaciones
@@ -457,9 +457,7 @@ es:
add: Añadir como Moderador add: Añadir como Moderador
delete: Borrar delete: Borrar
search: search:
email_placeholder: Buscar usuario por email title: 'Moderadores: Búsqueda de usuarios'
search: Buscar
user_not_found: Usuario no encontrado
newsletters: newsletters:
index: index:
title: Envío de newsletters title: Envío de newsletters
@@ -474,12 +472,9 @@ es:
no_valuators: No hay evaluadores. no_valuators: No hay evaluadores.
valuator: valuator:
description_placeholder: "Descripción (opcional)" description_placeholder: "Descripción (opcional)"
user_found: Usuario encontrado
add: Añadir como evaluador add: Añadir como evaluador
search: search:
email_placeholder: Buscar usuario por email title: 'Evaluadores: Búsqueda de usuarios'
search: Buscar
user_not_found: Usuario no encontrado
summary: summary:
title: Resumen de evaluación de propuestas de inversión title: Resumen de evaluación de propuestas de inversión
valuator_name: Evaluador valuator_name: Evaluador
@@ -529,6 +524,7 @@ es:
search_officer_placeholder: Buscar presidentes de mesa search_officer_placeholder: Buscar presidentes de mesa
search_officer_text: Busca al presidente de mesa para asignar un turno search_officer_text: Busca al presidente de mesa para asignar un turno
select_date: "Seleccionar día" select_date: "Seleccionar día"
no_voting_days: "Voting days ended"
select_task: "Seleccionar tarea" select_task: "Seleccionar tarea"
table_shift: "Turno" table_shift: "Turno"
table_email: "Email" table_email: "Email"
@@ -539,6 +535,17 @@ es:
date_missing: "Debe seleccionarse una fecha" date_missing: "Debe seleccionarse una fecha"
vote_collection: Recoger Votos vote_collection: Recoger Votos
recount_scrutiny: Recuento & Escrutinio recount_scrutiny: Recuento & Escrutinio
booth_assignments:
manage_assignments: Gestionar asignaciones
manage:
assignments_list: "Asignaciones para la votación '%{poll}'"
status:
assign_status: Asignación
assigned: Asignada
unassigned: No asignada
actions:
assign: Assign booth
unassign: Unassign booth
poll_booth_assignments: poll_booth_assignments:
flash: flash:
destroy: "Urna desasignada" destroy: "Urna desasignada"
@@ -562,9 +569,6 @@ es:
no_booths: "No hay urnas asignadas a esta votación." no_booths: "No hay urnas asignadas a esta votación."
table_name: "Nombre" table_name: "Nombre"
table_location: "Ubicación" table_location: "Ubicación"
table_assignment: "Asignación"
remove_booth: "Desasignar urna"
add_booth: "Asignar urna"
polls: polls:
index: index:
title: "Listado de votaciones" title: "Listado de votaciones"
@@ -575,6 +579,10 @@ es:
geozone_restricted: "Restringida a los distritos" geozone_restricted: "Restringida a los distritos"
new: new:
title: "Nueva votación" title: "Nueva votación"
show_results_and_stats: "Mostrar resultados y estadísticas"
show_results: "Mostrar resultados"
show_stats: "Mostrar estadísticas"
results_and_stats_reminder: "Si marcas estas casillas los resultados y/o estadísticas de esta votación serán públicos y podrán verlos todos los usuarios."
submit_button: "Crear votación" submit_button: "Crear votación"
edit: edit:
title: "Editar votación" title: "Editar votación"
@@ -683,6 +691,7 @@ es:
add_booth: "Añadir urna" add_booth: "Añadir urna"
name: "Nombre" name: "Nombre"
location: "Ubicación" location: "Ubicación"
no_location: "Sin Ubicación"
new: new:
title: "Nueva urna" title: "Nueva urna"
name: "Nombre" name: "Nombre"

View File

@@ -501,6 +501,7 @@ es:
videos: "Vídeo externo" videos: "Vídeo externo"
info_menu: "Información" info_menu: "Información"
stats_menu: "Estadísticas de participación" stats_menu: "Estadísticas de participación"
results_menu: "Resultados de la votación"
stats: stats:
title: "Datos de participación" title: "Datos de participación"
total_participation: "Participación total" total_participation: "Participación total"
@@ -512,6 +513,9 @@ es:
valid: "Válidos" valid: "Válidos"
white: "En blanco" white: "En blanco"
null_votes: "Nulos" null_votes: "Nulos"
results:
title: "Preguntas"
most_voted_answer: "Respuesta más votada: "
poll_questions: poll_questions:
create_question: "Crear pregunta para votación" create_question: "Crear pregunta para votación"
show: show:

View File

@@ -113,6 +113,10 @@ Rails.application.routes.draw do
end end
resources :polls, only: [:show, :index] do resources :polls, only: [:show, :index] do
member do
get :stats
get :results
end
resources :questions, controller: 'polls/questions', shallow: true do resources :questions, controller: 'polls/questions', shallow: true do
post :answer, on: :member post :answer, on: :member
end end
@@ -273,10 +277,12 @@ Rails.application.routes.draw do
scope module: :poll do scope module: :poll do
resources :polls do resources :polls do
get :booth_assignments, on: :collection
patch :add_question, on: :member patch :add_question, on: :member
resources :booth_assignments, only: [:index, :show, :create, :destroy] do resources :booth_assignments, only: [:index, :show, :create, :destroy] do
get :search_booths, on: :collection get :search_booths, on: :collection
get :manage, on: :collection
end end
resources :officer_assignments, only: [:index, :create, :destroy] do resources :officer_assignments, only: [:index, :create, :destroy] do

View File

@@ -96,6 +96,11 @@ poll_officer = create_user('poll_officer@consul.dev', 'Paul O. Fisher')
poll_officer.create_poll_officer poll_officer.create_poll_officer
poll_officer.update(residence_verified_at: Time.current, confirmed_phone: Faker::PhoneNumber.phone_number, document_type: "1", verified_at: Time.current, document_number: "2211111111") poll_officer.update(residence_verified_at: Time.current, confirmed_phone: Faker::PhoneNumber.phone_number, document_type: "1", verified_at: Time.current, document_number: "2211111111")
poll_officer2 = create_user('poll_officer2@consul.dev', 'Pauline M. Espinosa')
poll_officer2.create_poll_officer
poll_officer2.update(residence_verified_at: Time.current, confirmed_phone: Faker::PhoneNumber.phone_number, document_type: "1", verified_at: Time.current, document_number: "3311111111")
create_user('unverified@consul.dev', 'unverified') create_user('unverified@consul.dev', 'unverified')
level_2 = create_user('leveltwo@consul.dev', 'level 2') level_2 = create_user('leveltwo@consul.dev', 'level 2')
@@ -523,40 +528,53 @@ print "Creating polls"
puts " ✅" puts " ✅"
print "Active Polls" print "Active Polls"
(1..3).each do |i| poll_active = Poll.create(name: "Active Poll",
poll = Poll.create(name: "Active Poll #{i}", slug: "active-poll",
# slug: "active-poll-#{i}",
starts_at: 1.month.ago, starts_at: 1.month.ago,
ends_at: 1.month.from_now, ends_at: 1.month.from_now,
geozone_restricted: false) geozone_restricted: false)
end
(1..5).each do |i| poll_active_geolocalized = Poll.create(name: "Active Poll Restricted",
poll = Poll.create(name: "Active Poll #{i}", slug: "active-poll-restricted",
# slug: "active-poll-#{i}",
starts_at: 1.month.ago, starts_at: 1.month.ago,
ends_at: 1.month.from_now, ends_at: 1.month.from_now,
geozone_restricted: true, geozone_restricted: true,
geozones: Geozone.reorder("RANDOM()").limit(3)) geozones: Geozone.reorder("RANDOM()").limit(3))
end
puts " ✅" puts " ✅"
print "Upcoming Poll" print "Upcoming Poll"
poll = Poll.create(name: "Upcoming Poll", poll = Poll.create(name: "Upcoming Poll",
# slug: "upcoming-poll", slug: "upcoming-poll",
starts_at: 1.month.from_now, starts_at: 1.month.from_now,
ends_at: 2.months.from_now) ends_at: 2.months.from_now)
puts " ✅"
print "Recounting Poll"
poll = Poll.create(name: "Recounting Poll",
# slug: "recounting-poll",
starts_at: 1.months.ago,
ends_at: 5.days.ago)
puts " ✅" puts " ✅"
print "Expired Poll" print "Expired Poll"
poll = Poll.create(name: "Expired Poll", poll_expired = Poll.create(name: "Expired Poll",
# slug: "expired-poll", slug: "expired-poll",
starts_at: 2.months.ago, starts_at: 2.months.ago,
ends_at: 1.month.ago) ends_at: 1.month.ago)
puts " ✅"
print "Expired Poll with Stats & Results"
poll = Poll.create(name: "Expired Poll with Stats & Results",
# slug: "expired-poll-with-stats-and-results",
starts_at: 2.months.ago,
ends_at: 1.month.ago,
results_enabled: true,
stats_enabled: true)
puts " ✅" puts " ✅"
print "Creating Poll Questions" print "Creating Poll Questions"
50.times do 25.times do
poll = Poll.reorder("RANDOM()").first poll = Poll.reorder("RANDOM()").first
author = User.reorder("RANDOM()").first author = User.reorder("RANDOM()").first
description = "<p>#{Faker::Lorem.paragraphs.join('</p><p>')}</p>" description = "<p>#{Faker::Lorem.paragraphs.join('</p><p>')}</p>"
@@ -571,7 +589,7 @@ end
puts " ✅" puts " ✅"
print "Creating Poll Booths" print "Creating Poll Booths"
30.times.each_with_index do |i| 20.times.each_with_index do |i|
Poll::Booth.create(name: "Booth #{i}", polls: [Poll.all.sample]) Poll::Booth.create(name: "Booth #{i}", polls: [Poll.all.sample])
end end
@@ -591,6 +609,24 @@ print "Creating Poll Officer Assignments"
end end
end end
puts " ✅"
print "Creating Poll Shifts for Poll Officers"
Poll::BoothAssignment.all.each do |booth_assignment|
Poll::Shift.create(booth_id: booth_assignment.booth_id,
officer_id: poll_officer.poll_officer.id,
date: Date.current,
officer_name: poll_officer.poll_officer.name,
officer_email: poll_officer.poll_officer.email,
task: 0)
Poll::Shift.create(booth_id: booth_assignment.booth_id,
officer_id: poll_officer.poll_officer.id,
date: Date.current,
officer_name: poll_officer.poll_officer.name,
officer_email: poll_officer.poll_officer.email,
task: 1)
end
puts " ✅" puts " ✅"
print "Creating Poll Questions from Proposals" print "Creating Poll Questions from Proposals"
@@ -634,10 +670,46 @@ end
puts " ✅" puts " ✅"
print "Creating Poll Voters" print "Creating Poll Voters"
puts " ✅"
print "For Active Poll"
10.times do 10.times do
poll = Poll.all.sample
user = User.level_two_verified.sample user = User.level_two_verified.sample
Poll::Voter.create(poll: poll, user: user) Poll::Voter.create(poll_id: poll_active.id, user_id: user.id, document_number: user.document_number, origin: 'web')
user = User.level_two_verified.sample
Poll::Voter.create(poll_id: poll_active.id, user_id: user.id, document_number: user.document_number, origin: 'booth')
end
puts " ✅"
print "For Active Geolocalized Poll"
10.times do
user = User.level_two_verified.sample
Poll::Voter.create(poll_id: poll_active_geolocalized.id, user_id: user.id, document_number: user.document_number, origin: 'web')
user = User.level_two_verified.sample
Poll::Voter.create(poll_id: poll_active_geolocalized.id, user_id: user.id, document_number: user.document_number, origin: 'booth')
end
puts " ✅"
print "For Expired Poll"
10.times do
user = User.level_two_verified.sample
Poll::Voter.create(poll_id: poll_expired.id, user_id: user.id, document_number: user.document_number, origin: 'web')
user = User.level_two_verified.sample
Poll::Voter.create(poll_id: poll_expired.id, user_id: user.id, document_number: user.document_number, origin: 'web')
end
puts " ✅"
print "Creating Poll Answers"
Poll::Voter.all.each do |voter|
voter.poll.questions.each do |question|
answer = question.question_answers.sample
unless answer.nil?
Poll::Answer.create(question_id: question.id, author_id: voter.user_id, answer: answer.title)
end
end
end end
puts " ✅" puts " ✅"

View File

@@ -0,0 +1,5 @@
class AddMostVotedToPollQuestionAnswer < ActiveRecord::Migration
def change
add_column :poll_question_answers, :most_voted, :boolean, default: false
end
end

View File

@@ -0,0 +1,6 @@
class AddResultsAndStatsToPolls < ActiveRecord::Migration
def change
add_column :polls, :results_enabled, :boolean, default: false
add_column :polls, :stats_enabled, :boolean, default: false
end
end

View File

@@ -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: 20171017221546) do ActiveRecord::Schema.define(version: 20171020163240) 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"
@@ -666,6 +666,7 @@ ActiveRecord::Schema.define(version: 20171017221546) do
t.text "description" t.text "description"
t.integer "question_id" t.integer "question_id"
t.integer "given_order", default: 1 t.integer "given_order", default: 1
t.boolean "most_voted", default: false
end end
add_index "poll_question_answers", ["question_id"], name: "index_poll_question_answers_on_question_id", using: :btree add_index "poll_question_answers", ["question_id"], name: "index_poll_question_answers_on_question_id", using: :btree
@@ -759,6 +760,8 @@ ActiveRecord::Schema.define(version: 20171017221546) do
t.integer "comments_count", default: 0 t.integer "comments_count", default: 0
t.integer "author_id" t.integer "author_id"
t.datetime "hidden_at" t.datetime "hidden_at"
t.boolean "results_enabled", default: false
t.boolean "stats_enabled", default: false
end end
add_index "polls", ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at", using: :btree add_index "polls", ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at", using: :btree

View File

@@ -16,7 +16,7 @@ feature 'Admin administrators' do
end end
scenario 'Create Administrator', :js do scenario 'Create Administrator', :js do
fill_in 'email', with: @user.email fill_in 'name_or_email', with: @user.email
click_button 'Search' click_button 'Search'
expect(page).to have_content @user.name expect(page).to have_content @user.name
@@ -41,5 +41,53 @@ feature 'Admin administrators' do
expect(page).to have_content I18n.t("admin.administrators.administrator.restricted_removal") expect(page).to have_content I18n.t("admin.administrators.administrator.restricted_removal")
end end
end end
context 'Search' do
background do
user = create(:user, username: 'Bernard Sumner', email: 'bernard@sumner.com')
user2 = create(:user, username: 'Tony Soprano', email: 'tony@soprano.com')
@administrator1 = create(:administrator, user: user)
@administrator2 = create(:administrator, user: user2)
visit admin_administrators_path
end end
scenario 'returns no results if search term is empty' do
expect(page).to have_content(@administrator1.name)
expect(page).to have_content(@administrator2.name)
fill_in 'name_or_email', with: ' '
click_button 'Search'
expect(page).to have_content('Administrators: User search')
expect(page).to have_content('users cannot be found')
expect(page).to_not have_content(@administrator1.name)
expect(page).to_not have_content(@administrator2.name)
end
scenario 'search by name' do
expect(page).to have_content(@administrator1.name)
expect(page).to have_content(@administrator2.name)
fill_in 'name_or_email', with: 'Sumn'
click_button 'Search'
expect(page).to have_content('Administrators: User search')
expect(page).to have_content(@administrator1.name)
expect(page).to_not have_content(@administrator2.name)
end
scenario 'search by email' do
expect(page).to have_content(@administrator1.email)
expect(page).to have_content(@administrator2.email)
fill_in 'name_or_email', with: @administrator2.email
click_button 'Search'
expect(page).to have_content('Administrators: User search')
expect(page).to have_content(@administrator2.email)
expect(page).to_not have_content(@administrator1.email)
end
end
end

View File

@@ -16,7 +16,7 @@ feature 'Admin managers' do
end end
scenario 'Create Manager', :js do scenario 'Create Manager', :js do
fill_in 'email', with: @user.email fill_in 'name_or_email', with: @user.email
click_button 'Search' click_button 'Search'
expect(page).to have_content @user.name expect(page).to have_content @user.name
@@ -34,4 +34,52 @@ feature 'Admin managers' do
end end
end end
context 'Search' do
background do
user = create(:user, username: 'Taylor Swift', email: 'taylor@swift.com')
user2 = create(:user, username: 'Stephanie Corneliussen', email: 'steph@mrrobot.com')
@manager1 = create(:manager, user: user)
@manager2 = create(:manager, user: user2)
visit admin_managers_path
end
scenario 'returns no results if search term is empty' do
expect(page).to have_content(@manager1.name)
expect(page).to have_content(@manager2.name)
fill_in 'name_or_email', with: ' '
click_button 'Search'
expect(page).to have_content('Managers: User search')
expect(page).to have_content('users cannot be found')
expect(page).to_not have_content(@manager1.name)
expect(page).to_not have_content(@manager2.name)
end
scenario 'search by name' do
expect(page).to have_content(@manager1.name)
expect(page).to have_content(@manager2.name)
fill_in 'name_or_email', with: 'Taylor'
click_button 'Search'
expect(page).to have_content('Managers: User search')
expect(page).to have_content(@manager1.name)
expect(page).to_not have_content(@manager2.name)
end
scenario 'search by email' do
expect(page).to have_content(@manager1.email)
expect(page).to have_content(@manager2.email)
fill_in 'name_or_email', with: @manager2.email
click_button 'Search'
expect(page).to have_content('Managers: User search')
expect(page).to have_content(@manager2.email)
expect(page).to_not have_content(@manager1.email)
end
end
end end

View File

@@ -16,7 +16,7 @@ feature 'Admin moderators' do
end end
scenario 'Create Moderator', :js do scenario 'Create Moderator', :js do
fill_in 'email', with: @user.email fill_in 'name_or_email', with: @user.email
click_button 'Search' click_button 'Search'
expect(page).to have_content @user.name expect(page).to have_content @user.name
@@ -33,5 +33,53 @@ feature 'Admin moderators' do
expect(page).to_not have_content @moderator.name expect(page).to_not have_content @moderator.name
end end
end end
context 'Search' do
background do
user = create(:user, username: 'Elizabeth Bathory', email: 'elizabeth@bathory.com')
user2 = create(:user, username: 'Ada Lovelace', email: 'ada@lovelace.com')
@moderator1 = create(:moderator, user: user)
@moderator2 = create(:moderator, user: user2)
visit admin_moderators_path
end end
scenario 'returns no results if search term is empty' do
expect(page).to have_content(@moderator1.name)
expect(page).to have_content(@moderator2.name)
fill_in 'name_or_email', with: ' '
click_button 'Search'
expect(page).to have_content('Moderators: User search')
expect(page).to have_content('users cannot be found')
expect(page).to_not have_content(@moderator1.name)
expect(page).to_not have_content(@moderator2.name)
end
scenario 'search by name' do
expect(page).to have_content(@moderator1.name)
expect(page).to have_content(@moderator2.name)
fill_in 'name_or_email', with: 'Eliz'
click_button 'Search'
expect(page).to have_content('Moderators: User search')
expect(page).to have_content(@moderator1.name)
expect(page).to_not have_content(@moderator2.name)
end
scenario 'search by email' do
expect(page).to have_content(@moderator1.email)
expect(page).to have_content(@moderator2.email)
fill_in 'name_or_email', with: @moderator2.email
click_button 'Search'
expect(page).to have_content('Moderators: User search')
expect(page).to have_content(@moderator2.email)
expect(page).to_not have_content(@moderator1.email)
end
end
end

View File

@@ -7,55 +7,31 @@ feature 'Admin booths assignments' do
login_as(admin.user) login_as(admin.user)
end end
scenario 'Assign booth to poll', :js do feature 'Admin Booth Assignment management' do
poll = create(:poll)
booth = create(:poll_booth)
visit admin_poll_path(poll) let!(:poll) { create(:poll) }
within('#poll-resources') do let!(:booth) { create(:poll_booth) }
click_link 'Booths (0)'
scenario 'List Polls and Booths to manage', :js do
second_poll = create(:poll)
second_booth = create(:poll_booth)
visit booth_assignments_admin_polls_path
expect(page).to have_content(poll.name)
expect(page).to have_content(second_poll.name)
within("#poll_#{second_poll.id}") do
click_link 'Manage assignments'
end end
expect(page).to have_content 'There are no booths assigned to this poll.' expect(page).to have_content "Assignments for poll '#{second_poll.name}'"
fill_in 'search-booths', with: booth.name
click_button 'Search'
expect(page).to have_content(booth.name) expect(page).to have_content(booth.name)
expect(page).to have_content(second_booth.name)
within('#search-booths-results') do
click_link 'Assign booth'
end end
expect(page).to have_content 'Booth assigned' scenario 'Assign booth to poll', :js do
visit admin_poll_path(poll)
within('#poll-resources') do
click_link 'Booths (1)'
end
expect(page).to_not have_content 'There are no booths assigned to this poll.'
expect(page).to have_content booth.name
end
scenario 'Remove booth from poll', :js do
poll = create(:poll)
booth = create(:poll_booth)
assignment = create(:poll_booth_assignment, poll: poll, booth: booth)
visit admin_poll_path(poll)
within('#poll-resources') do
click_link 'Booths (1)'
end
expect(page).to_not have_content 'There are no booths assigned to this poll.'
expect(page).to have_content booth.name
within("#poll_booth_assignment_#{assignment.id}") do
click_link 'Remove booth from poll'
end
expect(page).to have_content 'Booth not assigned anymore'
visit admin_poll_path(poll) visit admin_poll_path(poll)
within('#poll-resources') do within('#poll-resources') do
click_link 'Booths (0)' click_link 'Booths (0)'
@@ -63,10 +39,77 @@ feature 'Admin booths assignments' do
expect(page).to have_content 'There are no booths assigned to this poll.' expect(page).to have_content 'There are no booths assigned to this poll.'
expect(page).to_not have_content booth.name expect(page).to_not have_content booth.name
fill_in 'search-booths', with: booth.name
click_button 'Search'
expect(page).to have_content(booth.name)
visit manage_admin_poll_booth_assignments_path(poll)
expect(page).to have_content "Assignments for poll '#{poll.name}'"
within("#poll_booth_#{booth.id}") do
expect(page).to have_content(booth.name)
expect(page).to have_content "Unassigned"
click_link 'Assign booth'
expect(page).not_to have_content "Unassigned"
expect(page).to have_content "Assigned"
expect(page).to have_link "Unassign booth"
end
visit admin_poll_path(poll)
within('#poll-resources') do
click_link 'Booths (1)'
end
expect(page).to_not have_content 'There are no booths assigned to this poll.'
expect(page).to have_content booth.name
end
scenario 'Unassign booth from poll', :js do
assignment = create(:poll_booth_assignment, poll: poll, booth: booth)
visit admin_poll_path(poll)
within('#poll-resources') do
click_link 'Booths (1)'
end
expect(page).not_to have_content 'There are no booths assigned to this poll.'
expect(page).to have_content booth.name
fill_in 'search-booths', with: booth.name
click_button 'Search'
expect(page).to have_content(booth.name)
visit manage_admin_poll_booth_assignments_path(poll)
expect(page).to have_content "Assignments for poll '#{poll.name}'"
within("#poll_booth_#{booth.id}") do
expect(page).to have_content(booth.name)
expect(page).to have_content "Assigned"
click_link 'Unassign booth'
expect(page).to have_content "Unassigned"
expect(page).not_to have_content "Assigned"
expect(page).to have_link "Assign booth"
end
visit admin_poll_path(poll)
within('#poll-resources') do
click_link 'Booths (0)'
end
expect(page).to have_content 'There are no booths assigned to this poll.'
expect(page).not_to have_content booth.name
end
end end
feature 'Show' do feature 'Show' do
scenario 'Lists all assigned poll oficers' do scenario 'Lists all assigned poll officers' do
poll = create(:poll) poll = create(:poll)
booth = create(:poll_booth) booth = create(:poll_booth)
booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth) booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth)

View File

@@ -60,6 +60,10 @@ feature 'Admin polls' do
fill_in 'poll_ends_at', with: end_date.strftime("%d/%m/%Y") fill_in 'poll_ends_at', with: end_date.strftime("%d/%m/%Y")
fill_in 'poll_summary', with: "Upcoming poll's summary. This poll..." fill_in 'poll_summary', with: "Upcoming poll's summary. This poll..."
fill_in 'poll_description', with: "Upcomming poll's description. This poll..." fill_in 'poll_description', with: "Upcomming poll's description. This poll..."
expect(page).to_not have_css("#poll_results_enabled")
expect(page).to_not have_css("#poll_stats_enabled")
click_button "Create poll" click_button "Create poll"
expect(page).to have_content "Poll created successfully" expect(page).to have_content "Poll created successfully"
@@ -79,14 +83,25 @@ feature 'Admin polls' do
expect(page).to have_css("img[alt='#{poll.image.title}']") expect(page).to have_css("img[alt='#{poll.image.title}']")
expect(page).to have_css("#poll_results_enabled")
expect(page).to have_css("#poll_stats_enabled")
fill_in "poll_name", with: "Next Poll" fill_in "poll_name", with: "Next Poll"
fill_in 'poll_ends_at', with: end_date.strftime("%d/%m/%Y") fill_in 'poll_ends_at', with: end_date.strftime("%d/%m/%Y")
check 'poll_results_enabled'
check 'poll_stats_enabled'
click_button "Update poll" click_button "Update poll"
expect(page).to have_content "Poll updated successfully" expect(page).to have_content "Poll updated successfully"
expect(page).to have_content "Next Poll" expect(page).to have_content "Next Poll"
expect(page).to have_content I18n.l(end_date.to_date) expect(page).to have_content I18n.l(end_date.to_date)
click_link "Edit poll"
expect(page).to have_field('poll_results_enabled', checked: true)
expect(page).to have_field('poll_stats_enabled', checked: true)
end end
scenario 'Edit from index' do scenario 'Edit from index' do

View File

@@ -10,24 +10,71 @@ feature 'Admin valuators' do
end end
scenario 'Index' do scenario 'Index' do
expect(page).to have_content @valuator.name expect(page).to have_content(@valuator.name)
expect(page).to have_content @valuator.email expect(page).to have_content(@valuator.email)
expect(page).to_not have_content @user.name expect(page).to_not have_content(@user.name)
end end
scenario 'Create Valuator', :js do scenario 'Create Valuator', :js do
fill_in 'email', with: @user.email fill_in 'name_or_email', with: @user.email
click_button 'Search' click_button 'Search'
expect(page).to have_content @user.name expect(page).to have_content(@user.name)
fill_in 'valuator_description', with: 'environmental expert' fill_in 'valuator_description', with: 'environmental expert'
click_button 'Add to valuators' click_button 'Add to valuators'
within("#valuators") do within('#valuators') do
expect(page).to have_content @user.name expect(page).to have_content(@user.name)
expect(page).to have_content 'environmental expert' expect(page).to have_content('environmental expert')
end
end
context 'Search' do
background do
user = create(:user, username: 'David Foster Wallace', email: 'david@wallace.com')
user2 = create(:user, username: 'Steven Erikson', email: 'steven@erikson.com')
@valuator1 = create(:valuator, user: user)
@valuator2 = create(:valuator, user: user2)
visit admin_valuators_path
end
scenario 'returns no results if search term is empty' do
expect(page).to have_content(@valuator1.name)
expect(page).to have_content(@valuator2.name)
fill_in 'name_or_email', with: ' '
click_button 'Search'
expect(page).to have_content('Valuators: User search')
expect(page).to have_content('users cannot be found')
expect(page).to_not have_content(@valuator1.name)
expect(page).to_not have_content(@valuator2.name)
end
scenario 'search by name' do
expect(page).to have_content(@valuator1.name)
expect(page).to have_content(@valuator2.name)
fill_in 'name_or_email', with: 'Foster'
click_button 'Search'
expect(page).to have_content('Valuators: User search')
expect(page).to have_content(@valuator1.name)
expect(page).to_not have_content(@valuator2.name)
end
scenario 'search by email' do
expect(page).to have_content(@valuator1.email)
expect(page).to have_content(@valuator2.email)
fill_in 'name_or_email', with: @valuator2.email
click_button 'Search'
expect(page).to have_content('Valuators: User search')
expect(page).to have_content(@valuator2.email)
expect(page).to_not have_content(@valuator1.email)
end end
end end
end end

View File

@@ -14,6 +14,12 @@ feature "Notifications" do
let(:legislation_question) { create(:legislation_question, process: process, author: administrator) } let(:legislation_question) { create(:legislation_question, process: process, author: administrator) }
let(:legislation_annotation) { create(:legislation_annotation, author: author) } let(:legislation_annotation) { create(:legislation_annotation, author: author) }
let(:topic) {
proposal = create(:proposal)
community = proposal.community
create(:topic, community: community, author: author)
}
scenario "User commented on my debate", :js do scenario "User commented on my debate", :js do
create(:notification, notifiable: debate, user: author) create(:notification, notifiable: debate, user: author)
login_as author login_as author
@@ -40,6 +46,19 @@ feature "Notifications" do
expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']" expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']"
end end
scenario "User commented on my topic", :js do
create(:notification, notifiable: topic, user: author)
login_as author
visit root_path
find(".icon-notification").click
expect(page).to have_css ".notification", count: 1
expect(page).to have_content "Someone commented on"
expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']"
end
scenario "Multiple comments on my proposal", :js do scenario "Multiple comments on my proposal", :js do
login_as user login_as user
visit proposal_path proposal visit proposal_path proposal

View File

@@ -55,7 +55,22 @@ feature 'Poll Officing' do
expect(page).to have_content "You do not have permission to access this page" expect(page).to have_content "You do not have permission to access this page"
end end
scenario 'Access as an poll officer is authorized' do scenario 'Access as an administrator is not authorized' do
create(:administrator, user: user)
create(:poll)
login_as(user)
visit root_path
expect(page).to_not have_link("Polling officers")
visit officing_root_path
expect(current_path).not_to eq(officing_root_path)
expect(current_path).to eq(root_path)
expect(page).to have_content "You do not have permission to access this page"
end
scenario 'Access as an administrator with poll officer role is authorized' do
create(:administrator, user: user)
create(:poll_officer, user: user) create(:poll_officer, user: user)
create(:poll) create(:poll)
login_as(user) login_as(user)
@@ -68,8 +83,8 @@ feature 'Poll Officing' do
expect(page).to_not have_content "You do not have permission to access this page" expect(page).to_not have_content "You do not have permission to access this page"
end end
scenario 'Access as an administrator is authorized' do scenario 'Access as an poll officer is authorized' do
create(:administrator, user: user) create(:poll_officer, user: user)
create(:poll) create(:poll)
login_as(user) login_as(user)
visit root_path visit root_path

View File

@@ -59,6 +59,22 @@ feature 'Polls' do
expect(page).to have_link('Incoming') expect(page).to have_link('Incoming')
expect(page).to_not have_link('Expired') expect(page).to_not have_link('Expired')
end end
scenario "Poll title link to stats if enabled" do
poll = create(:poll, name: "Poll with stats", stats_enabled: true)
visit polls_path
expect(page).to have_link("Poll with stats", href: stats_poll_path(poll))
end
scenario "Poll title link to results if enabled" do
poll = create(:poll, name: "Poll with results", stats_enabled: true, results_enabled: true)
visit polls_path
expect(page).to have_link("Poll with results", href: results_poll_path(poll))
end
end end
context 'Show' do context 'Show' do
@@ -369,15 +385,72 @@ feature 'Polls' do
end end
context "Results and stats" do context "Results and stats" do
scenario "See polls statistics", :js do scenario "Show poll results and stats if enabled and poll expired" do
poll = create(:poll, :expired, results_enabled: true, stats_enabled: true)
user = create(:user) user = create(:user)
poll = create(:poll, summary: "Summary", description: "Description")
login_as user login_as user
visit poll_path(poll) visit poll_path(poll)
click_link "Participation statistics" expect(page).to have_content("Poll results")
expect(page).to have_content("Participation statistics")
expect(page).to have_content("Total participation") visit results_poll_path(poll)
expect(page).to have_content("Questions")
visit stats_poll_path(poll)
expect(page).to have_content("Participation data")
end
scenario "Don't show poll results and stats if not enabled" do
poll = create(:poll, :expired, results_enabled: false, stats_enabled: false)
user = create(:user)
login_as user
visit poll_path(poll)
expect(page).to_not have_content("Poll results")
expect(page).to_not have_content("Participation statistics")
visit results_poll_path(poll)
expect(page).to have_content("You do not have permission to carry out the action 'results' on poll.")
visit stats_poll_path(poll)
expect(page).to have_content("You do not have permission to carry out the action 'stats' on poll.")
end
scenario "Don't show poll results and stats if is not expired" do
poll = create(:poll, :current, results_enabled: true, stats_enabled: true)
user = create(:user)
login_as user
visit poll_path(poll)
expect(page).to_not have_content("Poll results")
expect(page).to_not have_content("Participation statistics")
visit results_poll_path(poll)
expect(page).to have_content("You do not have permission to carry out the action 'results' on poll.")
visit stats_poll_path(poll)
expect(page).to have_content("You do not have permission to carry out the action 'stats' on poll.")
end
scenario "Show poll results and stats if user is administrator" do
poll = create(:poll, :current, results_enabled: false, stats_enabled: false)
user = create(:administrator).user
login_as user
visit poll_path(poll)
expect(page).to have_content("Poll results")
expect(page).to have_content("Participation statistics")
visit results_poll_path(poll)
expect(page).to have_content("Questions")
visit stats_poll_path(poll)
expect(page).to have_content("Participation data")
end end
end end
end end

View File

@@ -0,0 +1,55 @@
require 'rails_helper'
feature 'Poll Results' do
scenario 'List each Poll question', :js do
user1 = create(:user, :level_two)
user2 = create(:user, :level_two)
user3 = create(:user, :level_two)
poll = create(:poll, results_enabled: true)
question1 = create(:poll_question, poll: poll)
answer1 = create(:poll_question_answer, question: question1, title: 'Yes')
answer2 = create(:poll_question_answer, question: question1, title: 'No')
question2 = create(:poll_question, poll: poll)
answer3 = create(:poll_question_answer, question: question2, title: 'Blue')
answer4 = create(:poll_question_answer, question: question2, title: 'Green')
answer5 = create(:poll_question_answer, question: question2, title: 'Yellow')
login_as user1
vote_for_poll_via_web(poll, question1, 'Yes')
vote_for_poll_via_web(poll, question2, 'Blue')
expect(Poll::Voter.count).to eq(1)
logout
login_as user2
vote_for_poll_via_web(poll, question1, 'Yes')
vote_for_poll_via_web(poll, question2, 'Green')
expect(Poll::Voter.count).to eq(2)
logout
login_as user3
vote_for_poll_via_web(poll, question1, 'No')
vote_for_poll_via_web(poll, question2, 'Yellow')
expect(Poll::Voter.count).to eq(3)
logout
poll.update(ends_at: 1.day.ago)
visit results_poll_path(poll)
expect(page).to have_content(question1.title)
expect(page).to have_content(question2.title)
within("#question_#{question1.id}_results_table") do
expect(find("#answer_#{answer1.id}_result")).to have_content("2 (66.0%)")
expect(find("#answer_#{answer2.id}_result")).to have_content("1 (33.0%)")
end
within("#question_#{question2.id}_results_table") do
expect(find("#answer_#{answer3.id}_result")).to have_content("1 (33.0%)")
expect(find("#answer_#{answer4.id}_result")).to have_content("1 (33.0%)")
expect(find("#answer_#{answer5.id}_result")).to have_content("1 (33.0%)")
end
end
end

View File

@@ -95,7 +95,8 @@ feature "Voter" do
scenario "Trying to vote in web and then in booth", :js do scenario "Trying to vote in web and then in booth", :js do
login_as user login_as user
vote_for_poll_via_web(poll, question) vote_for_poll_via_web(poll, question, 'Yes')
expect(Poll::Voter.count).to eq(1)
click_link "Sign out" click_link "Sign out"
@@ -127,7 +128,8 @@ feature "Voter" do
scenario "Trying to vote in web again", :js do scenario "Trying to vote in web again", :js do
login_as user login_as user
vote_for_poll_via_web(poll, question) vote_for_poll_via_web(poll, question, 'Yes')
expect(Poll::Voter.count).to eq(1)
visit poll_path(poll) visit poll_path(poll)

View File

@@ -299,15 +299,13 @@ module CommonActions
end end
end end
def vote_for_poll_via_web(poll, question) def vote_for_poll_via_web(poll, question, answer)
visit poll_path(poll) visit poll_path(poll)
within("#poll_question_#{question.id}_answers") do within("#poll_question_#{question.id}_answers") do
click_link 'Yes' click_link "#{answer}"
expect(page).to_not have_link('Yes') expect(page).to_not have_link("#{answer}")
end end
expect(Poll::Voter.count).to eq(1)
end end
def vote_for_poll_via_booth def vote_for_poll_via_booth