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"
buttons = $(this).find(':button, :submit')
App.PreventDoubleSubmission.disable_buttons(buttons)
).on('ajax:success', ->
).on('ajax:success', (event) ->
unless event.target.id == "new_officing_voter"
buttons = $(this).find(':button, :submit')
App.PreventDoubleSubmission.reset_buttons(buttons)

View File

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

View File

@@ -8,6 +8,7 @@
// 06. Budget
// 07. Proposals successful
// 08. Polls
// 09. Polls results and stats
//
// 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
def search
@user = User.find_by(email: params[:email])
respond_to do |format|
if @user
@administrator = Administrator.find_or_initialize_by(user: @user)
format.js
else
format.js { render "user_not_found" }
end
end
@users = User.search(params[:name_or_email])
.includes(:administrator)
.page(params[:page])
.for_render
end
def create

View File

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

View File

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

View File

@@ -23,18 +23,24 @@ class Admin::Poll::BoothAssignmentsController < Admin::Poll::BaseController
end
def create
@booth_assignment = ::Poll::BoothAssignment.new(poll_id: booth_assignment_params[:poll_id],
booth_id: booth_assignment_params[:booth_id])
@poll = Poll.find(booth_assignment_params[:poll_id])
@booth = Poll::Booth.find(booth_assignment_params[:booth_id])
@booth_assignment = ::Poll::BoothAssignment.new(poll: @poll,
booth: @booth)
if @booth_assignment.save
notice = t("admin.poll_booth_assignments.flash.create")
else
notice = t("admin.poll_booth_assignments.flash.error_create")
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 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])
if @booth_assignment.destroy
@@ -42,7 +48,14 @@ class Admin::Poll::BoothAssignmentsController < Admin::Poll::BaseController
else
notice = t("admin.poll_booth_assignments.flash.error_destroy")
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
private

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,6 +7,6 @@ class Officing::BaseController < ApplicationController
skip_authorization_check
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

View File

@@ -13,6 +13,9 @@ class Polls::QuestionsController < ApplicationController
answer.touch if answer.persisted?
answer.save!
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] }
end

View File

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

View File

@@ -1,10 +1,12 @@
module ShiftsHelper
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)
end
def shift_recount_scrutiny_dates(booth, polls)
return [] if polls.blank?
dates = polls.map(&:ends_at).map(&:to_date).sort.inject([]) do |total, date|
initial_date = date < Date.current ? Date.current : date
total << (initial_date..date + Poll::RECOUNT_DURATION).to_a

View File

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

View File

@@ -56,10 +56,10 @@ module Abilities
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 [:search, :create, :index, :destroy], ::Poll::Officer
can [:create, :destroy], ::Poll::BoothAssignment
can [:create, :destroy, :manage], ::Poll::BoothAssignment
can [:create, :destroy], ::Poll::OfficerAssignment
can [:read, :create, :update], Poll::Question
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, Comment
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, :welcome], Budget
can :read, SpendingProposal
@@ -23,7 +29,6 @@ module Abilities
can [:read], Legislation::Question
can [:create], Legislation::Answer
can [:search, :comments, :read, :create, :new_comment], Legislation::Annotation
can :read_stats, Poll
end
end
end

View File

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

View File

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

View File

@@ -31,4 +31,24 @@ class Poll::Question::Answer < ActiveRecord::Base
def self.last_position(question_id)
where(question_id: question_id).maximum('given_order') || 0
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

View File

