Merge branch 'master' into site-customization
This commit is contained in:
@@ -49,6 +49,7 @@
|
||||
//= require fixed_bar
|
||||
//= require banners
|
||||
//= require social_share
|
||||
//= require checkbox_toggle
|
||||
//= require custom
|
||||
|
||||
var initialize_modules = function() {
|
||||
@@ -74,6 +75,7 @@ var initialize_modules = function() {
|
||||
App.FixedBar.initialize();
|
||||
App.Banners.initialize();
|
||||
App.SocialShare.initialize();
|
||||
App.CheckboxToggle.initialize();
|
||||
};
|
||||
|
||||
$(function(){
|
||||
|
||||
12
app/assets/javascripts/checkbox_toggle.js.coffee
Normal file
12
app/assets/javascripts/checkbox_toggle.js.coffee
Normal file
@@ -0,0 +1,12 @@
|
||||
App.CheckboxToggle =
|
||||
|
||||
initialize: ->
|
||||
$('[data-checkbox-toggle]').on 'change', ->
|
||||
$this = $(this)
|
||||
$target = $($this.data('checkbox-toggle'))
|
||||
if $this.is(':checked')
|
||||
$target.show()
|
||||
else
|
||||
$target.hide()
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ $budget: #7E328A;
|
||||
$budget-hover: #7571BF;
|
||||
|
||||
$highlight: #E7F2FC;
|
||||
$light: #F5F7FA;
|
||||
$featured: #FFDC5C;
|
||||
|
||||
$footer-border: #BFC1C3;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// 03. List elements
|
||||
// 04. Stats
|
||||
// 05. Management
|
||||
// 06. Polls
|
||||
//
|
||||
|
||||
// 01. Global styles
|
||||
@@ -20,6 +21,11 @@ body.admin {
|
||||
.top-links {
|
||||
background: darken($admin-color, 15%);
|
||||
}
|
||||
|
||||
.back-web {
|
||||
padding-top: $line-height/4;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
@@ -27,19 +33,37 @@ body.admin {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.top-bar-title {
|
||||
|
||||
h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
form {
|
||||
|
||||
.button {
|
||||
margin-top: 0;
|
||||
|
||||
&.margin-top {
|
||||
margin-top: $line-height;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="text"], textarea {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.input-group input[type="text"] {
|
||||
border-radius: 0;
|
||||
margin-bottom: 0 !important;
|
||||
.fieldset {
|
||||
|
||||
select {
|
||||
height: $line-height*2;
|
||||
}
|
||||
|
||||
.input-group input[type="text"] {
|
||||
border-radius: 0;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +72,15 @@ body.admin {
|
||||
th {
|
||||
text-align: left;
|
||||
|
||||
&.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&.text-right {
|
||||
padding-right: $line-height;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&.with-button {
|
||||
line-height: $line-height*2;
|
||||
}
|
||||
@@ -62,9 +95,20 @@ body.admin {
|
||||
}
|
||||
}
|
||||
|
||||
&.fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
input[type="submit"] ~ a, a ~ a {
|
||||
margin-left: $line-height/2;
|
||||
margin-right: $line-height/2;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
margin-top: $line-height/2;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
margin-left: $line-height/2;
|
||||
margin-right: $line-height/2;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +121,11 @@ body.admin {
|
||||
color: $admin-color;
|
||||
}
|
||||
|
||||
.tabs-panel {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
#proposals {
|
||||
width: 100% !important;
|
||||
}
|
||||
@@ -148,6 +197,13 @@ body.admin {
|
||||
}
|
||||
}
|
||||
|
||||
.input-group {
|
||||
|
||||
.input-group-button {
|
||||
padding-bottom: rem-calc(16);
|
||||
}
|
||||
}
|
||||
|
||||
// 02. Sidebar
|
||||
// -----------
|
||||
|
||||
@@ -155,7 +211,7 @@ body.admin {
|
||||
border-right: 1px solid $border;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
padding-bottom: $line-height*3;
|
||||
min-height: rem-calc(1100);
|
||||
}
|
||||
|
||||
ul {
|
||||
@@ -165,10 +221,12 @@ body.admin {
|
||||
padding: 0;
|
||||
|
||||
[class^="icon-"] {
|
||||
color: $admin-color;
|
||||
display: inline-block;
|
||||
font-size: rem-calc(24);
|
||||
padding-right: rem-calc(12);
|
||||
padding-top: rem-calc(4);
|
||||
line-height: $line-height;
|
||||
padding: $line-height/2 $line-height/4;
|
||||
padding-left: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@@ -177,19 +235,26 @@ body.admin {
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
|
||||
ul {
|
||||
margin-left: $line-height/1.5;
|
||||
border-left: 1px solid $border;
|
||||
padding-left: $line-height/2;
|
||||
}
|
||||
|
||||
&.section-title {
|
||||
border-bottom: 1px solid $border;
|
||||
}
|
||||
|
||||
&.active a {
|
||||
background: #f3f6f7;
|
||||
border-radius: rem-calc(6);
|
||||
-moz-border-radius: rem-calc(6);
|
||||
-webkit-border-radius: rem-calc(6);
|
||||
color: $admin-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
li.section {
|
||||
border-bottom: 1px dotted #d5d5d5;
|
||||
border-top: 1px dotted #d5d5d5;
|
||||
height: $line-height/2;
|
||||
}
|
||||
|
||||
li a {
|
||||
color: $text;
|
||||
display: block;
|
||||
@@ -199,10 +264,38 @@ body.admin {
|
||||
|
||||
&:hover {
|
||||
background: #f3f6f7;
|
||||
border-radius: rem-calc(6);
|
||||
-moz-border-radius: rem-calc(6);
|
||||
-webkit-border-radius: rem-calc(6);
|
||||
color: $admin-color;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.is-accordion-submenu-parent {
|
||||
|
||||
& > a::after {
|
||||
border-color: $admin-color transparent transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.submenu {
|
||||
border-bottom: 0;
|
||||
margin-left: $line-height;
|
||||
|
||||
li:first-child {
|
||||
padding-top: $line-height/2;
|
||||
}
|
||||
|
||||
li:last-child {
|
||||
padding-bottom: $line-height/2;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 03. List elements
|
||||
@@ -404,10 +497,43 @@ table.investment-projects-summary {
|
||||
}
|
||||
}
|
||||
|
||||
// 05. CMS
|
||||
.geozone {
|
||||
background: #ececec;
|
||||
border-radius: rem-calc(6);
|
||||
color: $text;
|
||||
display: inline-block;
|
||||
font-size: $small-font-size;
|
||||
margin-bottom: $line-height/3;
|
||||
padding: $line-height/4 $line-height/3;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
background: #e0e0e0;
|
||||
}
|
||||
}
|
||||
|
||||
// 06. Polls
|
||||
// -----------------
|
||||
|
||||
.count-error {
|
||||
background: $alert-bg !important;
|
||||
color: $color-alert;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table {
|
||||
|
||||
.callout {
|
||||
height: $line-height*2;
|
||||
line-height: $line-height*2;
|
||||
padding: 0 $line-height/2;
|
||||
}
|
||||
}
|
||||
|
||||
// 07. CMS
|
||||
// --------------
|
||||
.cms_page_list {
|
||||
|
||||
|
||||
[class^="icon-"] {
|
||||
padding-right: $menu-icon-spacing;
|
||||
vertical-align: middle;
|
||||
|
||||
@@ -163,6 +163,12 @@
|
||||
.icon-whatsapp:before {
|
||||
content: "\50";
|
||||
}
|
||||
.icon-zip:before {
|
||||
content: "\4f";
|
||||
}
|
||||
.icon-banner:before {
|
||||
content: "\51";
|
||||
}
|
||||
.icon-arrow-down:before {
|
||||
content: "\52";
|
||||
}
|
||||
|
||||
@@ -144,6 +144,10 @@ a {
|
||||
padding-top: $line-height;
|
||||
}
|
||||
|
||||
.light {
|
||||
background: $light;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background: $highlight;
|
||||
}
|
||||
@@ -204,6 +208,30 @@ a {
|
||||
}
|
||||
}
|
||||
|
||||
.menu.vertical {
|
||||
background: white;
|
||||
margin: $line-height 0;
|
||||
padding: $line-height;
|
||||
|
||||
li {
|
||||
margin-bottom: $line-height;
|
||||
|
||||
a {
|
||||
color: $text-medium;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: $base-font-size;
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-bottom: 2px solid $brand;
|
||||
color: $brand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.small {
|
||||
font-size: $small-font-size;
|
||||
}
|
||||
@@ -462,6 +490,7 @@ header {
|
||||
|
||||
.input-group-button {
|
||||
line-height: $line-height*1.5;
|
||||
padding-bottom: 0;
|
||||
|
||||
button {
|
||||
background: $border;
|
||||
@@ -483,7 +512,6 @@ header {
|
||||
}
|
||||
|
||||
.submenu {
|
||||
background: white;
|
||||
border-bottom: 1px solid $border;
|
||||
clear: both;
|
||||
margin-bottom: $line-height/2;
|
||||
@@ -585,7 +613,8 @@ footer {
|
||||
// 04. Tags
|
||||
// --------
|
||||
|
||||
.tags a , .tag-cloud a, .categories a, .geozone a, .sidebar-links a {
|
||||
.tags a , .tag-cloud a, .categories a, .geozone a, .sidebar-links a,
|
||||
.tags span {
|
||||
background: #ececec;
|
||||
border-radius: rem-calc(6);
|
||||
color: $text;
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
// 04. List participation
|
||||
// 05. Featured
|
||||
// 06. Budget
|
||||
// 07. Proposals successfull
|
||||
// 07. Proposals successful
|
||||
// 08. Polls
|
||||
//
|
||||
|
||||
// 01. Votes and supports
|
||||
@@ -297,7 +298,8 @@
|
||||
.debate-show,
|
||||
.proposal-show,
|
||||
.investment-project-show,
|
||||
.budget-investment-show {
|
||||
.budget-investment-show,
|
||||
.polls-show {
|
||||
|
||||
p {
|
||||
word-wrap: break-word;
|
||||
@@ -769,7 +771,7 @@
|
||||
// ------------
|
||||
|
||||
.featured-debates, .featured-proposals,
|
||||
.proposals-ballot, .proposals-ballot-list {
|
||||
.enquiries-list {
|
||||
padding: $line-height/2 0;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
@@ -1206,7 +1208,7 @@ ul.ballot-list {
|
||||
}
|
||||
}
|
||||
|
||||
// 07. Proposals successfull
|
||||
// 07. Proposals successful
|
||||
// -------------------------
|
||||
|
||||
.dark-heading {
|
||||
@@ -1239,7 +1241,7 @@ ul.ballot-list {
|
||||
}
|
||||
}
|
||||
|
||||
.featured-proposals-ballot-banner {
|
||||
.featured-proposals-ballot-banner, .sucessfull-proposals-banner {
|
||||
background: #2D3E50 image-url("ballot_tiny.gif") no-repeat;
|
||||
background-position: 75% 0;
|
||||
position: relative;
|
||||
@@ -1263,10 +1265,10 @@ ul.ballot-list {
|
||||
}
|
||||
}
|
||||
|
||||
.featured-proposals-ballot-banner,
|
||||
.successfull .panel {
|
||||
.sucessfull-proposals-banner,
|
||||
.successful .panel {
|
||||
|
||||
.icon-successfull {
|
||||
.icon-successful {
|
||||
border-right: 60px solid #FFD200;
|
||||
border-top: 0;
|
||||
border-bottom: 60px solid transparent;
|
||||
@@ -1287,17 +1289,7 @@ ul.ballot-list {
|
||||
}
|
||||
}
|
||||
|
||||
.proposals-ballot-list {
|
||||
|
||||
.proposal-sucessfull {
|
||||
background: white;
|
||||
border-top: 1px solid $border;
|
||||
padding: $line-height 0;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.successfull {
|
||||
.successful {
|
||||
|
||||
.panel {
|
||||
position: relative;
|
||||
@@ -1318,3 +1310,199 @@ ul.ballot-list {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 08. Polls
|
||||
// ----------------------
|
||||
|
||||
.dark-heading {
|
||||
background: #2D3E50;
|
||||
color: white;
|
||||
|
||||
.title {
|
||||
color: #92BA48;
|
||||
}
|
||||
|
||||
.button {
|
||||
background: white;
|
||||
color: $brand;
|
||||
}
|
||||
|
||||
.callout {
|
||||
|
||||
&.warning a {
|
||||
color: $color-warning;
|
||||
}
|
||||
|
||||
&.primary a {
|
||||
color: $color-info;
|
||||
}
|
||||
|
||||
&.alert a {
|
||||
color: $color-alert;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
background: #314253;
|
||||
padding: $line-height;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
border-top: rem-calc(6) solid #92BA48;
|
||||
}
|
||||
}
|
||||
|
||||
a:not(.button) {
|
||||
color: white;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.back, .icon-angle-left {
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.polls-show-header {
|
||||
min-height: $line-height*8;
|
||||
}
|
||||
}
|
||||
|
||||
.poll, .poll-question {
|
||||
background: white;
|
||||
border-radius: rem-calc(6);
|
||||
margin-bottom: $line-height/2;
|
||||
}
|
||||
|
||||
.poll {
|
||||
padding: $line-height;
|
||||
position: relative;
|
||||
|
||||
.icon-poll-answer {
|
||||
border-top: 0;
|
||||
border-bottom: 60px solid transparent;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 0;
|
||||
|
||||
&.can-answer:after,
|
||||
&.cant-answer:after,
|
||||
&.not-logged-in:after,
|
||||
&.already-answer:after,
|
||||
&.unverified:after {
|
||||
font-family: "icons" !important;
|
||||
left: 34px;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
&.can-answer {
|
||||
border-right: 60px solid $info-bg;
|
||||
|
||||
&:after {
|
||||
color: $color-info;
|
||||
content: "\6c";
|
||||
}
|
||||
}
|
||||
|
||||
&.cant-answer {
|
||||
border-right: 60px solid $alert-bg;
|
||||
|
||||
&:after {
|
||||
color: $color-alert;
|
||||
content: "\74";
|
||||
}
|
||||
}
|
||||
|
||||
&.not-logged-in {
|
||||
border-right: 60px solid $info-bg;
|
||||
|
||||
&:after {
|
||||
color: $color-info;
|
||||
content: "\6f";
|
||||
}
|
||||
}
|
||||
|
||||
&.unverified {
|
||||
border-right: 60px solid $warning-bg;
|
||||
|
||||
&:after {
|
||||
color: $color-warning;
|
||||
content: "\6f";
|
||||
}
|
||||
}
|
||||
|
||||
&.already-answer {
|
||||
border-right: 60px solid $success-bg;
|
||||
|
||||
&:after {
|
||||
color: $color-success;
|
||||
content: "\59";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dates {
|
||||
color: $text-medium;
|
||||
font-size: $small-font-size;
|
||||
margin-bottom: $line-height/2;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: rem-calc(30);
|
||||
line-height: $line-height*1.5;
|
||||
|
||||
a {
|
||||
color: $text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h2.questions-callout {
|
||||
font-size: $base-font-size;
|
||||
}
|
||||
|
||||
h3.section-title-divider {
|
||||
border-bottom: 2px solid $brand;
|
||||
color: $brand;
|
||||
margin-bottom: $line-height;
|
||||
}
|
||||
|
||||
.poll-question {
|
||||
padding: 0 $line-height;
|
||||
|
||||
h3 {
|
||||
padding-top: $line-height;
|
||||
|
||||
a {
|
||||
color: $text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.poll-question-answers {
|
||||
|
||||
.button {
|
||||
margin-right: $line-height/4;
|
||||
min-width: rem-calc(168);
|
||||
|
||||
&.answered {
|
||||
background: #F4F8EC;
|
||||
border: 2px solid #92BA48;
|
||||
color: $text;
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
background: #92BA48;
|
||||
border-radius: rem-calc(20);
|
||||
content: "\6c";
|
||||
color: white;
|
||||
font-family: "icons" !important;
|
||||
font-size: rem-calc(12);
|
||||
padding: $line-height/4;
|
||||
position: absolute;
|
||||
right: -6px;
|
||||
top: -6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
66
app/controllers/admin/poll/booth_assignments_controller.rb
Normal file
66
app/controllers/admin/poll/booth_assignments_controller.rb
Normal file
@@ -0,0 +1,66 @@
|
||||
class Admin::Poll::BoothAssignmentsController < Admin::BaseController
|
||||
|
||||
before_action :load_poll, except: [:create, :destroy]
|
||||
|
||||
def index
|
||||
@booth_assignments = @poll.booth_assignments.includes(:booth).order('poll_booths.name').page(params[:page]).per(50)
|
||||
end
|
||||
|
||||
def search_booths
|
||||
load_search
|
||||
@booths = ::Poll::Booth.search(@search)
|
||||
respond_to do |format|
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@booth_assignment = @poll.booth_assignments.includes(:recounts, :final_recounts, :voters, officer_assignments: [officer: [:user]]).find(params[:id])
|
||||
@voters_by_date = @booth_assignment.voters.group_by {|v| v.created_at.to_date}
|
||||
end
|
||||
|
||||
def create
|
||||
@booth_assignment = ::Poll::BoothAssignment.new(poll_id: booth_assignment_params[:poll_id], booth_id: booth_assignment_params[:booth_id])
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
def destroy
|
||||
@booth_assignment = ::Poll::BoothAssignment.find(params[:id])
|
||||
|
||||
if @booth_assignment.destroy
|
||||
notice = t("admin.poll_booth_assignments.flash.destroy")
|
||||
else
|
||||
notice = t("admin.poll_booth_assignments.flash.error_destroy")
|
||||
end
|
||||
redirect_to admin_poll_booth_assignments_path(@booth_assignment.poll_id), notice: notice
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_booth_assignment
|
||||
@booth_assignment = ::Poll::BoothAssignment.find(params[:id])
|
||||
end
|
||||
|
||||
def booth_assignment_params
|
||||
params.permit(:booth_id, :poll_id)
|
||||
end
|
||||
|
||||
def load_poll
|
||||
@poll = ::Poll.find(params[:poll_id])
|
||||
end
|
||||
|
||||
def search_params
|
||||
params.permit(:poll_id, :search)
|
||||
end
|
||||
|
||||
def load_search
|
||||
@search = search_params[:search]
|
||||
end
|
||||
|
||||
end
|
||||
39
app/controllers/admin/poll/booths_controller.rb
Normal file
39
app/controllers/admin/poll/booths_controller.rb
Normal file
@@ -0,0 +1,39 @@
|
||||
class Admin::Poll::BoothsController < Admin::BaseController
|
||||
load_and_authorize_resource class: 'Poll::Booth'
|
||||
|
||||
def index
|
||||
@booths = @booths.order(name: :asc).page(params[:page])
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def new
|
||||
end
|
||||
|
||||
def create
|
||||
if @booth.save
|
||||
redirect_to admin_booths_path, notice: t("flash.actions.create.poll_booth")
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if @booth.update(booth_params)
|
||||
redirect_to admin_booth_path(@booth), notice: t("flash.actions.update.poll_booth")
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def booth_params
|
||||
params.require(:poll_booth).permit(:name, :location)
|
||||
end
|
||||
|
||||
end
|
||||
92
app/controllers/admin/poll/officer_assignments_controller.rb
Normal file
92
app/controllers/admin/poll/officer_assignments_controller.rb
Normal file
@@ -0,0 +1,92 @@
|
||||
class Admin::Poll::OfficerAssignmentsController < Admin::BaseController
|
||||
|
||||
before_action :load_poll
|
||||
before_action :redirect_if_blank_required_params, only: [:by_officer]
|
||||
before_action :load_booth_assignment, only: [:create]
|
||||
|
||||
def index
|
||||
@officers = ::Poll::Officer.
|
||||
includes(:user).
|
||||
order('users.username').
|
||||
where(
|
||||
id: @poll.officer_assignments.select(:officer_id).distinct.map(&:officer_id)
|
||||
).page(params[:page]).per(50)
|
||||
end
|
||||
|
||||
def by_officer
|
||||
@poll = ::Poll.includes(:booths).find(params[:poll_id])
|
||||
@officer = ::Poll::Officer.includes(:user).find(officer_assignment_params[:officer_id])
|
||||
@officer_assignments = ::Poll::OfficerAssignment.
|
||||
joins(:booth_assignment).
|
||||
includes(:recount, :final_recounts, booth_assignment: :booth).
|
||||
where("officer_id = ? AND poll_booth_assignments.poll_id = ?", @officer.id, @poll.id).
|
||||
order(:date)
|
||||
end
|
||||
|
||||
def search_officers
|
||||
load_search
|
||||
@officers = User.joins(:poll_officer).search(@search).order(username: :asc)
|
||||
|
||||
respond_to do |format|
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@officer_assignment = ::Poll::OfficerAssignment.new(booth_assignment: @booth_assignment,
|
||||
officer_id: create_params[:officer_id],
|
||||
date: create_params[:date])
|
||||
@officer_assignment.final = true if @officer_assignment.date > @booth_assignment.poll.ends_at.to_date
|
||||
|
||||
if @officer_assignment.save
|
||||
notice = t("admin.poll_officer_assignments.flash.create")
|
||||
else
|
||||
notice = t("admin.poll_officer_assignments.flash.error_create")
|
||||
end
|
||||
redirect_to by_officer_admin_poll_officer_assignments_path(poll_id: create_params[:poll_id], officer_id: create_params[:officer_id]), notice: notice
|
||||
end
|
||||
|
||||
def destroy
|
||||
@officer_assignment = ::Poll::OfficerAssignment.includes(:booth_assignment).find(params[:id])
|
||||
|
||||
if @officer_assignment.destroy
|
||||
notice = t("admin.poll_officer_assignments.flash.destroy")
|
||||
else
|
||||
notice = t("admin.poll_officer_assignments.flash.error_destroy")
|
||||
end
|
||||
redirect_to by_officer_admin_poll_officer_assignments_path(poll_id: @officer_assignment.poll_id, officer_id: @officer_assignment.officer_id), notice: notice
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def officer_assignment_params
|
||||
params.permit(:officer_id)
|
||||
end
|
||||
|
||||
def create_params
|
||||
params.permit(:poll_id, :booth_id, :date, :officer_id)
|
||||
end
|
||||
|
||||
def load_booth_assignment
|
||||
@booth_assignment = ::Poll::BoothAssignment.includes(:poll).find_by(poll_id: create_params[:poll_id], booth_id: create_params[:booth_id])
|
||||
end
|
||||
|
||||
def load_poll
|
||||
@poll = ::Poll.find(params[:poll_id])
|
||||
end
|
||||
|
||||
def redirect_if_blank_required_params
|
||||
if officer_assignment_params[:officer_id].blank?
|
||||
redirect_to admin_poll_path(@poll)
|
||||
end
|
||||
end
|
||||
|
||||
def search_params
|
||||
params.permit(:poll_id, :search)
|
||||
end
|
||||
|
||||
def load_search
|
||||
@search = search_params[:search]
|
||||
end
|
||||
|
||||
end
|
||||
39
app/controllers/admin/poll/officers_controller.rb
Normal file
39
app/controllers/admin/poll/officers_controller.rb
Normal file
@@ -0,0 +1,39 @@
|
||||
class Admin::Poll::OfficersController < Admin::BaseController
|
||||
load_and_authorize_resource :officer, class: "Poll::Officer", except: [:edit, :show]
|
||||
|
||||
def index
|
||||
@officers = @officers.page(params[:page])
|
||||
end
|
||||
|
||||
def search
|
||||
@user = User.find_by(email: params[:email])
|
||||
|
||||
respond_to do |format|
|
||||
if @user
|
||||
@officer = Poll::Officer.find_or_initialize_by(user: @user)
|
||||
format.js
|
||||
else
|
||||
format.js { render "user_not_found" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@officer.user_id = params[:user_id]
|
||||
@officer.save
|
||||
|
||||
redirect_to admin_officers_path
|
||||
end
|
||||
|
||||
def destroy
|
||||
@officer.destroy
|
||||
redirect_to admin_officers_path
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
end
|
||||
86
app/controllers/admin/poll/polls_controller.rb
Normal file
86
app/controllers/admin/poll/polls_controller.rb
Normal file
@@ -0,0 +1,86 @@
|
||||
class Admin::Poll::PollsController < Admin::BaseController
|
||||
load_and_authorize_resource
|
||||
|
||||
before_action :load_search, only: [:search_booths, :search_questions, :search_officers]
|
||||
before_action :load_geozones, only: [:new, :create, :edit, :update]
|
||||
|
||||
def index
|
||||
end
|
||||
|
||||
def show
|
||||
@poll = Poll.includes(:questions).
|
||||
order('poll_questions.title').
|
||||
find(params[:id])
|
||||
end
|
||||
|
||||
def new
|
||||
end
|
||||
|
||||
def create
|
||||
if @poll.save
|
||||
redirect_to [:admin, @poll], notice: t("flash.actions.create.poll")
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if @poll.update(poll_params)
|
||||
redirect_to [:admin, @poll], notice: t("flash.actions.update.poll")
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def add_question
|
||||
question = ::Poll::Question.find(params[:question_id])
|
||||
|
||||
if question.present?
|
||||
@poll.questions << question
|
||||
notice = t("admin.polls.flash.question_added")
|
||||
else
|
||||
notice = t("admin.polls.flash.error_on_question_added")
|
||||
end
|
||||
redirect_to admin_poll_path(@poll), notice: notice
|
||||
end
|
||||
|
||||
def remove_question
|
||||
question = ::Poll::Question.find(params[:question_id])
|
||||
|
||||
if @poll.questions.include? question
|
||||
@poll.questions.delete(question)
|
||||
notice = t("admin.polls.flash.question_removed")
|
||||
else
|
||||
notice = t("admin.polls.flash.error_on_question_removed")
|
||||
end
|
||||
redirect_to admin_poll_path(@poll), notice: notice
|
||||
end
|
||||
|
||||
def search_questions
|
||||
@questions = ::Poll::Question.where("poll_id IS ? OR poll_id != ?", nil, @poll.id).search({search: @search}).order(title: :asc)
|
||||
respond_to do |format|
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def load_geozones
|
||||
@geozones = Geozone.all.order(:name)
|
||||
end
|
||||
|
||||
def poll_params
|
||||
params.require(:poll).permit(:name, :starts_at, :ends_at, :geozone_restricted, geozone_ids: [])
|
||||
end
|
||||
|
||||
def search_params
|
||||
params.permit(:poll_id, :search)
|
||||
end
|
||||
|
||||
def load_search
|
||||
@search = search_params[:search]
|
||||
end
|
||||
|
||||
end
|
||||
64
app/controllers/admin/poll/questions_controller.rb
Normal file
64
app/controllers/admin/poll/questions_controller.rb
Normal file
@@ -0,0 +1,64 @@
|
||||
class Admin::Poll::QuestionsController < Admin::BaseController
|
||||
load_and_authorize_resource :poll
|
||||
load_and_authorize_resource :question, class: 'Poll::Question'
|
||||
|
||||
def index
|
||||
@polls = Poll.all
|
||||
@search = search_params[:search]
|
||||
|
||||
@questions = @questions.search(search_params).page(params[:page]).order("created_at DESC")
|
||||
|
||||
@proposals = Proposal.successful.sort_by_confidence_score
|
||||
end
|
||||
|
||||
def new
|
||||
@polls = Poll.all
|
||||
@question.valid_answers = I18n.t('poll_questions.default_valid_answers')
|
||||
proposal = Proposal.find(params[:proposal_id]) if params[:proposal_id].present?
|
||||
@question.copy_attributes_from_proposal(proposal)
|
||||
end
|
||||
|
||||
def create
|
||||
@question.author = @question.proposal.try(:author) || current_user
|
||||
|
||||
if @question.save
|
||||
redirect_to admin_question_path(@question)
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if @question.update(question_params)
|
||||
redirect_to admin_question_path(@question), notice: t("flash.actions.save_changes.notice")
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @question.destroy
|
||||
notice = "Question destroyed succesfully"
|
||||
else
|
||||
notice = t("flash.actions.destroy.error")
|
||||
end
|
||||
redirect_to admin_questions_path, notice: notice
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def question_params
|
||||
params.require(:poll_question).permit(:poll_id, :title, :question, :description, :proposal_id, :valid_answers)
|
||||
end
|
||||
|
||||
def search_params
|
||||
params.permit(:poll_id, :search)
|
||||
end
|
||||
|
||||
end
|
||||
16
app/controllers/admin/poll/recounts_controller.rb
Normal file
16
app/controllers/admin/poll/recounts_controller.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
class Admin::Poll::RecountsController < Admin::BaseController
|
||||
before_action :load_poll
|
||||
|
||||
def index
|
||||
@booth_assignments = @poll.booth_assignments.
|
||||
includes(:booth, :recounts, :final_recounts, :voters).
|
||||
order("poll_booths.name").
|
||||
page(params[:page]).per(50)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_poll
|
||||
@poll = ::Poll.find(params[:poll_id])
|
||||
end
|
||||
end
|
||||
13
app/controllers/admin/poll/results_controller.rb
Normal file
13
app/controllers/admin/poll/results_controller.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
class Admin::Poll::ResultsController < Admin::BaseController
|
||||
before_action :load_poll
|
||||
|
||||
def index
|
||||
@partial_results = @poll.partial_results
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_poll
|
||||
@poll = ::Poll.includes(:questions).find(params[:poll_id])
|
||||
end
|
||||
end
|
||||
@@ -22,7 +22,7 @@ class DebatesController < ApplicationController
|
||||
|
||||
def index_customization
|
||||
@featured_debates = @debates.featured
|
||||
@proposal_successfull_exists = Proposal.successfull.exists?
|
||||
@proposal_successfull_exists = Proposal.successful.exists?
|
||||
end
|
||||
|
||||
def show
|
||||
|
||||
12
app/controllers/officing/base_controller.rb
Normal file
12
app/controllers/officing/base_controller.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
class Officing::BaseController < ApplicationController
|
||||
layout 'admin'
|
||||
|
||||
before_action :authenticate_user!
|
||||
before_action :verify_officer
|
||||
|
||||
skip_authorization_check
|
||||
|
||||
def verify_officer
|
||||
raise CanCan::AccessDenied unless current_user.try(:poll_officer?) || current_user.try(:administrator?)
|
||||
end
|
||||
end
|
||||
6
app/controllers/officing/dashboard_controller.rb
Normal file
6
app/controllers/officing/dashboard_controller.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
class Officing::DashboardController < Officing::BaseController
|
||||
|
||||
def index
|
||||
end
|
||||
|
||||
end
|
||||
47
app/controllers/officing/final_recounts_controller.rb
Normal file
47
app/controllers/officing/final_recounts_controller.rb
Normal file
@@ -0,0 +1,47 @@
|
||||
class Officing::FinalRecountsController < Officing::BaseController
|
||||
before_action :load_poll
|
||||
before_action :load_officer_assignment, only: :create
|
||||
|
||||
def new
|
||||
@officer_assignments = ::Poll::OfficerAssignment.
|
||||
includes(:final_recounts, booth_assignment: [:booth]).
|
||||
joins(:booth_assignment).
|
||||
final.
|
||||
where(id: current_user.poll_officer.officer_assignment_ids).
|
||||
where("poll_booth_assignments.poll_id = ?", @poll.id).
|
||||
order(date: :asc)
|
||||
|
||||
@final_recounts = @officer_assignments.select {|oa| oa.final_recounts.any?}.map(&:final_recounts).flatten
|
||||
end
|
||||
|
||||
def create
|
||||
@final_recount = ::Poll::FinalRecount.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id, date: final_recount_params[:date])
|
||||
@final_recount.officer_assignment_id = @officer_assignment.id
|
||||
@final_recount.count = final_recount_params[:count]
|
||||
|
||||
if @final_recount.save
|
||||
msg = { notice: t("officing.final_recounts.flash.create") }
|
||||
else
|
||||
msg = { alert: t("officing.final_recounts.flash.error_create") }
|
||||
end
|
||||
redirect_to new_officing_poll_final_recount_path(@poll), msg
|
||||
end
|
||||
|
||||
private
|
||||
def load_poll
|
||||
@poll = Poll.expired.find(params[:poll_id])
|
||||
end
|
||||
|
||||
def load_officer_assignment
|
||||
@officer_assignment = current_user.poll_officer.
|
||||
officer_assignments.final.find_by(id: final_recount_params[:officer_assignment_id])
|
||||
if @officer_assignment.blank?
|
||||
redirect_to new_officing_poll_final_recount_path(@poll), alert: t("officing.final_recounts.flash.error_create")
|
||||
end
|
||||
end
|
||||
|
||||
def final_recount_params
|
||||
params.permit(:officer_assignment_id, :count, :date)
|
||||
end
|
||||
|
||||
end
|
||||
15
app/controllers/officing/polls_controller.rb
Normal file
15
app/controllers/officing/polls_controller.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
class Officing::PollsController < Officing::BaseController
|
||||
|
||||
def index
|
||||
@polls = current_user.poll_officer? ? current_user.poll_officer.voting_days_assigned_polls : []
|
||||
@polls = @polls.select {|poll| poll.current?(Time.current) || poll.current?(1.day.ago)}
|
||||
end
|
||||
|
||||
def final
|
||||
@polls = current_user.poll_officer? ? current_user.poll_officer.final_days_assigned_polls : []
|
||||
return unless current_user.poll_officer?
|
||||
|
||||
@polls = @polls.select {|poll| poll.ends_at > 1.week.ago && poll.expired?}
|
||||
end
|
||||
|
||||
end
|
||||
46
app/controllers/officing/recounts_controller.rb
Normal file
46
app/controllers/officing/recounts_controller.rb
Normal file
@@ -0,0 +1,46 @@
|
||||
class Officing::RecountsController < Officing::BaseController
|
||||
before_action :load_poll
|
||||
before_action :load_officer_assignment, only: :create
|
||||
|
||||
def new
|
||||
@officer_assignments = ::Poll::OfficerAssignment.
|
||||
includes(:recount, booth_assignment: :booth).
|
||||
joins(:booth_assignment).
|
||||
voting_days.
|
||||
where(id: current_user.poll_officer.officer_assignment_ids).
|
||||
where("poll_booth_assignments.poll_id = ?", @poll.id).
|
||||
order(date: :asc)
|
||||
@recounted = @officer_assignments.select {|oa| oa.recount.present?}.reverse
|
||||
end
|
||||
|
||||
def create
|
||||
@recount = ::Poll::Recount.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id, date: @officer_assignment.date)
|
||||
@recount.officer_assignment_id = @officer_assignment.id
|
||||
@recount.count = recount_params[:count]
|
||||
|
||||
if @recount.save
|
||||
msg = { notice: t("officing.recounts.flash.create") }
|
||||
else
|
||||
msg = { alert: t("officing.recounts.flash.error_create") }
|
||||
end
|
||||
redirect_to new_officing_poll_recount_path(@poll), msg
|
||||
end
|
||||
|
||||
private
|
||||
def load_poll
|
||||
@poll = Poll.find(params[:poll_id])
|
||||
end
|
||||
|
||||
def load_officer_assignment
|
||||
@officer_assignment = current_user.poll_officer.
|
||||
officer_assignments.find_by(id: recount_params[:officer_assignment_id])
|
||||
if @officer_assignment.blank?
|
||||
redirect_to new_officing_poll_recount_path(@poll), alert: t("officing.recounts.flash.error_create")
|
||||
end
|
||||
end
|
||||
|
||||
def recount_params
|
||||
params.permit(:officer_assignment_id, :count)
|
||||
end
|
||||
|
||||
end
|
||||
37
app/controllers/officing/residence_controller.rb
Normal file
37
app/controllers/officing/residence_controller.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
class Officing::ResidenceController < Officing::BaseController
|
||||
|
||||
before_action :load_officer_assignment
|
||||
before_action :validate_officer_assignment, only: :create
|
||||
|
||||
def new
|
||||
@residence = Officing::Residence.new
|
||||
end
|
||||
|
||||
def create
|
||||
@residence = Officing::Residence.new(residence_params.merge(officer: current_user.poll_officer))
|
||||
if @residence.save
|
||||
redirect_to new_officing_voter_path(id: @residence.user.id), notice: t("officing.residence.flash.create")
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def residence_params
|
||||
params.require(:residence).permit(:document_number, :document_type, :year_of_birth)
|
||||
end
|
||||
|
||||
def load_officer_assignment
|
||||
@officer_assignments = current_user.poll_officer.
|
||||
officer_assignments.
|
||||
voting_days.
|
||||
where(date: Time.current.to_date)
|
||||
end
|
||||
|
||||
def validate_officer_assignment
|
||||
if @officer_assignments.blank?
|
||||
redirect_to officing_root_path, notice: t("officing.residence.flash.not_allowed")
|
||||
end
|
||||
end
|
||||
end
|
||||
141
app/controllers/officing/results_controller.rb
Normal file
141
app/controllers/officing/results_controller.rb
Normal file
@@ -0,0 +1,141 @@
|
||||
class Officing::ResultsController < Officing::BaseController
|
||||
before_action :load_poll
|
||||
|
||||
before_action :load_officer_assignments, only: :new
|
||||
before_action :load_partial_results, only: :new
|
||||
|
||||
before_action :load_officer_assignment, only: :create
|
||||
before_action :check_booth_and_date, only: :create
|
||||
before_action :build_results, only: :create
|
||||
|
||||
def new
|
||||
end
|
||||
|
||||
def create
|
||||
@results.each { |result| result.save! }
|
||||
|
||||
notice = t("officing.results.flash.create")
|
||||
redirect_to new_officing_poll_result_path(@poll), notice: notice
|
||||
end
|
||||
|
||||
def index
|
||||
@booth_assignment = ::Poll::BoothAssignment.includes(:booth).find(index_params[:booth_assignment_id])
|
||||
if current_user.poll_officer.officer_assignments.final.
|
||||
where(booth_assignment_id: @booth_assignment.id).exists?
|
||||
|
||||
@partial_results = ::Poll::PartialResult.includes(:question).
|
||||
where(booth_assignment_id: index_params[:booth_assignment_id]).
|
||||
where(date: index_params[:date])
|
||||
@whites = ::Poll::WhiteResult.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date]).sum(:amount)
|
||||
@nulls = ::Poll::NullResult.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date]).sum(:amount)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_booth_and_date
|
||||
if @officer_assignment.blank?
|
||||
go_back_to_new(t("officing.results.flash.error_wrong_booth"))
|
||||
elsif results_params[:date].blank? ||
|
||||
Date.parse(results_params[:date]) < @poll.starts_at.to_date ||
|
||||
Date.parse(results_params[:date]) > @poll.ends_at.to_date
|
||||
go_back_to_new(t("officing.results.flash.error_wrong_date"))
|
||||
end
|
||||
end
|
||||
|
||||
def build_results
|
||||
@results = []
|
||||
|
||||
params[:questions].each_pair do |question_id, results|
|
||||
question = @poll.questions.find(question_id)
|
||||
go_back_to_new if question.blank?
|
||||
|
||||
results.each_pair do |answer_index, count|
|
||||
if count.present?
|
||||
answer = question.valid_answers[answer_index.to_i]
|
||||
go_back_to_new if question.blank?
|
||||
|
||||
partial_result = ::Poll::PartialResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
|
||||
date: results_params[:date],
|
||||
question_id: question_id,
|
||||
answer: answer)
|
||||
partial_result.officer_assignment_id = @officer_assignment.id
|
||||
partial_result.amount = count.to_i
|
||||
partial_result.author = current_user
|
||||
partial_result.origin = 'booth'
|
||||
@results << partial_result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
build_white_results
|
||||
build_null_results
|
||||
end
|
||||
|
||||
def build_white_results
|
||||
if results_params[:whites].present?
|
||||
white_result = ::Poll::WhiteResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
|
||||
date: results_params[:date])
|
||||
white_result.officer_assignment_id = @officer_assignment.id
|
||||
white_result.amount = results_params[:whites].to_i
|
||||
white_result.author = current_user
|
||||
white_result.origin = 'booth'
|
||||
@results << white_result
|
||||
end
|
||||
end
|
||||
|
||||
def build_null_results
|
||||
if results_params[:nulls].present?
|
||||
null_result = ::Poll::NullResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
|
||||
date: results_params[:date])
|
||||
null_result.officer_assignment_id = @officer_assignment.id
|
||||
null_result.amount = results_params[:nulls].to_i
|
||||
null_result.author = current_user
|
||||
null_result.origin = 'booth'
|
||||
@results << null_result
|
||||
end
|
||||
end
|
||||
|
||||
def go_back_to_new(alert = nil)
|
||||
params[:d] = results_params[:date]
|
||||
params[:oa] = results_params[:officer_assignment_id]
|
||||
flash.now[:alert] = (alert || t("officing.results.flash.error_create"))
|
||||
load_officer_assignments
|
||||
load_partial_results
|
||||
render :new
|
||||
end
|
||||
|
||||
def load_poll
|
||||
@poll = ::Poll.expired.includes(:questions).find(params[:poll_id])
|
||||
end
|
||||
|
||||
def load_officer_assignment
|
||||
@officer_assignment = current_user.poll_officer.
|
||||
officer_assignments.final.find_by(id: results_params[:officer_assignment_id])
|
||||
end
|
||||
|
||||
def load_officer_assignments
|
||||
@officer_assignments = ::Poll::OfficerAssignment.
|
||||
includes(booth_assignment: [:booth]).
|
||||
joins(:booth_assignment).
|
||||
final.
|
||||
where(id: current_user.poll_officer.officer_assignment_ids).
|
||||
where("poll_booth_assignments.poll_id = ?", @poll.id).
|
||||
order(date: :asc)
|
||||
end
|
||||
|
||||
def load_partial_results
|
||||
if @officer_assignments.present?
|
||||
@partial_results = ::Poll::PartialResult.where(officer_assignment_id: @officer_assignments.map(&:id)).order(:booth_assignment_id, :date)
|
||||
end
|
||||
end
|
||||
|
||||
def results_params
|
||||
params.permit(:officer_assignment_id, :date, :questions, :whites, :nulls)
|
||||
end
|
||||
|
||||
def index_params
|
||||
params.permit(:booth_assignment_id, :date)
|
||||
end
|
||||
|
||||
end
|
||||
25
app/controllers/officing/voters_controller.rb
Normal file
25
app/controllers/officing/voters_controller.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
class Officing::VotersController < Officing::BaseController
|
||||
respond_to :html, :js
|
||||
|
||||
def new
|
||||
@user = User.find(params[:id])
|
||||
@polls = Poll.answerable_by(@user)
|
||||
end
|
||||
|
||||
def create
|
||||
@poll = Poll.find(voter_params[:poll_id])
|
||||
@user = User.find(voter_params[:user_id])
|
||||
@voter = Poll::Voter.new(document_type: @user.document_type,
|
||||
document_number: @user.document_number,
|
||||
user: @user,
|
||||
poll: @poll)
|
||||
@voter.save!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def voter_params
|
||||
params.require(:voter).permit(:poll_id, :user_id)
|
||||
end
|
||||
|
||||
end
|
||||
27
app/controllers/polls/questions_controller.rb
Normal file
27
app/controllers/polls/questions_controller.rb
Normal file
@@ -0,0 +1,27 @@
|
||||
class Polls::QuestionsController < ApplicationController
|
||||
|
||||
load_and_authorize_resource :poll
|
||||
load_and_authorize_resource :question, class: 'Poll::Question'
|
||||
|
||||
has_orders %w{most_voted newest oldest}, only: :show
|
||||
|
||||
def show
|
||||
@commentable = @question.proposal.present? ? @question.proposal : @question
|
||||
@comment_tree = CommentTree.new(@commentable, params[:page], @current_order)
|
||||
set_comment_flags(@comment_tree.comments)
|
||||
|
||||
question_answer = @question.answers.where(author_id: current_user.try(:id)).first
|
||||
@answers_by_question_id = {@question.id => question_answer.try(:answer)}
|
||||
end
|
||||
|
||||
def answer
|
||||
answer = @question.answers.find_or_initialize_by(author: current_user)
|
||||
|
||||
answer.answer = params[:answer]
|
||||
answer.save!
|
||||
answer.record_voter_participation
|
||||
|
||||
@answers_by_question_id = {@question.id => params[:answer]}
|
||||
end
|
||||
|
||||
end
|
||||
23
app/controllers/polls_controller.rb
Normal file
23
app/controllers/polls_controller.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
class PollsController < ApplicationController
|
||||
|
||||
load_and_authorize_resource
|
||||
|
||||
has_filters %w{current expired incoming}
|
||||
|
||||
::Poll::Answer # trigger autoload
|
||||
|
||||
def index
|
||||
@polls = @polls.send(@current_filter).includes(:geozones).sort_for_list.page(params[:page])
|
||||
end
|
||||
|
||||
def show
|
||||
@questions = @poll.questions.for_render.sort_for_list
|
||||
|
||||
@answers_by_question_id = {}
|
||||
poll_answers = ::Poll::Answer.by_question(@poll.question_ids).by_author(current_user.try(:id))
|
||||
poll_answers.each do |answer|
|
||||
@answers_by_question_id[answer.question_id] = answer.answer
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,8 +0,0 @@
|
||||
class ProposalBallotsController < ApplicationController
|
||||
skip_authorization_check
|
||||
|
||||
def index
|
||||
@proposal_ballots = Proposal.successfull.sort_by_confidence_score
|
||||
end
|
||||
|
||||
end
|
||||
@@ -28,8 +28,8 @@ class ProposalsController < ApplicationController
|
||||
def index_customization
|
||||
discard_archived
|
||||
load_retired
|
||||
load_proposal_ballots
|
||||
load_featured unless @proposal_successfull_exists
|
||||
load_successful_proposals
|
||||
load_featured unless @proposal_successful_exists
|
||||
end
|
||||
|
||||
def vote
|
||||
@@ -103,8 +103,8 @@ class ProposalsController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def load_proposal_ballots
|
||||
@proposal_successfull_exists = Proposal.successfull.exists?
|
||||
def load_successful_proposals
|
||||
@proposal_successful_exists = Proposal.successful.exists?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -4,6 +4,38 @@ module AdminHelper
|
||||
render "/#{namespace}/menu"
|
||||
end
|
||||
|
||||
def namespaced_root_path
|
||||
"/#{namespace}"
|
||||
end
|
||||
|
||||
def namespaced_header_title
|
||||
t("#{namespace}.header.title")
|
||||
end
|
||||
|
||||
def menu_tags?
|
||||
["tags"].include? controller_name
|
||||
end
|
||||
|
||||
def menu_moderated_content?
|
||||
["proposals", "debates", "comments", "users"].include? controller_name
|
||||
end
|
||||
|
||||
def menu_budget?
|
||||
["spending_proposals"].include? controller_name
|
||||
end
|
||||
|
||||
def menu_polls?
|
||||
["polls", "questions", "officers", "booths", "officer_assignments", "booth_assignments", "recounts", "results"].include? controller_name
|
||||
end
|
||||
|
||||
def menu_profiles?
|
||||
["organizations", "officials", "moderators", "valuators", "managers"].include? controller_name
|
||||
end
|
||||
|
||||
def menu_banners?
|
||||
["banners"].include? controller_name
|
||||
end
|
||||
|
||||
def official_level_options
|
||||
options = [["", 0]]
|
||||
(1..5).each do |i|
|
||||
@@ -16,10 +48,14 @@ module AdminHelper
|
||||
Administrator.all.order('users.username asc').includes(:user).collect { |v| [ v.name, v.id ] }
|
||||
end
|
||||
|
||||
def admin_submit_action(resource)
|
||||
resource.persisted? ? "edit" : "new"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def namespace
|
||||
controller.class.parent.name.downcase
|
||||
controller.class.parent.name.downcase.gsub("::", "/")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -10,7 +10,7 @@ module BudgetsHelper
|
||||
|
||||
def namespaced_budget_investment_path(investment, options={})
|
||||
case namespace
|
||||
when "management::budgets"
|
||||
when "management/budgets"
|
||||
management_budget_investment_path(investment.budget, investment, options)
|
||||
else
|
||||
budget_investment_path(investment.budget, investment, options)
|
||||
@@ -19,7 +19,7 @@ module BudgetsHelper
|
||||
|
||||
def namespaced_budget_investment_vote_path(investment, options={})
|
||||
case namespace
|
||||
when "management::budgets"
|
||||
when "management/budgets"
|
||||
vote_management_budget_investment_path(investment.budget, investment, options)
|
||||
else
|
||||
vote_budget_investment_path(investment.budget, investment, options)
|
||||
|
||||
@@ -23,6 +23,8 @@ module CommentsHelper
|
||||
def commentable_path(comment)
|
||||
if comment.commentable_type == "Budget::Investment"
|
||||
budget_investment_path(comment.commentable.budget_id, comment.commentable)
|
||||
elsif comment.commentable_type == "Poll::Question"
|
||||
question_path(comment.commentable)
|
||||
else
|
||||
comment.commentable
|
||||
end
|
||||
|
||||
7
app/helpers/officers_helper.rb
Normal file
7
app/helpers/officers_helper.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
module OfficersHelper
|
||||
|
||||
def officer_label(officer)
|
||||
truncate([officer.name, officer.email].compact.join(' - '), length: 100)
|
||||
end
|
||||
|
||||
end
|
||||
36
app/helpers/officing_helper.rb
Normal file
36
app/helpers/officing_helper.rb
Normal file
@@ -0,0 +1,36 @@
|
||||
module OfficingHelper
|
||||
|
||||
def officer_assignments_select_options(officer_assignments)
|
||||
options = []
|
||||
officer_assignments.each do |oa|
|
||||
options << ["#{oa.booth_assignment.booth.name}: #{l(oa.date.to_date, format: :long)}", oa.id]
|
||||
end
|
||||
options_for_select(options)
|
||||
end
|
||||
|
||||
def booths_for_officer_select_options(officer_assignments)
|
||||
options = []
|
||||
officer_assignments.each do |oa|
|
||||
options << ["#{oa.booth_assignment.booth.name}", oa.id]
|
||||
end
|
||||
options.sort! {|x,y| x[0]<=>y[0]}
|
||||
options_for_select(options, params[:oa])
|
||||
end
|
||||
|
||||
def recount_to_compare_with_final_recount(final_recount)
|
||||
recount = final_recount.booth_assignment.recounts.select {|r| r.date == final_recount.date}.first
|
||||
recount.present? ? recount.count : "-"
|
||||
end
|
||||
|
||||
def system_recount_to_compare_with_final_recount(final_recount)
|
||||
final_recount.booth_assignment.voters.select {|v| v.created_at.to_date == final_recount.date}.size
|
||||
end
|
||||
|
||||
def answer_result_value(question_id, answer_index)
|
||||
return nil if params.blank?
|
||||
return nil if params[:questions].blank?
|
||||
return nil if params[:questions][question_id.to_s].blank?
|
||||
params[:questions][question_id.to_s][answer_index.to_s]
|
||||
end
|
||||
|
||||
end
|
||||
7
app/helpers/poll_final_recounts_helper.rb
Normal file
7
app/helpers/poll_final_recounts_helper.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
module PollFinalRecountsHelper
|
||||
|
||||
def final_recount_for_date(final_recounts, date)
|
||||
final_recounts.select {|f| f.date == date}.first
|
||||
end
|
||||
|
||||
end
|
||||
15
app/helpers/poll_recounts_helper.rb
Normal file
15
app/helpers/poll_recounts_helper.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
module PollRecountsHelper
|
||||
|
||||
def recount_for_date(recounts, date)
|
||||
recounts.select {|r| r.date == date}.first
|
||||
end
|
||||
|
||||
def booth_assignment_sum_recounts(ba)
|
||||
ba.recounts.any? ? ba.recounts.to_a.sum(&:count) : nil
|
||||
end
|
||||
|
||||
def booth_assignment_sum_final_recounts(ba)
|
||||
ba.final_recounts.any? ? ba.final_recounts.to_a.sum(&:count) :nil
|
||||
end
|
||||
|
||||
end
|
||||
49
app/helpers/polls_helper.rb
Normal file
49
app/helpers/polls_helper.rb
Normal file
@@ -0,0 +1,49 @@
|
||||
module PollsHelper
|
||||
|
||||
def poll_select_options(include_all=nil)
|
||||
options = @polls.collect {|poll|
|
||||
[poll.name, current_path_with_query_params(poll_id: poll.id)]
|
||||
}
|
||||
options << all_polls if include_all
|
||||
options_for_select(options, request.fullpath)
|
||||
end
|
||||
|
||||
def all_polls
|
||||
[I18n.t("polls.all"), admin_questions_path]
|
||||
end
|
||||
|
||||
def poll_dates(poll)
|
||||
if poll.starts_at.blank? || poll.ends_at.blank?
|
||||
I18n.t("polls.no_dates")
|
||||
else
|
||||
I18n.t("polls.dates", open_at: l(poll.starts_at.to_date), closed_at: l(poll.ends_at.to_date))
|
||||
end
|
||||
end
|
||||
|
||||
def poll_dates_select_options(poll)
|
||||
options = []
|
||||
(poll.starts_at.to_date..poll.ends_at.to_date).each do |date|
|
||||
options << [l(date, format: :long), l(date)]
|
||||
end
|
||||
options_for_select(options, params[:d])
|
||||
end
|
||||
|
||||
def poll_final_recount_option(poll)
|
||||
final_date = poll.ends_at.to_date + 1.day
|
||||
options_for_select([[I18n.t("polls.final_date"), l(final_date)]])
|
||||
end
|
||||
|
||||
def poll_booths_select_options(poll)
|
||||
options = []
|
||||
poll.booths.each do |booth|
|
||||
options << [booth_name_with_location(booth), booth.id]
|
||||
end
|
||||
options_for_select(options)
|
||||
end
|
||||
|
||||
def booth_name_with_location(booth)
|
||||
location = booth.location.blank? ? "" : " (#{booth.location})"
|
||||
booth.name + location
|
||||
end
|
||||
|
||||
end
|
||||
@@ -32,7 +32,7 @@ module Abilities
|
||||
can :mark_featured, Debate
|
||||
can :unmark_featured, Debate
|
||||
|
||||
can :comment_as_administrator, [Debate, Comment, Proposal, Budget::Investment]
|
||||
can :comment_as_administrator, [Debate, Comment, Proposal, Poll::Question, Budget::Investment]
|
||||
|
||||
can [:search, :create, :index, :destroy], ::Moderator
|
||||
can [:search, :create, :index, :summary], ::Valuator
|
||||
@@ -50,8 +50,17 @@ module Abilities
|
||||
can :create, Budget::ValuatorAssignment
|
||||
|
||||
can [:search, :edit, :update, :create, :index, :destroy], Banner
|
||||
|
||||
can [:index, :create, :edit, :update, :destroy], Geozone
|
||||
|
||||
can [:read, :create, :update, :destroy, :add_question, :remove_question, :search_booths, :search_questions, :search_officers], Poll
|
||||
can [:read, :create, :update, :destroy], Poll::Booth
|
||||
can [:search, :create, :index, :destroy], ::Poll::Officer
|
||||
can [:create, :destroy], ::Poll::BoothAssignment
|
||||
can [:create, :destroy], ::Poll::OfficerAssignment
|
||||
can [:read, :create, :update], Poll::Question
|
||||
can :destroy, Poll::Question # , comments_count: 0, votes_up: 0
|
||||
|
||||
can :manage, SiteCustomization::Page
|
||||
can :manage, SiteCustomization::Image
|
||||
can :manage, SiteCustomization::ContentBlock
|
||||
|
||||
@@ -53,6 +53,12 @@ module Abilities
|
||||
|
||||
can :create, DirectMessage
|
||||
can :show, DirectMessage, sender_id: user.id
|
||||
can :answer, Poll do |poll|
|
||||
poll.answerable_by?(user)
|
||||
end
|
||||
can :answer, Poll::Question do |question|
|
||||
question.answerable_by?(user)
|
||||
end
|
||||
end
|
||||
|
||||
can [:create, :show], ProposalNotification, proposal: { author_id: user.id }
|
||||
|
||||
@@ -6,6 +6,8 @@ module Abilities
|
||||
can [:read, :map], Debate
|
||||
can [:read, :map, :summary], Proposal
|
||||
can :read, Comment
|
||||
can :read, Poll
|
||||
can :read, Poll::Question
|
||||
can [:read, :welcome], Budget
|
||||
can :read, Budget::Investment
|
||||
can :read, SpendingProposal
|
||||
|
||||
@@ -5,7 +5,7 @@ module Abilities
|
||||
def initialize(user)
|
||||
self.merge Abilities::Moderation.new(user)
|
||||
|
||||
can :comment_as_moderator, [Debate, Comment, Proposal, Budget::Investment]
|
||||
can :comment_as_moderator, [Debate, Comment, Proposal, Budget::Investment, Poll::Question]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,7 +10,8 @@ class Comment < ActiveRecord::Base
|
||||
|
||||
validates :body, presence: true
|
||||
validates :user, presence: true
|
||||
validates_inclusion_of :commentable_type, in: ["Debate", "Proposal", "Budget::Investment"]
|
||||
|
||||
validates_inclusion_of :commentable_type, in: ["Debate", "Proposal", "Budget::Investment", "Poll::Question"]
|
||||
|
||||
validate :validate_body_length
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ module Searchable
|
||||
},
|
||||
ignoring: :accents,
|
||||
ranked_by: '(:tsearch)',
|
||||
order_within_rank: "#{self.table_name}.cached_votes_up DESC"
|
||||
order_within_rank: (self.column_names.include?('cached_votes_up') ? "#{self.table_name}.cached_votes_up DESC" : nil)
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
class FailedCensusCall < ActiveRecord::Base
|
||||
belongs_to :user, counter_cache: true
|
||||
belongs_to :poll_officer, class_name: 'Poll::Officer', counter_cache: true
|
||||
end
|
||||
|
||||
@@ -9,6 +9,10 @@ class Geozone < ActiveRecord::Base
|
||||
Geozone.pluck(:name)
|
||||
end
|
||||
|
||||
def self.city
|
||||
where(name: 'city').first
|
||||
end
|
||||
|
||||
def safe_to_destroy?
|
||||
Geozone.reflect_on_all_associations(:has_many).all? do |association|
|
||||
association.klass.where(geozone: self).empty?
|
||||
|
||||
126
app/models/officing/residence.rb
Normal file
126
app/models/officing/residence.rb
Normal file
@@ -0,0 +1,126 @@
|
||||
class Officing::Residence
|
||||
include ActiveModel::Model
|
||||
include ActiveModel::Validations::Callbacks
|
||||
|
||||
attr_accessor :user, :officer, :document_number, :document_type, :year_of_birth
|
||||
|
||||
before_validation :call_census_api
|
||||
|
||||
validates_presence_of :document_number
|
||||
validates_presence_of :document_type
|
||||
validates_presence_of :year_of_birth
|
||||
|
||||
validate :allowed_age
|
||||
validate :residence_in_madrid
|
||||
|
||||
def initialize(attrs={})
|
||||
super
|
||||
clean_document_number
|
||||
end
|
||||
|
||||
def save
|
||||
return false unless valid?
|
||||
|
||||
if user_exists?
|
||||
self.user = find_user_by_document
|
||||
self.user.update(verified_at: Time.current)
|
||||
else
|
||||
user_params = {
|
||||
document_number: document_number,
|
||||
document_type: document_type,
|
||||
geozone: self.geozone,
|
||||
date_of_birth: date_of_birth.to_datetime,
|
||||
gender: gender,
|
||||
residence_verified_at: Time.current,
|
||||
verified_at: Time.current,
|
||||
erased_at: Time.current,
|
||||
password: random_password,
|
||||
terms_of_service: '1',
|
||||
email: nil
|
||||
}
|
||||
self.user = User.create!(user_params)
|
||||
end
|
||||
end
|
||||
|
||||
def store_failed_census_call
|
||||
FailedCensusCall.create({
|
||||
user: user,
|
||||
document_number: document_number,
|
||||
document_type: document_type,
|
||||
year_of_birth: year_of_birth,
|
||||
poll_officer: officer
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
def user_exists?
|
||||
find_user_by_document.present?
|
||||
end
|
||||
|
||||
def find_user_by_document
|
||||
User.where(document_number: document_number,
|
||||
document_type: document_type).first
|
||||
end
|
||||
|
||||
def residence_in_madrid
|
||||
return if errors.any?
|
||||
|
||||
unless residency_valid?
|
||||
store_failed_census_call
|
||||
errors.add(:residence_in_madrid, false)
|
||||
end
|
||||
end
|
||||
|
||||
def allowed_age
|
||||
return if errors[:year_of_birth].any?
|
||||
return unless @census_api_response.valid?
|
||||
|
||||
unless allowed_age?
|
||||
errors.add(:year_of_birth, I18n.t('verification.residence.new.error_not_allowed_age'))
|
||||
end
|
||||
end
|
||||
|
||||
def allowed_age?
|
||||
Age.in_years(date_of_birth) >= User.minimum_required_age
|
||||
end
|
||||
|
||||
def geozone
|
||||
Geozone.where(census_code: district_code).first
|
||||
end
|
||||
|
||||
def district_code
|
||||
@census_api_response.district_code
|
||||
end
|
||||
|
||||
def gender
|
||||
@census_api_response.gender
|
||||
end
|
||||
|
||||
def date_of_birth
|
||||
@census_api_response.date_of_birth
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def call_census_api
|
||||
@census_api_response = CensusApi.new.call(document_type, document_number)
|
||||
end
|
||||
|
||||
def residency_valid?
|
||||
@census_api_response.valid? &&
|
||||
@census_api_response.date_of_birth.year.to_s == year_of_birth.to_s
|
||||
end
|
||||
|
||||
def census_year_of_birth
|
||||
@census_api_response.date_of_birth.year
|
||||
end
|
||||
|
||||
def clean_document_number
|
||||
self.document_number = self.document_number.gsub(/[^a-z0-9]+/i, "").upcase unless self.document_number.blank?
|
||||
end
|
||||
|
||||
def random_password
|
||||
(0...20).map { ('a'..'z').to_a[rand(26)] }.join
|
||||
end
|
||||
|
||||
end
|
||||
65
app/models/poll.rb
Normal file
65
app/models/poll.rb
Normal file
@@ -0,0 +1,65 @@
|
||||
class Poll < ActiveRecord::Base
|
||||
has_many :booth_assignments, class_name: "Poll::BoothAssignment"
|
||||
has_many :booths, through: :booth_assignments
|
||||
has_many :partial_results, through: :booth_assignments
|
||||
has_many :white_results, through: :booth_assignments
|
||||
has_many :null_results, through: :booth_assignments
|
||||
has_many :voters
|
||||
has_many :officer_assignments, through: :booth_assignments
|
||||
has_many :officers, through: :officer_assignments
|
||||
has_many :questions
|
||||
|
||||
has_and_belongs_to_many :geozones
|
||||
|
||||
validates :name, presence: true
|
||||
|
||||
validate :date_range
|
||||
|
||||
scope :current, -> { where('starts_at <= ? and ? <= ends_at', Time.current, Time.current) }
|
||||
scope :incoming, -> { where('? < starts_at', Time.current) }
|
||||
scope :expired, -> { where('ends_at < ?', Time.current) }
|
||||
scope :published, -> { where('published = ?', true) }
|
||||
scope :by_geozone_id, ->(geozone_id) { where(geozones: {id: geozone_id}.joins(:geozones)) }
|
||||
|
||||
scope :sort_for_list, -> { order(:geozone_restricted, :starts_at, :name) }
|
||||
|
||||
def current?(timestamp = DateTime.current)
|
||||
starts_at <= timestamp && timestamp <= ends_at
|
||||
end
|
||||
|
||||
def incoming?(timestamp = DateTime.current)
|
||||
timestamp < starts_at
|
||||
end
|
||||
|
||||
def expired?(timestamp = DateTime.current)
|
||||
ends_at < timestamp
|
||||
end
|
||||
|
||||
def answerable_by?(user)
|
||||
user.present? &&
|
||||
user.level_two_or_three_verified? &&
|
||||
current? &&
|
||||
(!geozone_restricted || geozone_ids.include?(user.geozone_id))
|
||||
end
|
||||
|
||||
def self.answerable_by(user)
|
||||
return none if user.nil? || user.unverified?
|
||||
current.joins('LEFT JOIN "geozones_polls" ON "geozones_polls"."poll_id" = "polls"."id"')
|
||||
.where('geozone_restricted = ? OR geozones_polls.geozone_id = ?', false, user.geozone_id)
|
||||
end
|
||||
|
||||
def votable_by?(user)
|
||||
!document_has_voted?(user.document_number, user.document_type)
|
||||
end
|
||||
|
||||
def document_has_voted?(document_number, document_type)
|
||||
voters.where(document_number: document_number, document_type: document_type).exists?
|
||||
end
|
||||
|
||||
def date_range
|
||||
unless starts_at.present? && ends_at.present? && starts_at <= ends_at
|
||||
errors.add(:starts_at, I18n.t('errors.messages.invalid_date_range'))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
19
app/models/poll/answer.rb
Normal file
19
app/models/poll/answer.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
class Poll::Answer < ActiveRecord::Base
|
||||
|
||||
belongs_to :question, -> { with_hidden }
|
||||
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
||||
|
||||
delegate :poll, :poll_id, to: :question
|
||||
|
||||
validates :question, presence: true
|
||||
validates :author, presence: true
|
||||
validates :answer, presence: true
|
||||
validates :answer, inclusion: {in: ->(a) { a.question.valid_answers }}
|
||||
|
||||
scope :by_author, -> (author_id) { where(author_id: author_id) }
|
||||
scope :by_question, -> (question_id) { where(question_id: question_id) }
|
||||
|
||||
def record_voter_participation
|
||||
Poll::Voter.create!(user: author, poll: poll)
|
||||
end
|
||||
end
|
||||
13
app/models/poll/booth.rb
Normal file
13
app/models/poll/booth.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
class Poll
|
||||
class Booth < ActiveRecord::Base
|
||||
has_many :booth_assignments, class_name: "Poll::BoothAssignment"
|
||||
has_many :polls, through: :booth_assignments
|
||||
|
||||
validates :name, presence: true, uniqueness: true
|
||||
|
||||
def self.search(terms)
|
||||
return Booth.none if terms.blank?
|
||||
Booth.where("name ILIKE ? OR location ILIKE ?", "%#{terms}%", "%#{terms}%")
|
||||
end
|
||||
end
|
||||
end
|
||||
15
app/models/poll/booth_assignment.rb
Normal file
15
app/models/poll/booth_assignment.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
class Poll
|
||||
class BoothAssignment < ActiveRecord::Base
|
||||
belongs_to :booth
|
||||
belongs_to :poll
|
||||
|
||||
has_many :officer_assignments, class_name: "Poll::OfficerAssignment", dependent: :destroy
|
||||
has_many :recounts, class_name: "Poll::Recount", dependent: :destroy
|
||||
has_many :final_recounts, class_name: "Poll::FinalRecount", dependent: :destroy
|
||||
has_many :officers, through: :officer_assignments
|
||||
has_many :voters
|
||||
has_many :partial_results
|
||||
has_many :white_results
|
||||
has_many :null_results
|
||||
end
|
||||
end
|
||||
19
app/models/poll/final_recount.rb
Normal file
19
app/models/poll/final_recount.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
class Poll
|
||||
class FinalRecount < ActiveRecord::Base
|
||||
belongs_to :booth_assignment, class_name: "Poll::BoothAssignment"
|
||||
belongs_to :officer_assignment, class_name: "Poll::OfficerAssignment"
|
||||
|
||||
validates :booth_assignment_id, presence: true
|
||||
validates :date, presence: true, uniqueness: {scope: :booth_assignment_id}
|
||||
validates :count, presence: true, numericality: {only_integer: true}
|
||||
|
||||
before_save :update_logs
|
||||
|
||||
def update_logs
|
||||
if self.count_changed? && self.count_was.present?
|
||||
self.count_log += ":#{self.count_was.to_s}"
|
||||
self.officer_assignment_id_log += ":#{self.officer_assignment_id_was.to_s}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
23
app/models/poll/null_result.rb
Normal file
23
app/models/poll/null_result.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
class Poll::NullResult < ActiveRecord::Base
|
||||
|
||||
VALID_ORIGINS = %w{ web booth }
|
||||
|
||||
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
||||
belongs_to :booth_assignment
|
||||
belongs_to :officer_assignment
|
||||
|
||||
validates :author, presence: true
|
||||
validates :origin, inclusion: {in: VALID_ORIGINS}
|
||||
|
||||
scope :by_author, -> (author_id) { where(author_id: author_id) }
|
||||
|
||||
before_save :update_logs
|
||||
|
||||
def update_logs
|
||||
if self.amount_changed? && self.amount_was.present?
|
||||
self.amount_log += ":#{self.amount_was.to_s}"
|
||||
self.officer_assignment_id_log += ":#{self.officer_assignment_id_was.to_s}"
|
||||
self.author_id_log += ":#{self.author_id_was.to_s}"
|
||||
end
|
||||
end
|
||||
end
|
||||
26
app/models/poll/officer.rb
Normal file
26
app/models/poll/officer.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
class Poll
|
||||
class Officer < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
has_many :officer_assignments, class_name: "Poll::OfficerAssignment"
|
||||
has_many :failed_census_calls, foreign_key: :poll_officer_id
|
||||
|
||||
validates :user_id, presence: true, uniqueness: true
|
||||
|
||||
delegate :name, :email, to: :user
|
||||
|
||||
def voting_days_assigned_polls
|
||||
officer_assignments.voting_days.includes(booth_assignment: :poll).
|
||||
map(&:booth_assignment).
|
||||
map(&:poll).uniq.compact.
|
||||
sort {|x, y| y.ends_at <=> x.ends_at}
|
||||
end
|
||||
|
||||
def final_days_assigned_polls
|
||||
officer_assignments.final.includes(booth_assignment: :poll).
|
||||
map(&:booth_assignment).
|
||||
map(&:poll).uniq.compact.
|
||||
sort {|x, y| y.ends_at <=> x.ends_at}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
25
app/models/poll/officer_assignment.rb
Normal file
25
app/models/poll/officer_assignment.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
class Poll
|
||||
class OfficerAssignment < ActiveRecord::Base
|
||||
belongs_to :officer
|
||||
belongs_to :booth_assignment
|
||||
has_one :recount
|
||||
has_many :final_recounts
|
||||
has_many :partial_results
|
||||
has_many :voters
|
||||
|
||||
validates :officer_id, presence: true
|
||||
validates :booth_assignment_id, presence: true
|
||||
validates :date, presence: true, uniqueness: { scope: [:officer_id, :booth_assignment_id] }
|
||||
|
||||
delegate :poll_id, :booth_id, to: :booth_assignment
|
||||
|
||||
scope :voting_days, -> { where(final: false) }
|
||||
scope :final, -> { where(final: true) }
|
||||
|
||||
before_create :log_user_data
|
||||
|
||||
def log_user_data
|
||||
self.user_data_log = "#{officer.user_id} - #{officer.user.name_and_email}"
|
||||
end
|
||||
end
|
||||
end
|
||||
28
app/models/poll/partial_result.rb
Normal file
28
app/models/poll/partial_result.rb
Normal file
@@ -0,0 +1,28 @@
|
||||
class Poll::PartialResult < ActiveRecord::Base
|
||||
|
||||
VALID_ORIGINS = %w{ web booth }
|
||||
|
||||
belongs_to :question, -> { with_hidden }
|
||||
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
||||
belongs_to :booth_assignment
|
||||
belongs_to :officer_assignment
|
||||
|
||||
validates :question, presence: true
|
||||
validates :author, presence: true
|
||||
validates :answer, presence: true
|
||||
validates :answer, inclusion: {in: ->(a) { a.question.valid_answers }}
|
||||
validates :origin, inclusion: {in: VALID_ORIGINS}
|
||||
|
||||
scope :by_author, -> (author_id) { where(author_id: author_id) }
|
||||
scope :by_question, -> (question_id) { where(question_id: question_id) }
|
||||
|
||||
before_save :update_logs
|
||||
|
||||
def update_logs
|
||||
if self.amount_changed? && self.amount_was.present?
|
||||
self.amount_log += ":#{self.amount_was.to_s}"
|
||||
self.officer_assignment_id_log += ":#{self.officer_assignment_id_was.to_s}"
|
||||
self.author_id_log += ":#{self.author_id_was.to_s}"
|
||||
end
|
||||
end
|
||||
end
|
||||
70
app/models/poll/question.rb
Normal file
70
app/models/poll/question.rb
Normal file
@@ -0,0 +1,70 @@
|
||||
class Poll::Question < ActiveRecord::Base
|
||||
include Measurable
|
||||
include Searchable
|
||||
|
||||
acts_as_paranoid column: :hidden_at
|
||||
include ActsAsParanoidAliases
|
||||
|
||||
belongs_to :poll
|
||||
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
||||
|
||||
has_many :comments, as: :commentable
|
||||
has_many :answers
|
||||
has_many :partial_results
|
||||
belongs_to :proposal
|
||||
|
||||
validates :title, presence: true
|
||||
validates :author, presence: true
|
||||
|
||||
validates :title, length: { minimum: 4 }
|
||||
validates :description, length: { maximum: Poll::Question.description_max_length }
|
||||
|
||||
scope :by_poll_id, ->(poll_id) { where(poll_id: poll_id) }
|
||||
|
||||
scope :sort_for_list, -> { order('poll_questions.proposal_id IS NULL', :created_at)}
|
||||
scope :for_render, -> { includes(:author, :proposal) }
|
||||
|
||||
def self.search(params)
|
||||
results = self.all
|
||||
results = results.by_poll_id(params[:poll_id]) if params[:poll_id].present?
|
||||
results = results.pg_search(params[:search]) if params[:search].present?
|
||||
results
|
||||
end
|
||||
|
||||
def searchable_values
|
||||
{ title => 'A',
|
||||
proposal.try(:title) => 'A',
|
||||
description => 'B',
|
||||
author.username => 'C',
|
||||
author_visible_name => 'C' }
|
||||
end
|
||||
|
||||
def description
|
||||
super.try :html_safe
|
||||
end
|
||||
|
||||
def valid_answers
|
||||
(super.try(:split, ',').compact || []).map(&:strip)
|
||||
end
|
||||
|
||||
def copy_attributes_from_proposal(proposal)
|
||||
if proposal.present?
|
||||
self.author = proposal.author
|
||||
self.author_visible_name = proposal.author.name
|
||||
self.proposal_id = proposal.id
|
||||
self.title = proposal.title
|
||||
self.description = proposal.description
|
||||
self.valid_answers = I18n.t('poll_questions.default_valid_answers')
|
||||
end
|
||||
end
|
||||
|
||||
def answerable_by?(user)
|
||||
poll.answerable_by?(user)
|
||||
end
|
||||
|
||||
def self.answerable_by(user)
|
||||
return none if user.nil? || user.unverified?
|
||||
where(poll_id: Poll.answerable_by(user).pluck(:id))
|
||||
end
|
||||
|
||||
end
|
||||
20
app/models/poll/recount.rb
Normal file
20
app/models/poll/recount.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
class Poll
|
||||
class Recount < ActiveRecord::Base
|
||||
belongs_to :booth_assignment, class_name: "Poll::BoothAssignment"
|
||||
belongs_to :officer_assignment, class_name: "Poll::OfficerAssignment"
|
||||
|
||||
validates :booth_assignment_id, presence: true
|
||||
validates :date, presence: true, uniqueness: {scope: :booth_assignment_id}
|
||||
validates :officer_assignment_id, presence: true, uniqueness: {scope: :booth_assignment_id}
|
||||
validates :count, presence: true, numericality: {only_integer: true}
|
||||
|
||||
before_save :update_logs
|
||||
|
||||
def update_logs
|
||||
if self.count_changed? && self.count_was.present?
|
||||
self.count_log += ":#{self.count_was.to_s}"
|
||||
self.officer_assignment_id_log += ":#{self.officer_assignment_id_was.to_s}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
59
app/models/poll/voter.rb
Normal file
59
app/models/poll/voter.rb
Normal file
@@ -0,0 +1,59 @@
|
||||
class Poll
|
||||
class Voter < ActiveRecord::Base
|
||||
belongs_to :poll
|
||||
belongs_to :user
|
||||
belongs_to :geozone
|
||||
belongs_to :booth_assignment
|
||||
belongs_to :officer_assignment
|
||||
|
||||
validates :poll_id, presence: true
|
||||
validates :user_id, presence: true
|
||||
|
||||
validates :document_number, presence: true, uniqueness: { scope: [:poll_id, :document_type], message: :has_voted }
|
||||
|
||||
before_validation :set_demographic_info, :set_document_info
|
||||
|
||||
def set_demographic_info
|
||||
return unless user.present?
|
||||
|
||||
self.gender = user.gender
|
||||
self.age = user.age
|
||||
self.geozone = user.geozone
|
||||
end
|
||||
|
||||
def set_document_info
|
||||
return unless user.present?
|
||||
|
||||
self.document_type = user.document_type
|
||||
self.document_number = user.document_number
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def in_census?
|
||||
census_api_response.valid?
|
||||
end
|
||||
|
||||
def census_api_response
|
||||
@census_api_response ||= CensusApi.new.call(document_type, document_number)
|
||||
end
|
||||
|
||||
def fill_stats_fields
|
||||
if in_census?
|
||||
self.gender = census_api_response.gender
|
||||
self.geozone_id = Geozone.select(:id).where(census_code: census_api_response.district_code).first.try(:id)
|
||||
self.age = voter_age(census_api_response.date_of_birth)
|
||||
end
|
||||
end
|
||||
|
||||
def voter_age(dob)
|
||||
if dob.blank?
|
||||
nil
|
||||
else
|
||||
now = Time.now.utc.to_date
|
||||
now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
23
app/models/poll/white_result.rb
Normal file
23
app/models/poll/white_result.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
class Poll::WhiteResult < ActiveRecord::Base
|
||||
|
||||
VALID_ORIGINS = %w{ web booth }
|
||||
|
||||
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
|
||||
belongs_to :booth_assignment
|
||||
belongs_to :officer_assignment
|
||||
|
||||
validates :author, presence: true
|
||||
validates :origin, inclusion: {in: VALID_ORIGINS}
|
||||
|
||||
scope :by_author, -> (author_id) { where(author_id: author_id) }
|
||||
|
||||
before_save :update_logs
|
||||
|
||||
def update_logs
|
||||
if self.amount_changed? && self.amount_was.present?
|
||||
self.amount_log += ":#{self.amount_was.to_s}"
|
||||
self.officer_assignment_id_log += ":#{self.officer_assignment_id_was.to_s}"
|
||||
self.author_id_log += ":#{self.author_id_was.to_s}"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -45,12 +45,12 @@ class Proposal < ActiveRecord::Base
|
||||
scope :sort_by_relevance, -> { all }
|
||||
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
||||
scope :sort_by_archival_date, -> { archived.sort_by_confidence_score }
|
||||
scope :archived, -> { where("proposals.created_at <= ?", Setting["months_to_archive_proposals"].to_i.months.ago)}
|
||||
scope :not_archived, -> { where("proposals.created_at > ?", Setting["months_to_archive_proposals"].to_i.months.ago)}
|
||||
scope :archived, -> { where("proposals.created_at <= ?", Setting["months_to_archive_proposals"].to_i.months.ago) }
|
||||
scope :not_archived, -> { where("proposals.created_at > ?", Setting["months_to_archive_proposals"].to_i.months.ago) }
|
||||
scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)}
|
||||
scope :retired, -> { where.not(retired_at: nil) }
|
||||
scope :not_retired, -> { where(retired_at: nil) }
|
||||
scope :successfull, -> { where("cached_votes_up >= ?", Proposal.votes_needed_for_success)}
|
||||
scope :successful, -> { where("cached_votes_up >= ?", Proposal.votes_needed_for_success) }
|
||||
|
||||
def to_param
|
||||
"#{id}-#{title}".parameterize
|
||||
@@ -155,7 +155,7 @@ class Proposal < ActiveRecord::Base
|
||||
Setting['votes_for_proposal_success'].to_i
|
||||
end
|
||||
|
||||
def successfull?
|
||||
def successful?
|
||||
total_votes >= Proposal.votes_needed_for_success
|
||||
end
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ class Signature < ActiveRecord::Base
|
||||
user_params = {
|
||||
document_number: document_number,
|
||||
created_from_signature: true,
|
||||
verified_at: Time.now,
|
||||
erased_at: Time.now,
|
||||
verified_at: Time.current,
|
||||
erased_at: Time.current,
|
||||
password: random_password,
|
||||
terms_of_service: '1',
|
||||
email: nil,
|
||||
|
||||
@@ -13,6 +13,7 @@ class User < ActiveRecord::Base
|
||||
has_one :moderator
|
||||
has_one :valuator
|
||||
has_one :manager
|
||||
has_one :poll_officer, class_name: "Poll::Officer"
|
||||
has_one :organization
|
||||
has_one :lock
|
||||
has_many :flags
|
||||
@@ -55,6 +56,7 @@ class User < ActiveRecord::Base
|
||||
scope :by_document, -> (document_type, document_number) { where(document_type: document_type, document_number: document_number) }
|
||||
scope :email_digest, -> { where(email_digest: true) }
|
||||
scope :active, -> { where(erased_at: nil) }
|
||||
scope :erased, -> { where.not(erased_at: nil) }
|
||||
|
||||
before_validation :clean_document_number
|
||||
|
||||
@@ -123,6 +125,10 @@ class User < ActiveRecord::Base
|
||||
manager.present?
|
||||
end
|
||||
|
||||
def poll_officer?
|
||||
poll_officer.present?
|
||||
end
|
||||
|
||||
def organization?
|
||||
organization.present?
|
||||
end
|
||||
@@ -188,6 +194,22 @@ class User < ActiveRecord::Base
|
||||
erased_at.present?
|
||||
end
|
||||
|
||||
def take_votes_if_erased_document(document_number, document_type)
|
||||
erased_user = User.erased.where(document_number: document_number).where(document_type: document_type).first
|
||||
if erased_user.present?
|
||||
self.take_votes_from(erased_user)
|
||||
erased_user.update(document_number: nil, document_type: nil)
|
||||
end
|
||||
end
|
||||
|
||||
def take_votes_from(other_user)
|
||||
return if other_user.blank?
|
||||
Poll::Voter.where(user_id: other_user.id).update_all(user_id: self.id)
|
||||
Budget::Ballot.where(user_id: other_user.id).update_all(user_id: self.id)
|
||||
Vote.where("voter_id = ? AND voter_type = ?", other_user.id, "User").update_all(voter_id: self.id)
|
||||
self.update(former_users_data_log: "#{self.former_users_data_log} | id: #{other_user.id} - #{Time.current.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
end
|
||||
|
||||
def locked?
|
||||
Lock.find_or_create_by(user: self).locked?
|
||||
end
|
||||
@@ -241,6 +263,10 @@ class User < ActiveRecord::Base
|
||||
"#{name} (#{email})"
|
||||
end
|
||||
|
||||
def age
|
||||
Age.in_years(date_of_birth)
|
||||
end
|
||||
|
||||
def save_requiring_finish_signup
|
||||
begin
|
||||
self.registering_with_oauth = true
|
||||
|
||||
@@ -32,7 +32,7 @@ class Verification::Management::Document
|
||||
end
|
||||
|
||||
def under_age?(response)
|
||||
User.minimum_required_age.years.ago.beginning_of_day < response.date_of_birth.beginning_of_day
|
||||
response.date_of_birth.blank? || Age.in_years(response.date_of_birth) < User.minimum_required_age
|
||||
end
|
||||
|
||||
def verified?
|
||||
|
||||
@@ -26,6 +26,9 @@ class Verification::Residence
|
||||
|
||||
def save
|
||||
return false unless valid?
|
||||
|
||||
user.take_votes_if_erased_document(document_number, document_type)
|
||||
|
||||
user.update(document_number: document_number,
|
||||
document_type: document_type,
|
||||
geozone: self.geozone,
|
||||
@@ -36,11 +39,11 @@ class Verification::Residence
|
||||
|
||||
def allowed_age
|
||||
return if errors[:date_of_birth].any?
|
||||
errors.add(:date_of_birth, I18n.t('verification.residence.new.error_not_allowed_age')) unless self.date_of_birth <= User.minimum_required_age.years.ago
|
||||
errors.add(:date_of_birth, I18n.t('verification.residence.new.error_not_allowed_age')) unless Age.in_years(self.date_of_birth) >= User.minimum_required_age
|
||||
end
|
||||
|
||||
def document_number_uniqueness
|
||||
errors.add(:document_number, I18n.t('errors.messages.taken')) if User.where(document_number: document_number).any?
|
||||
errors.add(:document_number, I18n.t('errors.messages.taken')) if User.active.where(document_number: document_number).any?
|
||||
end
|
||||
|
||||
def store_failed_attempt
|
||||
|
||||
@@ -1,144 +1,166 @@
|
||||
<nav class="admin-sidebar">
|
||||
<ul id="admin_menu">
|
||||
<div class="admin-sidebar" data-equalizer-watch>
|
||||
<ul id="admin_menu" data-accordion-menu>
|
||||
|
||||
<li <%= "class=active" if controller_name == "tags" %>>
|
||||
<%= link_to admin_tags_path do %>
|
||||
<span class="icon-tag"></span><%= t("admin.menu.debate_topics") %>
|
||||
<% end %>
|
||||
<li class="section-title">
|
||||
<a href="#">
|
||||
<span class="icon-proposals"></span>
|
||||
<strong><%= t("admin.menu.title_categories") %></strong>
|
||||
</a>
|
||||
<ul <%= "class=is-active" if menu_tags? %>>
|
||||
<li <%= "class=active" if controller_name == "tags" %>>
|
||||
<%= link_to t("admin.menu.proposals_topics"), admin_tags_path %>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "proposals" %>>
|
||||
<%= link_to admin_proposals_path do %>
|
||||
<span class="icon-proposals"></span><%= t("admin.menu.hidden_proposals") %>
|
||||
<% end %>
|
||||
</li>
|
||||
<li class="section-title">
|
||||
<a href="#">
|
||||
<span class="icon-eye"></span>
|
||||
<strong><%= t("admin.menu.title_moderated_content") %></strong>
|
||||
</a>
|
||||
<ul <%= "class=is-active" if menu_moderated_content? %>>
|
||||
<li <%= "class=active" if controller_name == "proposals" %>>
|
||||
<%= link_to t("admin.menu.hidden_proposals"), admin_proposals_path %>
|
||||
</li>
|
||||
|
||||
<% if feature?(:debates) %>
|
||||
<li <%= "class=active" if controller_name == "debates" %>>
|
||||
<%= link_to admin_debates_path do %>
|
||||
<span class="icon-debates"></span><%= t("admin.menu.hidden_debates") %>
|
||||
<% if feature?(:debates) %>
|
||||
<li <%= "class=active" if controller_name == "debates" %>>
|
||||
<%= link_to t("admin.menu.hidden_debates"), admin_debates_path %>
|
||||
</li>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<li <%= "class=active" if controller_name == "comments" %>>
|
||||
<%= link_to admin_comments_path do %>
|
||||
<span class="icon-comments"></span><%= t("admin.menu.hidden_comments") %>
|
||||
<% end %>
|
||||
<li <%= "class=active" if controller_name == "comments" %>>
|
||||
<%= link_to t("admin.menu.hidden_comments"), admin_comments_path %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "users" %>>
|
||||
<%= link_to t("admin.menu.hidden_users"), admin_users_path %>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<% if feature?(:spending_proposals) %>
|
||||
<li <%= "class=active" if controller_name == "spending_proposals" %>>
|
||||
<%= link_to admin_spending_proposals_path do %>
|
||||
<span class="icon-budget"></span><%= t("admin.menu.spending_proposals") %>
|
||||
<% end %>
|
||||
<li class="section-title">
|
||||
<a href="#">
|
||||
<span class="icon-budget"></span>
|
||||
<strong><%= t("admin.menu.title_budgets") %></strong>
|
||||
</a>
|
||||
<ul <%= "class=is-active" if menu_budget? %>>
|
||||
<li <%= "class=active" if controller_name == "spending_proposals" %>>
|
||||
<%= link_to t("admin.menu.spending_proposals"), admin_spending_proposals_path %>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
|
||||
<% if feature?(:polls) %>
|
||||
<li class="section-title">
|
||||
<a href="#">
|
||||
<span class="icon-checkmark-circle"></span>
|
||||
<strong><%= t("admin.menu.title_polls") %></strong>
|
||||
</a>
|
||||
<ul id="polls_menu" <%= "class=is-active" if menu_polls? %>>
|
||||
<li <%= 'class=active' if ["polls", "officer_assignments", "booth_assignments", "recounts", "results"].include? controller_name %>>
|
||||
<%= link_to t('admin.menu.polls'), admin_polls_path %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "questions" %>>
|
||||
<%= link_to t("admin.menu.poll_questions"), admin_questions_path %>
|
||||
</li>
|
||||
|
||||
<li <%= 'class=active' if controller_name == 'officers' %>>
|
||||
<%= link_to t('admin.menu.poll_officers'), admin_officers_path %>
|
||||
</li>
|
||||
|
||||
<li <%= 'class=active' if controller_name == 'booths' %>>
|
||||
<%= link_to t('admin.menu.poll_booths'), admin_booths_path %>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if feature?(:budgets) %>
|
||||
<li <%= "class=active" if controller_name == "budgets" %>>
|
||||
<li class="section-title" <%= "class=active" if controller_name == "budgets" %>>
|
||||
<%= link_to admin_budgets_path do %>
|
||||
<span class="icon-budget"></span><%= t("admin.menu.budgets") %>
|
||||
<span class="icon-budget"></span>
|
||||
<strong><%= t("admin.menu.budgets") %></strong>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<li class="section-title">
|
||||
<a href="#">
|
||||
<span class="icon-organizations"></span>
|
||||
<strong><%= t("admin.menu.title_profiles") %></strong>
|
||||
</a>
|
||||
<ul <%= "class=is-active" if menu_profiles? %>>
|
||||
<li <%= "class=active" if controller_name == "organizations" %>>
|
||||
<%= link_to t("admin.menu.organizations"), admin_organizations_path %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "officials" %>>
|
||||
<%= link_to t("admin.menu.officials"), admin_officials_path %>
|
||||
</li>
|
||||
|
||||
<li <%= 'class=active' if controller_name == 'moderators' %>>
|
||||
<%= link_to t('admin.menu.moderators'), admin_moderators_path%>
|
||||
</li>
|
||||
|
||||
<li <%= 'class=active' if controller_name == 'valuators' %>>
|
||||
<%= link_to t('admin.menu.valuators'), admin_valuators_path %>
|
||||
</li>
|
||||
|
||||
<li <%= 'class=active' if controller_name == 'managers' %>>
|
||||
<%= link_to t('admin.menu.managers'), admin_managers_path %>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="section-title">
|
||||
<a href="#">
|
||||
<span class="icon-banner"></span>
|
||||
<strong><%= t("admin.menu.title_banners") %></strong>
|
||||
</a>
|
||||
<ul <%= "class=is-active" if menu_banners? %>>
|
||||
<li <%= "class=active" if controller_name == "banners" %>>
|
||||
<%= link_to t("admin.menu.banner"), admin_banners_path %>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="section-title" <%= 'class=active' if controller_name == 'geozones' %>>
|
||||
<%= link_to admin_geozones_path do %>
|
||||
<strong><%= t('admin.menu.geozones') %></strong>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<% if feature?(:signature_sheets) %>
|
||||
<li <%= "class=active" if controller_name == "signature_sheets" %>>
|
||||
<li class="section-title" <%= "class=active" if controller_name == "signature_sheets" %>>
|
||||
<%= link_to admin_signature_sheets_path do %>
|
||||
<span class="icon-budget"></span><%= t("admin.menu.signature_sheets") %>
|
||||
<strong><%= t("admin.menu.signature_sheets") %></strong>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<li <%= "class=active" if controller_name == "banners" %>>
|
||||
<%= link_to admin_banners_path do %>
|
||||
<span class="icon-eye"></span><%= t("admin.menu.banner") %>
|
||||
<% end %>
|
||||
</li>
|
||||
<li class="section-title">
|
||||
<a href="#">
|
||||
<span class="icon-settings"></span>
|
||||
<strong><%= t("admin.menu.title_site_customization") %></strong>
|
||||
</a>
|
||||
<ul <%= "class=is-active" if menu_profiles? %>>
|
||||
<li <%= "class=active" if controller_name == "pages" %>>
|
||||
<%= link_to t("admin.menu.site_customization.pages"), admin_site_customization_pages_path %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "users" %>>
|
||||
<%= link_to admin_users_path do %>
|
||||
<span class="icon-eye"></span><%= t("admin.menu.hidden_users") %>
|
||||
<% end %>
|
||||
</li>
|
||||
<li <%= "class=active" if controller_name == "images" %>>
|
||||
<%= link_to t("admin.menu.site_customization.images"), admin_site_customization_images_path %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "verifications" %>>
|
||||
<%= link_to admin_verifications_path do %>
|
||||
<span class="icon-eye"></span><%= t("admin.menu.incomplete_verifications") %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "organizations" %>>
|
||||
<%= link_to admin_organizations_path do %>
|
||||
<span class="icon-organizations"></span><%= t("admin.menu.organizations") %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "officials" %>>
|
||||
<%= link_to admin_officials_path do %>
|
||||
<span class="icon-user"></span><%= t("admin.menu.officials") %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= 'class=active' if controller_name == 'moderators' %>>
|
||||
<%= link_to admin_moderators_path do %>
|
||||
<span class="icon-user"></span><%= t('admin.menu.moderators') %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= 'class=active' if controller_name == 'valuators' %>>
|
||||
<%= link_to admin_valuators_path do %>
|
||||
<span class="icon-user"></span><%= t('admin.menu.valuators') %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= 'class=active' if controller_name == 'managers' %>>
|
||||
<%= link_to admin_managers_path do %>
|
||||
<span class="icon-user"></span><%= t('admin.menu.managers') %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= 'class=active' if controller_name == 'geozones' %>>
|
||||
<%= link_to admin_geozones_path do %>
|
||||
<span class="icon-settings"></span><%= t('admin.menu.geozones') %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= 'class=active' if controller_name == 'activity' %>>
|
||||
<%= link_to admin_activity_path do %>
|
||||
<span class="icon-eye"></span><%= t('admin.menu.activity') %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= 'class=active' if controller_name == 'settings' %>>
|
||||
<%= link_to admin_settings_path do %>
|
||||
<span class="icon-settings"></span><%= t("admin.menu.settings") %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "stats" %>>
|
||||
<%= link_to admin_stats_path do %>
|
||||
<span class="icon-stats"></span><%= t("admin.menu.stats") %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "pages" %>>
|
||||
<%= link_to admin_site_customization_pages_path do %>
|
||||
<span class="icon-settings"></span><%= t("admin.menu.site_customization.pages") %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "images" %>>
|
||||
<%= link_to admin_site_customization_images_path do %>
|
||||
<span class="icon-settings"></span><%= t("admin.menu.site_customization.images") %>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "content_blocks" %>>
|
||||
<%= link_to admin_site_customization_content_blocks_path do %>
|
||||
<span class="icon-settings"></span><%= t("admin.menu.site_customization.content_blocks") %>
|
||||
<% end %>
|
||||
<li <%= 'class=active' if controller_name == 'content_blocks' %>>
|
||||
<%= link_to t("admin.menu.site_customization.content_blocks"), admin_site_customization_content_blocks_path%>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
<%= link_to t("admin.dashboard.index.back") + " " + setting['org_name'], root_path, class: "button float-right" %>
|
||||
<%= link_to admin_settings_path, class: "button float-right" do %>
|
||||
<span class="icon-settings"></span>
|
||||
<%= t("admin.menu.settings") %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to admin_stats_path, class: "button float-right" do %>
|
||||
<span class="icon-stats"></span>
|
||||
<%= t("admin.menu.stats") %>
|
||||
<% end %>
|
||||
|
||||
<h2 class="inline-block"><%= t("admin.dashboard.index.title") %></h2>
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<h2><%= t("admin.moderators.index.title") %></h2>
|
||||
<%= link_to t('admin.menu.activity'), admin_activity_path, class: "button hollow float-right" %>
|
||||
|
||||
<h2 class="inline-block"><%= t("admin.moderators.index.title") %></h2>
|
||||
|
||||
<div class="row">
|
||||
<%= form_tag search_admin_moderators_path, method: :get, remote: true do %>
|
||||
|
||||
1
app/views/admin/poll/_menu.html.erb
Normal file
1
app/views/admin/poll/_menu.html.erb
Normal file
@@ -0,0 +1 @@
|
||||
<%= render "admin/menu" %>
|
||||
@@ -0,0 +1,16 @@
|
||||
<div class="row">
|
||||
<div class="small-12 medium-6 column">
|
||||
<%= form_tag(search_booths_admin_poll_booth_assignments_path(@poll), method: :get, remote: true) do |f| %>
|
||||
<div class="input-group">
|
||||
<%= text_field_tag :search,
|
||||
@search,
|
||||
placeholder: t("admin.shared.booths_search.placeholder"), id: "search-booths" %>
|
||||
<div class="input-group-button">
|
||||
<%= submit_tag t("admin.shared.booths_search.button"), class: "button" %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-booths-results"></div>
|
||||
@@ -0,0 +1,39 @@
|
||||
<% if @booths.blank? %>
|
||||
<div class="callout alert margin-bottom">
|
||||
<%= t('admin.shared.no_search_results') %>
|
||||
</div>
|
||||
<% else %>
|
||||
<h3><%= t('admin.shared.search_results') %></h3>
|
||||
<% end %>
|
||||
|
||||
<% if @booths.any? %>
|
||||
<table>
|
||||
<thead>
|
||||
<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>
|
||||
<% @booths.each do |booth| %>
|
||||
<tr>
|
||||
<td>
|
||||
<%= booth.name %>
|
||||
</td>
|
||||
<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>
|
||||
</table>
|
||||
<% end %>
|
||||
43
app/views/admin/poll/booth_assignments/index.html.erb
Normal file
43
app/views/admin/poll/booth_assignments/index.html.erb
Normal file
@@ -0,0 +1,43 @@
|
||||
<%= 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>
|
||||
|
||||
<% if @booth_assignments.empty? %>
|
||||
<div class="callout primary margin-top">
|
||||
<%= t("admin.poll_booth_assignments.index.no_booths") %>
|
||||
</div>
|
||||
<% else %>
|
||||
<table id="assigned_booths_list" class="fixed margin">
|
||||
<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| %>
|
||||
<tr id="<%= dom_id(booth_assignment) %>" class="booth">
|
||||
<td>
|
||||
<strong>
|
||||
<%= link_to booth_assignment.booth.name, admin_poll_booth_assignment_path(@poll, booth_assignment) %>
|
||||
</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" %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= paginate @booth_assignments %>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
$("#search-booths-results").html("<%= j render 'search_booths_results' %>");
|
||||
87
app/views/admin/poll/booth_assignments/show.html.erb
Normal file
87
app/views/admin/poll/booth_assignments/show.html.erb
Normal file
@@ -0,0 +1,87 @@
|
||||
<%= link_to admin_poll_booth_assignments_path(@poll) do %>
|
||||
<span class="icon-angle-left"></span>
|
||||
<%= @poll.name %>
|
||||
<% end %>
|
||||
|
||||
<h2><%= @booth_assignment.booth.name %></h2>
|
||||
|
||||
<% if @booth_assignment.booth.location.present? %>
|
||||
<p>
|
||||
<strong><%= t("admin.poll_booth_assignments.show.location") %></strong>:
|
||||
<%= @booth_assignment.booth.location %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<div class="tabs-content" data-tabs-content="booths-tabs">
|
||||
<ul class="tabs" data-tabs id="booths-tabs">
|
||||
<li class="tabs-title is-active">
|
||||
<%= link_to t("admin.poll_booth_assignments.show.officers"), "#tab-officers" %>
|
||||
</li>
|
||||
<li class="tabs-title">
|
||||
<%= link_to t("admin.poll_booth_assignments.show.recounts"), "#tab-recounts" %>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tabs-panel is-active" id="tab-officers">
|
||||
<% if @booth_assignment.officers.empty? %>
|
||||
<div class="callout primary margin-top">
|
||||
<%= t("admin.poll_booth_assignments.show.no_officers") %>
|
||||
</div>
|
||||
<% else %>
|
||||
<h3><%= t("admin.poll_booth_assignments.show.officers_list") %></h3>
|
||||
|
||||
<table id="officers_list">
|
||||
<tbody>
|
||||
<% @booth_assignment.officers.uniq.each do |officer| %>
|
||||
<tr id="officer_<%= officer.id %>" class="officer">
|
||||
<td><%= link_to officer.name, by_officer_admin_poll_officer_assignments_path(@poll, officer_id: officer.id) %></td>
|
||||
<td><%= officer.email %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="tabs-panel" id="tab-recounts">
|
||||
<% if @booth_assignment.recounts.empty? %>
|
||||
<div class="callout primary margin-top">
|
||||
<%= t("admin.poll_booth_assignments.show.no_recounts") %>
|
||||
</div>
|
||||
<% else %>
|
||||
<h3><%= t("admin.poll_booth_assignments.show.recounts_list") %></h3>
|
||||
<table id="recounts_list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.poll_booth_assignments.show.date") %></th>
|
||||
<th class="text-center"><%= t("admin.poll_booth_assignments.show.count_by_officer") %></th>
|
||||
<th class="text-center"><%= t("admin.poll_booth_assignments.show.count_final") %></th>
|
||||
<th class="text-center"><%= t("admin.poll_booth_assignments.show.count_by_system") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% (@poll.starts_at.to_date..@poll.ends_at.to_date).each do |voting_date| %>
|
||||
<% recount = recount_for_date(@booth_assignment.recounts, voting_date) %>
|
||||
<% final_recount = final_recount_for_date(@booth_assignment.final_recounts, voting_date) %>
|
||||
<% system_count = @voters_by_date[voting_date].present? ? @voters_by_date[voting_date].size : 0 %>
|
||||
<tr id="recounting_<%= voting_date.strftime('%Y%m%d') %>">
|
||||
<td><%= l voting_date %></td>
|
||||
<% if recount.present? %>
|
||||
|
||||
<td class="text-center <%= 'count-error' if recount.count != system_count %>" title="<%= recount.officer_assignment.officer.name %>"><%= recount.count %></td>
|
||||
<% else %>
|
||||
<td class="text-center" title=""> - </td>
|
||||
<% end %>
|
||||
<% if final_recount.present? %>
|
||||
<td class="text-center <%= 'count-error' if final_recount.count != system_count %>" title="<%= final_recount.officer_assignment.officer.name %>"><%= final_recount.count %></td>
|
||||
<% else %>
|
||||
<td class="text-center" title=""> - </td>
|
||||
<% end %>
|
||||
<td class="text-center"><%= system_count %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
13
app/views/admin/poll/booths/_booth.html.erb
Normal file
13
app/views/admin/poll/booths/_booth.html.erb
Normal file
@@ -0,0 +1,13 @@
|
||||
<tr id="booth_<%= booth.id %>" class="booth">
|
||||
<td>
|
||||
<%= booth.name %>
|
||||
</td>
|
||||
<td>
|
||||
<%= booth.location %>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<%= link_to t("admin.actions.edit"),
|
||||
edit_admin_booth_path(booth),
|
||||
class: "button hollow" %>
|
||||
</td>
|
||||
</tr>
|
||||
20
app/views/admin/poll/booths/_form.html.erb
Normal file
20
app/views/admin/poll/booths/_form.html.erb
Normal file
@@ -0,0 +1,20 @@
|
||||
<div class="row">
|
||||
<div class="small-12 medium-6 column">
|
||||
<%= f.text_field :name,
|
||||
placeholder: t('admin.booths.new.name'),
|
||||
label: t("admin.booths.new.name") %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
<%= f.text_field :location,
|
||||
placeholder: t("admin.booths.new.location"),
|
||||
label: t("admin.booths.new.location") %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 medium-4 column">
|
||||
<%= f.submit t("admin.booths.#{admin_submit_action(@booth)}.submit_button"),
|
||||
class: "button success expanded" %>
|
||||
</div>
|
||||
</div>
|
||||
7
app/views/admin/poll/booths/edit.html.erb
Normal file
7
app/views/admin/poll/booths/edit.html.erb
Normal file
@@ -0,0 +1,7 @@
|
||||
<%= back_link_to admin_booths_path %>
|
||||
|
||||
<h2><%= t("admin.booths.edit.title") %></h2>
|
||||
|
||||
<%= form_for @booth, url: admin_booth_path(@booth) do |f| %>
|
||||
<%= render "form", f: f %>
|
||||
<% end %>
|
||||
28
app/views/admin/poll/booths/index.html.erb
Normal file
28
app/views/admin/poll/booths/index.html.erb
Normal file
@@ -0,0 +1,28 @@
|
||||
<h2 class="inline-block"><%= t("admin.booths.index.title") %></h2>
|
||||
|
||||
<%= link_to t("admin.booths.index.add_booth"), new_admin_booth_path,
|
||||
class: "button success float-right" %>
|
||||
|
||||
<% if @booths.empty? %>
|
||||
<div class="callout primary">
|
||||
<%= t("admin.booths.index.no_booths") %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if @booths.any? %>
|
||||
<h3><%= page_entries_info @booths %></h3>
|
||||
<table>
|
||||
<thead>
|
||||
<th><%= t("admin.booths.index.name") %></th>
|
||||
<th><%= t("admin.booths.index.location") %></th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @booths.each do |booth| %>
|
||||
<%= render partial: "booth", locals: { booth: booth } %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= paginate @booths %>
|
||||
<% end %>
|
||||
7
app/views/admin/poll/booths/new.html.erb
Normal file
7
app/views/admin/poll/booths/new.html.erb
Normal file
@@ -0,0 +1,7 @@
|
||||
<%= back_link_to admin_booths_path %>
|
||||
|
||||
<h2><%= t("admin.booths.new.title") %></h2>
|
||||
|
||||
<%= form_for @booth, url: admin_booths_path(@booth) do |f| %>
|
||||
<%= render "form", f: f %>
|
||||
<% end %>
|
||||
12
app/views/admin/poll/booths/show.html.erb
Normal file
12
app/views/admin/poll/booths/show.html.erb
Normal file
@@ -0,0 +1,12 @@
|
||||
<%= back_link_to admin_booths_path %>
|
||||
|
||||
<div class="clear"></div>
|
||||
|
||||
<h2 class="inline-block">
|
||||
<%= @booth.name %>
|
||||
</h2>
|
||||
|
||||
<p>
|
||||
<strong><%= t("admin.booths.show.location") %></strong>:
|
||||
<%= @booth.location %>
|
||||
</p>
|
||||
@@ -0,0 +1,16 @@
|
||||
<div class="row">
|
||||
<div class="small-12 medium-6 column">
|
||||
<%= form_tag(search_officers_admin_poll_officer_assignments_path(@poll), method: :get, remote: true) do |f| %>
|
||||
<div class="input-group">
|
||||
<%= text_field_tag :search,
|
||||
@search,
|
||||
placeholder: t("admin.shared.poll_officers_search.placeholder"), id: "search-officers" %>
|
||||
<div class="input-group-button">
|
||||
<%= submit_tag t("admin.shared.poll_officers_search.button"), class: "button" %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-officers-results"></div>
|
||||
@@ -0,0 +1,42 @@
|
||||
<% if @officers.blank? %>
|
||||
<div class="callout alert margin-bottom">
|
||||
<%= t('admin.shared.no_search_results') %>
|
||||
</div>
|
||||
<% else %>
|
||||
<h3><%= t('admin.shared.search_results') %></h3>
|
||||
<% end %>
|
||||
|
||||
<% if @officers.any? %>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.poll_officer_assignments.index.table_name") %></th>
|
||||
<th><%= t("admin.poll_officer_assignments.index.table_email") %></th>
|
||||
<th class="text-center"><%= t("admin.polls.show.table_assignment") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @officers.each do |user| %>
|
||||
<tr>
|
||||
<td>
|
||||
<%= user.name %>
|
||||
</td>
|
||||
<td>
|
||||
<%= user.email %>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<% if @poll.officer_ids.include?(user.poll_officer.id) %>
|
||||
<%= link_to t("admin.poll_officer_assignments.index.edit_officer_assignments"),
|
||||
by_officer_admin_poll_officer_assignments_path(@poll, officer_id: user.poll_officer.id),
|
||||
class: "button hollow alert" %>
|
||||
<% else %>
|
||||
<%= link_to t("admin.poll_officer_assignments.index.add_officer_assignments"),
|
||||
by_officer_admin_poll_officer_assignments_path(@poll, officer_id: user.poll_officer.id),
|
||||
class: "button hollow" %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
127
app/views/admin/poll/officer_assignments/by_officer.html.erb
Normal file
127
app/views/admin/poll/officer_assignments/by_officer.html.erb
Normal file
@@ -0,0 +1,127 @@
|
||||
<%= link_to admin_poll_officer_assignments_path(@poll) do %>
|
||||
<span class="icon-angle-left"></span>
|
||||
<%= @poll.name %>
|
||||
<% end %>
|
||||
|
||||
<h2><%= @officer.name %> - <%= @officer.email %></h2>
|
||||
|
||||
<%= form_tag(admin_poll_officer_assignments_path(@poll), {id: "officer_assignment_form"}) do %>
|
||||
<fieldset class="fieldset">
|
||||
<legend><%= t("admin.poll_officer_assignments.by_officer.new_assignment") %></legend>
|
||||
<div class="small-12 medium-4 column">
|
||||
<label><%= t("admin.poll_officer_assignments.by_officer.date") %></label>
|
||||
<%= select_tag :date,
|
||||
poll_dates_select_options(@poll) + poll_final_recount_option(@poll),
|
||||
{ prompt: t("admin.poll_officer_assignments.by_officer.select_date"),
|
||||
label: false } %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-4 column">
|
||||
<label><%= t("admin.poll_officer_assignments.by_officer.booth") %></label>
|
||||
<%= select_tag :booth_id,
|
||||
poll_booths_select_options(@poll),
|
||||
{ prompt: t("admin.poll_officer_assignments.by_officer.select_booth"),
|
||||
label: false } %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-4 column">
|
||||
<%= hidden_field_tag :officer_id, @officer.id %>
|
||||
<%= hidden_field_tag :poll_id, @poll.id %>
|
||||
<%= submit_tag t("admin.poll_officer_assignments.by_officer.add_assignment"),
|
||||
class: "button expanded hollow margin-top" %>
|
||||
</div>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
|
||||
|
||||
<% if @officer_assignments.empty? %>
|
||||
<div class="callout primary margin-top">
|
||||
<%= t("admin.poll_officer_assignments.by_officer.no_assignments") %>
|
||||
</div>
|
||||
<% else %>
|
||||
<h3><%= t("admin.poll_officer_assignments.by_officer.assignments") %></h3>
|
||||
<table class="fixed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.poll_officer_assignments.by_officer.date") %></th>
|
||||
<th><%= t("admin.poll_officer_assignments.by_officer.booth") %></th>
|
||||
<th class="text-right"><%= t("admin.poll_officer_assignments.by_officer.assignment") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @officer_assignments.each do |officer_assignment| %>
|
||||
<tr id="<%= dom_id officer_assignment %>">
|
||||
<td><%= officer_assignment.final? ? t('polls.final_date') : l(officer_assignment.date.to_date) %></td>
|
||||
<td><%= booth_name_with_location(officer_assignment.booth_assignment.booth) %></td>
|
||||
<td class="text-right">
|
||||
<%= link_to t("admin.poll_officer_assignments.by_officer.remove_assignment"),
|
||||
admin_poll_officer_assignment_path(@poll, officer_assignment),
|
||||
method: :delete,
|
||||
class: "button hollow alert" %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
|
||||
<% voting_days_officer_assignments = @officer_assignments.select{|oa| oa.final == false} %>
|
||||
<% if voting_days_officer_assignments.any? %>
|
||||
<h3><%= t("admin.poll_officer_assignments.by_officer.recounts") %></h3>
|
||||
<table id="recount_list" class="fixed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.poll_officer_assignments.by_officer.date") %></th>
|
||||
<th><%= t("admin.poll_officer_assignments.by_officer.booth") %></th>
|
||||
<th class="text-right"><%= t("admin.poll_officer_assignments.by_officer.recount") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% voting_days_officer_assignments.each do |officer_assignment| %>
|
||||
<tr id="recount_<%= officer_assignment.date.to_date.strftime('%Y%m%d') %>">
|
||||
<td><%= l(officer_assignment.date.to_date) %></td>
|
||||
<td><%= booth_name_with_location(officer_assignment.booth_assignment.booth) %></td>
|
||||
<td class="text-right">
|
||||
<% if officer_assignment.recount.present? %>
|
||||
<%= officer_assignment.recount.count %>
|
||||
<% else %>
|
||||
<span>-</span>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
|
||||
<% final_officer_assignments = @officer_assignments.select{|oa| oa.final == true} %>
|
||||
<% if final_officer_assignments.any? %>
|
||||
<h3><%= t("admin.poll_officer_assignments.by_officer.final_recounts") %></h3>
|
||||
<table id="final_recount_list" class="fixed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.poll_officer_assignments.by_officer.date") %></th>
|
||||
<th><%= t("admin.poll_officer_assignments.by_officer.booth") %></th>
|
||||
<th class="text-right"><%= t("admin.poll_officer_assignments.by_officer.final_recount") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% final_officer_assignments.each do |officer_assignment| %>
|
||||
<tr id="final_recount_<%= officer_assignment.date.to_date.strftime('%Y%m%d') %>">
|
||||
<td><%= l(officer_assignment.date.to_date) %></td>
|
||||
<td><%= booth_name_with_location(officer_assignment.booth_assignment.booth) %></td>
|
||||
<td class="text-right">
|
||||
<% if officer_assignment.final_recounts.any? %>
|
||||
<%= officer_assignment.final_recounts.to_a.sum(&:count) %>
|
||||
<% else %>
|
||||
<span>-</span>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
||||
43
app/views/admin/poll/officer_assignments/index.html.erb
Normal file
43
app/views/admin/poll/officer_assignments/index.html.erb
Normal file
@@ -0,0 +1,43 @@
|
||||
<%= render "/admin/poll/polls/poll_header" %>
|
||||
<div id="poll-resources">
|
||||
<%= render "/admin/poll/polls/subnav" %>
|
||||
|
||||
<%= render "search_officers" %>
|
||||
|
||||
<h3><%= t("admin.poll_officer_assignments.index.officers_title") %></h3>
|
||||
|
||||
<% if @officers.empty? %>
|
||||
<div class="callout primary margin-top">
|
||||
<%= t("admin.poll_officer_assignments.index.no_officers") %>
|
||||
</div>
|
||||
<% else %>
|
||||
<table class="fixed margin">
|
||||
<thead>
|
||||
<th><%= t("admin.poll_officer_assignments.index.table_name") %></th>
|
||||
<th><%= t("admin.poll_officer_assignments.index.table_email") %></th>
|
||||
<th class="text-right"><%= t("admin.actions.actions") %></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @officers.each do |officer| %>
|
||||
<tr id="officer_<%= officer.id %>" class="officer">
|
||||
<td>
|
||||
<strong>
|
||||
<%= link_to officer.name, by_officer_admin_poll_officer_assignments_path(@poll, officer_id: officer.id) %>
|
||||
</strong>
|
||||
</td>
|
||||
<td>
|
||||
<%= officer.email %>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<%= link_to t("admin.poll_officer_assignments.index.edit_officer_assignments"),
|
||||
by_officer_admin_poll_officer_assignments_path(@poll, officer_id: officer.id),
|
||||
class: "button hollow" %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= paginate @officers %>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
$("#search-officers-results").html("<%= j render 'search_officers_results' %>");
|
||||
30
app/views/admin/poll/officers/_officer.html.erb
Normal file
30
app/views/admin/poll/officers/_officer.html.erb
Normal file
@@ -0,0 +1,30 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t('admin.poll_officers.officer.name') %></th>
|
||||
<th colspan="2"><%= t('admin.poll_officers.officer.email') %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<%= officer.name %>
|
||||
</td>
|
||||
<td>
|
||||
<%= officer.email %>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<% if officer.persisted? %>
|
||||
<%= link_to t('admin.poll_officers.officer.delete'),
|
||||
admin_poll_officer_path(officer),
|
||||
method: :delete,
|
||||
class: "button hollow alert" %>
|
||||
<% else %>
|
||||
<%= link_to t('admin.poll_officers.officer.add'),{ controller: "admin/poll/officers", action: :create, user_id: officer.user_id },
|
||||
method: :post,
|
||||
class: "button success" %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
9
app/views/admin/poll/officers/_search.html.erb
Normal file
9
app/views/admin/poll/officers/_search.html.erb
Normal file
@@ -0,0 +1,9 @@
|
||||
<%= form_tag search_admin_officers_path, method: :get, remote: true do %>
|
||||
<div class="input-group">
|
||||
<%= text_field_tag :email, '',
|
||||
placeholder: t("admin.poll_officers.search.email_placeholder") %>
|
||||
<div class="input-group-button">
|
||||
<%= submit_tag t("admin.poll_officers.search.search"), class: "button" %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
1
app/views/admin/poll/officers/edit.html.erb
Normal file
1
app/views/admin/poll/officers/edit.html.erb
Normal file
@@ -0,0 +1 @@
|
||||
officer edit
|
||||
53
app/views/admin/poll/officers/index.html.erb
Normal file
53
app/views/admin/poll/officers/index.html.erb
Normal file
@@ -0,0 +1,53 @@
|
||||
<h2><%= t("admin.poll_officers.index.title") %></h2>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 medium-6 column">
|
||||
<%= render 'search' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-result"></div>
|
||||
|
||||
<h3>
|
||||
<%= page_entries_info @officers, entry_name: t('admin.poll_officers.officer.entry_name') %>
|
||||
</h3>
|
||||
|
||||
<% if @officers.any? %>
|
||||
<table id="officers">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t('admin.poll_officers.officer.name') %></th>
|
||||
<th colspan="2"><%= t('admin.poll_officers.officer.email') %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @officers.each do |officer| %>
|
||||
<tr>
|
||||
<td>
|
||||
<%= officer.name %>
|
||||
</td>
|
||||
<td>
|
||||
<%= officer.email %>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<% if officer.persisted? %>
|
||||
<%= link_to t('admin.poll_officers.officer.delete'),
|
||||
admin_officer_path(officer),
|
||||
method: :delete,
|
||||
class: "button hollow alert"
|
||||
%>
|
||||
<% else %>
|
||||
<%= link_to t('admin.poll_officers.officer.add'),
|
||||
{ controller: "admin/poll/officers", action: :create,
|
||||
user_id: officer.user_id },
|
||||
method: :post,
|
||||
class: "button success" %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= paginate @officers %>
|
||||
<% end %>
|
||||
1
app/views/admin/poll/officers/search.js.erb
Normal file
1
app/views/admin/poll/officers/search.js.erb
Normal file
@@ -0,0 +1 @@
|
||||
$("#search-result").html("<%= j render 'officer', officer: @officer %>");
|
||||
1
app/views/admin/poll/officers/show.html.erb
Normal file
1
app/views/admin/poll/officers/show.html.erb
Normal file
@@ -0,0 +1 @@
|
||||
officer show
|
||||
1
app/views/admin/poll/officers/user_not_found.js.erb
Normal file
1
app/views/admin/poll/officers/user_not_found.js.erb
Normal file
@@ -0,0 +1 @@
|
||||
$("#search-result").html("<div class=\"callout alert\"><%= j t('admin.poll_officers.search.user_not_found') %></div>");
|
||||
46
app/views/admin/poll/polls/_form.html.erb
Normal file
46
app/views/admin/poll/polls/_form.html.erb
Normal file
@@ -0,0 +1,46 @@
|
||||
<%= form_for [:admin, @poll] do |f| %>
|
||||
<div class="row">
|
||||
<div class="small-12 medium-6 column">
|
||||
<%= f.text_field :name %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 medium-6 column">
|
||||
<%= f.text_field :starts_at,
|
||||
value: @poll.starts_at.present? ? l(@poll.starts_at.to_date) : nil,
|
||||
class: "js-calendar-full" %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-6 column">
|
||||
<%= f.text_field :ends_at,
|
||||
value: @poll.ends_at.present? ? l(@poll.ends_at.to_date) : nil,
|
||||
class: "js-calendar-full" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-6 medium-6 column">
|
||||
<%= f.check_box :geozone_restricted, data: { checkbox_toggle: "#geozones" } %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="geozones" style="<%= @poll.geozone_restricted? ? '' : 'display:none' %>">
|
||||
<div class="row">
|
||||
<%= f.collection_check_boxes(:geozone_ids, @geozones, :id, :name) do |b| %>
|
||||
<div class="small-6 medium-3 column">
|
||||
<%= b.label do %>
|
||||
<%= b.check_box + b.text %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 medium-4 column">
|
||||
<%= f.submit t("admin.polls.#{admin_submit_action(@poll)}.submit_button"),
|
||||
class: "button success expanded" %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
18
app/views/admin/poll/polls/_poll.html.erb
Normal file
18
app/views/admin/poll/polls/_poll.html.erb
Normal file
@@ -0,0 +1,18 @@
|
||||
<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>
|
||||
<%= link_to t("admin.actions.edit"),
|
||||
edit_admin_poll_path(poll),
|
||||
class: "button hollow" %>
|
||||
<%= link_to t("admin.actions.configure"),
|
||||
admin_poll_path(poll),
|
||||
class: "button hollow" %>
|
||||
</td>
|
||||
</tr>
|
||||
17
app/views/admin/poll/polls/_poll_header.html.erb
Normal file
17
app/views/admin/poll/polls/_poll_header.html.erb
Normal file
@@ -0,0 +1,17 @@
|
||||
<%= link_to t("admin.actions.edit"),
|
||||
edit_admin_poll_path(@poll),
|
||||
class: "button hollow float-right" %>
|
||||
|
||||
<h2 class="inline-block">
|
||||
<%= @poll.name %>
|
||||
</h2>
|
||||
<br>
|
||||
<span>
|
||||
(<%= l @poll.starts_at.to_date %> - <%= l @poll.ends_at.to_date %>)
|
||||
</span>
|
||||
<% if @poll.geozone_restricted %>
|
||||
<span class="bullet"> • </span>
|
||||
<span>
|
||||
<%= @poll.geozones.pluck(:name).to_sentence %>
|
||||
<span>
|
||||
<% end %>
|
||||
31
app/views/admin/poll/polls/_questions.html.erb
Normal file
31
app/views/admin/poll/polls/_questions.html.erb
Normal file
@@ -0,0 +1,31 @@
|
||||
<h3><%= t("admin.polls.show.questions_title") %></h3>
|
||||
|
||||
<% if @poll.questions.empty? %>
|
||||
<div class="callout primary margin-top">
|
||||
<%= t('admin.polls.show.no_questions') %>
|
||||
</div>
|
||||
<% else %>
|
||||
<table class="fixed margin">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t('admin.polls.show.table_title') %></th>
|
||||
<th class="text-right"><%= t('admin.polls.show.table_assignment') %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<% @poll.questions.each do |question| %>
|
||||
<tr id="<%= dom_id(question) %>">
|
||||
<td>
|
||||
<strong>
|
||||
<%= link_to question.title, admin_question_path(question) %>
|
||||
</strong>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<%= link_to t('admin.polls.show.remove_question'),
|
||||
remove_question_admin_poll_path(poll_id: @poll.id, question_id: question.id),
|
||||
class: "button hollow alert",
|
||||
method: :patch %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
<% end %>
|
||||
17
app/views/admin/poll/polls/_search_questions.html.erb
Normal file
17
app/views/admin/poll/polls/_search_questions.html.erb
Normal file
@@ -0,0 +1,17 @@
|
||||
<div class="row">
|
||||
<div class="small-12 medium-6 column">
|
||||
<%= form_tag(search_questions_admin_poll_path(@poll), method: :get, remote: true) do |f| %>
|
||||
<div class="input-group">
|
||||
<%= text_field_tag :search,
|
||||
@search,
|
||||
placeholder: t("admin.shared.poll_questions_search.placeholder"), id: "search-questions" %>
|
||||
|
||||
<div class="input-group-button">
|
||||
<%= submit_tag t("admin.shared.poll_questions_search.button"), class: "button" %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="search-questions-results"></div>
|
||||
@@ -0,0 +1,33 @@
|
||||
<% if @questions.blank? %>
|
||||
<div class="callout alert margin-bottom">
|
||||
<%= t('admin.shared.no_search_results') %>
|
||||
</div>
|
||||
<% else %>
|
||||
<h3><%= t('admin.shared.search_results') %></h3>
|
||||
<% end %>
|
||||
|
||||
<% if @questions.any? %>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.polls.show.table_name") %></th>
|
||||
<th class="text-center"><%= t("admin.polls.show.table_assignment") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @questions.each do |question| %>
|
||||
<tr>
|
||||
<td>
|
||||
<%= question.title %>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<%= link_to t("admin.polls.show.add_question"),
|
||||
add_question_admin_poll_path(poll_id: @poll.id, question_id: question.id),
|
||||
method: :patch,
|
||||
class: "button hollow" %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
63
app/views/admin/poll/polls/_subnav.html.erb
Normal file
63
app/views/admin/poll/polls/_subnav.html.erb
Normal file
@@ -0,0 +1,63 @@
|
||||
<ul class="menu simple clear" id="assigned-resources-tabs">
|
||||
<% if controller_name == "polls" %>
|
||||
<li class="active">
|
||||
<%= t("admin.polls.show.questions_tab") %>
|
||||
(<%= @poll.questions.count %>)
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<%= link_to admin_poll_path(@poll) do %>
|
||||
<%= t("admin.polls.show.questions_tab") %>
|
||||
(<%= @poll.questions.count %>)
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if controller_name == "booth_assignments" %>
|
||||
<li class="active">
|
||||
<%= t("admin.polls.show.booths_tab") %>
|
||||
(<%= @poll.booth_assignments.select(:booth_id).distinct.count %>)
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<%= link_to admin_poll_booth_assignments_path(@poll) do %>
|
||||
<%= t("admin.polls.show.booths_tab") %>
|
||||
(<%= @poll.booth_assignments.select(:booth_id).distinct.count %>)
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if controller_name == "officer_assignments" %>
|
||||
<li class="active">
|
||||
<%= t("admin.polls.show.officers_tab") %>
|
||||
(<%= @poll.officer_assignments.select(:officer_id).distinct.count %>)
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<%= link_to admin_poll_officer_assignments_path(@poll) do %>
|
||||
<%= t("admin.polls.show.officers_tab") %>
|
||||
(<%= @poll.officer_assignments.select(:officer_id).distinct.count %>)
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if controller_name == "recounts" %>
|
||||
<li class="active">
|
||||
<%= t("admin.polls.show.recounts_tab") %>
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<%= link_to t("admin.polls.show.recounts_tab"), admin_poll_recounts_path(@poll) %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% if controller_name == "results" %>
|
||||
<li class="active">
|
||||
<%= t("admin.polls.show.results_tab") %>
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<%= link_to t("admin.polls.show.results_tab"), admin_poll_results_path(@poll) %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
5
app/views/admin/poll/polls/edit.html.erb
Normal file
5
app/views/admin/poll/polls/edit.html.erb
Normal file
@@ -0,0 +1,5 @@
|
||||
<%= render 'shared/back_link' %>
|
||||
|
||||
<h2><%= t("admin.polls.edit.title") %></h2>
|
||||
|
||||
<%= render "form" %>
|
||||
22
app/views/admin/poll/polls/index.html.erb
Normal file
22
app/views/admin/poll/polls/index.html.erb
Normal file
@@ -0,0 +1,22 @@
|
||||
<h2 class="inline-block"><%= t("admin.polls.index.title") %></h2>
|
||||
|
||||
<%= link_to t("admin.polls.index.create"),
|
||||
new_admin_poll_path,
|
||||
class: "button success float-right" %>
|
||||
|
||||
<% if @polls.any? %>
|
||||
<table class="fixed">
|
||||
<thead>
|
||||
<th><%= t("admin.polls.index.name") %></th>
|
||||
<th><%= t("admin.polls.index.dates") %></th>
|
||||
<th><%= t("admin.actions.actions") %></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%= render @polls %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% else %>
|
||||
<div class="callout primary">
|
||||
<%= t("admin.polls.index.no_polls") %>
|
||||
</div>
|
||||
<% end %>
|
||||
5
app/views/admin/poll/polls/new.html.erb
Normal file
5
app/views/admin/poll/polls/new.html.erb
Normal file
@@ -0,0 +1,5 @@
|
||||
<%= render 'shared/back_link' %>
|
||||
|
||||
<h2><%= t("admin.polls.new.title") %></h2>
|
||||
|
||||
<%= render "form" %>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user