Merge branch 'master' into feature/1929#add_shift_task_usage
This commit is contained in:
2
Gemfile
2
Gemfile
@@ -59,7 +59,7 @@ end
|
|||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem "bullet", '~> 5.5.1'
|
gem "bullet", '~> 5.5.1'
|
||||||
gem 'byebug', '~> 9.0.6'
|
gem 'byebug', '~> 9.1.0'
|
||||||
gem 'factory_girl_rails', '~> 4.8.0'
|
gem 'factory_girl_rails', '~> 4.8.0'
|
||||||
gem "faker", '~> 1.7.3'
|
gem "faker", '~> 1.7.3'
|
||||||
gem 'i18n-tasks', '~> 0.9.15'
|
gem 'i18n-tasks', '~> 0.9.15'
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ GEM
|
|||||||
bullet (5.5.1)
|
bullet (5.5.1)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
uniform_notifier (~> 1.10.0)
|
uniform_notifier (~> 1.10.0)
|
||||||
byebug (9.0.6)
|
byebug (9.1.0)
|
||||||
cancancan (1.16.0)
|
cancancan (1.16.0)
|
||||||
capistrano (3.8.2)
|
capistrano (3.8.2)
|
||||||
airbrussh (>= 1.0.0)
|
airbrussh (>= 1.0.0)
|
||||||
@@ -494,7 +494,7 @@ DEPENDENCIES
|
|||||||
ancestry (~> 2.2.2)
|
ancestry (~> 2.2.2)
|
||||||
browser (~> 2.3.0)
|
browser (~> 2.3.0)
|
||||||
bullet (~> 5.5.1)
|
bullet (~> 5.5.1)
|
||||||
byebug (~> 9.0.6)
|
byebug (~> 9.1.0)
|
||||||
cancancan (~> 1.16.0)
|
cancancan (~> 1.16.0)
|
||||||
capistrano (~> 3.8.1)
|
capistrano (~> 3.8.1)
|
||||||
capistrano-bundler (~> 1.2)
|
capistrano-bundler (~> 1.2)
|
||||||
|
|||||||
Binary file not shown.
@@ -62,4 +62,5 @@
|
|||||||
<glyph glyph-name="expand" unicode="0" d="M26 168l-26-158c0-2 1-5 3-7 0 0 0 0 0 0 2-2 5-3 7-3l158 27c3 0 6 3 7 6 1 3 0 7-3 9l-30 31 82 82c4 4 4 9 0 13l-57 57c-3 3-9 3-12 0l-83-83-31 31c-2 2-5 3-9 2-3-1-5-4-6-7z m460 176l26 158c0 2-1 5-3 7 0 0 0 0 0 0-2 2-5 3-7 3l-158-27c-3 0-6-3-7-6-1-3 0-7 3-9l30-31-82-82c-4-4-4-9 0-13l57-57c3-3 9-3 12 0l83 83 31-31c2-2 5-3 9-2 3 1 5 4 6 7z"/>
|
<glyph glyph-name="expand" unicode="0" d="M26 168l-26-158c0-2 1-5 3-7 0 0 0 0 0 0 2-2 5-3 7-3l158 27c3 0 6 3 7 6 1 3 0 7-3 9l-30 31 82 82c4 4 4 9 0 13l-57 57c-3 3-9 3-12 0l-83-83-31 31c-2 2-5 3-9 2-3-1-5-4-6-7z m460 176l26 158c0 2-1 5-3 7 0 0 0 0 0 0-2 2-5 3-7 3l-158-27c-3 0-6-3-7-6-1-3 0-7 3-9l30-31-82-82c-4-4-4-9 0-13l57-57c3-3 9-3 12 0l83 83 31-31c2-2 5-3 9-2 3 1 5 4 6 7z"/>
|
||||||
<glyph glyph-name="telegram" unicode="1" d="M504 509c6-5 9-11 8-18l-73-439c-1-6-4-10-10-13-2-2-5-2-8-2-3 0-5 0-7 1l-130 53-69-84c-3-5-8-7-14-7-2 0-4 0-6 1-4 1-7 4-9 7-2 3-3 6-3 10l0 100 247 303-306-265-113 47c-7 2-10 7-11 15 0 8 3 14 9 17l476 274c2 2 5 3 9 3 4 0 7-1 10-3z"/>
|
<glyph glyph-name="telegram" unicode="1" d="M504 509c6-5 9-11 8-18l-73-439c-1-6-4-10-10-13-2-2-5-2-8-2-3 0-5 0-7 1l-130 53-69-84c-3-5-8-7-14-7-2 0-4 0-6 1-4 1-7 4-9 7-2 3-3 6-3 10l0 100 247 303-306-265-113 47c-7 2-10 7-11 15 0 8 3 14 9 17l476 274c2 2 5 3 9 3 4 0 7-1 10-3z"/>
|
||||||
<glyph glyph-name="instagram" unicode="2" d="M426 105l0 185-39 0c4-12 6-25 6-38 0-24-6-46-18-66-13-20-29-36-50-48-21-12-44-18-69-18-37 0-69 13-96 39-27 26-40 57-40 93 0 13 2 26 6 38l-41 0 0-185c0-5 2-10 5-13 4-3 8-5 13-5l305 0c5 0 9 2 13 5 3 3 5 8 5 13z m-81 152c0 23-9 44-26 60-18 17-38 25-63 25-24 0-45-8-62-25-17-16-26-37-26-60 0-24 9-44 26-61 17-16 38-25 62-25 25 0 45 9 63 25 17 17 26 37 26 61z m81 103l0 47c0 5-2 10-6 14-4 4-8 6-14 6l-50 0c-5 0-10-2-14-6-4-4-5-9-5-14l0-47c0-6 1-10 5-14 4-4 9-6 14-6l50 0c6 0 10 2 14 6 4 4 6 8 6 14z m49 59l0-326c0-16-5-29-16-40-11-11-24-16-40-16l-326 0c-16 0-29 5-40 16-11 11-16 24-16 40l0 326c0 16 5 29 16 40 11 11 24 16 40 16l326 0c16 0 29-5 40-16 11-11 16-24 16-40z"/>
|
<glyph glyph-name="instagram" unicode="2" d="M426 105l0 185-39 0c4-12 6-25 6-38 0-24-6-46-18-66-13-20-29-36-50-48-21-12-44-18-69-18-37 0-69 13-96 39-27 26-40 57-40 93 0 13 2 26 6 38l-41 0 0-185c0-5 2-10 5-13 4-3 8-5 13-5l305 0c5 0 9 2 13 5 3 3 5 8 5 13z m-81 152c0 23-9 44-26 60-18 17-38 25-63 25-24 0-45-8-62-25-17-16-26-37-26-60 0-24 9-44 26-61 17-16 38-25 62-25 25 0 45 9 63 25 17 17 26 37 26 61z m81 103l0 47c0 5-2 10-6 14-4 4-8 6-14 6l-50 0c-5 0-10-2-14-6-4-4-5-9-5-14l0-47c0-6 1-10 5-14 4-4 9-6 14-6l50 0c6 0 10 2 14 6 4 4 6 8 6 14z m49 59l0-326c0-16-5-29-16-40-11-11-24-16-40-16l-326 0c-16 0-29 5-40 16-11 11-16 24-16 40l0 326c0 16 5 29 16 40 11 11 24 16 40 16l326 0c16 0 29-5 40-16 11-11 16-24 16-40z"/>
|
||||||
|
<glyph glyph-name="image" unicode="3" d="M165 347c0-15-6-28-16-38-11-11-24-16-39-16-16 0-28 5-39 16-11 10-16 23-16 38 0 16 5 29 16 39 11 11 23 16 39 16 15 0 28-5 39-16 10-10 16-23 16-39z m292-109l0-128-402 0 0 55 91 91 46-46 146 147z m28 201l-458 0c-2 0-4-1-6-3-2-2-3-4-3-6l0-348c0-2 1-4 3-6 2-2 4-3 6-3l458 0c2 0 4 1 6 3 2 2 3 4 3 6l0 348c0 2-1 4-3 6-2 2-4 3-6 3z m45-9l0-348c0-12-4-23-13-32-9-9-20-13-32-13l-458 0c-12 0-23 4-32 13-9 9-13 20-13 32l0 348c0 12 4 23 13 32 9 9 20 13 32 13l458 0c12 0 23-4 32-13 9-9 13-20 13-32z"/>
|
||||||
</font></defs></svg>
|
</font></defs></svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 29 KiB |
Binary file not shown.
Binary file not shown.
@@ -411,7 +411,7 @@ $maincontent-shadow: 0 0 10px rgba($black, 0.5);
|
|||||||
|
|
||||||
$orbit-bullet-background: $medium-gray;
|
$orbit-bullet-background: $medium-gray;
|
||||||
$orbit-bullet-background-active: $dark-gray;
|
$orbit-bullet-background-active: $dark-gray;
|
||||||
$orbit-bullet-diameter: 1.2rem;
|
$orbit-bullet-diameter: 0.8rem;
|
||||||
$orbit-bullet-margin: 0.1rem;
|
$orbit-bullet-margin: 0.1rem;
|
||||||
$orbit-bullet-margin-top: 0.8rem;
|
$orbit-bullet-margin-top: 0.8rem;
|
||||||
$orbit-bullet-margin-bottom: 0.8rem;
|
$orbit-bullet-margin-bottom: 0.8rem;
|
||||||
|
|||||||
@@ -97,10 +97,6 @@
|
|||||||
content: '\72';
|
content: '\72';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-documents::before {
|
|
||||||
content: '\68';
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-proposals::before {
|
.icon-proposals::before {
|
||||||
content: '\68';
|
content: '\68';
|
||||||
}
|
}
|
||||||
@@ -197,10 +193,6 @@
|
|||||||
content: '\53';
|
content: '\53';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-image::before {
|
|
||||||
content: '\68';
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-notification::before {
|
.icon-notification::before {
|
||||||
content: '\6e';
|
content: '\6e';
|
||||||
}
|
}
|
||||||
@@ -264,3 +256,7 @@
|
|||||||
.icon-instagram::before {
|
.icon-instagram::before {
|
||||||
content: '\32';
|
content: '\32';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-image::before {
|
||||||
|
content: '\33';
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
// 16. Flags
|
// 16. Flags
|
||||||
// 17. Activity
|
// 17. Activity
|
||||||
// 18. Banners
|
// 18. Banners
|
||||||
// 19. Documents
|
// 19. Recommended Section Home
|
||||||
|
// 20. Documents
|
||||||
//
|
//
|
||||||
|
|
||||||
// 01. Global styles
|
// 01. Global styles
|
||||||
@@ -341,10 +342,30 @@ a {
|
|||||||
background: $brand;
|
background: $brand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.truncate-horizontal-text {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
-o-text-overflow: ellipsis;
|
||||||
|
-ms-text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
.align-top {
|
.align-top {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.aling-middle {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
display: table;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-cell {
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
// 02. Header
|
// 02. Header
|
||||||
// ----------
|
// ----------
|
||||||
|
|
||||||
@@ -612,7 +633,7 @@ header {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
@include breakpoint(medium) {
|
@include breakpoint(medium) {
|
||||||
margin-right: $line-height * 1.5;
|
margin-right: rem-calc(24);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@@ -2161,6 +2182,142 @@ table {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 19. Recommended Section Home
|
||||||
|
// -----------
|
||||||
|
|
||||||
|
.home-page {
|
||||||
|
.push {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-recommended {
|
||||||
|
padding: $line-height * 2 0;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-bottom: $line-height * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debates,
|
||||||
|
.proposals,
|
||||||
|
.budget-investments {
|
||||||
|
|
||||||
|
@include breakpoint(medium) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include breakpoint(small) {
|
||||||
|
margin-bottom: $line-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.hollow {
|
||||||
|
margin-top: rem-calc(15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
|
||||||
|
.card-section {
|
||||||
|
padding: $line-height 0;
|
||||||
|
max-width: 300px;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: rem-calc(15);
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.orbit {
|
||||||
|
height: 300px;
|
||||||
|
|
||||||
|
.orbit-wrapper {
|
||||||
|
max-height: 250px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orbit-bullets {
|
||||||
|
@include orbit-bullets;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card .orbit .orbit-wrapper .truncate {
|
||||||
|
background: image-url('truncate.png');
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
bottom: 0;
|
||||||
|
height: 20px;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debates-inner {
|
||||||
|
border-top: 4px solid $debates;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proposals-inner {
|
||||||
|
border-top: 4px solid $proposals;
|
||||||
|
}
|
||||||
|
|
||||||
|
.budget-investments-inner {
|
||||||
|
border-top: 4px solid $budget;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debates-inner,
|
||||||
|
.proposals-inner,
|
||||||
|
.budget-investments-inner {
|
||||||
|
background: #fff;
|
||||||
|
max-height: 350px;
|
||||||
|
|
||||||
|
@include breakpoint(small) {
|
||||||
|
max-height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin-top: $line-height;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-size: rem-calc(18);
|
||||||
|
min-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: rem-calc(14);
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-image {
|
||||||
|
|
||||||
|
.card .orbit {
|
||||||
|
height: 480px;
|
||||||
|
|
||||||
|
.orbit-wrapper {
|
||||||
|
max-height: 450px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.debates-inner,
|
||||||
|
.proposals-inner,
|
||||||
|
.budget-investments-inner {
|
||||||
|
max-height: 500px;
|
||||||
|
|
||||||
|
@include breakpoint(small) {
|
||||||
|
max-height: 600px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.carousel-image .orbit-wrapper img {
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
@include breakpoint(small) {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 19. Documents
|
// 19. Documents
|
||||||
.documents-list {
|
.documents-list {
|
||||||
|
|
||||||
@@ -2218,6 +2375,5 @@ table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Table of Contents
|
// Table of Contents
|
||||||
//
|
//
|
||||||
// 01. Logo
|
// 01. Logo
|
||||||
|
// 02. Orbit bullets
|
||||||
//
|
//
|
||||||
|
|
||||||
// 01. Logo
|
// 01. Logo
|
||||||
@@ -31,12 +32,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 02. Orbit bullet
|
||||||
|
// ----------------
|
||||||
|
@mixin orbit-bullets {
|
||||||
|
@include disable-mouse-outline;
|
||||||
|
position: relative;
|
||||||
|
margin-top: $orbit-bullet-margin-top;
|
||||||
|
margin-bottom: $orbit-bullet-margin-bottom;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: $orbit-bullet-diameter;
|
||||||
|
height: $orbit-bullet-diameter;
|
||||||
|
margin: $orbit-bullet-margin;
|
||||||
|
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: $orbit-bullet-background;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $orbit-bullet-background-active;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
background-color: $orbit-bullet-background-active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 02. Direct uploads
|
||||||
|
// ------------------
|
||||||
@mixin direct-uploads {
|
@mixin direct-uploads {
|
||||||
|
|
||||||
.cached-image {
|
.cached-image {
|
||||||
max-width: 150px;
|
max-width: rem-calc(150);
|
||||||
max-height: 150px;
|
max-height: rem-calc(150);
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-bar-placeholder {
|
.progress-bar-placeholder {
|
||||||
@@ -49,15 +78,23 @@
|
|||||||
|
|
||||||
.document-attachment,
|
.document-attachment,
|
||||||
.image-attachment {
|
.image-attachment {
|
||||||
padding-left:0;
|
padding-left: 0;
|
||||||
|
|
||||||
p{
|
p {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
input.js-document-attachment,
|
|
||||||
input.js-image-attachment{
|
.attachment-errors {
|
||||||
display: none;
|
|
||||||
|
> .js-image-attachment,
|
||||||
|
> .js-document-attachment {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
~ .error {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,4 +133,5 @@
|
|||||||
.loading-bar.no-transition {
|
.loading-bar.no-transition {
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,7 +255,6 @@
|
|||||||
.icon-debates,
|
.icon-debates,
|
||||||
.icon-proposals,
|
.icon-proposals,
|
||||||
.icon-budget,
|
.icon-budget,
|
||||||
.icon-documents,
|
|
||||||
.icon-image {
|
.icon-image {
|
||||||
font-size: rem-calc(50);
|
font-size: rem-calc(50);
|
||||||
line-height: $line-height;
|
line-height: $line-height;
|
||||||
@@ -267,7 +266,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.icon-proposals,
|
.icon-proposals,
|
||||||
.icon-documents,
|
|
||||||
.icon-image {
|
.icon-image {
|
||||||
color: $proposals;
|
color: $proposals;
|
||||||
}
|
}
|
||||||
@@ -312,12 +310,10 @@
|
|||||||
.budget-investment-new,
|
.budget-investment-new,
|
||||||
.proposal-form,
|
.proposal-form,
|
||||||
.proposal-edit,
|
.proposal-edit,
|
||||||
.new_poll_question,
|
.poll-question-form {
|
||||||
.edit_poll_question {
|
|
||||||
@include direct-uploads;
|
@include direct-uploads;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 03. Show participation
|
// 03. Show participation
|
||||||
// ----------------------
|
// ----------------------
|
||||||
|
|
||||||
@@ -358,8 +354,7 @@
|
|||||||
width: rem-calc(48);
|
width: rem-calc(48);
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-debate,
|
.edit-debate {
|
||||||
.edit-proposal {
|
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,20 +656,17 @@
|
|||||||
.proposals-list .proposal {
|
.proposals-list .proposal {
|
||||||
|
|
||||||
@include breakpoint(small) {
|
@include breakpoint(small) {
|
||||||
|
|
||||||
.no-image {
|
.no-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 300px;
|
max-width: rem-calc(300);
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
|
||||||
|
|
||||||
.no-image::before {
|
&::before {
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
padding-top: 100%;
|
padding-top: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.3rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.column:first-child {
|
.column:first-child {
|
||||||
@@ -683,19 +675,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@include breakpoint(medium) {
|
@include breakpoint(medium) {
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
padding: 0 0.75rem 0 0;
|
padding: 0 $line-height / 2 0 0;
|
||||||
|
|
||||||
.no-image {
|
.no-image {
|
||||||
height: 245px;
|
height: 100%;
|
||||||
width: 140px;
|
min-height: rem-calc(245);
|
||||||
|
width: rem-calc(140);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.column:first-child {
|
.column:first-child {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
@@ -705,7 +695,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.column:last-child:not(:first-child) {
|
.column:last-child:not(:first-child) {
|
||||||
padding-top: 0.75rem;
|
padding-top: $line-height / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
@@ -1701,9 +1691,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.section-title-divider {
|
.section-title-divider {
|
||||||
border-bottom: 2px solid $brand;
|
border-bottom: 1px solid #eee;
|
||||||
color: $brand;
|
color: #000;
|
||||||
margin-bottom: $line-height;
|
margin: $line-height 0;
|
||||||
|
|
||||||
|
span {
|
||||||
|
border-bottom: 1px solid #000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.poll-question {
|
.poll-question {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class Admin::Poll::BoothAssignmentsController < Admin::Poll::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@booth_assignment = @poll.booth_assignments.includes(:total_results, :voters,
|
@booth_assignment = @poll.booth_assignments.includes(:recounts, :voters,
|
||||||
officer_assignments: [officer: [:user]]).find(params[:id])
|
officer_assignments: [officer: [:user]]).find(params[:id])
|
||||||
@voters_by_date = @booth_assignment.voters.group_by {|v| v.created_at.to_date}
|
@voters_by_date = @booth_assignment.voters.group_by {|v| v.created_at.to_date}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class Admin::Poll::OfficerAssignmentsController < Admin::Poll::BaseController
|
|||||||
@officer = ::Poll::Officer.includes(:user).find(officer_assignment_params[:officer_id])
|
@officer = ::Poll::Officer.includes(:user).find(officer_assignment_params[:officer_id])
|
||||||
@officer_assignments = ::Poll::OfficerAssignment.
|
@officer_assignments = ::Poll::OfficerAssignment.
|
||||||
joins(:booth_assignment).
|
joins(:booth_assignment).
|
||||||
includes(:total_results, booth_assignment: :booth).
|
includes(:recounts, booth_assignment: :booth).
|
||||||
where("officer_id = ? AND poll_booth_assignments.poll_id = ?", @officer.id, @poll.id).
|
where("officer_id = ? AND poll_booth_assignments.poll_id = ?", @officer.id, @poll.id).
|
||||||
order(:date)
|
order(:date)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ class Admin::Poll::RecountsController < Admin::Poll::BaseController
|
|||||||
|
|
||||||
def index
|
def index
|
||||||
@booth_assignments = @poll.booth_assignments.
|
@booth_assignments = @poll.booth_assignments.
|
||||||
includes(:booth, :total_results, :voters).
|
includes(:booth, :recounts, :voters).
|
||||||
order("poll_booths.name").
|
order("poll_booths.name").
|
||||||
page(params[:page]).per(50)
|
page(params[:page]).per(50)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,17 +4,22 @@ module CommentableActions
|
|||||||
include Search
|
include Search
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@resources = @search_terms.present? ? resource_model.search(@search_terms) : resource_model.all
|
@resources = resource_model.all
|
||||||
@resources = @advanced_search_terms.present? ? @resources.filter(@advanced_search_terms) : @resources
|
|
||||||
|
|
||||||
|
@resources = @current_order == "recommendations" && current_user.present? ? @resources.recommendations(current_user) : @resources.for_render
|
||||||
|
@resources = @resources.search(@search_terms) if @search_terms.present?
|
||||||
|
@resources = @advanced_search_terms.present? ? @resources.filter(@advanced_search_terms) : @resources
|
||||||
@resources = @resources.tagged_with(@tag_filter) if @tag_filter
|
@resources = @resources.tagged_with(@tag_filter) if @tag_filter
|
||||||
@resources = @resources.page(params[:page]).for_render.send("sort_by_#{@current_order}")
|
|
||||||
|
@resources = @resources.page(params[:page]).send("sort_by_#{@current_order}")
|
||||||
|
|
||||||
index_customization if index_customization.present?
|
index_customization if index_customization.present?
|
||||||
|
|
||||||
@tag_cloud = tag_cloud
|
@tag_cloud = tag_cloud
|
||||||
@banners = Banner.with_active
|
@banners = Banner.with_active
|
||||||
|
|
||||||
set_resource_votes(@resources)
|
set_resource_votes(@resources)
|
||||||
|
|
||||||
set_resources_instance
|
set_resources_instance
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class DebatesController < ApplicationController
|
|||||||
|
|
||||||
invisible_captcha only: [:create, :update], honeypot: :subtitle
|
invisible_captcha only: [:create, :update], honeypot: :subtitle
|
||||||
|
|
||||||
has_orders %w{hot_score confidence_score created_at relevance}, only: :index
|
has_orders ->(c) { Debate.debates_orders(c.current_user) }, only: :index
|
||||||
has_orders %w{most_voted newest oldest}, only: :show
|
has_orders %w{most_voted newest oldest}, only: :show
|
||||||
|
|
||||||
load_and_authorize_resource
|
load_and_authorize_resource
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class NotificationsController < ApplicationController
|
|||||||
|
|
||||||
def show
|
def show
|
||||||
@notification = current_user.notifications.find(params[:id])
|
@notification = current_user.notifications.find(params[:id])
|
||||||
redirect_to url_for(@notification.linkable_resource)
|
redirect_to linkable_resource_path(@notification)
|
||||||
end
|
end
|
||||||
|
|
||||||
def mark_all_as_read
|
def mark_all_as_read
|
||||||
@@ -25,4 +25,13 @@ class NotificationsController < ApplicationController
|
|||||||
@notification.mark_as_read
|
@notification.mark_as_read
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def linkable_resource_path(notification)
|
||||||
|
case notification.linkable_resource.class.name
|
||||||
|
when "Budget::Investment"
|
||||||
|
budget_investment_path @notification.linkable_resource.budget, @notification.linkable_resource
|
||||||
|
else
|
||||||
|
url_for @notification.linkable_resource
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -26,9 +26,7 @@ class Officing::ResultsController < Officing::BaseController
|
|||||||
@partial_results = ::Poll::PartialResult.includes(:question).
|
@partial_results = ::Poll::PartialResult.includes(:question).
|
||||||
where(booth_assignment_id: index_params[:booth_assignment_id]).
|
where(booth_assignment_id: index_params[:booth_assignment_id]).
|
||||||
where(date: index_params[:date])
|
where(date: index_params[:date])
|
||||||
@whites = ::Poll::WhiteResult.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date]).sum(:amount)
|
@recounts = ::Poll::Recount.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date])
|
||||||
@nulls = ::Poll::NullResult.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date]).sum(:amount)
|
|
||||||
@total = ::Poll::TotalResult.where(booth_assignment_id: @booth_assignment.id, date: index_params[:date]).sum(:amount)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -52,14 +50,14 @@ class Officing::ResultsController < Officing::BaseController
|
|||||||
go_back_to_new if question.blank?
|
go_back_to_new if question.blank?
|
||||||
|
|
||||||
results.each_pair do |answer_index, count|
|
results.each_pair do |answer_index, count|
|
||||||
next unless count.present?
|
next if count.blank?
|
||||||
answer = question.valid_answers[answer_index.to_i]
|
answer = question.valid_answers[answer_index.to_i]
|
||||||
go_back_to_new if question.blank?
|
go_back_to_new if question.blank?
|
||||||
|
|
||||||
partial_result = ::Poll::PartialResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
|
partial_result = ::Poll::PartialResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
|
||||||
date: results_params[:date],
|
date: results_params[:date],
|
||||||
question_id: question_id,
|
question_id: question_id,
|
||||||
answer: answer)
|
answer: answer)
|
||||||
partial_result.officer_assignment_id = @officer_assignment.id
|
partial_result.officer_assignment_id = @officer_assignment.id
|
||||||
partial_result.amount = count.to_i
|
partial_result.amount = count.to_i
|
||||||
partial_result.author = current_user
|
partial_result.author = current_user
|
||||||
@@ -68,45 +66,21 @@ class Officing::ResultsController < Officing::BaseController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
build_white_results
|
build_recounts
|
||||||
build_null_results
|
|
||||||
build_total_results
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_white_results
|
def build_recounts
|
||||||
if results_params[:whites].present?
|
recount = ::Poll::Recount.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
|
||||||
white_result = ::Poll::WhiteResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
|
date: results_params[:date])
|
||||||
date: results_params[:date])
|
recount.officer_assignment_id = @officer_assignment.id
|
||||||
white_result.officer_assignment_id = @officer_assignment.id
|
recount.author = current_user
|
||||||
white_result.amount = results_params[:whites].to_i
|
recount.origin = 'booth'
|
||||||
white_result.author = current_user
|
[:whites, :nulls, :total].each do |recount_type|
|
||||||
white_result.origin = 'booth'
|
if results_params[recount_type].present?
|
||||||
@results << white_result
|
recount["#{recount_type.to_s.singularize}_amount"] = results_params[recount_type].to_i
|
||||||
end
|
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 build_total_results
|
|
||||||
if results_params[:total].present?
|
|
||||||
total_result = ::Poll::TotalResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
|
|
||||||
date: results_params[:date])
|
|
||||||
total_result.officer_assignment_id = @officer_assignment.id
|
|
||||||
total_result.amount = results_params[:total].to_i
|
|
||||||
total_result.author = current_user
|
|
||||||
total_result.origin = 'booth'
|
|
||||||
@results << total_result
|
|
||||||
end
|
end
|
||||||
|
@results << recount
|
||||||
end
|
end
|
||||||
|
|
||||||
def go_back_to_new(alert = nil)
|
def go_back_to_new(alert = nil)
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ class Officing::VotersController < Officing::BaseController
|
|||||||
@voter = Poll::Voter.new(document_type: @user.document_type,
|
@voter = Poll::Voter.new(document_type: @user.document_type,
|
||||||
document_number: @user.document_number,
|
document_number: @user.document_number,
|
||||||
user: @user,
|
user: @user,
|
||||||
poll: @poll)
|
poll: @poll,
|
||||||
|
origin: "booth")
|
||||||
@voter.save!
|
@voter.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class ProposalsController < ApplicationController
|
|||||||
|
|
||||||
invisible_captcha only: [:create, :update], honeypot: :subtitle
|
invisible_captcha only: [:create, :update], honeypot: :subtitle
|
||||||
|
|
||||||
has_orders %w{hot_score confidence_score created_at relevance archival_date}, only: :index
|
has_orders ->(c) { Proposal.proposals_orders(c.current_user) }, only: :index
|
||||||
has_orders %w{most_voted newest oldest}, only: :show
|
has_orders %w{most_voted newest oldest}, only: :show
|
||||||
|
|
||||||
load_and_authorize_resource
|
load_and_authorize_resource
|
||||||
@@ -113,7 +113,7 @@ class ProposalsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def load_featured
|
def load_featured
|
||||||
return unless !@advanced_search_terms && @search_terms.blank? && @tag_filter.blank? && params[:retired].blank?
|
return unless !@advanced_search_terms && @search_terms.blank? && @tag_filter.blank? && params[:retired].blank? && @current_order != "recommendations"
|
||||||
@featured_proposals = Proposal.not_archived.sort_by_confidence_score.limit(3)
|
@featured_proposals = Proposal.not_archived.sort_by_confidence_score.limit(3)
|
||||||
if @featured_proposals.present?
|
if @featured_proposals.present?
|
||||||
set_featured_proposal_votes(@featured_proposals)
|
set_featured_proposal_votes(@featured_proposals)
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
class WelcomeController < ApplicationController
|
class WelcomeController < ApplicationController
|
||||||
skip_authorization_check
|
skip_authorization_check
|
||||||
|
before_action :set_user_recommendations, only: :index, if: :current_user
|
||||||
|
|
||||||
layout "devise", only: [:welcome, :verification]
|
layout "devise", only: [:welcome, :verification]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
if current_user
|
|
||||||
redirect_to :proposals
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def welcome
|
def welcome
|
||||||
@@ -16,4 +14,11 @@ class WelcomeController < ApplicationController
|
|||||||
redirect_to verification_path if signed_in?
|
redirect_to verification_path if signed_in?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_user_recommendations
|
||||||
|
@recommended_debates = Debate.recommendations(current_user).sort_by_recommendations.limit(3)
|
||||||
|
@recommended_proposals = Proposal.recommendations(current_user).sort_by_recommendations.limit(3)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,4 +4,12 @@ module DebatesHelper
|
|||||||
Debate.all.featured.count > 0
|
Debate.all.featured.count > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def empty_recommended_debates_message_text(user)
|
||||||
|
if user.interests.any?
|
||||||
|
t('debates.index.recommendations.without_results')
|
||||||
|
else
|
||||||
|
t('debates.index.recommendations.without_interests')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
module PollRecountsHelper
|
module PollRecountsHelper
|
||||||
|
|
||||||
def total_recounts_by_booth(booth_assignment)
|
def total_recounts_by_booth(booth_assignment)
|
||||||
booth_assignment.total_results.any? ? booth_assignment.total_results.to_a.sum(&:amount) : nil
|
booth_assignment.recounts.any? ? booth_assignment.recounts.to_a.sum(&:total_amount) : nil
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -32,6 +32,14 @@ module ProposalsHelper
|
|||||||
Proposal::RETIRE_OPTIONS.collect { |option| [ t("proposals.retire_options.#{option}"), option ] }
|
Proposal::RETIRE_OPTIONS.collect { |option| [ t("proposals.retire_options.#{option}"), option ] }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def empty_recommended_proposals_message_text(user)
|
||||||
|
if user.interests.any?
|
||||||
|
t('proposals.index.recommendations.without_results')
|
||||||
|
else
|
||||||
|
t('proposals.index.recommendations.without_interests')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def author_of_proposal?(proposal)
|
def author_of_proposal?(proposal)
|
||||||
author_of?(proposal, current_user)
|
author_of?(proposal, current_user)
|
||||||
end
|
end
|
||||||
|
|||||||
62
app/helpers/welcome_helper.rb
Normal file
62
app/helpers/welcome_helper.rb
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
module WelcomeHelper
|
||||||
|
|
||||||
|
def active_class(index)
|
||||||
|
"is-active is-in" if index == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def slide_display(index)
|
||||||
|
"display: none;" if index > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def recommended_path(recommended)
|
||||||
|
case recommended.class.name
|
||||||
|
when "Debate"
|
||||||
|
debate_path(recommended)
|
||||||
|
when "Proposal"
|
||||||
|
proposal_path(recommended)
|
||||||
|
else
|
||||||
|
'#'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_recommendation_image(recommended, image_default)
|
||||||
|
image_path = calculate_image_path(recommended, image_default)
|
||||||
|
image_tag(image_path) if image_path.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculate_image_path(recommended, image_default)
|
||||||
|
if recommended.try(:image) && recommended.image.present? && recommended.image.attachment.exists?
|
||||||
|
recommended.image.attachment.send("url", :medium)
|
||||||
|
elsif image_default.present?
|
||||||
|
image_default
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculate_carousel_size(debates, proposals, apply_offset)
|
||||||
|
offset = calculate_offset(debates, proposals, apply_offset)
|
||||||
|
centered = calculate_centered(debates, proposals)
|
||||||
|
"#{offset if offset} #{centered if centered}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculate_centered(debates, proposals)
|
||||||
|
if (debates.blank? && proposals.any?) ||
|
||||||
|
(debates.any? && proposals.blank?)
|
||||||
|
centered = "medium-centered large-centered"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculate_offset(debates, proposals, apply_offset)
|
||||||
|
if (debates.any? && proposals.any?)
|
||||||
|
if apply_offset
|
||||||
|
offset = "medium-offset-2 large-offset-2"
|
||||||
|
else
|
||||||
|
offset = "end"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def highlight_background
|
||||||
|
(feature?("user.recommendations") && current_user) ? "highlight" : ""
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -45,7 +45,7 @@ module Abilities
|
|||||||
|
|
||||||
can [:read, :update, :valuate, :destroy, :summary], SpendingProposal
|
can [:read, :update, :valuate, :destroy, :summary], SpendingProposal
|
||||||
|
|
||||||
can [:index, :read, :new, :create, :update, :destroy, :calculate_winners], Budget
|
can [:index, :read, :new, :create, :update, :destroy, :calculate_winners, :read_results], Budget
|
||||||
can [:read, :create, :update, :destroy], Budget::Group
|
can [:read, :create, :update, :destroy], Budget::Group
|
||||||
can [:read, :create, :update, :destroy], Budget::Heading
|
can [:read, :create, :update, :destroy], Budget::Heading
|
||||||
can [:hide, :update, :toggle_selection], Budget::Investment
|
can [:hide, :update, :toggle_selection], Budget::Investment
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ module Followable
|
|||||||
included do
|
included do
|
||||||
has_many :follows, as: :followable, dependent: :destroy
|
has_many :follows, as: :followable, dependent: :destroy
|
||||||
has_many :followers, through: :follows, source: :user
|
has_many :followers, through: :follows, source: :user
|
||||||
|
|
||||||
|
scope :followed_by_user, -> (user){
|
||||||
|
joins(:follows).where("follows.user_id = ?", user.id)
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def followed_by?(user)
|
def followed_by?(user)
|
||||||
|
|||||||
@@ -37,14 +37,21 @@ class Debate < ActiveRecord::Base
|
|||||||
scope :sort_by_random, -> { reorder("RANDOM()") }
|
scope :sort_by_random, -> { reorder("RANDOM()") }
|
||||||
scope :sort_by_relevance, -> { all }
|
scope :sort_by_relevance, -> { all }
|
||||||
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
||||||
|
scope :sort_by_recommendations, -> { order(cached_votes_total: :desc) }
|
||||||
scope :last_week, -> { where("created_at >= ?", 7.days.ago)}
|
scope :last_week, -> { where("created_at >= ?", 7.days.ago)}
|
||||||
scope :featured, -> { where("featured_at is not null")}
|
scope :featured, -> { where("featured_at is not null")}
|
||||||
scope :public_for_api, -> { all }
|
scope :public_for_api, -> { all }
|
||||||
|
|
||||||
# Ahoy setup
|
# Ahoy setup
|
||||||
visitable # Ahoy will automatically assign visit_id on create
|
visitable # Ahoy will automatically assign visit_id on create
|
||||||
|
|
||||||
attr_accessor :link_required
|
attr_accessor :link_required
|
||||||
|
|
||||||
|
def self.recommendations(user)
|
||||||
|
tagged_with(user.interests, any: true).
|
||||||
|
where("author_id != ?", user.id)
|
||||||
|
end
|
||||||
|
|
||||||
def searchable_values
|
def searchable_values
|
||||||
{ title => 'A',
|
{ title => 'A',
|
||||||
author.username => 'B',
|
author.username => 'B',
|
||||||
@@ -135,4 +142,9 @@ class Debate < ActiveRecord::Base
|
|||||||
featured_at.present?
|
featured_at.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.debates_orders(user)
|
||||||
|
orders = %w{hot_score confidence_score created_at relevance}
|
||||||
|
orders << "recommendations" if user.present?
|
||||||
|
orders
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ class Poll < ActiveRecord::Base
|
|||||||
has_many :booth_assignments, class_name: "Poll::BoothAssignment"
|
has_many :booth_assignments, class_name: "Poll::BoothAssignment"
|
||||||
has_many :booths, through: :booth_assignments
|
has_many :booths, through: :booth_assignments
|
||||||
has_many :partial_results, through: :booth_assignments
|
has_many :partial_results, through: :booth_assignments
|
||||||
has_many :white_results, through: :booth_assignments
|
has_many :recounts, through: :booth_assignments
|
||||||
has_many :null_results, through: :booth_assignments
|
|
||||||
has_many :total_results, through: :booth_assignments
|
|
||||||
has_many :voters
|
has_many :voters
|
||||||
has_many :officer_assignments, through: :booth_assignments
|
has_many :officer_assignments, through: :booth_assignments
|
||||||
has_many :officers, through: :officer_assignments
|
has_many :officers, through: :officer_assignments
|
||||||
@@ -61,6 +59,10 @@ class Poll < ActiveRecord::Base
|
|||||||
voters.where(document_number: document_number, document_type: document_type).exists?
|
voters.where(document_number: document_number, document_type: document_type).exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def voted_in_booth?(user)
|
||||||
|
Poll::Voter.where(poll: self, user: user, origin: "booth").exists?
|
||||||
|
end
|
||||||
|
|
||||||
def date_range
|
def date_range
|
||||||
unless starts_at.present? && ends_at.present? && starts_at <= ends_at
|
unless starts_at.present? && ends_at.present? && starts_at <= ends_at
|
||||||
errors.add(:starts_at, I18n.t('errors.messages.invalid_date_range'))
|
errors.add(:starts_at, I18n.t('errors.messages.invalid_date_range'))
|
||||||
|
|||||||
@@ -8,12 +8,13 @@ class Poll::Answer < ActiveRecord::Base
|
|||||||
validates :question, presence: true
|
validates :question, presence: true
|
||||||
validates :author, presence: true
|
validates :author, presence: true
|
||||||
validates :answer, presence: true
|
validates :answer, presence: true
|
||||||
validates :answer, inclusion: {in: ->(a) { a.question.valid_answers }}
|
validates :answer, inclusion: { in: ->(a) { a.question.valid_answers }},
|
||||||
|
unless: ->(a) { a.question.blank? }
|
||||||
|
|
||||||
scope :by_author, ->(author_id) { where(author_id: author_id) }
|
scope :by_author, ->(author_id) { where(author_id: author_id) }
|
||||||
scope :by_question, ->(question_id) { where(question_id: question_id) }
|
scope :by_question, ->(question_id) { where(question_id: question_id) }
|
||||||
|
|
||||||
def record_voter_participation
|
def record_voter_participation
|
||||||
Poll::Voter.create!(user: author, poll: poll)
|
Poll::Voter.find_or_create_by!(user: author, poll: poll, origin: "web")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -7,8 +7,6 @@ class Poll
|
|||||||
has_many :officers, through: :officer_assignments
|
has_many :officers, through: :officer_assignments
|
||||||
has_many :voters
|
has_many :voters
|
||||||
has_many :partial_results
|
has_many :partial_results
|
||||||
has_many :white_results
|
has_many :recounts
|
||||||
has_many :null_results
|
|
||||||
has_many :total_results
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ class Poll
|
|||||||
belongs_to :officer
|
belongs_to :officer
|
||||||
belongs_to :booth_assignment
|
belongs_to :booth_assignment
|
||||||
has_many :partial_results
|
has_many :partial_results
|
||||||
has_many :white_results
|
has_many :recounts
|
||||||
has_many :null_results
|
|
||||||
has_many :total_results
|
|
||||||
has_many :voters
|
has_many :voters
|
||||||
|
|
||||||
validates :officer_id, presence: true
|
validates :officer_id, presence: true
|
||||||
|
|||||||
36
app/models/poll/recount.rb
Normal file
36
app/models/poll/recount.rb
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
class Poll::Recount < ActiveRecord::Base
|
||||||
|
|
||||||
|
VALID_ORIGINS = %w{web booth letter}.freeze
|
||||||
|
|
||||||
|
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 :web, -> { where(origin: 'web') }
|
||||||
|
scope :booth, -> { where(origin: 'booth') }
|
||||||
|
scope :letter, -> { where(origin: 'letter') }
|
||||||
|
|
||||||
|
scope :by_author, ->(author_id) { where(author_id: author_id) }
|
||||||
|
|
||||||
|
before_save :update_logs
|
||||||
|
|
||||||
|
def update_logs
|
||||||
|
amounts_changed = false
|
||||||
|
|
||||||
|
[:white, :null, :total].each do |amount|
|
||||||
|
next unless send("#{amount}_amount_changed?") && send("#{amount}_amount_was").present?
|
||||||
|
self["#{amount}_amount_log"] += ":#{send("#{amount}_amount_was")}"
|
||||||
|
amounts_changed = true
|
||||||
|
end
|
||||||
|
|
||||||
|
update_officer_author if amounts_changed
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_officer_author
|
||||||
|
self.officer_assignment_id_log += ":#{officer_assignment_id_was}"
|
||||||
|
self.author_id_log += ":#{author_id_was}"
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
class Poll
|
class Poll
|
||||||
class Voter < ActiveRecord::Base
|
class Voter < ActiveRecord::Base
|
||||||
|
|
||||||
|
VALID_ORIGINS = %w{ web booth }
|
||||||
|
|
||||||
belongs_to :poll
|
belongs_to :poll
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :geozone
|
belongs_to :geozone
|
||||||
@@ -10,9 +13,13 @@ class Poll
|
|||||||
validates :user_id, presence: true
|
validates :user_id, presence: true
|
||||||
|
|
||||||
validates :document_number, presence: true, uniqueness: { scope: [:poll_id, :document_type], message: :has_voted }
|
validates :document_number, presence: true, uniqueness: { scope: [:poll_id, :document_type], message: :has_voted }
|
||||||
|
validates :origin, inclusion: { in: VALID_ORIGINS }
|
||||||
|
|
||||||
before_validation :set_demographic_info, :set_document_info
|
before_validation :set_demographic_info, :set_document_info
|
||||||
|
|
||||||
|
scope :web, -> { where(origin: 'web') }
|
||||||
|
scope :booth, -> { where(origin: 'booth') }
|
||||||
|
|
||||||
def set_demographic_info
|
def set_demographic_info
|
||||||
return if user.blank?
|
return if user.blank?
|
||||||
|
|
||||||
|
|||||||
@@ -58,14 +58,27 @@ class Proposal < ActiveRecord::Base
|
|||||||
scope :sort_by_relevance, -> { all }
|
scope :sort_by_relevance, -> { all }
|
||||||
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
||||||
scope :sort_by_archival_date, -> { archived.sort_by_confidence_score }
|
scope :sort_by_archival_date, -> { archived.sort_by_confidence_score }
|
||||||
|
scope :sort_by_recommendations, -> { order(cached_votes_up: :desc) }
|
||||||
scope :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 :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 :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)}
|
||||||
scope :retired, -> { where.not(retired_at: nil) }
|
scope :retired, -> { where.not(retired_at: nil) }
|
||||||
scope :not_retired, -> { where(retired_at: nil) }
|
scope :not_retired, -> { where(retired_at: nil) }
|
||||||
scope :successful, -> { where("cached_votes_up >= ?", Proposal.votes_needed_for_success) }
|
scope :successful, -> { where("cached_votes_up >= ?", Proposal.votes_needed_for_success) }
|
||||||
|
scope :unsuccessful, -> { where("cached_votes_up < ?", Proposal.votes_needed_for_success) }
|
||||||
scope :public_for_api, -> { all }
|
scope :public_for_api, -> { all }
|
||||||
|
|
||||||
|
def self.recommendations(user)
|
||||||
|
tagged_with(user.interests, any: true).
|
||||||
|
where("author_id != ?", user.id).
|
||||||
|
unsuccessful.
|
||||||
|
not_followed_by_user(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.not_followed_by_user(user)
|
||||||
|
where.not(id: followed_by_user(user).pluck(:id))
|
||||||
|
end
|
||||||
|
|
||||||
def to_param
|
def to_param
|
||||||
"#{id}-#{title}".parameterize
|
"#{id}-#{title}".parameterize
|
||||||
end
|
end
|
||||||
@@ -185,6 +198,12 @@ class Proposal < ActiveRecord::Base
|
|||||||
(voters + followers).uniq
|
(voters + followers).uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.proposals_orders(user)
|
||||||
|
orders = %w{hot_score confidence_score created_at relevance archival_date}
|
||||||
|
orders << "recommendations" if user.present?
|
||||||
|
orders
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def set_responsible_name
|
def set_responsible_name
|
||||||
|
|||||||
@@ -88,12 +88,12 @@ class User < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def debate_votes(debates)
|
def debate_votes(debates)
|
||||||
voted = votes.for_debates(debates)
|
voted = votes.for_debates(Array(debates).map(&:id))
|
||||||
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
|
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
|
||||||
end
|
end
|
||||||
|
|
||||||
def proposal_votes(proposals)
|
def proposal_votes(proposals)
|
||||||
voted = votes.for_proposals(proposals)
|
voted = votes.for_proposals(Array(proposals).map(&:id))
|
||||||
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
|
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,8 @@
|
|||||||
<td><%= l(officer_assignment.date.to_date) %></td>
|
<td><%= l(officer_assignment.date.to_date) %></td>
|
||||||
<td><%= booth_name_with_location(officer_assignment.booth_assignment.booth) %></td>
|
<td><%= booth_name_with_location(officer_assignment.booth_assignment.booth) %></td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<% if officer_assignment.total_results.any? %>
|
<% if officer_assignment.recounts.any? %>
|
||||||
<%= officer_assignment.total_results.to_a.sum(&:amount) %>
|
<%= officer_assignment.recounts.to_a.sum(&:total_amount) %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<span>-</span>
|
<span>-</span>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -2,4 +2,6 @@
|
|||||||
|
|
||||||
<h2><%= t("admin.questions.edit.title") %></h2>
|
<h2><%= t("admin.questions.edit.title") %></h2>
|
||||||
|
|
||||||
<%= render "form", form_url: admin_question_path(@question) %>
|
<div class="poll-question-form">
|
||||||
|
<%= render "form", form_url: admin_question_path(@question) %>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -2,4 +2,6 @@
|
|||||||
|
|
||||||
<h2><%= t("admin.questions.new.title") %></h2>
|
<h2><%= t("admin.questions.new.title") %></h2>
|
||||||
|
|
||||||
<%= render "form", form_url: admin_questions_path %>
|
<div class="poll-question-form">
|
||||||
|
<%= render "form", form_url: admin_questions_path %>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -18,9 +18,9 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td id="white_results"><%= @poll.white_results.sum(:amount) %></td>
|
<td id="white_results"><%= @poll.recounts.sum(:white_amount) %></td>
|
||||||
<td id="null_results"><%= @poll.null_results.sum(:amount) %></td>
|
<td id="null_results"><%= @poll.recounts.sum(:null_amount) %></td>
|
||||||
<td id="total_results"><%= @poll.total_results.sum(:amount) %></td>
|
<td id="total_results"><%= @poll.recounts.sum(:total_amount) %></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
<div id="<%= dom_id(investment) %>" class="budget-investment clear">
|
<div id="<%= dom_id(investment) %>" class="budget-investment clear">
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<div class="row">
|
<div class="row" data-equalizer>
|
||||||
|
|
||||||
<div class="small-12 medium-3 large-2 column">
|
<div class="small-12 medium-3 large-2 column">
|
||||||
<% if investment.image.present? %>
|
<div data-equalizer-watch>
|
||||||
<%= image_tag investment.image_url(:thumb), alt: investment.image.title %>
|
<% if investment.image.present? %>
|
||||||
<% else %>
|
<%= image_tag investment.image_url(:thumb), alt: investment.image.title %>
|
||||||
<div class="no-image"></div>
|
<% else %>
|
||||||
<% end %>
|
<div class="no-image"></div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="small-12 medium-6 large-7 column">
|
<div class="small-12 medium-6 large-7 column">
|
||||||
@@ -53,7 +55,7 @@
|
|||||||
|
|
||||||
<% if investment.should_show_votes? %>
|
<% if investment.should_show_votes? %>
|
||||||
<div id="<%= dom_id(investment) %>_votes"
|
<div id="<%= dom_id(investment) %>_votes"
|
||||||
class="small-12 medium-3 column text-center">
|
class="small-12 medium-3 column text-center" data-equalizer-watch>
|
||||||
<%= render partial: '/budgets/investments/votes', locals: {
|
<%= render partial: '/budgets/investments/votes', locals: {
|
||||||
investment: investment,
|
investment: investment,
|
||||||
investment_votes: investment_votes,
|
investment_votes: investment_votes,
|
||||||
@@ -62,7 +64,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<% elsif investment.should_show_vote_count? %>
|
<% elsif investment.should_show_vote_count? %>
|
||||||
<div id="<%= dom_id(investment) %>_votes"
|
<div id="<%= dom_id(investment) %>_votes"
|
||||||
class="small-12 medium-3 column text-center">
|
class="small-12 medium-3 column text-center" data-equalizer-watch>
|
||||||
<div class="supports js-participation">
|
<div class="supports js-participation">
|
||||||
<span class="total-supports no-button">
|
<span class="total-supports no-button">
|
||||||
<%= t("budgets.investments.investment.supports",
|
<%= t("budgets.investments.investment.supports",
|
||||||
@@ -72,7 +74,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<% elsif investment.should_show_ballots? %>
|
<% elsif investment.should_show_ballots? %>
|
||||||
<div id="<%= dom_id(investment) %>_ballot"
|
<div id="<%= dom_id(investment) %>_ballot"
|
||||||
class="small-12 medium-3 column text-center">
|
class="small-12 medium-3 column text-center" data-equalizer-watch>
|
||||||
<%= render partial: '/budgets/investments/ballot', locals: {
|
<%= render partial: '/budgets/investments/ballot', locals: {
|
||||||
investment: investment,
|
investment: investment,
|
||||||
investment_ids: investment_ids,
|
investment_ids: investment_ids,
|
||||||
@@ -81,11 +83,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<% elsif investment.should_show_price? %>
|
<% elsif investment.should_show_price? %>
|
||||||
<div id="<%= dom_id(investment) %>_price"
|
<div id="<%= dom_id(investment) %>_price"
|
||||||
class="supports small-12 medium-3 column text-center">
|
class="supports small-12 medium-3 column text-center" data-equalizer-watch>
|
||||||
<p class="investment-project-amount margin-top">
|
<p class="investment-project-amount margin-top">
|
||||||
<%= investment.formatted_price %>
|
<%= investment.formatted_price %>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<div data-equalizer-watch></div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if @budget.finished? %>
|
<% if @budget.finished? || (@budget.balloting? && can?(:read_results, @budget)) %>
|
||||||
<%= link_to t("budgets.show.see_results"),
|
<%= link_to t("budgets.show.see_results"),
|
||||||
budget_results_path(@budget, heading_id: @budget.headings.first),
|
budget_results_path(@budget, heading_id: @budget.headings.first),
|
||||||
class: "button margin-top expanded" %>
|
class: "button margin-top expanded" %>
|
||||||
|
|||||||
@@ -54,7 +54,11 @@
|
|||||||
<%= link_to t("debates.index.start_debate"), new_debate_path, class: 'button expanded' %>
|
<%= link_to t("debates.index.start_debate"), new_debate_path, class: 'button expanded' %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= render @debates %>
|
<% if @debates.any? || current_user.blank? %>
|
||||||
|
<%= render @debates %>
|
||||||
|
<% else %>
|
||||||
|
<%= empty_recommended_debates_message_text(current_user) %>
|
||||||
|
<% end %>
|
||||||
<%= paginate @debates %>
|
<%= paginate @debates %>
|
||||||
|
|
||||||
<% unless @search_terms || @advanced_search_terms || @tag_filter %>
|
<% unless @search_terms || @advanced_search_terms || @tag_filter %>
|
||||||
|
|||||||
@@ -20,7 +20,4 @@
|
|||||||
<div id="max-documents-notice" class="max-documents-notice callout warning text-center <%= "hide" unless max_documents_allowed?(documentable) %>">
|
<div id="max-documents-notice" class="max-documents-notice callout warning text-center <%= "hide" unless max_documents_allowed?(documentable) %>">
|
||||||
<%= t "documents.max_documents_allowed_reached_html" %>
|
<%= t "documents.max_documents_allowed_reached_html" %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -28,4 +28,5 @@
|
|||||||
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
|
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
<div>
|
<%= f.label :image, t("images.form.title") %>
|
||||||
<%= f.label :image, t("images.form.title") %>
|
<p class="help-text"><%= imageables_note(imageable) %></p>
|
||||||
<p class="help-text"><%= imageables_note(imageable) %></p>
|
|
||||||
|
|
||||||
<div id="nested-image">
|
<div id="nested-image">
|
||||||
<%= f.fields_for :image do |image_builder| %>
|
<%= f.fields_for :image do |image_builder| %>
|
||||||
<%= render 'images/image_fields', f: image_builder, imageable: imageable %>
|
<%= render 'images/image_fields', f: image_builder, imageable: imageable %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= link_to_add_association t('images.form.add_new_image'), f, :image,
|
<%= link_to_add_association t('images.form.add_new_image'), f, :image,
|
||||||
@@ -21,5 +19,3 @@
|
|||||||
association_insertion_node: "#nested-image",
|
association_insertion_node: "#nested-image",
|
||||||
association_insertion_method: "append"
|
association_insertion_method: "append"
|
||||||
} %>
|
} %>
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
<%= setting['per_page_code_head'].try(:html_safe) %>
|
<%= setting['per_page_code_head'].try(:html_safe) %>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="<%= yield (:body_class) %>">
|
||||||
<%= setting['per_page_code_body'].try(:html_safe) %>
|
<%= setting['per_page_code_body'].try(:html_safe) %>
|
||||||
|
|
||||||
<h1 class="show-for-sr"><%= setting['org_name'] %></h1>
|
<h1 class="show-for-sr"><%= setting['org_name'] %></h1>
|
||||||
|
|||||||
@@ -21,9 +21,9 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td id="white_results"><%= @whites %></td>
|
<td id="white_results"><%= @recounts.sum(:white_amount) %></td>
|
||||||
<td id="null_results"><%= @nulls %></td>
|
<td id="null_results"><%= @recounts.sum(:null_amount) %></td>
|
||||||
<td id="total_results"><%= @total %></td>
|
<td id="total_results"><%= @recounts.sum(:total_amount) %></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -33,23 +33,30 @@
|
|||||||
<span class="show-for-sr"><%= t("polls.index.cant_answer") %></span>
|
<span class="show-for-sr"><%= t("polls.index.cant_answer") %></span>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<div class="row">
|
<div class="row" data-equalizer>
|
||||||
<div class="small-12 column">
|
<div class="small-12 medium-3 column" data-equalizer-watch>
|
||||||
<div class="dates"><%= poll_dates(poll) %></div>
|
<!-- PENDING TO REPLACE THIS BLOCK WITH POLL MAIN IMAGE -->
|
||||||
|
<div style="background: #eee; width: 100%; height: 100%; display: block; margin: -12px;"> </div>
|
||||||
|
<!-- /. PENDING TO REPLACE THIS BLOCK WITH POLL MAIN IMAGE -->
|
||||||
|
</div>
|
||||||
|
<div class="small-12 medium-6 column" data-equalizer-watch>
|
||||||
|
<div class="dates"></div>
|
||||||
<% if poll.questions.count == 1 %>
|
<% if poll.questions.count == 1 %>
|
||||||
<% poll.questions.each do |question| %>
|
<% poll.questions.each do |question| %>
|
||||||
<h4 class="inline-block"><%= link_to question.title, poll %></h4>
|
<h4><%= link_to question.title, poll %></h4>
|
||||||
|
<%= poll_dates(poll) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<h4 class="inline-block"><%= link_to poll.name, poll %></h4>
|
<h4><%= link_to poll.name, poll %></h4>
|
||||||
<ul>
|
<%= poll_dates(poll) %>
|
||||||
|
<ul class="margin-top">
|
||||||
<% poll.questions.each do |question| %>
|
<% poll.questions.each do |question| %>
|
||||||
<li><%= link_to question.title, question_path(question) %></li>
|
<li><%= link_to question.title, question_path(question) %></li>
|
||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% if poll.geozones.any? %>
|
<% if poll.geozones.any? %>
|
||||||
<p class="inline-block">
|
<p>
|
||||||
<small><%= t("polls.index.geozone_info") %></small>
|
<small><%= t("polls.index.geozone_info") %></small>
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -59,16 +66,18 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="small-12 medium-6 large-4 column end">
|
<div class="small-12 medium-3 column table" data-equalizer-watch>
|
||||||
<%= link_to poll, class: "button expanded" do %>
|
<div class="table-cell aling-middle">
|
||||||
<% if poll.expired? %>
|
<%= link_to poll, class: "button hollow expanded" do %>
|
||||||
<%= t("polls.index.participate_button_expired") %>
|
<% if poll.expired? %>
|
||||||
<% elsif poll.incoming? %>
|
<%= t("polls.index.participate_button_expired") %>
|
||||||
<%= t("polls.index.participate_button_incoming") %>
|
<% elsif poll.incoming? %>
|
||||||
<% else %>
|
<%= t("polls.index.participate_button_incoming") %>
|
||||||
<%= t("polls.index.participate_button") %>
|
<% else %>
|
||||||
|
<%= t("polls.index.participate_button") %>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,18 +6,22 @@
|
|||||||
<%= render "shared/section_header", i18n_namespace: "polls.index.section_header", image: "polls" %>
|
<%= render "shared/section_header", i18n_namespace: "polls.index.section_header", image: "polls" %>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="small-12 medium-9 column">
|
<div class="small-12 column">
|
||||||
<%= render 'shared/filter_subnav', i18n_namespace: "polls.index" %>
|
<%= render 'shared/filter_subnav', i18n_namespace: "polls.index" %>
|
||||||
|
|
||||||
<% polls_by_geozone_restriction = @polls.group_by(&:geozone_restricted) %>
|
<% polls_by_geozone_restriction = @polls.group_by(&:geozone_restricted) %>
|
||||||
|
|
||||||
<% if polls_by_geozone_restriction[false].present? %>
|
<% if polls_by_geozone_restriction[false].present? %>
|
||||||
<h3 class="section-title-divider"><%= t("polls.index.no_geozone_restricted") %></h3>
|
<h3 class="section-title-divider">
|
||||||
|
<span><%= t("polls.index.no_geozone_restricted") %></span>
|
||||||
|
</h3>
|
||||||
<%= render partial: 'poll_group', locals: {poll_group: polls_by_geozone_restriction[false]} %>
|
<%= render partial: 'poll_group', locals: {poll_group: polls_by_geozone_restriction[false]} %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if polls_by_geozone_restriction[true].present? %>
|
<% if polls_by_geozone_restriction[true].present? %>
|
||||||
<h3 class="section-title-divider"><%= t("polls.index.geozone_restricted") %></h3>
|
<h3 class="section-title-divider">
|
||||||
|
<span><%= t("polls.index.geozone_restricted") %></span>
|
||||||
|
</h3>
|
||||||
<%= render partial: 'poll_group', locals: {poll_group: polls_by_geozone_restriction[true]} %>
|
<%= render partial: 'poll_group', locals: {poll_group: polls_by_geozone_restriction[true]} %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,14 @@
|
|||||||
|
|
||||||
<div class="row margin-top">
|
<div class="row margin-top">
|
||||||
<div class="small-12 medium-9 column">
|
<div class="small-12 medium-9 column">
|
||||||
<% @questions.each do |question| %>
|
<% if @poll.voted_in_booth?(current_user) %>
|
||||||
<%= render 'polls/questions/question', question: question %>
|
<div class="callout warning">
|
||||||
|
<%= t("polls.show.already_voted_in_booth") %>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<% @questions.each do |question| %>
|
||||||
|
<%= render 'polls/questions/question', question: question %>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,16 @@
|
|||||||
data-type="proposal">
|
data-type="proposal">
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<div class="icon-successful"></div>
|
<div class="icon-successful"></div>
|
||||||
<div class="row">
|
<div class="row" data-equalizer>
|
||||||
|
|
||||||
<div class="small-12 medium-3 large-2 column">
|
<div class="small-12 medium-3 large-2 column">
|
||||||
<% if proposal.image.present? %>
|
<div data-equalizer-watch>
|
||||||
<%= image_tag proposal.image_url(:thumb), alt: proposal.image.title %>
|
<% if proposal.image.present? %>
|
||||||
<% else %>
|
<%= image_tag proposal.image_url(:thumb), alt: proposal.image.title %>
|
||||||
<div class="no-image"></div>
|
<% else %>
|
||||||
<% end %>
|
<div class="no-image"></div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="small-12 medium-6 large-7 column">
|
<div class="small-12 medium-6 large-7 column">
|
||||||
@@ -58,7 +60,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="<%= dom_id(proposal) %>_votes" class="small-12 medium-3 column supports-container">
|
<div id="<%= dom_id(proposal) %>_votes" class="small-12 medium-3 column supports-container" data-equalizer-watch>
|
||||||
<% if proposal.successful? %>
|
<% if proposal.successful? %>
|
||||||
<div class="padding text-center">
|
<div class="padding text-center">
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,13 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="small-12 column">
|
<div class="small-12 column">
|
||||||
<% if @search_terms || @advanced_search_terms %>
|
<% if @search_terms || @advanced_search_terms %>
|
||||||
<h2><%= t("shared.search_results") %></h2>
|
<h2><%= t("shared.search_results") %></h2>
|
||||||
<p>
|
<p>
|
||||||
<%= page_entries_info @proposals %>
|
<%= page_entries_info @proposals %>
|
||||||
<% if !@advanced_search_terms %>
|
<% if !@advanced_search_terms %>
|
||||||
<%= t("proposals.index.search_results_html", count: @proposals.size, search_term: @search_terms) %>
|
<%= t("proposals.index.search_results_html", count: @proposals.size, search_term: @search_terms) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<p>
|
<p>
|
||||||
<% elsif @tag_filter %>
|
<% elsif @tag_filter %>
|
||||||
<h2><%= t("shared.search_results") %></h2>
|
<h2><%= t("shared.search_results") %></h2>
|
||||||
<p>
|
<p>
|
||||||
@@ -68,7 +68,11 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<div id="proposals-list">
|
<div id="proposals-list">
|
||||||
<%= render partial: 'proposals/proposal', collection: @proposals %>
|
<% if @proposals.any? || current_user.blank? %>
|
||||||
|
<%= render partial: 'proposals/proposal', collection: @proposals %>
|
||||||
|
<% else %>
|
||||||
|
<%= empty_recommended_proposals_message_text(current_user) %>
|
||||||
|
<% end %>
|
||||||
<%= paginate @proposals %>
|
<%= paginate @proposals %>
|
||||||
|
|
||||||
<% unless @search_terms || @advanced_search_terms || @tag_filter %>
|
<% unless @search_terms || @advanced_search_terms || @tag_filter %>
|
||||||
|
|||||||
@@ -117,6 +117,13 @@
|
|||||||
<h2><%= t("proposals.show.author") %></h2>
|
<h2><%= t("proposals.show.author") %></h2>
|
||||||
<div class="show-actions-menu">
|
<div class="show-actions-menu">
|
||||||
|
|
||||||
|
<% if current_editable?(@proposal) %>
|
||||||
|
<%= link_to edit_proposal_path(@proposal), class: 'button hollow expanded' do %>
|
||||||
|
<span class="icon-edit"></span>
|
||||||
|
<%= t("proposals.show.edit_proposal_link") %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<% if author_of_proposal?(@proposal) %>
|
<% if author_of_proposal?(@proposal) %>
|
||||||
<%= link_to new_proposal_notification_path(proposal_id: @proposal.id),
|
<%= link_to new_proposal_notification_path(proposal_id: @proposal.id),
|
||||||
class: 'button hollow expanded' do %>
|
class: 'button hollow expanded' do %>
|
||||||
@@ -128,20 +135,13 @@
|
|||||||
<% if can_destroy_image?(@proposal) %>
|
<% if can_destroy_image?(@proposal) %>
|
||||||
<%= link_to image_path(@proposal.image, from: request.url),
|
<%= link_to image_path(@proposal.image, from: request.url),
|
||||||
method: :delete,
|
method: :delete,
|
||||||
class: 'button hollow expanded',
|
class: 'button hollow alert expanded',
|
||||||
data: { confirm: t('images.actions.destroy.confirm') } do %>
|
data: { confirm: t('images.actions.destroy.confirm') } do %>
|
||||||
<span class="icon-document"></span>
|
<span class="icon-image"></span>
|
||||||
<%= t("images.remove_image") %>
|
<%= t("images.remove_image") %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if current_editable?(@proposal) %>
|
|
||||||
<%= link_to edit_proposal_path(@proposal), class: 'edit-proposal button hollow expanded' do %>
|
|
||||||
<span class="icon-edit"></span>
|
|
||||||
<%= t("proposals.show.edit_proposal_link") %>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
|||||||
31
app/views/welcome/_recommended.html.erb
Normal file
31
app/views/welcome/_recommended.html.erb
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<div class="small-12 column section-recommended padding">
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<h2 class="text-center"><%= t("welcome.recommended.title") %></h2>
|
||||||
|
<div class="small-12 column carousel-image">
|
||||||
|
<% if recommended_debates.any? %>
|
||||||
|
<% carousel_size = calculate_carousel_size(recommended_debates, recommended_proposals, true) %>
|
||||||
|
<%= render "recommended_carousel", recommendeds: recommended_debates,
|
||||||
|
key: "debates",
|
||||||
|
image_field: nil,
|
||||||
|
image_version: nil,
|
||||||
|
image_default: nil,
|
||||||
|
carousel_size: carousel_size,
|
||||||
|
btn_text_link: t("welcome.recommended.debates.btn_text_link"),
|
||||||
|
btn_path_link: debates_path(order: "recommendations") %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% if recommended_proposals.any? %>
|
||||||
|
<% carousel_size = calculate_carousel_size(recommended_debates, recommended_proposals, false) %>
|
||||||
|
<%= render "recommended_carousel", recommendeds: recommended_proposals,
|
||||||
|
key: "proposals",
|
||||||
|
image_field: :attachment,
|
||||||
|
image_version: :thumb,
|
||||||
|
image_default: nil,
|
||||||
|
carousel_size: carousel_size,
|
||||||
|
btn_text_link: t("welcome.recommended.proposals.btn_text_link"),
|
||||||
|
btn_path_link: proposals_path(order: "recommendations") %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
42
app/views/welcome/_recommended_carousel.html.erb
Normal file
42
app/views/welcome/_recommended_carousel.html.erb
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<div class="small-12 medium-4 large-4 <%= carousel_size %> column text-center <%= key %> ">
|
||||||
|
<div class="card small-centered <%= key %>-inner">
|
||||||
|
|
||||||
|
<h4><%= t("welcome.recommended.#{key.underscore}.title") %></h4>
|
||||||
|
|
||||||
|
<div class="orbit" role="region" data-orbit data-use-m-u-i="false">
|
||||||
|
<div class="orbit-wrapper">
|
||||||
|
|
||||||
|
<ul class="orbit-container no-bullet" tabindex="0" >
|
||||||
|
<% recommendeds.each_with_index do |recommended, index| %>
|
||||||
|
|
||||||
|
<li class="orbit-slide <%= active_class(index) %>" data-slide="<%= index %>" style="position: relative; <%= slide_display(index) %>" aria-live="polite">
|
||||||
|
<div class="card">
|
||||||
|
<%= render_recommendation_image(recommended, image_default) %>
|
||||||
|
<div class="card-section">
|
||||||
|
<%= link_to recommended_path(recommended) do %>
|
||||||
|
<h5 class="truncate-horizontal-text"><%= recommended.title %></h5>
|
||||||
|
<% end %>
|
||||||
|
<p><%= recommended.description %></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
|
<div class="truncate"></div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="orbit-bullets">
|
||||||
|
<% recommendeds.each_with_index do |recommended, index| %>
|
||||||
|
<button data-slide="<%= index %>" class="<%= active_class(index) %>">
|
||||||
|
<span class="show-for-sr">Second slide details.</span>
|
||||||
|
</button>
|
||||||
|
<% end %>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<%= link_to btn_text_link, btn_path_link, class: 'button hollow expanded' %>
|
||||||
|
</div>
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
<% content_for :body_class, "home-page" %>
|
||||||
|
|
||||||
<% content_for :canonical do %>
|
<% content_for :canonical do %>
|
||||||
<%= render "shared/canonical", href: root_url %>
|
<%= render "shared/canonical", href: root_url %>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -16,37 +18,35 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<% if feature?("user.recommendations") && (@recommended_debates.present? || @recommended_proposals.present?) %>
|
||||||
|
<%= render "recommended",
|
||||||
|
recommended_debates: @recommended_debates,
|
||||||
|
recommended_proposals: @recommended_proposals %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<% cache [locale_and_user_status, @featured_debates, @featured_proposals, 'featured'] do %>
|
<% cache [locale_and_user_status, @featured_debates, @featured_proposals, 'featured'] do %>
|
||||||
<main>
|
<main>
|
||||||
<div class="row">
|
|
||||||
<div class="small-12 medium-6 column">
|
|
||||||
<p>
|
|
||||||
<span class="lead"><strong><%= t("welcome.debates.title") %></strong></span><br>
|
|
||||||
<%= t("welcome.debates.description") %>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
<div class="small-12 column text-center <%= highlight_background %>">
|
||||||
<div class="small-12 medium-6 column">
|
<div class="row margin padding">
|
||||||
<p>
|
<div class="small-12 medium-3 column">
|
||||||
<span class="lead"><strong><%= t("welcome.proposal.title") %></strong></span><br>
|
<h2><%= t("welcome.debates.title") %></h2>
|
||||||
<%= t("welcome.proposal.description") %>
|
<p><%= t("welcome.debates.description") %></p>
|
||||||
</p>
|
</div>
|
||||||
|
<div class="small-12 medium-3 column">
|
||||||
|
<h2><%= t("welcome.proposal.title") %></h2>
|
||||||
|
<p><%= t("welcome.proposal.description") %></p>
|
||||||
|
</div>
|
||||||
|
<div class="small-12 medium-3 column">
|
||||||
|
<h2><%= t("welcome.decide.title") %></h2>
|
||||||
|
<p><%= t("welcome.decide.description") %></p>
|
||||||
|
</div>
|
||||||
|
<div class="small-12 medium-3 column">
|
||||||
|
<h2><%= t("welcome.do.title") %></h2>
|
||||||
|
<p><%= t("welcome.do.description") %></p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row margin-top">
|
|
||||||
<div class="small-12 medium-6 column">
|
|
||||||
<p>
|
|
||||||
<span class="lead"><strong><%= t("welcome.decide.title") %></strong></span><br>
|
|
||||||
<%= t("welcome.decide.description") %>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="small-12 medium-6 column">
|
|
||||||
<p>
|
|
||||||
<span class="lead"><strong><%= t("welcome.do.title") %></strong></span><br>
|
|
||||||
<%= t("welcome.do.description") %>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -109,6 +109,10 @@ en:
|
|||||||
hot_score: most active
|
hot_score: most active
|
||||||
most_commented: most commented
|
most_commented: most commented
|
||||||
relevance: relevance
|
relevance: relevance
|
||||||
|
recommendations: recommendations
|
||||||
|
recommendations:
|
||||||
|
without_results: There are not debates related to your interests
|
||||||
|
without_interests: Follow proposals so we can give you recommendations
|
||||||
search_form:
|
search_form:
|
||||||
button: Search
|
button: Search
|
||||||
placeholder: Search debates...
|
placeholder: Search debates...
|
||||||
@@ -348,6 +352,10 @@ en:
|
|||||||
most_commented: most commented
|
most_commented: most commented
|
||||||
relevance: relevance
|
relevance: relevance
|
||||||
archival_date: Archived
|
archival_date: Archived
|
||||||
|
recommendations: recommendations
|
||||||
|
recommendations:
|
||||||
|
without_results: There are not proposals related to your interests
|
||||||
|
without_interests: Follow proposals so we can give you recommendations
|
||||||
retired_proposals: Retired proposals
|
retired_proposals: Retired proposals
|
||||||
retired_proposals_link: "Proposals retired by the author"
|
retired_proposals_link: "Proposals retired by the author"
|
||||||
retired_links:
|
retired_links:
|
||||||
@@ -473,6 +481,7 @@ en:
|
|||||||
help_text_1: "Voting takes place when a citizen proposal supports reaches 1% of the census with voting rights. Voting can also include questions that the City Council ask to the citizens decision."
|
help_text_1: "Voting takes place when a citizen proposal supports reaches 1% of the census with voting rights. Voting can also include questions that the City Council ask to the citizens decision."
|
||||||
help_text_2: "To participate in the next vote you have to sign up on %{org} and verify your account. All registered voters in the city over 16 years old can vote. The results of all votes are binding on the government."
|
help_text_2: "To participate in the next vote you have to sign up on %{org} and verify your account. All registered voters in the city over 16 years old can vote. The results of all votes are binding on the government."
|
||||||
show:
|
show:
|
||||||
|
already_voted_in_booth: "You have already participated in a booth for this poll."
|
||||||
dates_title: "Participation dates"
|
dates_title: "Participation dates"
|
||||||
cant_answer_not_logged_in: "You must %{signin} or %{signup} to participate."
|
cant_answer_not_logged_in: "You must %{signin} or %{signup} to participate."
|
||||||
signin: Sign in
|
signin: Sign in
|
||||||
@@ -753,6 +762,16 @@ en:
|
|||||||
proposal:
|
proposal:
|
||||||
description: Open space for citizen proposals about the kind of city we want to live in.
|
description: Open space for citizen proposals about the kind of city we want to live in.
|
||||||
title: You propose
|
title: You propose
|
||||||
|
recommended:
|
||||||
|
title: Recommendations that may interest you
|
||||||
|
debates:
|
||||||
|
title: Recommended debates
|
||||||
|
btn_text_link: All recommended debates
|
||||||
|
proposals:
|
||||||
|
title: Recommended proposals
|
||||||
|
btn_text_link: All recommended proposals
|
||||||
|
budget_investments:
|
||||||
|
title: Recommended investments
|
||||||
verification:
|
verification:
|
||||||
i_dont_have_an_account: I don't have an account
|
i_dont_have_an_account: I don't have an account
|
||||||
i_have_an_account: I already have an account
|
i_have_an_account: I already have an account
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ en:
|
|||||||
spending_proposal_features:
|
spending_proposal_features:
|
||||||
voting_allowed: Voting on investment projects
|
voting_allowed: Voting on investment projects
|
||||||
legislation: Legislation
|
legislation: Legislation
|
||||||
|
user:
|
||||||
|
recommendations: Recommendeds
|
||||||
community: Community on proposals and investments
|
community: Community on proposals and investments
|
||||||
map: Proposals and budget investments geolocation
|
map: Proposals and budget investments geolocation
|
||||||
map_latitude: Latitude
|
map_latitude: Latitude
|
||||||
|
|||||||
@@ -109,6 +109,10 @@ es:
|
|||||||
hot_score: Más activos hoy
|
hot_score: Más activos hoy
|
||||||
most_commented: Más comentados
|
most_commented: Más comentados
|
||||||
relevance: Más relevantes
|
relevance: Más relevantes
|
||||||
|
recommendations: Recomendaciones
|
||||||
|
recommendations:
|
||||||
|
without_results: No existen debates relacionados con tus intereses
|
||||||
|
without_interests: Sigue propuestas para que podamos darte recomendaciones
|
||||||
search_form:
|
search_form:
|
||||||
button: Buscar
|
button: Buscar
|
||||||
placeholder: Buscar debates...
|
placeholder: Buscar debates...
|
||||||
@@ -348,6 +352,10 @@ es:
|
|||||||
most_commented: Más comentadas
|
most_commented: Más comentadas
|
||||||
relevance: Más relevantes
|
relevance: Más relevantes
|
||||||
archival_date: Archivadas
|
archival_date: Archivadas
|
||||||
|
recommendations: Recomendaciones
|
||||||
|
recommendations:
|
||||||
|
without_results: No existen propuestas relacionadas con tus intereses
|
||||||
|
without_interests: Sigue propuestas para que podamos darte recomendaciones
|
||||||
retired_proposals: Propuestas retiradas
|
retired_proposals: Propuestas retiradas
|
||||||
retired_proposals_link: "Propuestas retiradas por sus autores"
|
retired_proposals_link: "Propuestas retiradas por sus autores"
|
||||||
retired_links:
|
retired_links:
|
||||||
@@ -394,7 +402,7 @@ es:
|
|||||||
proposal:
|
proposal:
|
||||||
created: "¡Has creado una propuesta!"
|
created: "¡Has creado una propuesta!"
|
||||||
share:
|
share:
|
||||||
guide: "Compártela para que la gente empieze a apoyarla."
|
guide: "Compártela para que la gente empiece a apoyarla."
|
||||||
edit: "Antes de que se publique podrás modificar el texto a tu gusto."
|
edit: "Antes de que se publique podrás modificar el texto a tu gusto."
|
||||||
view_proposal: "Ahora no, ir a mi propuesta"
|
view_proposal: "Ahora no, ir a mi propuesta"
|
||||||
improve_info: "Mejora tu campaña y consigue más apoyos"
|
improve_info: "Mejora tu campaña y consigue más apoyos"
|
||||||
@@ -473,6 +481,7 @@ es:
|
|||||||
help_text_1: "Las votaciones se convocan cuando una propuesta ciudadana alcanza el 1% de apoyos del censo con derecho a voto. En las votaciones también se pueden incluir cuestiones que el Ayuntamiento somete a decisión directa de la ciudadanía."
|
help_text_1: "Las votaciones se convocan cuando una propuesta ciudadana alcanza el 1% de apoyos del censo con derecho a voto. En las votaciones también se pueden incluir cuestiones que el Ayuntamiento somete a decisión directa de la ciudadanía."
|
||||||
help_text_2: "Para participar en la próxima votación tienes que registrarte en %{org} y verificar tu cuenta. Pueden votar todas las personas empadronadas en la ciudad mayores de 16 años. Los resultados de todas las votaciones serán vinculantes para el gobierno."
|
help_text_2: "Para participar en la próxima votación tienes que registrarte en %{org} y verificar tu cuenta. Pueden votar todas las personas empadronadas en la ciudad mayores de 16 años. Los resultados de todas las votaciones serán vinculantes para el gobierno."
|
||||||
show:
|
show:
|
||||||
|
already_voted_in_booth: "Ya has participado en esta votación en una urna."
|
||||||
dates_title: "Fechas de participación"
|
dates_title: "Fechas de participación"
|
||||||
cant_answer_not_logged_in: "Necesitas %{signin} o %{signup} para participar."
|
cant_answer_not_logged_in: "Necesitas %{signin} o %{signup} para participar."
|
||||||
signin: iniciar sesión
|
signin: iniciar sesión
|
||||||
@@ -753,6 +762,16 @@ es:
|
|||||||
proposal:
|
proposal:
|
||||||
description: Espacio abierto para propuestas ciudadanas sobre el tipo de ciudad en el que queremos vivir.
|
description: Espacio abierto para propuestas ciudadanas sobre el tipo de ciudad en el que queremos vivir.
|
||||||
title: Propones
|
title: Propones
|
||||||
|
recommended:
|
||||||
|
title: Recomendaciones que te pueden interesar
|
||||||
|
debates:
|
||||||
|
title: Debates recomendados
|
||||||
|
btn_text_link: Todos los debates recomendados
|
||||||
|
proposals:
|
||||||
|
title: Propuestas recomendadas
|
||||||
|
btn_text_link: Todas las propuestas recomendadas
|
||||||
|
budget_investments:
|
||||||
|
title: Presupuestos recomendados
|
||||||
verification:
|
verification:
|
||||||
i_dont_have_an_account: No tengo cuenta, quiero crear una y verificarla
|
i_dont_have_an_account: No tengo cuenta, quiero crear una y verificarla
|
||||||
i_have_an_account: Ya tengo una cuenta que quiero verificar
|
i_have_an_account: Ya tengo una cuenta que quiero verificar
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ es:
|
|||||||
spending_proposal_features:
|
spending_proposal_features:
|
||||||
voting_allowed: Votaciones sobre propuestas de inversión
|
voting_allowed: Votaciones sobre propuestas de inversión
|
||||||
legislation: Legislación
|
legislation: Legislación
|
||||||
|
user:
|
||||||
|
recommendations: Recomendaciones
|
||||||
community: Comunidad en propuestas y proyectos de inversión
|
community: Comunidad en propuestas y proyectos de inversión
|
||||||
map: Geolocalización de propuestas y proyectos de inversión
|
map: Geolocalización de propuestas y proyectos de inversión
|
||||||
map_latitude: Latitud
|
map_latitude: Latitud
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ Setting.create(key: 'feature.facebook_login', value: "true")
|
|||||||
Setting.create(key: 'feature.google_login', value: "true")
|
Setting.create(key: 'feature.google_login', value: "true")
|
||||||
Setting.create(key: 'feature.signature_sheets', value: "true")
|
Setting.create(key: 'feature.signature_sheets', value: "true")
|
||||||
Setting.create(key: 'feature.legislation', value: "true")
|
Setting.create(key: 'feature.legislation', value: "true")
|
||||||
|
Setting.create(key: 'feature.user.recommendations', value: "true")
|
||||||
Setting.create(key: 'feature.community', value: "true")
|
Setting.create(key: 'feature.community', value: "true")
|
||||||
Setting.create(key: 'feature.map', value: "true")
|
Setting.create(key: 'feature.map', value: "true")
|
||||||
Setting.create(key: 'per_page_code_head', value: "")
|
Setting.create(key: 'per_page_code_head', value: "")
|
||||||
|
|||||||
5
db/migrate/20171002121658_add_origin_to_poll_voters.rb
Normal file
5
db/migrate/20171002121658_add_origin_to_poll_voters.rb
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class AddOriginToPollVoters < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :poll_voters, :origin, :string
|
||||||
|
end
|
||||||
|
end
|
||||||
24
db/migrate/20171002122312_create_poll_recount.rb
Normal file
24
db/migrate/20171002122312_create_poll_recount.rb
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
class CreatePollRecount < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :poll_recounts do |t|
|
||||||
|
t.integer :author_id
|
||||||
|
t.string :origin
|
||||||
|
t.date :date
|
||||||
|
t.integer :booth_assignment_id
|
||||||
|
t.integer :officer_assignment_id
|
||||||
|
t.text :officer_assignment_id_log, default: ""
|
||||||
|
t.text :author_id_log, default: ""
|
||||||
|
t.integer :white_amount
|
||||||
|
t.text :white_amount_log, default: ""
|
||||||
|
t.integer :null_amount
|
||||||
|
t.text :null_amount_log, default: ""
|
||||||
|
t.integer :total_amount
|
||||||
|
t.text :total_amount_log, default: ""
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :poll_recounts, :booth_assignment_id
|
||||||
|
add_index :poll_recounts, :officer_assignment_id
|
||||||
|
add_foreign_key :poll_recounts, :poll_booth_assignments, column: :booth_assignment_id
|
||||||
|
add_foreign_key :poll_recounts, :poll_officer_assignments, column: :officer_assignment_id
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class AddDefaultToRecountAmounts < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
change_column_default :poll_recounts, :white_amount, 0
|
||||||
|
change_column_default :poll_recounts, :null_amount, 0
|
||||||
|
change_column_default :poll_recounts, :total_amount, 0
|
||||||
|
end
|
||||||
|
end
|
||||||
24
db/schema.rb
24
db/schema.rb
@@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20171002103314) do
|
ActiveRecord::Schema.define(version: 20171002191347) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@@ -690,6 +690,25 @@ ActiveRecord::Schema.define(version: 20171002103314) do
|
|||||||
add_index "poll_questions", ["proposal_id"], name: "index_poll_questions_on_proposal_id", using: :btree
|
add_index "poll_questions", ["proposal_id"], name: "index_poll_questions_on_proposal_id", using: :btree
|
||||||
add_index "poll_questions", ["tsv"], name: "index_poll_questions_on_tsv", using: :gin
|
add_index "poll_questions", ["tsv"], name: "index_poll_questions_on_tsv", using: :gin
|
||||||
|
|
||||||
|
create_table "poll_recounts", force: :cascade do |t|
|
||||||
|
t.integer "author_id"
|
||||||
|
t.string "origin"
|
||||||
|
t.date "date"
|
||||||
|
t.integer "booth_assignment_id"
|
||||||
|
t.integer "officer_assignment_id"
|
||||||
|
t.text "officer_assignment_id_log", default: ""
|
||||||
|
t.text "author_id_log", default: ""
|
||||||
|
t.integer "white_amount", default: 0
|
||||||
|
t.text "white_amount_log", default: ""
|
||||||
|
t.integer "null_amount", default: 0
|
||||||
|
t.text "null_amount_log", default: ""
|
||||||
|
t.integer "total_amount", default: 0
|
||||||
|
t.text "total_amount_log", default: ""
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index "poll_recounts", ["booth_assignment_id"], name: "index_poll_recounts_on_booth_assignment_id", using: :btree
|
||||||
|
add_index "poll_recounts", ["officer_assignment_id"], name: "index_poll_recounts_on_officer_assignment_id", using: :btree
|
||||||
|
|
||||||
create_table "poll_shifts", force: :cascade do |t|
|
create_table "poll_shifts", force: :cascade do |t|
|
||||||
t.integer "booth_id"
|
t.integer "booth_id"
|
||||||
t.integer "officer_id"
|
t.integer "officer_id"
|
||||||
@@ -734,6 +753,7 @@ ActiveRecord::Schema.define(version: 20171002103314) do
|
|||||||
t.integer "answer_id"
|
t.integer "answer_id"
|
||||||
t.integer "officer_assignment_id"
|
t.integer "officer_assignment_id"
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
|
t.string "origin"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "poll_voters", ["booth_assignment_id"], name: "index_poll_voters_on_booth_assignment_id", using: :btree
|
add_index "poll_voters", ["booth_assignment_id"], name: "index_poll_voters_on_booth_assignment_id", using: :btree
|
||||||
@@ -1127,6 +1147,8 @@ ActiveRecord::Schema.define(version: 20171002103314) do
|
|||||||
add_foreign_key "poll_questions", "polls"
|
add_foreign_key "poll_questions", "polls"
|
||||||
add_foreign_key "poll_questions", "proposals"
|
add_foreign_key "poll_questions", "proposals"
|
||||||
add_foreign_key "poll_questions", "users", column: "author_id"
|
add_foreign_key "poll_questions", "users", column: "author_id"
|
||||||
|
add_foreign_key "poll_recounts", "poll_booth_assignments", column: "booth_assignment_id"
|
||||||
|
add_foreign_key "poll_recounts", "poll_officer_assignments", column: "officer_assignment_id"
|
||||||
add_foreign_key "poll_voters", "polls"
|
add_foreign_key "poll_voters", "polls"
|
||||||
add_foreign_key "poll_white_results", "poll_booth_assignments", column: "booth_assignment_id"
|
add_foreign_key "poll_white_results", "poll_booth_assignments", column: "booth_assignment_id"
|
||||||
add_foreign_key "poll_white_results", "poll_officer_assignments", column: "officer_assignment_id"
|
add_foreign_key "poll_white_results", "poll_officer_assignments", column: "officer_assignment_id"
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ Setting['feature.public_stats'] = true
|
|||||||
Setting['feature.budgets'] = true
|
Setting['feature.budgets'] = true
|
||||||
Setting['feature.signature_sheets'] = true
|
Setting['feature.signature_sheets'] = true
|
||||||
Setting['feature.legislation'] = true
|
Setting['feature.legislation'] = true
|
||||||
|
Setting['feature.user.recommendations'] = true
|
||||||
Setting['feature.community'] = true
|
Setting['feature.community'] = true
|
||||||
Setting['feature.map'] = nil
|
Setting['feature.map'] = nil
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,12 @@ FactoryGirl.define do
|
|||||||
trait :verified do
|
trait :verified do
|
||||||
verified_at Time.current
|
verified_at Time.current
|
||||||
end
|
end
|
||||||
|
|
||||||
|
trait :in_census do
|
||||||
|
document_number "12345678Z"
|
||||||
|
document_type "1"
|
||||||
|
verified_at Time.current
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
factory :identity do
|
factory :identity do
|
||||||
@@ -525,6 +531,7 @@ FactoryGirl.define do
|
|||||||
factory :poll_voter, class: 'Poll::Voter' do
|
factory :poll_voter, class: 'Poll::Voter' do
|
||||||
poll
|
poll
|
||||||
association :user, :level_two
|
association :user, :level_two
|
||||||
|
origin "web"
|
||||||
|
|
||||||
trait :from_booth do
|
trait :from_booth do
|
||||||
association :booth_assignment, factory: :poll_booth_assignment
|
association :booth_assignment, factory: :poll_booth_assignment
|
||||||
@@ -569,6 +576,11 @@ FactoryGirl.define do
|
|||||||
origin { 'web' }
|
origin { 'web' }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
factory :poll_recount, class: 'Poll::Recount' do
|
||||||
|
association :author, factory: :user
|
||||||
|
origin { 'web' }
|
||||||
|
end
|
||||||
|
|
||||||
factory :officing_residence, class: 'Officing::Residence' do
|
factory :officing_residence, class: 'Officing::Residence' do
|
||||||
user
|
user
|
||||||
association :officer, factory: :poll_officer
|
association :officer, factory: :poll_officer
|
||||||
|
|||||||
@@ -249,18 +249,18 @@ feature 'Admin polls' do
|
|||||||
booth_assignment_final_recounted = create(:poll_booth_assignment, poll: poll)
|
booth_assignment_final_recounted = create(:poll_booth_assignment, poll: poll)
|
||||||
|
|
||||||
3.times do |i|
|
3.times do |i|
|
||||||
create(:poll_total_result,
|
create(:poll_recount,
|
||||||
booth_assignment: booth_assignment,
|
booth_assignment: booth_assignment,
|
||||||
date: poll.starts_at + i.days,
|
date: poll.starts_at + i.days,
|
||||||
amount: 21)
|
total_amount: 21)
|
||||||
end
|
end
|
||||||
|
|
||||||
2.times { create(:poll_voter, booth_assignment: booth_assignment_final_recounted) }
|
2.times { create(:poll_voter, booth_assignment: booth_assignment_final_recounted) }
|
||||||
|
|
||||||
create(:poll_total_result,
|
create(:poll_recount,
|
||||||
booth_assignment: booth_assignment_final_recounted,
|
booth_assignment: booth_assignment_final_recounted,
|
||||||
date: poll.ends_at,
|
date: poll.ends_at,
|
||||||
amount: 55555)
|
total_amount: 55555)
|
||||||
|
|
||||||
visit admin_poll_path(poll)
|
visit admin_poll_path(poll)
|
||||||
|
|
||||||
@@ -318,12 +318,10 @@ feature 'Admin polls' do
|
|||||||
answer: 'Tomorrow',
|
answer: 'Tomorrow',
|
||||||
amount: 5)
|
amount: 5)
|
||||||
end
|
end
|
||||||
create(:poll_white_result,
|
create(:poll_recount,
|
||||||
booth_assignment: booth_assignment_1,
|
booth_assignment: booth_assignment_1,
|
||||||
amount: 21)
|
white_amount: 21,
|
||||||
create(:poll_null_result,
|
null_amount: 44)
|
||||||
booth_assignment: booth_assignment_3,
|
|
||||||
amount: 44)
|
|
||||||
|
|
||||||
visit admin_poll_path(poll)
|
visit admin_poll_path(poll)
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ feature 'Admin' do
|
|||||||
visit admin_root_path
|
visit admin_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(admin_root_path)
|
expect(current_path).not_to eq(admin_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ feature 'Admin' do
|
|||||||
visit admin_root_path
|
visit admin_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(admin_root_path)
|
expect(current_path).not_to eq(admin_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ feature 'Admin' do
|
|||||||
visit admin_root_path
|
visit admin_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(admin_root_path)
|
expect(current_path).not_to eq(admin_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ feature 'Admin' do
|
|||||||
visit admin_root_path
|
visit admin_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(admin_root_path)
|
expect(current_path).not_to eq(admin_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ feature 'Admin' do
|
|||||||
visit admin_root_path
|
visit admin_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(admin_root_path)
|
expect(current_path).not_to eq(admin_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ feature 'Debates' do
|
|||||||
|
|
||||||
visit edit_debate_path(debate)
|
visit edit_debate_path(debate)
|
||||||
expect(current_path).not_to eq(edit_debate_path(debate))
|
expect(current_path).not_to eq(edit_debate_path(debate))
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to carry out the action 'edit' on debate."
|
expect(page).to have_content "You do not have permission to carry out the action 'edit' on debate."
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -234,7 +234,7 @@ feature 'Debates' do
|
|||||||
visit edit_debate_path(debate)
|
visit edit_debate_path(debate)
|
||||||
|
|
||||||
expect(current_path).not_to eq(edit_debate_path(debate))
|
expect(current_path).not_to eq(edit_debate_path(debate))
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content 'You do not have permission to'
|
expect(page).to have_content 'You do not have permission to'
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -351,6 +351,69 @@ feature 'Debates' do
|
|||||||
expect(current_url).to include('order=created_at')
|
expect(current_url).to include('order=created_at')
|
||||||
expect(current_url).to include('page=1')
|
expect(current_url).to include('page=1')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'Recommendations' do
|
||||||
|
|
||||||
|
background do
|
||||||
|
Setting['feature.user.recommendations'] = true
|
||||||
|
create(:debate, title: 'Best', cached_votes_total: 10, tag_list: "Sport")
|
||||||
|
create(:debate, title: 'Medium', cached_votes_total: 5, tag_list: "Sport")
|
||||||
|
create(:debate, title: 'Worst', cached_votes_total: 1, tag_list: "Sport")
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
Setting['feature.user.recommendations'] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Debates can not ordered by recommendations when there is not an user logged', :js do
|
||||||
|
visit debates_path
|
||||||
|
|
||||||
|
expect(page).not_to have_selector('a', text: 'recommendations')
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Should display text when there are not recommendeds results', :js do
|
||||||
|
user = create(:user)
|
||||||
|
proposal = create(:proposal, tag_list: "Distinct_to_sport")
|
||||||
|
create(:follow, followable: proposal, user: user)
|
||||||
|
login_as(user)
|
||||||
|
visit debates_path
|
||||||
|
|
||||||
|
click_link 'recommendations'
|
||||||
|
|
||||||
|
expect(page).to have_content "There are not debates related to your interests"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Should display text when user has not related interests', :js do
|
||||||
|
user = create(:user)
|
||||||
|
login_as(user)
|
||||||
|
visit debates_path
|
||||||
|
|
||||||
|
click_link 'recommendations'
|
||||||
|
|
||||||
|
expect(page).to have_content "Follow proposals so we can give you recommendations"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Debates are ordered by recommendations when there is a user logged', :js do
|
||||||
|
proposal = create(:proposal, tag_list: "Sport" )
|
||||||
|
user = create(:user)
|
||||||
|
create(:follow, followable: proposal, user: user)
|
||||||
|
login_as(user)
|
||||||
|
|
||||||
|
visit debates_path
|
||||||
|
|
||||||
|
click_link 'recommendations'
|
||||||
|
|
||||||
|
expect(page).to have_selector('a.active', text: 'recommendations')
|
||||||
|
|
||||||
|
within '#debates' do
|
||||||
|
expect('Best').to appear_before('Medium')
|
||||||
|
expect('Medium').to appear_before('Worst')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(current_url).to include('order=recommendations')
|
||||||
|
expect(current_url).to include('page=1')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "Search" do
|
context "Search" do
|
||||||
@@ -759,6 +822,32 @@ feature 'Debates' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario "Reorder by recommendations results maintaing search", :js do
|
||||||
|
Setting['feature.user.recommendations'] = true
|
||||||
|
user = create(:user)
|
||||||
|
login_as(user)
|
||||||
|
debate1 = create(:debate, title: "Show you got", cached_votes_total: 10, tag_list: "Sport")
|
||||||
|
debate2 = create(:debate, title: "Show what you got", cached_votes_total: 1, tag_list: "Sport")
|
||||||
|
debate3 = create(:debate, title: "Do not display with same tag", cached_votes_total: 100, tag_list: "Sport")
|
||||||
|
debate4 = create(:debate, title: "Do not display", cached_votes_total: 1)
|
||||||
|
proposal1 = create(:proposal, tag_list: "Sport")
|
||||||
|
create(:follow, followable: proposal1, user: user)
|
||||||
|
|
||||||
|
visit debates_path
|
||||||
|
fill_in "search", with: "Show you got"
|
||||||
|
click_button "Search"
|
||||||
|
click_link 'recommendations'
|
||||||
|
expect(page).to have_selector("a.active", text: "recommendations")
|
||||||
|
|
||||||
|
within("#debates") do
|
||||||
|
expect(all(".debate")[0].text).to match "Show you got"
|
||||||
|
expect(all(".debate")[1].text).to match "Show what you got"
|
||||||
|
expect(page).to_not have_content "Do not display with same tag"
|
||||||
|
expect(page).to_not have_content "Do not display"
|
||||||
|
end
|
||||||
|
Setting['feature.user.recommendations'] = nil
|
||||||
|
end
|
||||||
|
|
||||||
scenario 'After a search do not show featured debates' do
|
scenario 'After a search do not show featured debates' do
|
||||||
featured_debates = create_featured_debates
|
featured_debates = create_featured_debates
|
||||||
debate = create(:debate, title: "Abcdefghi")
|
debate = create(:debate, title: "Abcdefghi")
|
||||||
|
|||||||
@@ -3,20 +3,138 @@ require 'rails_helper'
|
|||||||
feature "Home" do
|
feature "Home" do
|
||||||
|
|
||||||
feature "For not logged users" do
|
feature "For not logged users" do
|
||||||
|
|
||||||
scenario 'Welcome message' do
|
scenario 'Welcome message' do
|
||||||
visit root_path
|
visit root_path
|
||||||
|
|
||||||
expect(page).to have_content "Love the city, and it will become a city you love"
|
expect(page).to have_content "Love the city, and it will become a city you love"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario 'Not display recommended section' do
|
||||||
|
debate = create(:debate)
|
||||||
|
|
||||||
|
visit root_path
|
||||||
|
|
||||||
|
expect(page).not_to have_content "Recommendations that may interest you"
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature "For signed in users" do
|
feature "For signed in users" do
|
||||||
scenario 'Redirect to proposals' do
|
|
||||||
login_as(create(:user))
|
|
||||||
visit root_path
|
|
||||||
|
|
||||||
expect(current_path).to eq proposals_path
|
feature "Recommended" do
|
||||||
|
|
||||||
|
background do
|
||||||
|
Setting['feature.user.recommendations'] = true
|
||||||
|
user = create(:user)
|
||||||
|
proposal = create(:proposal, tag_list: "Sport" )
|
||||||
|
create(:follow, followable: proposal, user: user)
|
||||||
|
login_as(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
Setting['feature.user.recommendations'] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Display recommended section' do
|
||||||
|
debate = create(:debate, tag_list: "Sport")
|
||||||
|
visit root_path
|
||||||
|
expect(page).to have_content "Recommendations that may interest you"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Display recommended section when feature flag recommended is active' do
|
||||||
|
debate = create(:debate, tag_list: "Sport")
|
||||||
|
visit root_path
|
||||||
|
expect(page).to have_content "Recommendations that may interest you"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Not display recommended section when feature flag recommended is not active' do
|
||||||
|
debate = create(:debate, tag_list: "Sport")
|
||||||
|
Setting['feature.user.recommendations'] = false
|
||||||
|
|
||||||
|
visit root_path
|
||||||
|
|
||||||
|
expect(page).not_to have_content "Recommendations that may interest you"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Display debates' do
|
||||||
|
debate = create(:debate, tag_list: "Sport")
|
||||||
|
|
||||||
|
visit root_path
|
||||||
|
|
||||||
|
expect(page).to have_content debate.title
|
||||||
|
expect(page).to have_content debate.description
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Display all recommended debates link' do
|
||||||
|
debate = create(:debate, tag_list: "Sport")
|
||||||
|
visit root_path
|
||||||
|
expect(page).to have_link("All recommended debates", href: debates_path(order: "recommendations"))
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Display proposal' do
|
||||||
|
proposal = create(:proposal, tag_list: "Sport")
|
||||||
|
|
||||||
|
visit root_path
|
||||||
|
|
||||||
|
expect(page).to have_content proposal.title
|
||||||
|
expect(page).to have_content proposal.description
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Display all recommended proposals link' do
|
||||||
|
debate = create(:proposal, tag_list: "Sport")
|
||||||
|
visit root_path
|
||||||
|
expect(page).to have_link("All recommended proposals", href: proposals_path(order: "recommendations"))
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Display orbit carrousel' do
|
||||||
|
create_list(:debate, 3, tag_list: "Sport")
|
||||||
|
|
||||||
|
visit root_path
|
||||||
|
|
||||||
|
expect(page).to have_selector('li[data-slide="0"]')
|
||||||
|
expect(page).to have_selector('li[data-slide="1"]', visible: false)
|
||||||
|
expect(page).to have_selector('li[data-slide="2"]', visible: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Display recommended show when click on carousel' do
|
||||||
|
debate = create(:debate, tag_list: "Sport")
|
||||||
|
|
||||||
|
visit root_path
|
||||||
|
click_on debate.title
|
||||||
|
|
||||||
|
expect(current_path).to eq debate_path(debate)
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Do not display recommended section when there are not debates and proposals' do
|
||||||
|
visit root_path
|
||||||
|
expect(page).not_to have_content "Recommendations that may interest you"
|
||||||
|
end
|
||||||
|
|
||||||
|
feature 'Carousel size' do
|
||||||
|
|
||||||
|
scenario 'Display debates centered when there are no proposals' do
|
||||||
|
debate = create(:debate, tag_list: "Sport")
|
||||||
|
visit root_path
|
||||||
|
expect(page).to have_selector('.medium-centered.large-centered')
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Correct display debates and proposals' do
|
||||||
|
proposal = create(:proposal, tag_list: "Sport")
|
||||||
|
debates = create(:debate, tag_list: "Sport")
|
||||||
|
|
||||||
|
visit root_path
|
||||||
|
|
||||||
|
expect(page).to have_selector('.debates.medium-offset-2.large-offset-2')
|
||||||
|
expect(page).not_to have_selector('.proposals.medium-offset-2.large-offset-2')
|
||||||
|
expect(page).not_to have_selector('.debates.end')
|
||||||
|
expect(page).to have_selector('.proposals.end')
|
||||||
|
expect(page).not_to have_selector('.medium-centered.large-centered')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
feature 'IE alert' do
|
feature 'IE alert' do
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ feature 'Moderation' do
|
|||||||
visit moderation_root_path
|
visit moderation_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(moderation_root_path)
|
expect(current_path).not_to eq(moderation_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ feature 'Moderation' do
|
|||||||
visit moderation_root_path
|
visit moderation_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(moderation_root_path)
|
expect(current_path).not_to eq(moderation_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ feature 'Moderation' do
|
|||||||
visit moderation_root_path
|
visit moderation_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(moderation_root_path)
|
expect(current_path).not_to eq(moderation_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ feature 'Moderation' do
|
|||||||
visit moderation_root_path
|
visit moderation_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(moderation_root_path)
|
expect(current_path).not_to eq(moderation_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,16 +15,7 @@ feature "Notifications" do
|
|||||||
let(:legislation_annotation) { create(:legislation_annotation, author: author) }
|
let(:legislation_annotation) { create(:legislation_annotation, author: author) }
|
||||||
|
|
||||||
scenario "User commented on my debate", :js do
|
scenario "User commented on my debate", :js do
|
||||||
login_as user
|
create(:notification, notifiable: debate, user: author)
|
||||||
visit debate_path debate
|
|
||||||
|
|
||||||
fill_in "comment-body-debate_#{debate.id}", with: "I commented on your debate"
|
|
||||||
click_button "Publish comment"
|
|
||||||
within "#comments" do
|
|
||||||
expect(page).to have_content "I commented on your debate"
|
|
||||||
end
|
|
||||||
|
|
||||||
logout
|
|
||||||
login_as author
|
login_as author
|
||||||
visit root_path
|
visit root_path
|
||||||
|
|
||||||
@@ -37,17 +28,7 @@ feature "Notifications" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
scenario "User commented on my legislation question", :js do
|
scenario "User commented on my legislation question", :js do
|
||||||
verified_user = create(:user, :level_two)
|
create(:notification, notifiable: legislation_question, user: administrator)
|
||||||
login_as verified_user
|
|
||||||
visit legislation_process_question_path legislation_question.process, legislation_question
|
|
||||||
|
|
||||||
fill_in "comment-body-legislation_question_#{legislation_question.id}", with: "I answered your question"
|
|
||||||
click_button "Publish answer"
|
|
||||||
within "#comments" do
|
|
||||||
expect(page).to have_content "I answered your question"
|
|
||||||
end
|
|
||||||
|
|
||||||
logout
|
|
||||||
login_as administrator
|
login_as administrator
|
||||||
visit root_path
|
visit root_path
|
||||||
|
|
||||||
@@ -82,6 +63,7 @@ feature "Notifications" do
|
|||||||
logout
|
logout
|
||||||
login_as author
|
login_as author
|
||||||
visit root_path
|
visit root_path
|
||||||
|
visit root_path
|
||||||
|
|
||||||
find(".icon-notification").click
|
find(".icon-notification").click
|
||||||
|
|
||||||
@@ -107,8 +89,10 @@ feature "Notifications" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
logout
|
logout
|
||||||
|
|
||||||
login_as author
|
login_as author
|
||||||
visit root_path
|
visit root_path
|
||||||
|
visit root_path
|
||||||
|
|
||||||
find(".icon-notification").click
|
find(".icon-notification").click
|
||||||
|
|
||||||
@@ -137,6 +121,7 @@ feature "Notifications" do
|
|||||||
|
|
||||||
login_as author
|
login_as author
|
||||||
visit root_path
|
visit root_path
|
||||||
|
visit root_path
|
||||||
|
|
||||||
find(".icon-notification").click
|
find(".icon-notification").click
|
||||||
|
|
||||||
@@ -208,6 +193,7 @@ feature "Notifications" do
|
|||||||
logout
|
logout
|
||||||
login_as user1
|
login_as user1
|
||||||
visit root_path
|
visit root_path
|
||||||
|
visit root_path
|
||||||
|
|
||||||
find(".icon-notification").click
|
find(".icon-notification").click
|
||||||
|
|
||||||
@@ -219,6 +205,7 @@ feature "Notifications" do
|
|||||||
logout
|
logout
|
||||||
login_as user2
|
login_as user2
|
||||||
visit root_path
|
visit root_path
|
||||||
|
visit root_path
|
||||||
|
|
||||||
find(".icon-notification").click
|
find(".icon-notification").click
|
||||||
|
|
||||||
@@ -230,6 +217,7 @@ feature "Notifications" do
|
|||||||
logout
|
logout
|
||||||
login_as user3
|
login_as user3
|
||||||
visit root_path
|
visit root_path
|
||||||
|
visit root_path
|
||||||
|
|
||||||
find(".icon-no-notification").click
|
find(".icon-no-notification").click
|
||||||
|
|
||||||
|
|||||||
@@ -127,21 +127,13 @@ feature 'Officing Results' do
|
|||||||
date: @poll.ends_at,
|
date: @poll.ends_at,
|
||||||
question: @question_1,
|
question: @question_1,
|
||||||
amount: 33)
|
amount: 33)
|
||||||
white_result = create(:poll_white_result,
|
poll_recount = create(:poll_recount,
|
||||||
officer_assignment: @officer_assignment,
|
officer_assignment: @officer_assignment,
|
||||||
booth_assignment: @officer_assignment.booth_assignment,
|
booth_assignment: @officer_assignment.booth_assignment,
|
||||||
date: @poll.ends_at,
|
date: @poll.ends_at,
|
||||||
amount: 21)
|
white_amount: 21,
|
||||||
null_result = create(:poll_null_result,
|
null_amount: 44,
|
||||||
officer_assignment: @officer_assignment,
|
total_amount: 66)
|
||||||
booth_assignment: @officer_assignment.booth_assignment,
|
|
||||||
date: @poll.ends_at,
|
|
||||||
amount: 44)
|
|
||||||
total_result = create(:poll_total_result,
|
|
||||||
officer_assignment: @officer_assignment,
|
|
||||||
booth_assignment: @officer_assignment.booth_assignment,
|
|
||||||
date: @poll.ends_at,
|
|
||||||
amount: 66)
|
|
||||||
|
|
||||||
visit officing_poll_results_path(@poll,
|
visit officing_poll_results_path(@poll,
|
||||||
date: I18n.l(@poll.ends_at.to_date),
|
date: I18n.l(@poll.ends_at.to_date),
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ feature 'Poll Officing' do
|
|||||||
visit officing_root_path
|
visit officing_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(officing_root_path)
|
expect(current_path).not_to eq(officing_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ feature 'Poll Officing' do
|
|||||||
visit officing_root_path
|
visit officing_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(officing_root_path)
|
expect(current_path).not_to eq(officing_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ feature 'Poll Officing' do
|
|||||||
visit officing_root_path
|
visit officing_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(officing_root_path)
|
expect(current_path).not_to eq(officing_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ feature 'Poll Officing' do
|
|||||||
visit officing_root_path
|
visit officing_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(officing_root_path)
|
expect(current_path).not_to eq(officing_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ feature 'Polls' do
|
|||||||
poll.geozones << geozone
|
poll.geozones << geozone
|
||||||
create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca')
|
create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca')
|
||||||
user = create(:user, :level_two, geozone: geozone)
|
user = create(:user, :level_two, geozone: geozone)
|
||||||
|
|
||||||
login_as user
|
login_as user
|
||||||
visit poll_path(poll)
|
visit poll_path(poll)
|
||||||
|
|
||||||
@@ -193,5 +194,25 @@ feature 'Polls' do
|
|||||||
expect(page).to have_link('Chewbacca')
|
expect(page).to have_link('Chewbacca')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario 'Level 2 users changing answer', :js do
|
||||||
|
poll.update(geozone_restricted: true)
|
||||||
|
poll.geozones << geozone
|
||||||
|
create(:poll_question, poll: poll, valid_answers: 'Han Solo, Chewbacca')
|
||||||
|
user = create(:user, :level_two, geozone: geozone)
|
||||||
|
|
||||||
|
login_as user
|
||||||
|
visit poll_path(poll)
|
||||||
|
|
||||||
|
click_link 'Han Solo'
|
||||||
|
|
||||||
|
expect(page).to_not have_link('Han Solo')
|
||||||
|
expect(page).to have_link('Chewbacca')
|
||||||
|
|
||||||
|
click_link 'Chewbacca'
|
||||||
|
|
||||||
|
expect(page).to_not have_link('Chewbacca')
|
||||||
|
expect(page).to have_link('Han Solo')
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
94
spec/features/polls/voter_spec.rb
Normal file
94
spec/features/polls/voter_spec.rb
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
feature "Voter" do
|
||||||
|
|
||||||
|
context "Origin" do
|
||||||
|
|
||||||
|
scenario "Voting via web", :js do
|
||||||
|
poll = create(:poll)
|
||||||
|
question = create(:poll_question, poll: poll, valid_answers: 'Yes, No')
|
||||||
|
user = create(:user, :level_two)
|
||||||
|
|
||||||
|
login_as user
|
||||||
|
visit question_path(question)
|
||||||
|
|
||||||
|
click_link 'Answer this question'
|
||||||
|
click_link 'Yes'
|
||||||
|
|
||||||
|
expect(page).to_not have_link('Yes')
|
||||||
|
expect(Poll::Voter.count).to eq(1)
|
||||||
|
expect(Poll::Voter.first.origin).to eq("web")
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Voting in booth", :js do
|
||||||
|
user = create(:user, :in_census)
|
||||||
|
create(:geozone, :in_census)
|
||||||
|
|
||||||
|
poll = create(:poll)
|
||||||
|
officer = create(:poll_officer)
|
||||||
|
|
||||||
|
ba = create(:poll_booth_assignment, poll: poll)
|
||||||
|
create(:poll_officer_assignment, officer: officer, booth_assignment: ba)
|
||||||
|
|
||||||
|
login_through_form_as_officer(officer.user)
|
||||||
|
|
||||||
|
visit new_officing_residence_path
|
||||||
|
officing_verify_residence
|
||||||
|
|
||||||
|
expect(page).to have_content poll.name
|
||||||
|
|
||||||
|
first(:button, "Confirm vote").click
|
||||||
|
expect(page).to have_content "Vote introduced!"
|
||||||
|
|
||||||
|
expect(Poll::Voter.count).to eq(1)
|
||||||
|
expect(Poll::Voter.first.origin).to eq("booth")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "Trying to vote the same poll in booth and web" do
|
||||||
|
|
||||||
|
let(:poll) { create(:poll) }
|
||||||
|
let(:question) { create(:poll_question, poll: poll, valid_answers: 'Yes, No') }
|
||||||
|
let!(:user) { create(:user, :in_census) }
|
||||||
|
|
||||||
|
let(:officer) { create(:poll_officer) }
|
||||||
|
let(:ba) { create(:poll_booth_assignment, poll: poll) }
|
||||||
|
let!(:oa) { create(:poll_officer_assignment, officer: officer, booth_assignment: ba) }
|
||||||
|
|
||||||
|
scenario "Trying to vote in web and then in booth", :js do
|
||||||
|
login_as user
|
||||||
|
vote_for_poll_via_web
|
||||||
|
|
||||||
|
click_link "Sign out"
|
||||||
|
|
||||||
|
login_through_form_as_officer(officer.user)
|
||||||
|
|
||||||
|
visit new_officing_residence_path
|
||||||
|
officing_verify_residence
|
||||||
|
|
||||||
|
expect(page).to have_content poll.name
|
||||||
|
expect(page).to_not have_button "Confirm vote"
|
||||||
|
expect(page).to have_content "Has already participated in this poll"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Trying to vote in booth and then in web", :js do
|
||||||
|
login_through_form_as_officer(officer.user)
|
||||||
|
|
||||||
|
vote_for_poll_via_booth
|
||||||
|
|
||||||
|
visit root_path
|
||||||
|
click_link "Sign out"
|
||||||
|
|
||||||
|
login_as user
|
||||||
|
visit question_path(question)
|
||||||
|
|
||||||
|
click_link 'Answer this question'
|
||||||
|
|
||||||
|
expect(page).to_not have_link('Yes')
|
||||||
|
expect(page).to have_content "You have already participated in a booth for this poll."
|
||||||
|
expect(Poll::Voter.count).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -189,7 +189,7 @@ feature 'Proposal Notifications' do
|
|||||||
login_as(user)
|
login_as(user)
|
||||||
visit new_proposal_notification_path(proposal_id: proposal.id)
|
visit new_proposal_notification_path(proposal_id: proposal.id)
|
||||||
|
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content("You do not have permission to carry out the action")
|
expect(page).to have_content("You do not have permission to carry out the action")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -556,7 +556,7 @@ feature 'Proposals' do
|
|||||||
|
|
||||||
visit edit_proposal_path(proposal)
|
visit edit_proposal_path(proposal)
|
||||||
expect(current_path).not_to eq(edit_proposal_path(proposal))
|
expect(current_path).not_to eq(edit_proposal_path(proposal))
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content 'You do not have permission'
|
expect(page).to have_content 'You do not have permission'
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -571,7 +571,7 @@ feature 'Proposals' do
|
|||||||
visit edit_proposal_path(proposal)
|
visit edit_proposal_path(proposal)
|
||||||
|
|
||||||
expect(current_path).not_to eq(edit_proposal_path(proposal))
|
expect(current_path).not_to eq(edit_proposal_path(proposal))
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content 'You do not have permission'
|
expect(page).to have_content 'You do not have permission'
|
||||||
Setting["max_votes_for_proposal_edit"] = 1000
|
Setting["max_votes_for_proposal_edit"] = 1000
|
||||||
end
|
end
|
||||||
@@ -663,6 +663,69 @@ feature 'Proposals' do
|
|||||||
expect(current_url).to include('order=created_at')
|
expect(current_url).to include('order=created_at')
|
||||||
expect(current_url).to include('page=1')
|
expect(current_url).to include('page=1')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'Recommendations' do
|
||||||
|
|
||||||
|
before do
|
||||||
|
Setting['feature.user.recommendations'] = true
|
||||||
|
create(:proposal, title: 'Best', cached_votes_up: 10, tag_list: "Sport")
|
||||||
|
create(:proposal, title: 'Medium', cached_votes_up: 5, tag_list: "Sport")
|
||||||
|
create(:proposal, title: 'Worst', cached_votes_up: 1, tag_list: "Sport")
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
Setting['feature.user.recommendations'] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Proposals can not ordered by recommendations when there is not an user logged', :js do
|
||||||
|
visit proposals_path
|
||||||
|
|
||||||
|
expect(page).not_to have_selector('a', text: 'recommendations')
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Should display text when there are not recommendeds results', :js do
|
||||||
|
user = create(:user)
|
||||||
|
proposal = create(:proposal, tag_list: "Distinct_to_sport")
|
||||||
|
create(:follow, followable: proposal, user: user)
|
||||||
|
login_as(user)
|
||||||
|
visit proposals_path
|
||||||
|
|
||||||
|
click_link 'recommendations'
|
||||||
|
|
||||||
|
expect(page).to have_content "There are not proposals related to your interests"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Should display text when user has not related interests', :js do
|
||||||
|
user = create(:user)
|
||||||
|
login_as(user)
|
||||||
|
visit proposals_path
|
||||||
|
|
||||||
|
click_link 'recommendations'
|
||||||
|
|
||||||
|
expect(page).to have_content "Follow proposals so we can give you recommendations"
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Proposals are ordered by recommendations when there is an user logged', :js do
|
||||||
|
user = create(:user)
|
||||||
|
proposal = create(:proposal, tag_list: "Sport")
|
||||||
|
create(:follow, followable: proposal, user: user)
|
||||||
|
login_as(user)
|
||||||
|
|
||||||
|
visit proposals_path
|
||||||
|
|
||||||
|
click_link 'recommendations'
|
||||||
|
|
||||||
|
expect(page).to have_selector('a.active', text: 'recommendations')
|
||||||
|
|
||||||
|
within '#proposals-list' do
|
||||||
|
expect('Best').to appear_before('Medium')
|
||||||
|
expect('Medium').to appear_before('Worst')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(current_url).to include('order=recommendations')
|
||||||
|
expect(current_url).to include('page=1')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
feature 'Archived proposals' do
|
feature 'Archived proposals' do
|
||||||
@@ -1198,6 +1261,32 @@ feature 'Proposals' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario "Reorder by recommendations results maintaing search", :js do
|
||||||
|
Setting['feature.user.recommendations'] = true
|
||||||
|
user = create(:user)
|
||||||
|
login_as(user)
|
||||||
|
proposal1 = create(:proposal, title: "Show you got", cached_votes_up: 10, tag_list: "Sport")
|
||||||
|
proposal2 = create(:proposal, title: "Show what you got", cached_votes_up: 1, tag_list: "Sport")
|
||||||
|
proposal3 = create(:proposal, title: "Do not display with same tag", cached_votes_up: 100, tag_list: "Sport")
|
||||||
|
proposal4 = create(:proposal, title: "Do not display", cached_votes_up: 1)
|
||||||
|
proposal5 = create(:proposal, tag_list: "Sport")
|
||||||
|
create(:follow, followable: proposal5, user: user)
|
||||||
|
|
||||||
|
visit proposals_path
|
||||||
|
fill_in "search", with: "Show you got"
|
||||||
|
click_button "Search"
|
||||||
|
click_link 'recommendations'
|
||||||
|
expect(page).to have_selector("a.active", text: "recommendations")
|
||||||
|
|
||||||
|
within("#proposals") do
|
||||||
|
expect(all(".proposal")[0].text).to match "Show you got"
|
||||||
|
expect(all(".proposal")[1].text).to match "Show what you got"
|
||||||
|
expect(page).to_not have_content "Do not display with same tag"
|
||||||
|
expect(page).to_not have_content "Do not display"
|
||||||
|
end
|
||||||
|
Setting['feature.user.recommendations'] = nil
|
||||||
|
end
|
||||||
|
|
||||||
scenario 'After a search do not show featured proposals' do
|
scenario 'After a search do not show featured proposals' do
|
||||||
featured_proposals = create_featured_proposals
|
featured_proposals = create_featured_proposals
|
||||||
proposal = create(:proposal, title: "Abcdefghi")
|
proposal = create(:proposal, title: "Abcdefghi")
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ feature 'Valuation' do
|
|||||||
visit valuation_root_path
|
visit valuation_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(valuation_root_path)
|
expect(current_path).not_to eq(valuation_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ feature 'Valuation' do
|
|||||||
visit valuation_root_path
|
visit valuation_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(valuation_root_path)
|
expect(current_path).not_to eq(valuation_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ feature 'Valuation' do
|
|||||||
visit valuation_root_path
|
visit valuation_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(valuation_root_path)
|
expect(current_path).not_to eq(valuation_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ feature 'Valuation' do
|
|||||||
visit valuation_root_path
|
visit valuation_root_path
|
||||||
|
|
||||||
expect(current_path).not_to eq(valuation_root_path)
|
expect(current_path).not_to eq(valuation_root_path)
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
expect(page).to have_content "You do not have permission to access this page"
|
expect(page).to have_content "You do not have permission to access this page"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ feature "Welcome screen" do
|
|||||||
|
|
||||||
login_through_form_as(user)
|
login_through_form_as(user)
|
||||||
|
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario 'is not shown to organizations' do
|
scenario 'is not shown to organizations' do
|
||||||
@@ -41,7 +41,7 @@ feature "Welcome screen" do
|
|||||||
|
|
||||||
login_through_form_as(organization.user)
|
login_through_form_as(organization.user)
|
||||||
|
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario 'it is not shown to level-2 users' do
|
scenario 'it is not shown to level-2 users' do
|
||||||
@@ -49,7 +49,7 @@ feature "Welcome screen" do
|
|||||||
|
|
||||||
login_through_form_as(user)
|
login_through_form_as(user)
|
||||||
|
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario 'it is not shown to level-3 users' do
|
scenario 'it is not shown to level-3 users' do
|
||||||
@@ -57,7 +57,7 @@ feature "Welcome screen" do
|
|||||||
|
|
||||||
login_through_form_as(user)
|
login_through_form_as(user)
|
||||||
|
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario 'is not shown to administrators' do
|
scenario 'is not shown to administrators' do
|
||||||
@@ -65,7 +65,7 @@ feature "Welcome screen" do
|
|||||||
|
|
||||||
login_through_form_as(administrator.user)
|
login_through_form_as(administrator.user)
|
||||||
|
|
||||||
expect(current_path).to eq(proposals_path)
|
expect(current_path).to eq(root_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ describe "Abilities::Administrator" do
|
|||||||
|
|
||||||
it { should be_able_to(:create, Budget) }
|
it { should be_able_to(:create, Budget) }
|
||||||
it { should be_able_to(:update, Budget) }
|
it { should be_able_to(:update, Budget) }
|
||||||
|
it { should be_able_to(:read_results, Budget) }
|
||||||
|
|
||||||
it { should be_able_to(:create, Budget::ValuatorAssignment) }
|
it { should be_able_to(:create, Budget::ValuatorAssignment) }
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ describe "Abilities::Everyone" do
|
|||||||
let(:debate) { create(:debate) }
|
let(:debate) { create(:debate) }
|
||||||
let(:proposal) { create(:proposal) }
|
let(:proposal) { create(:proposal) }
|
||||||
|
|
||||||
|
let(:reviewing_ballot_budget) { create(:budget, phase: 'reviewing_ballots') }
|
||||||
|
let(:finished_budget) { create(:budget, phase: 'finished') }
|
||||||
|
|
||||||
it { should be_able_to(:index, Debate) }
|
it { should be_able_to(:index, Debate) }
|
||||||
it { should be_able_to(:show, debate) }
|
it { should be_able_to(:show, debate) }
|
||||||
it { should_not be_able_to(:edit, Debate) }
|
it { should_not be_able_to(:edit, Debate) }
|
||||||
@@ -28,4 +31,7 @@ describe "Abilities::Everyone" do
|
|||||||
it { should_not be_able_to(:create, SpendingProposal) }
|
it { should_not be_able_to(:create, SpendingProposal) }
|
||||||
|
|
||||||
it { should be_able_to(:index, Budget) }
|
it { should be_able_to(:index, Budget) }
|
||||||
|
|
||||||
|
it { should be_able_to(:read_results, finished_budget) }
|
||||||
|
it { should_not be_able_to(:read_results, reviewing_ballot_budget) }
|
||||||
end
|
end
|
||||||
@@ -714,4 +714,53 @@ describe Debate do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#recommendations" do
|
||||||
|
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
|
||||||
|
it "Should not return any debates when user has not interests" do
|
||||||
|
create(:debate)
|
||||||
|
|
||||||
|
expect(Debate.recommendations(user).size).to eq 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Should return debates ordered by cached_votes_total" do
|
||||||
|
debate1 = create(:debate, cached_votes_total: 1, tag_list: "Sport" )
|
||||||
|
debate2 = create(:debate, cached_votes_total: 5, tag_list: "Sport" )
|
||||||
|
debate3 = create(:debate, cached_votes_total: 10, tag_list: "Sport" )
|
||||||
|
proposal = create(:proposal, tag_list: "Sport" )
|
||||||
|
create(:follow, followable: proposal, user: user)
|
||||||
|
|
||||||
|
result = Debate.recommendations(user).sort_by_recommendations
|
||||||
|
|
||||||
|
expect(result.first).to eq debate3
|
||||||
|
expect(result.second).to eq debate2
|
||||||
|
expect(result.third).to eq debate1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Should return debates related with user interests" do
|
||||||
|
debate1 = create(:debate, tag_list: "Sport")
|
||||||
|
debate2 = create(:debate, tag_list: "Politics")
|
||||||
|
proposal1 = create(:proposal, tag_list: "Sport")
|
||||||
|
create(:follow, followable: proposal1, user: user)
|
||||||
|
|
||||||
|
result = Debate.recommendations(user)
|
||||||
|
|
||||||
|
expect(result.size).to eq 1
|
||||||
|
expect(result).to eq [debate1]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Should not return debates when user is the author" do
|
||||||
|
debate1 = create(:debate, author: user, tag_list: "Sport")
|
||||||
|
debate2 = create(:debate, tag_list: "Sport")
|
||||||
|
proposal = create(:proposal, tag_list: "Sport" )
|
||||||
|
create(:follow, followable: proposal, user: user)
|
||||||
|
|
||||||
|
result = Debate.recommendations(user)
|
||||||
|
|
||||||
|
expect(result.size).to eq 1
|
||||||
|
expect(result).to eq [debate2]
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,28 +3,71 @@ require 'rails_helper'
|
|||||||
describe Poll::Answer do
|
describe Poll::Answer do
|
||||||
|
|
||||||
describe "validations" do
|
describe "validations" do
|
||||||
it "validates that the answers are included in the Poll::Question's list" do
|
|
||||||
q = create(:poll_question, valid_answers: 'One, Two, Three')
|
|
||||||
expect(build(:poll_answer, question: q, answer: 'One')).to be_valid
|
|
||||||
expect(build(:poll_answer, question: q, answer: 'Two')).to be_valid
|
|
||||||
expect(build(:poll_answer, question: q, answer: 'Three')).to be_valid
|
|
||||||
|
|
||||||
expect(build(:poll_answer, question: q, answer: 'Four')).to_not be_valid
|
let(:answer) { build(:poll_answer) }
|
||||||
|
|
||||||
|
it "should be valid" do
|
||||||
|
expect(answer).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid wihout a question" do
|
||||||
|
answer.question = nil
|
||||||
|
expect(answer).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without an author" do
|
||||||
|
answer.author = nil
|
||||||
|
expect(answer).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without an answer" do
|
||||||
|
answer.answer = nil
|
||||||
|
expect(answer).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be valid for answers included in the Poll::Question's list" do
|
||||||
|
question = create(:poll_question, valid_answers: 'One, Two, Three')
|
||||||
|
expect(build(:poll_answer, question: question, answer: 'One')).to be_valid
|
||||||
|
expect(build(:poll_answer, question: question, answer: 'Two')).to be_valid
|
||||||
|
expect(build(:poll_answer, question: question, answer: 'Three')).to be_valid
|
||||||
|
|
||||||
|
expect(build(:poll_answer, question: question, answer: 'Four')).to_not be_valid
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#record_voter_participation" do
|
describe "#record_voter_participation" do
|
||||||
|
|
||||||
|
let(:author) { create(:user, :level_two) }
|
||||||
|
let(:poll) { create(:poll) }
|
||||||
|
let(:question) { create(:poll_question, poll: poll, valid_answers: "Yes, No") }
|
||||||
|
|
||||||
it "creates a poll_voter with user and poll data" do
|
it "creates a poll_voter with user and poll data" do
|
||||||
answer = create(:poll_answer)
|
answer = create(:poll_answer, question: question, author: author, answer: "Yes")
|
||||||
expect(answer.poll.voters).to be_blank
|
expect(answer.poll.voters).to be_blank
|
||||||
|
|
||||||
answer.record_voter_participation
|
answer.record_voter_participation
|
||||||
expect(answer.poll.reload.voters.size).to eq(1)
|
expect(poll.reload.voters.size).to eq(1)
|
||||||
voter = answer.poll.voters.first
|
voter = poll.voters.first
|
||||||
|
|
||||||
expect(voter.document_number).to eq(answer.author.document_number)
|
expect(voter.document_number).to eq(answer.author.document_number)
|
||||||
expect(voter.poll_id).to eq(answer.poll.id)
|
expect(voter.poll_id).to eq(answer.poll.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "updates a poll_voter with user and poll data" do
|
||||||
|
answer = create(:poll_answer, question: question, author: author, answer: "Yes")
|
||||||
|
answer.record_voter_participation
|
||||||
|
|
||||||
|
expect(poll.reload.voters.size).to eq(1)
|
||||||
|
|
||||||
|
answer = create(:poll_answer, question: question, author: author, answer: "No")
|
||||||
|
answer.record_voter_participation
|
||||||
|
|
||||||
|
expect(poll.reload.voters.size).to eq(1)
|
||||||
|
|
||||||
|
voter = poll.voters.first
|
||||||
|
expect(voter.document_number).to eq(answer.author.document_number)
|
||||||
|
expect(voter.poll_id).to eq(answer.poll.id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -138,4 +138,33 @@ describe :poll do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#voted_in_booth?" do
|
||||||
|
|
||||||
|
it "returns true if the user has already voted in booth" do
|
||||||
|
user = create(:user, :level_two)
|
||||||
|
poll = create(:poll)
|
||||||
|
|
||||||
|
create(:poll_voter, poll: poll, user: user, origin: "booth")
|
||||||
|
|
||||||
|
expect(poll.voted_in_booth?(user)).to be
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false if the user has not already voted in a booth" do
|
||||||
|
user = create(:user, :level_two)
|
||||||
|
poll = create(:poll)
|
||||||
|
|
||||||
|
expect(poll.voted_in_booth?(user)).to_not be
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false if the user has voted in web" do
|
||||||
|
user = create(:user, :level_two)
|
||||||
|
poll = create(:poll)
|
||||||
|
|
||||||
|
create(:poll_voter, poll: poll, user: user, origin: "web")
|
||||||
|
|
||||||
|
expect(poll.voted_in_booth?(user)).to_not be
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
104
spec/models/poll/recount_spec.rb
Normal file
104
spec/models/poll/recount_spec.rb
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe Poll::Recount do
|
||||||
|
|
||||||
|
describe "logging changes" do
|
||||||
|
let(:author) { create(:user) }
|
||||||
|
let(:officer_assignment) { create(:poll_officer_assignment) }
|
||||||
|
let(:poll_recount) { create(:poll_recount, author: author, officer_assignment: officer_assignment) }
|
||||||
|
|
||||||
|
it "should update white_amount_log if white_amount changes" do
|
||||||
|
poll_recount.white_amount = 33
|
||||||
|
|
||||||
|
expect(poll_recount.white_amount_log).to eq("")
|
||||||
|
|
||||||
|
poll_recount.white_amount = 33
|
||||||
|
poll_recount.save
|
||||||
|
poll_recount.white_amount = 32
|
||||||
|
poll_recount.save
|
||||||
|
poll_recount.white_amount = 34
|
||||||
|
poll_recount.save
|
||||||
|
|
||||||
|
expect(poll_recount.white_amount_log).to eq(":0:33:32")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should update null_amount_log if null_amount changes" do
|
||||||
|
poll_recount.null_amount = 33
|
||||||
|
|
||||||
|
expect(poll_recount.null_amount_log).to eq("")
|
||||||
|
|
||||||
|
poll_recount.null_amount = 33
|
||||||
|
poll_recount.save
|
||||||
|
poll_recount.null_amount = 32
|
||||||
|
poll_recount.save
|
||||||
|
poll_recount.null_amount = 34
|
||||||
|
poll_recount.save
|
||||||
|
|
||||||
|
expect(poll_recount.null_amount_log).to eq(":0:33:32")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should update total_amount_log if total_amount changes" do
|
||||||
|
poll_recount.total_amount = 33
|
||||||
|
|
||||||
|
expect(poll_recount.total_amount_log).to eq("")
|
||||||
|
|
||||||
|
poll_recount.total_amount = 33
|
||||||
|
poll_recount.save
|
||||||
|
poll_recount.total_amount = 32
|
||||||
|
poll_recount.save
|
||||||
|
poll_recount.total_amount = 34
|
||||||
|
poll_recount.save
|
||||||
|
|
||||||
|
expect(poll_recount.total_amount_log).to eq(":0:33:32")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should update officer_assignment_id_log if amount changes" do
|
||||||
|
poll_recount.white_amount = 33
|
||||||
|
|
||||||
|
expect(poll_recount.white_amount_log).to eq("")
|
||||||
|
expect(poll_recount.officer_assignment_id_log).to eq("")
|
||||||
|
|
||||||
|
poll_recount.white_amount = 33
|
||||||
|
poll_recount.officer_assignment = create(:poll_officer_assignment, id: 101)
|
||||||
|
poll_recount.save
|
||||||
|
|
||||||
|
poll_recount.white_amount = 32
|
||||||
|
poll_recount.officer_assignment = create(:poll_officer_assignment, id: 102)
|
||||||
|
poll_recount.save
|
||||||
|
|
||||||
|
poll_recount.white_amount = 34
|
||||||
|
poll_recount.officer_assignment = create(:poll_officer_assignment, id: 103)
|
||||||
|
poll_recount.save
|
||||||
|
|
||||||
|
expect(poll_recount.white_amount_log).to eq(":0:33:32")
|
||||||
|
expect(poll_recount.officer_assignment_id_log).to eq(":#{officer_assignment.id}:101:102")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should update author_id if amount changes" do
|
||||||
|
poll_recount.white_amount = 33
|
||||||
|
|
||||||
|
expect(poll_recount.white_amount_log).to eq("")
|
||||||
|
expect(poll_recount.author_id_log).to eq("")
|
||||||
|
|
||||||
|
first_author = create(:poll_officer).user
|
||||||
|
second_author = create(:poll_officer).user
|
||||||
|
third_author = create(:poll_officer).user
|
||||||
|
|
||||||
|
poll_recount.white_amount = 33
|
||||||
|
poll_recount.author_id = first_author.id
|
||||||
|
poll_recount.save!
|
||||||
|
|
||||||
|
poll_recount.white_amount = 32
|
||||||
|
poll_recount.author_id = second_author.id
|
||||||
|
poll_recount.save!
|
||||||
|
|
||||||
|
poll_recount.white_amount = 34
|
||||||
|
poll_recount.author_id = third_author.id
|
||||||
|
poll_recount.save!
|
||||||
|
|
||||||
|
expect(poll_recount.white_amount_log).to eq(":0:33:32")
|
||||||
|
expect(poll_recount.author_id_log).to eq(":#{author.id}:#{first_author.id}:#{second_author.id}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -83,6 +83,64 @@ describe :voter do
|
|||||||
expect(voter.errors.messages[:document_number]).to eq(["User has already voted"])
|
expect(voter.errors.messages[:document_number]).to eq(["User has already voted"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "origin" do
|
||||||
|
|
||||||
|
it "should not be valid without an origin" do
|
||||||
|
voter.origin = nil
|
||||||
|
expect(voter).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not be valid without a valid origin" do
|
||||||
|
voter.origin = "invalid_origin"
|
||||||
|
expect(voter).to_not be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be valid with a booth origin" do
|
||||||
|
voter.origin = "booth"
|
||||||
|
expect(voter).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be valid with a web origin" do
|
||||||
|
voter.origin = "web"
|
||||||
|
expect(voter).to be_valid
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "scopes" do
|
||||||
|
|
||||||
|
describe "#web" do
|
||||||
|
it "returns voters with a web origin" do
|
||||||
|
voter1 = create(:poll_voter, origin: "web")
|
||||||
|
voter2 = create(:poll_voter, origin: "web")
|
||||||
|
voter3 = create(:poll_voter, origin: "booth")
|
||||||
|
|
||||||
|
web_voters = Poll::Voter.web
|
||||||
|
|
||||||
|
expect(web_voters.count).to eq(2)
|
||||||
|
expect(web_voters).to include(voter1)
|
||||||
|
expect(web_voters).to include(voter2)
|
||||||
|
expect(web_voters).to_not include(voter3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#booth" do
|
||||||
|
it "returns voters with a booth origin" do
|
||||||
|
voter1 = create(:poll_voter, origin: "booth")
|
||||||
|
voter2 = create(:poll_voter, origin: "booth")
|
||||||
|
voter3 = create(:poll_voter, origin: "web")
|
||||||
|
|
||||||
|
booth_voters = Poll::Voter.booth
|
||||||
|
|
||||||
|
expect(booth_voters.count).to eq(2)
|
||||||
|
expect(booth_voters).to include(voter1)
|
||||||
|
expect(booth_voters).to include(voter2)
|
||||||
|
expect(booth_voters).to_not include(voter3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "save" do
|
describe "save" do
|
||||||
|
|||||||
@@ -891,4 +891,63 @@ describe Proposal do
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#recommendations" do
|
||||||
|
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
|
||||||
|
it "Should not return any proposals when user has not interests" do
|
||||||
|
create(:proposal)
|
||||||
|
|
||||||
|
expect(Proposal.recommendations(user).size).to eq 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Should return proposals ordered by cached_votes_up" do
|
||||||
|
proposal1 = create(:proposal, cached_votes_up: 1, tag_list: "Sport" )
|
||||||
|
proposal2 = create(:proposal, cached_votes_up: 5, tag_list: "Sport" )
|
||||||
|
proposal3 = create(:proposal, cached_votes_up: 10, tag_list: "Sport" )
|
||||||
|
proposal4 = create(:proposal, tag_list: "Sport" )
|
||||||
|
create(:follow, followable: proposal4, user: user)
|
||||||
|
|
||||||
|
result = Proposal.recommendations(user).sort_by_recommendations
|
||||||
|
|
||||||
|
expect(result.first).to eq proposal3
|
||||||
|
expect(result.second).to eq proposal2
|
||||||
|
expect(result.third).to eq proposal1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Should return proposals related with user interests" do
|
||||||
|
proposal1 = create(:proposal, tag_list: "Sport")
|
||||||
|
proposal2 = create(:proposal, tag_list: "Sport")
|
||||||
|
proposal3 = create(:proposal, tag_list: "Politics")
|
||||||
|
create(:follow, followable: proposal1, user: user)
|
||||||
|
|
||||||
|
result = Proposal.recommendations(user)
|
||||||
|
|
||||||
|
expect(result.size).to eq 1
|
||||||
|
expect(result).to eq [proposal2]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Should not return proposals when user is follower" do
|
||||||
|
proposal1 = create(:proposal, tag_list: "Sport")
|
||||||
|
create(:follow, followable: proposal1, user: user)
|
||||||
|
|
||||||
|
result = Proposal.recommendations(user)
|
||||||
|
|
||||||
|
expect(result.size).to eq 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Should not return proposals when user is the author" do
|
||||||
|
proposal1 = create(:proposal, author: user, tag_list: "Sport")
|
||||||
|
proposal2 = create(:proposal, tag_list: "Sport")
|
||||||
|
proposal3 = create(:proposal, tag_list: "Sport")
|
||||||
|
create(:follow, followable: proposal3, user: user)
|
||||||
|
|
||||||
|
result = Proposal.recommendations(user)
|
||||||
|
|
||||||
|
expect(result.size).to eq 1
|
||||||
|
expect(result).to eq [proposal2]
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -24,6 +24,17 @@ module CommonActions
|
|||||||
click_button 'Enter'
|
click_button 'Enter'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def login_through_form_as_officer(user)
|
||||||
|
visit root_path
|
||||||
|
click_link 'Sign in'
|
||||||
|
|
||||||
|
fill_in 'user_login', with: user.email
|
||||||
|
fill_in 'user_password', with: user.password
|
||||||
|
|
||||||
|
click_button 'Enter'
|
||||||
|
visit new_officing_residence_path
|
||||||
|
end
|
||||||
|
|
||||||
def login_as_authenticated_manager
|
def login_as_authenticated_manager
|
||||||
expected_response = {login: login, user_key: user_key, date: date}.with_indifferent_access
|
expected_response = {login: login, user_key: user_key, date: date}.with_indifferent_access
|
||||||
login, user_key, date = "JJB042", "31415926", Time.current.strftime("%Y%m%d%H%M%S")
|
login, user_key, date = "JJB042", "31415926", Time.current.strftime("%Y%m%d%H%M%S")
|
||||||
@@ -287,4 +298,26 @@ module CommonActions
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def vote_for_poll_via_web
|
||||||
|
visit question_path(question)
|
||||||
|
|
||||||
|
click_link 'Answer this question'
|
||||||
|
click_link 'Yes'
|
||||||
|
|
||||||
|
expect(page).to_not have_link('Yes')
|
||||||
|
expect(Poll::Voter.count).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def vote_for_poll_via_booth
|
||||||
|
visit new_officing_residence_path
|
||||||
|
officing_verify_residence
|
||||||
|
|
||||||
|
expect(page).to have_content poll.name
|
||||||
|
|
||||||
|
first(:button, "Confirm vote").click
|
||||||
|
expect(page).to have_content "Vote introduced!"
|
||||||
|
|
||||||
|
expect(Poll::Voter.count).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
43
spec/views/welcome/index.html.erb_spec.rb
Normal file
43
spec/views/welcome/index.html.erb_spec.rb
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
RSpec.describe "welcome/index" do
|
||||||
|
|
||||||
|
it 'Display images on orbit carrousel when we have defined image_default' do
|
||||||
|
debate = create(:debate)
|
||||||
|
|
||||||
|
render template: "welcome/_recommended_carousel.html.erb",
|
||||||
|
locals: { key: "debates",
|
||||||
|
recommendeds: [debate],
|
||||||
|
image_field: nil,
|
||||||
|
image_version: nil,
|
||||||
|
image_default: "https://dummyimage.com/600x400/000/fff",
|
||||||
|
carousel_size: "medium-6 large-6 medium-centered large-centered",
|
||||||
|
btn_text_link: t("welcome.recommended.debates.btn_text_link"),
|
||||||
|
btn_path_link: debates_path(order: "recommendations")}
|
||||||
|
|
||||||
|
within 'li[data-slide="0"] .card' do
|
||||||
|
expect(page).to have_selector("img")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Not display images on orbit carrousel when we have not defined image_default' do
|
||||||
|
debate = create(:debate)
|
||||||
|
|
||||||
|
render template: "welcome/_recommended_carousel.html.erb",
|
||||||
|
locals: { key: "debates",
|
||||||
|
recommendeds: [debate],
|
||||||
|
image_field: nil,
|
||||||
|
image_version: nil,
|
||||||
|
image_default: nil,
|
||||||
|
carousel_size: "medium-6 large-6 medium-centered large-centered",
|
||||||
|
btn_text_link: t("welcome.recommended.debates.btn_text_link"),
|
||||||
|
btn_path_link: debates_path(order: "recommendations")}
|
||||||
|
|
||||||
|
within 'li[data-slide="0"] .card' do
|
||||||
|
expect(page).not_to have_selector("img")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user