@@ -18,107 +18,125 @@ class Poll
private
def total_participants
total_participants_web + total_participants_booth
stats_cache('total_participants') { total_participants_web + total_participants_booth }
end
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
def total_participants_web_percentage
(total_participants) == 0 ? 0 : total_participants_web * 100 / total_participants
stats_cache('total_participants_web_percentage') {
(total_participants) == 0 ? 0 : total_participants_web * 100 / total_participants
}
end
def total_participants_booth
voters.where(origin: 'booth').count
stats_cache('total_participants_booth') { voters.where(origin: 'booth').count }
end
def total_participants_booth_percentage
(total_participants) == 0 ? 0 : total_participants_booth * 100 / total_participants.to_f
stats_cache('total_participants_booth_percentage') {
(total_participants) == 0 ? 0 : total_participants_booth * 100 / total_participants.to_f
}
end
def total_web_valid
voters.where(origin: 'web').count
stats_cache('total_web_valid') { voters.where(origin: 'web').count }
end
def valid_percentage_web
(total_valid_votes) == 0 ? 0 : total_web_valid * 100 / total_valid_votes.to_f
stats_cache('valid_percentage_web') {
(total_valid_votes) == 0 ? 0 : total_web_valid * 100 / total_valid_votes.to_f
}
end
def total_web_white
0
stats_cache('total_web_white') { 0 }
end
def white_percentage_web
0
stats_cache('white_percentage_web') { 0 }
end
def total_web_null
0
stats_cache('total_web_null') { 0 }
end
def null_percentage_web
0
stats_cache('null_percentage_web') { 0 }
end
def total_booth_valid
recounts.sum(:total_amount)
stats_cache('total_booth_valid') { recounts.sum(:total_amount) }
end
def valid_percentage_booth
(total_valid_votes) == 0 ? 0 : total_booth_valid * 100 / total_valid_votes.to_f
stats_cache('valid_percentage_booth') {
(total_valid_votes) == 0 ? 0 : total_booth_valid * 100 / total_valid_votes.to_f
}
end
def total_booth_white
recounts.sum(:white_amount)
stats_cache('total_booth_white') { recounts.sum(:white_amount) }
end
def white_percentage_booth
(total_white_votes) == 0 ? 0 : total_booth_white * 100 / total_white_votes.to_f
stats_cache('white_percentage_booth') {
(total_white_votes) == 0 ? 0 : total_booth_white * 100 / total_white_votes.to_f
}
end
def total_booth_null
recounts.sum(:null_amount)
stats_cache('total_booth_null') { recounts.sum(:null_amount) }
end
def null_percentage_booth
(total_null_votes == 0) ? 0 : total_booth_null * 100 / total_null_votes.to_f
stats_cache('null_percentage_booth') {
(total_null_votes == 0) ? 0 : total_booth_null * 100 / total_null_votes.to_f
}
end
def total_valid_votes
total_web_valid + total_booth_valid
stats_cache('total_valid_votes') { total_web_valid + total_booth_valid }
end
def total_valid_percentage
(total_participants) == 0 ? 0 : total_valid_votes * 100 / total_participants.to_f
stats_cache('total_valid_percentage'){
(total_participants) == 0 ? 0 : total_valid_votes * 100 / total_participants.to_f
}
end
def total_white_votes
total_web_white + total_booth_white
stats_cache('total_white_votes') { total_web_white + total_booth_white }
end
def total_white_percentage
(total_participants) == 0 ? 0 : total_white_votes * 100 / total_participants.to_f
stats_cache('total_white_percentage') {
(total_participants) == 0 ? 0 : total_white_votes * 100 / total_participants.to_f
}
end
def total_null_votes
total_web_null + total_booth_null
stats_cache('total_null_votes') { total_web_null + total_booth_null }
end
def total_null_percentage
(total_participants) == 0 ? 0 : total_null_votes * 100 / total_participants.to_f
stats_cache('total_null_percentage') {
(total_participants) == 0 ? 0 : total_null_votes * 100 / total_participants.to_f
}
end
def voters
@poll.voters
stats_cache('voters') { @poll.voters }
end
def recounts
@poll.recounts
stats_cache('recounts') { @poll.recounts }
end
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

View File

@@ -60,7 +60,8 @@
<strong><%= t("admin.menu.title_polls") %></strong>
</a>
<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 %>
</li>
@@ -79,6 +80,10 @@
<%= link_to t('admin.menu.poll_booths'), admin_booths_path %>
</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" ||
controller_name == "booths" &&
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>
<div class="small-12 medium-6">
<%= 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>
<%= render 'admin/shared/user_search', url: search_admin_administrators_path %>
<% if @administrators.any? %>
<h3 class="margin"><%= page_entries_info @administrators %></h3>
@@ -42,8 +30,8 @@
<%= link_to t('admin.administrators.administrator.add'),
{ controller: "admin/administrators", action: :create,
user_id: administrator.user_id },
method: :post,
class: "button success expanded" %>
method: :post,
class: "button success expanded" %>
<% end %>
</td>
</tr>

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>
<div class="small-12 medium-6">
<%= 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>
<%= render 'admin/shared/user_search', url: search_admin_managers_path %>
<div id="managers">
<% if @managers.any? %>
@@ -40,8 +29,12 @@
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" %>
<%= 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>

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,63 +2,51 @@
<h2 class="inline-block"><%= t("admin.moderators.index.title") %></h2>
<div class="small-12 medium-6">
<%= 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>
<%= render 'admin/shared/user_search', url: search_admin_moderators_path %>
<div id="moderators">
<% if @moderators.any? %>
<% if @moderators.any? %>
<h3 class="margin"><%= page_entries_info @moderators %></h3>
<h3><%= page_entries_info @moderators %></h3>
<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>
<% @moderators.each do |moderator| %>
<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 },
<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>
<% @moderators.each do |moderator| %>
<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>
<% end %>
</tbody>
</table>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= paginate @moderators %>
<% else %>
<div class="callout primary">
<%= t("admin.moderators.index.no_moderators") %>
</div>
<% end %>
<%= paginate @moderators %>
<% else %>
<div class="callout primary">
<%= t("admin.moderators.index.no_moderators") %>
</div>
<% end %>
</div>

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>
<th><%= t("admin.poll_booth_assignments.index.table_name") %></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>
</thead>
<tbody>
@@ -24,14 +23,6 @@
<td>
<%= booth.location %>
</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>
<% end %>
</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" %>
<div id="poll-resources">
<%= render "/admin/poll/polls/subnav" %>
<%= render "search_booths" %>
<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? %>
<div class="callout primary margin-top">
<%= t("admin.poll_booth_assignments.index.no_booths") %>
@@ -14,7 +19,6 @@
<thead>
<th><%= t("admin.poll_booth_assignments.index.table_name") %></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>
<tbody>
<% @booth_assignments.each do |booth_assignment| %>
@@ -25,13 +29,7 @@
</strong>
</td>
<td>
<%= booth_assignment.booth.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" %>
<%= booth_assignment.booth.location || t("admin.booths.index.no_location") %>
</td>
</tr>
<% 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>
<% 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="small-12 medium-4 column">
<%= 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

@@ -3,7 +3,7 @@
<fieldset class="fieldset">
<legend>
<%= t("admin.poll_shifts.new.new_shift") %>
<%= t("admin.poll_shifts.new.new_shift") %>
</legend>
<div class="small-12 medium-3 column highlight padding">
@@ -24,12 +24,12 @@
<div class="small-12 medium-3 column">
<label><%= t("admin.poll_shifts.new.date") %></label>
<%= select 'shift[date]', 'vote_collection_date',
options_for_select(shift_vote_collection_dates(@booth, @booth.polls.current_or_incoming)),
{ prompt: t("admin.poll_shifts.new.select_date"),
options_for_select(shift_vote_collection_dates(@booth, @voting_polls)),
{ prompt: @voting_polls.present? ? t("admin.poll_shifts.new.select_date") : t("admin.poll_shifts.new.no_voting_days"),
label: false },
class: 'js-shift-vote-collection-dates' %>
<%= 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"),
label: false },
class: 'js-shift-recount-scrutiny-dates',

View File

@@ -1,10 +1,12 @@
<li>
<%= link_to admin_stats_path, title: t("admin.menu.stats") do %>
<span class="icon-stats"></span>
<% end %>
</li>
<li>
<%= link_to admin_settings_path, title: t("admin.menu.settings") do %>
<span class="icon-settings"></span>
<% end %>
</li>
<% if current_user.administrator? %>
<li>
<%= link_to admin_stats_path, title: t("admin.menu.stats") do %>
<span class="icon-stats"></span>
<% end %>
</li>
<li>
<%= link_to admin_settings_path, title: t("admin.menu.settings") do %>
<span class="icon-settings"></span>
<% end %>
</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>
<div class="small-12 medium-6">
<%= 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>
<%= render 'admin/shared/user_search', url: search_admin_valuators_path %>
<% if @valuators.any? %>
<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">
<ul class="tabs" data-tabs id="polls-tabs">
<ul class="tabs" data-tabs id="polls_tabs">
<li class="tabs-title is-active">
<%= link_to "#tab-comments" do %>
<h3>

View File

@@ -19,11 +19,27 @@
<div class="dates"></div>
<% if poll.questions.count == 1 %>
<% 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) %>
<% end %>
<% 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) %>
<ul class="margin-top">
<% 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 %>
<div class="polls-show">
<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") %>
<%= render "poll_header" %>
<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? %>
<ul class="no-bullet margin-top tags">
<% @poll.geozones.each do |g| %>
<li class="inline-block"><span><%= g.name %></span></li>
<% end %>
</ul>
<% 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) && !@poll.expired? %>
<div class="callout warning">
<%= t("polls.show.already_voted_in_web") %>
</div>
<% end %>
</div>
<% end %>
<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
} %>
</aside>
<% @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="tabs-content" data-tabs-content="polls-tabs" role="tablist">
<%= render "results_subnavigation" %>
<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>
<div id="tab-stats" class="tabs-panel">
<%= render "polls/stats/show" %>
<% 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 id="tab-information" class="tabs-panel is-active">
<%= render "show" %>
</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 %>
</li>
<% end %>
<% if current_user.administrator? || current_user.poll_officer? %>
<li>
<%= link_to t("layouts.header.officing"), officing_root_path %>
</li>
<% end %>
</ul>
</li>
<% end %>
<% if current_user && current_user.poll_officer? %>
<li>
<%= link_to t("layouts.header.officing"), officing_root_path %>
</li>
<% end %>

View File

@@ -390,9 +390,7 @@ en:
add: Add
delete: Delete
search:
email_placeholder: Search user by email
search: Search
user_not_found: User not found
title: 'Managers: User search'
menu:
activity: Moderator activity
admin: Admin menu
@@ -413,6 +411,7 @@ en:
poll_officers: Poll officers
polls: Polls
poll_booths: Booths location
poll_booth_assignments: Booths Assignments
poll_shifts: Manage shifts
officials: Officials
organizations: Organisations
@@ -447,6 +446,7 @@ en:
email_placeholder: Search user by email
search: Search
user_not_found: User not found.
title: "Administrators: User search"
moderators:
index:
title: Moderators
@@ -457,9 +457,7 @@ en:
add: Add
delete: Delete
search:
email_placeholder: Search user by email
search: Search
user_not_found: User not found
title: 'Moderators: User search'
newsletters:
index:
title: Newsletters
@@ -474,12 +472,9 @@ en:
no_valuators: There are no valuators.
valuator:
description_placeholder: 'Description (optional)'
user_found: User found
add: Add to valuators
search:
email_placeholder: Search user by email
search: Search
user_not_found: User not found
title: 'Valuators: User search'
summary:
title: Valuator summary for investment projects
valuator_name: Valuator
@@ -529,6 +524,7 @@ en:
search_officer_placeholder: Search officer
search_officer_text: Search for an officer to assign a new shift
select_date: "Select day"
no_voting_days: "Los dias de votación terminaron"
select_task: "Select task"
table_shift: "Shift"
table_email: "Email"
@@ -539,6 +535,17 @@ en:
date_missing: "A date must be selected"
vote_collection: Collect Votes
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:
flash:
destroy: "Booth not assigned anymore"
@@ -562,9 +569,6 @@ en:
no_booths: "There are no booths assigned to this poll."
table_name: "Name"
table_location: "Location"
table_assignment: "Assignment"
remove_booth: "Remove booth from poll"
add_booth: "Assign booth"
polls:
index:
title: "List of polls"
@@ -575,6 +579,10 @@ en:
geozone_restricted: "Restricted to districts"
new:
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"
edit:
title: "Edit poll"
@@ -681,6 +689,7 @@ en:
add_booth: "Add booth"
name: "Name"
location: "Location"
no_location: "No Location"
new:
title: "New booth"
name: "Name"

View File

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

View File

@@ -394,6 +394,7 @@ es:
email_placeholder: Buscar usuario por email
search: Buscar
user_not_found: Usuario no encontrado.
title: "Administradores: Búsqueda de usuarios"
managers:
index:
title: Gestores
@@ -404,9 +405,7 @@ es:
add: Añadir como Gestor
delete: Borrar
search:
email_placeholder: Buscar usuario por email
search: Buscar
user_not_found: Usuario no encontrado
title: 'Gestores: Búsqueda de usuarios'
menu:
activity: Actividad de moderadores
admin: Menú de administración
@@ -427,6 +426,7 @@ es:
poll_officers: Presidentes de mesa
polls: Votaciones
poll_booths: Ubicación de urnas
poll_booth_assignments: Asignación de urnas
poll_shifts: Asignar turnos
officials: Cargos públicos
organizations: Organizaciones
@@ -457,9 +457,7 @@ es:
add: Añadir como Moderador
delete: Borrar
search:
email_placeholder: Buscar usuario por email
search: Buscar
user_not_found: Usuario no encontrado
title: 'Moderadores: Búsqueda de usuarios'
newsletters:
index:
title: Envío de newsletters
@@ -474,12 +472,9 @@ es:
no_valuators: No hay evaluadores.
valuator:
description_placeholder: "Descripción (opcional)"
user_found: Usuario encontrado
add: Añadir como evaluador
search:
email_placeholder: Buscar usuario por email
search: Buscar
user_not_found: Usuario no encontrado
title: 'Evaluadores: Búsqueda de usuarios'
summary:
title: Resumen de evaluación de propuestas de inversión
valuator_name: Evaluador
@@ -529,6 +524,7 @@ es:
search_officer_placeholder: Buscar presidentes de mesa
search_officer_text: Busca al presidente de mesa para asignar un turno
select_date: "Seleccionar día"
no_voting_days: "Voting days ended"
select_task: "Seleccionar tarea"
table_shift: "Turno"
table_email: "Email"
@@ -539,6 +535,17 @@ es:
date_missing: "Debe seleccionarse una fecha"
vote_collection: Recoger Votos
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:
flash:
destroy: "Urna desasignada"
@@ -562,9 +569,6 @@ es:
no_booths: "No hay urnas asignadas a esta votación."
table_name: "Nombre"
table_location: "Ubicación"
table_assignment: "Asignación"
remove_booth: "Desasignar urna"
add_booth: "Asignar urna"
polls:
index:
title: "Listado de votaciones"
@@ -575,6 +579,10 @@ es:
geozone_restricted: "Restringida a los distritos"
new:
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"
edit:
title: "Editar votación"
@@ -683,6 +691,7 @@ es:
add_booth: "Añadir urna"
name: "Nombre"
location: "Ubicación"
no_location: "Sin Ubicación"
new:
title: "Nueva urna"
name: "Nombre"

View File

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

View File

@@ -113,6 +113,10 @@ Rails.application.routes.draw do
end
resources :polls, only: [:show, :index] do
member do
get :stats
get :results
end
resources :questions, controller: 'polls/questions', shallow: true do
post :answer, on: :member
end
@@ -273,10 +277,12 @@ Rails.application.routes.draw do
scope module: :poll do
resources :polls do
get :booth_assignments, on: :collection
patch :add_question, on: :member
resources :booth_assignments, only: [:index, :show, :create, :destroy] do
get :search_booths, on: :collection
get :manage, on: :collection
end
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.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')
level_2 = create_user('leveltwo@consul.dev', 'level 2')
@@ -523,40 +528,53 @@ print "Creating polls"
puts ""
print "Active Polls"
(1..3).each do |i|
poll = Poll.create(name: "Active Poll #{i}",
# slug: "active-poll-#{i}",
starts_at: 1.month.ago,
ends_at: 1.month.from_now,
geozone_restricted: false)
end
(1..5).each do |i|
poll = Poll.create(name: "Active Poll #{i}",
# slug: "active-poll-#{i}",
starts_at: 1.month.ago,
ends_at: 1.month.from_now,
geozone_restricted: true,
geozones: Geozone.reorder("RANDOM()").limit(3))
end
poll_active = Poll.create(name: "Active Poll",
slug: "active-poll",
starts_at: 1.month.ago,
ends_at: 1.month.from_now,
geozone_restricted: false)
poll_active_geolocalized = Poll.create(name: "Active Poll Restricted",
slug: "active-poll-restricted",
starts_at: 1.month.ago,
ends_at: 1.month.from_now,
geozone_restricted: true,
geozones: Geozone.reorder("RANDOM()").limit(3))
puts ""
print "Upcoming Poll"
poll = Poll.create(name: "Upcoming Poll",
# slug: "upcoming-poll",
slug: "upcoming-poll",
starts_at: 1.month.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 ""
print "Expired Poll"
poll = Poll.create(name: "Expired Poll",
# slug: "expired-poll",
poll_expired = Poll.create(name: "Expired Poll",
slug: "expired-poll",
starts_at: 2.months.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 ""
print "Creating Poll Questions"
50.times do
25.times do
poll = Poll.reorder("RANDOM()").first
author = User.reorder("RANDOM()").first
description = "<p>#{Faker::Lorem.paragraphs.join('</p><p>')}</p>"
@@ -571,7 +589,7 @@ end
puts ""
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])
end
@@ -591,6 +609,24 @@ print "Creating Poll Officer Assignments"
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 ""
print "Creating Poll Questions from Proposals"
@@ -634,10 +670,46 @@ end
puts ""
print "Creating Poll Voters"
puts ""
print "For Active Poll"
10.times do
poll = Poll.all.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
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.
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
enable_extension "plpgsql"
@@ -666,6 +666,7 @@ ActiveRecord::Schema.define(version: 20171017221546) do
t.text "description"
t.integer "question_id"
t.integer "given_order", default: 1
t.boolean "most_voted", default: false
end
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 "author_id"
t.datetime "hidden_at"
t.boolean "results_enabled", default: false
t.boolean "stats_enabled", default: false
end
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
scenario 'Create Administrator', :js do
fill_in 'email', with: @user.email
fill_in 'name_or_email', with: @user.email
click_button 'Search'
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")
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
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
scenario 'Create Manager', :js do
fill_in 'email', with: @user.email
fill_in 'name_or_email', with: @user.email
click_button 'Search'
expect(page).to have_content @user.name
@@ -34,4 +34,52 @@ feature 'Admin managers' do
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

View File

@@ -16,7 +16,7 @@ feature 'Admin moderators' do
end
scenario 'Create Moderator', :js do
fill_in 'email', with: @user.email
fill_in 'name_or_email', with: @user.email
click_button 'Search'
expect(page).to have_content @user.name
@@ -33,5 +33,53 @@ feature 'Admin moderators' do
expect(page).to_not have_content @moderator.name
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
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,66 +7,109 @@ feature 'Admin booths assignments' do
login_as(admin.user)
end
scenario 'Assign booth to poll', :js do
poll = create(:poll)
booth = create(:poll_booth)
feature 'Admin Booth Assignment management' do
visit admin_poll_path(poll)
within('#poll-resources') do
click_link 'Booths (0)'
let!(:poll) { create(:poll) }
let!(:booth) { create(:poll_booth) }
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
expect(page).to have_content "Assignments for poll '#{second_poll.name}'"
expect(page).to have_content(booth.name)
expect(page).to have_content(second_booth.name)
end
expect(page).to have_content 'There are no booths assigned to this poll.'
scenario 'Assign booth to poll', :js do
visit admin_poll_path(poll)
within('#poll-resources') do
click_link 'Booths (0)'
end
fill_in 'search-booths', with: booth.name
click_button 'Search'
expect(page).to have_content(booth.name)
expect(page).to have_content 'There are no booths assigned to this poll.'
expect(page).to_not have_content booth.name
within('#search-booths-results') do
click_link 'Assign booth'
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
expect(page).to have_content 'Booth assigned'
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)'
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
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)
within('#poll-resources') do
click_link 'Booths (0)'
end
expect(page).to have_content 'There are no booths assigned to this poll.'
expect(page).to_not have_content booth.name
end
feature 'Show' do
scenario 'Lists all assigned poll oficers' do
scenario 'Lists all assigned poll officers' do
poll = create(:poll)
booth = create(:poll_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_summary', with: "Upcoming poll's summary. 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"
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("#poll_results_enabled")
expect(page).to have_css("#poll_stats_enabled")
fill_in "poll_name", with: "Next Poll"
fill_in 'poll_ends_at', with: end_date.strftime("%d/%m/%Y")
check 'poll_results_enabled'
check 'poll_stats_enabled'
click_button "Update poll"
expect(page).to have_content "Poll updated successfully"
expect(page).to have_content "Next Poll"
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
scenario 'Edit from index' do

View File

@@ -2,32 +2,79 @@ require 'rails_helper'
feature 'Admin valuators' do
background do
@admin = create(:administrator)
@user = create(:user, username: 'Jose Luis Balbin')
@admin = create(:administrator)
@user = create(:user, username: 'Jose Luis Balbin')
@valuator = create(:valuator)
login_as(@admin.user)
visit admin_valuators_path
end
scenario 'Index' do
expect(page).to have_content @valuator.name
expect(page).to have_content @valuator.email
expect(page).to_not have_content @user.name
expect(page).to have_content(@valuator.name)
expect(page).to have_content(@valuator.email)
expect(page).to_not have_content(@user.name)
end
scenario 'Create Valuator', :js do
fill_in 'email', with: @user.email
fill_in 'name_or_email', with: @user.email
click_button 'Search'
expect(page).to have_content @user.name
expect(page).to have_content(@user.name)
fill_in 'valuator_description', with: 'environmental expert'
click_button 'Add to valuators'
within("#valuators") do
expect(page).to have_content @user.name
expect(page).to have_content 'environmental expert'
within('#valuators') do
expect(page).to have_content(@user.name)
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

View File

@@ -14,6 +14,12 @@ feature "Notifications" do
let(:legislation_question) { create(:legislation_question, process: process, author: administrator) }
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
create(:notification, notifiable: debate, user: author)
login_as author
@@ -40,6 +46,19 @@ feature "Notifications" do
expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']"
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
login_as user
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"
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)
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"
end
scenario 'Access as an administrator is authorized' do
create(:administrator, user: user)
scenario 'Access as an poll officer is authorized' do
create(:poll_officer, user: user)
create(:poll)
login_as(user)
visit root_path

View File

@@ -59,6 +59,22 @@ feature 'Polls' do
expect(page).to have_link('Incoming')
expect(page).to_not have_link('Expired')
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
context 'Show' do
@@ -369,15 +385,72 @@ feature 'Polls' do
end
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)
poll = create(:poll, summary: "Summary", description: "Description")
login_as user
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

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
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"
@@ -127,7 +128,8 @@ feature "Voter" do
scenario "Trying to vote in web again", :js do
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)

View File

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