From e90ac7e72d7093e947416f49f05d199db4e4dc94 Mon Sep 17 00:00:00 2001 From: iagirre Date: Tue, 26 Sep 2017 11:16:32 +0200 Subject: [PATCH 01/16] Admins can see the preview of the budgets' results before the balloting phase is finished. Cambios para hacer commit: modificado: app/models/abilities/administrator.rb modificado: app/views/budgets/show.html.erb modificado: spec/models/abilities/administrator_spec.rb modificado: spec/models/abilities/everyone_spec.rb --- app/models/abilities/administrator.rb | 2 +- app/views/budgets/show.html.erb | 2 +- spec/models/abilities/administrator_spec.rb | 1 + spec/models/abilities/everyone_spec.rb | 8 +++++++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index 773dabf34..302d4b4ca 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -45,7 +45,7 @@ module Abilities 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::Heading can [:hide, :update, :toggle_selection], Budget::Investment diff --git a/app/views/budgets/show.html.erb b/app/views/budgets/show.html.erb index 814488d9d..99e9cae3c 100644 --- a/app/views/budgets/show.html.erb +++ b/app/views/budgets/show.html.erb @@ -36,7 +36,7 @@ <% end %> <% end %> - <% if @budget.finished? %> + <% if @budget.finished? || (@budget.balloting? && can?(:read_results, @budget)) %> <%= link_to t("budgets.show.see_results"), budget_results_path(@budget, heading_id: @budget.headings.first), class: "button margin-top expanded" %> diff --git a/spec/models/abilities/administrator_spec.rb b/spec/models/abilities/administrator_spec.rb index dcb099ecd..4c9463c50 100644 --- a/spec/models/abilities/administrator_spec.rb +++ b/spec/models/abilities/administrator_spec.rb @@ -69,6 +69,7 @@ describe "Abilities::Administrator" do it { should be_able_to(:create, Budget) } it { should be_able_to(:update, Budget) } + it { should be_able_to(:read_results, Budget) } it { should be_able_to(:create, Budget::ValuatorAssignment) } diff --git a/spec/models/abilities/everyone_spec.rb b/spec/models/abilities/everyone_spec.rb index fcfff4e42..21568c999 100644 --- a/spec/models/abilities/everyone_spec.rb +++ b/spec/models/abilities/everyone_spec.rb @@ -8,6 +8,9 @@ describe "Abilities::Everyone" do let(:debate) { create(:debate) } 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(:show, 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 be_able_to(:index, Budget) } -end \ No newline at end of file + + it { should be_able_to(:read_results, finished_budget) } + it { should_not be_able_to(:read_results, reviewing_ballot_budget) } +end From 33d9d2d005d48a6637a0b418c5b73e462c22e918 Mon Sep 17 00:00:00 2001 From: decabeza Date: Thu, 28 Sep 2017 09:15:46 +0200 Subject: [PATCH 02/16] adds new icon image --- app/assets/fonts/icons.eot | Bin 11892 -> 12060 bytes app/assets/fonts/icons.svg | 1 + app/assets/fonts/icons.ttf | Bin 11736 -> 11904 bytes app/assets/fonts/icons.woff | Bin 9084 -> 9236 bytes app/assets/stylesheets/icons.scss | 12 ++++-------- 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/app/assets/fonts/icons.eot b/app/assets/fonts/icons.eot index c1afd24fd80760f201cbf406a9e81244401693b2..5f29191f77be1a7f8e4634f5e26a38271acc9df7 100644 GIT binary patch delta 584 zcmYk2O=uHA7>2*u-HeqWNp{nutUYYDNra@?mTj|1f1rX<@nVC;T1coaZA^r08f~B} zg6W}$c&u|3dZ~9Mc<`d&MGb-{FWQ5i1P?)M6-!~)uZw~M^Ub`^`_At{`Oz{R9s}6a zwy7cP9Bp*A&(_p(fLfVf7}Mu_<(B|t3H9QNWj6QTK9vBt zab&Nm=6ch0fyewT`UBPa-JAFB9DW55>HvxFwTiiViu-a6y*=zk4S_ID_Hk_(b-ZS^ z+P1$)0|=fVxL;peF^8Uy;9>j$YTGjHCUoE#`gzn!!?Y@)xd)#CQe|X~=GuB|bnC_? zfb=`Olm!G+*gG3XJJ$oVKf%u-0Qm5unE5xleN2iTAMoDcC2*04G!ERp+vh}YE6@5{ z1dq(HkEAag@4?=188X3saj(gA_XS@docOyd_^u|}$994f$tUoG2rB3RQkbe|lG(|e zp+|g!v1~3nM`9`+422^TG2O_9CX>-nn2yBMB+dLxG^OwV5kvGP^=~XV(jtd3w^>^^#?*Y%#TeLWewLV2Tyf qaY4^#rkI_+O=j4)bc-YT?(*n+LVdR^vsz&pJbap6)=vBX`@cT`SBDP( delta 435 zcmbOe_a%m{M2~^thVDc*GnS_!Ds>Yba_Y78m^g&%g{+KLseyk)BhTX0-ah z4+8^B1_Og?NJeU63itdc&Oo_4Kx~!)6kyS3Vg>3I0rFKca!cwfxRcoUfdU(V0yR1L z$%zs>1rit-m_GpdWx0tJ1q|&BTY>TxK)ym=Vs5H{P3JWR22G%Y8S@JAi%b4x#riWa zXagO@l*+&eR0YI!Dk4wg`E9;3a5Dh~7#OZPTwIJyGckb0IT)A>!17>CU?Dw-1|SJC z3K_6~MXV;@VthCG43jRS(d1uD#~B$mA7XZ41S;Rm!5XSM`KQ(gc0&d;23-cz$se>; xSPac{O(#p}6f#;(?$RmQqM+rbxWXGEI`8{mVs?LW4q`)$U0=F0susYVO{_L diff --git a/app/assets/fonts/icons.svg b/app/assets/fonts/icons.svg index 68d878942..2b884a912 100644 --- a/app/assets/fonts/icons.svg +++ b/app/assets/fonts/icons.svg @@ -62,4 +62,5 @@ + diff --git a/app/assets/fonts/icons.ttf b/app/assets/fonts/icons.ttf index a9443499bdbfec297ba8e65657a84a8be7abdfa6..2524576116599f0536ecdd99d106894ce5b7f0aa 100644 GIT binary patch delta 604 zcmYLH&ubG=5T3WYT`Qp^*-ewOc-U-{6gSl3)HP%eoywmqfCVh#JYsR>{1I)XTY3vXt{}d&YMb@m`xiU_HG|wv z#oVa7E>;3{3H8xR_1?|7BlMy-cix2$r@WM;@dCP$D+Sazcs zFxVjC=ZGIv*H_Jn*OPb|{R45+Hk))^L5Q{a_E{B&Neg=?B$kpoW8;$AB8>a!% zyZ9*EZw?#Wy8GwJ_2AM^2vC>?@Zr0m4E=FKar+p``NAj+b*zP)7ok$%_T4_k`K3JO z-(q}b(K$x?j90>$rW7*kT&3QTg^on$3B~>DSj@#_%afB7M?OISIFLXC;3KRwmCDRz zbuBtF9?xWB%OozbQJ@LVbujSJf1(=1Dq zE?QaO2RbhZJn8ZRDMrOmFg6hkiJR?gQ5BqXEIruvgG)4faIo!1me4wH4(}h(AO{M} zJ1^w~qve!&rzhVgi_Y0}gCe=kPI`~9Be!g`Qg$9G;?x4R&EO1%gYrHP>>ho(=lTCr GHI%>4l7!m; delta 412 zcmZpOy%Al{z{tSBz{}9Uz|0Wf<`&{xw%<*RfkAfDwsGz`&#f6g!ljSX}V`KhPuw-6=qMj`W<$G^5r3eHa*6 zG8h7JVjGpk@)EfJ#PgNdc|084N{D4-Nj6IetKq5(*P!U-9$ zfJLk(+cCbIY`~<;Xf!#F={O_9W;JFPMxgS|IV_>7lVi0$up2U%G3YXwP7cvlVKFq* lHJx0eUC3xP`JHyj<`kXtjFT<(6c{ZhN9jp(!(DZ8F#vbZSor_| diff --git a/app/assets/fonts/icons.woff b/app/assets/fonts/icons.woff index 09a6f6dc56bfb02621d8a376fbd542cac67d677e..2cf6dc4b73a9d4df579a75f015aa210bd68cd0a0 100644 GIT binary patch delta 9188 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 delta 9003 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 P`3F Date: Thu, 28 Sep 2017 09:16:08 +0200 Subject: [PATCH 03/16] improves delete image button on proposal show --- app/assets/stylesheets/participation.scss | 5 +---- app/views/proposals/show.html.erb | 18 +++++++++--------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index fbcda0ebb..6a915ca54 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -255,7 +255,6 @@ .icon-debates, .icon-proposals, .icon-budget, - .icon-documents, .icon-image { font-size: rem-calc(50); line-height: $line-height; @@ -267,7 +266,6 @@ } .icon-proposals, - .icon-documents, .icon-image { color: $proposals; } @@ -358,8 +356,7 @@ width: rem-calc(48); } - .edit-debate, - .edit-proposal { + .edit-debate { margin-bottom: 0; } diff --git a/app/views/proposals/show.html.erb b/app/views/proposals/show.html.erb index 96999ca7d..2e4c1148f 100644 --- a/app/views/proposals/show.html.erb +++ b/app/views/proposals/show.html.erb @@ -113,6 +113,13 @@

<%= t("proposals.show.author") %>

+ <% if current_editable?(@proposal) %> + <%= link_to edit_proposal_path(@proposal), class: 'button hollow expanded' do %> + + <%= t("proposals.show.edit_proposal_link") %> + <% end %> + <% end %> + <% if author_of_proposal?(@proposal) %> <%= link_to new_proposal_notification_path(proposal_id: @proposal.id), class: 'button hollow expanded' do %> @@ -124,20 +131,13 @@ <% if can_destroy_image?(@proposal) %> <%= link_to image_path(@proposal.image, from: request.url), method: :delete, - class: 'button hollow expanded', + class: 'button hollow alert expanded', data: { confirm: t('images.actions.destroy.confirm') } do %> - + <%= t("images.remove_image") %> <% end %> <% end %> - <% if current_editable?(@proposal) %> - <%= link_to edit_proposal_path(@proposal), class: 'edit-proposal button hollow expanded' do %> - - <%= t("proposals.show.edit_proposal_link") %> - <% end %> - <% end %> -
<% end %> From 8aaa0cb718583c7efd0f5fc109e1500e53e8b602 Mon Sep 17 00:00:00 2001 From: decabeza Date: Thu, 28 Sep 2017 15:20:00 +0200 Subject: [PATCH 04/16] adds data equalizer to fix height on items with images --- app/assets/stylesheets/participation.scss | 31 ++++++++----------- .../budgets/investments/_investment.html.erb | 22 +++++++------ app/views/proposals/_proposal.html.erb | 16 +++++----- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index 6a915ca54..62bf65d91 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -658,20 +658,17 @@ .proposals-list .proposal { @include breakpoint(small) { + .no-image { width: 100%; - max-width: 300px; + max-width: rem-calc(300); margin: 0 auto; - } - .no-image::before { - content: ''; - display: block; - padding-top: 100%; - } - - h3 { - font-size: 1.3rem; + &::before { + content: ''; + display: block; + padding-top: 100%; + } } .column:first-child { @@ -680,19 +677,17 @@ } @include breakpoint(medium) { + .panel { - padding: 0 0.75rem 0 0; + padding: 0 $line-height / 2 0 0; .no-image { - height: 245px; - width: 140px; + height: 100%; + min-height: rem-calc(245); + width: rem-calc(140); } } - h3 { - font-size: 1.4rem; - } - .column:first-child { overflow: hidden; } @@ -702,7 +697,7 @@ } .column:last-child:not(:first-child) { - padding-top: 0.75rem; + padding-top: $line-height / 2; } img { diff --git a/app/views/budgets/investments/_investment.html.erb b/app/views/budgets/investments/_investment.html.erb index e663229ad..b42f8be31 100644 --- a/app/views/budgets/investments/_investment.html.erb +++ b/app/views/budgets/investments/_investment.html.erb @@ -1,13 +1,15 @@
-
+
- <% if investment.image.present? %> - <%= image_tag investment.image_url(:thumb), alt: investment.image.title %> - <% else %> -
- <% end %> +
+ <% if investment.image.present? %> + <%= image_tag investment.image_url(:thumb), alt: investment.image.title %> + <% else %> +
+ <% end %> +
@@ -53,7 +55,7 @@ <% if investment.should_show_votes? %>
+ class="small-12 medium-3 column text-center" data-equalizer-watch> <%= render partial: '/budgets/investments/votes', locals: { investment: investment, investment_votes: investment_votes, @@ -62,7 +64,7 @@
<% elsif investment.should_show_vote_count? %>
+ class="small-12 medium-3 column text-center" data-equalizer-watch>
<%= t("budgets.investments.investment.supports", @@ -72,7 +74,7 @@
<% elsif investment.should_show_ballots? %>
+ class="small-12 medium-3 column text-center" data-equalizer-watch> <%= render partial: '/budgets/investments/ballot', locals: { investment: investment, investment_ids: investment_ids, @@ -81,7 +83,7 @@
<% elsif investment.should_show_price? %>
+ class="supports small-12 medium-3 column text-center" data-equalizer-watch>

<%= investment.formatted_price %>

diff --git a/app/views/proposals/_proposal.html.erb b/app/views/proposals/_proposal.html.erb index eb02ea316..be5ac8e17 100644 --- a/app/views/proposals/_proposal.html.erb +++ b/app/views/proposals/_proposal.html.erb @@ -3,14 +3,16 @@ data-type="proposal">
-
+
- <% if proposal.image.present? %> - <%= image_tag proposal.image_url(:thumb), alt: proposal.image.title %> - <% else %> -
- <% end %> +
+ <% if proposal.image.present? %> + <%= image_tag proposal.image_url(:thumb), alt: proposal.image.title %> + <% else %> +
+ <% end %> +
@@ -58,7 +60,7 @@
-
+
<% if proposal.successful? %>
From fd78eb30cce8158aed39890242be4d3d982dc418 Mon Sep 17 00:00:00 2001 From: decabeza Date: Thu, 28 Sep 2017 15:20:47 +0200 Subject: [PATCH 05/16] shows hr tag on forms only when expanded --- app/views/documents/_nested_documents.html.erb | 5 +---- app/views/images/_image_fields.html.erb | 1 + app/views/images/_nested_image.html.erb | 16 ++++++---------- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/app/views/documents/_nested_documents.html.erb b/app/views/documents/_nested_documents.html.erb index ecbe46ce7..04fd4e8a2 100644 --- a/app/views/documents/_nested_documents.html.erb +++ b/app/views/documents/_nested_documents.html.erb @@ -20,7 +20,4 @@
"> <%= t "documents.max_documents_allowed_reached_html" %>
- -
- -
\ No newline at end of file +
diff --git a/app/views/images/_image_fields.html.erb b/app/views/images/_image_fields.html.erb index 10a4cf898..092402706 100644 --- a/app/views/images/_image_fields.html.erb +++ b/app/views/images/_image_fields.html.erb @@ -28,4 +28,5 @@
+
diff --git a/app/views/images/_nested_image.html.erb b/app/views/images/_nested_image.html.erb index a981dd190..2f65b8760 100644 --- a/app/views/images/_nested_image.html.erb +++ b/app/views/images/_nested_image.html.erb @@ -1,12 +1,10 @@ -
- <%= f.label :image, t("images.form.title") %> -

<%= imageables_note(imageable) %>

+<%= f.label :image, t("images.form.title") %> +

<%= imageables_note(imageable) %>

-
- <%= f.fields_for :image do |image_builder| %> - <%= render 'images/image_fields', f: image_builder, imageable: imageable %> - <% end %> -
+
+ <%= f.fields_for :image do |image_builder| %> + <%= render 'images/image_fields', f: image_builder, imageable: imageable %> + <% end %>
<%= link_to_add_association t('images.form.add_new_image'), f, :image, @@ -21,5 +19,3 @@ association_insertion_node: "#nested-image", association_insertion_method: "append" } %> - -
From 876a2b530b9e63bb8c5a510c1b583d3faa4c923d Mon Sep 17 00:00:00 2001 From: decabeza Date: Thu, 28 Sep 2017 16:03:08 +0200 Subject: [PATCH 06/16] fixes lint warnings --- app/assets/stylesheets/mixins.scss | 13 +++++++------ app/assets/stylesheets/participation.scss | 4 +--- app/views/admin/poll/questions/edit.html.erb | 4 +++- app/views/admin/poll/questions/new.html.erb | 4 +++- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/app/assets/stylesheets/mixins.scss b/app/assets/stylesheets/mixins.scss index cc8fe9360..a0afec83b 100644 --- a/app/assets/stylesheets/mixins.scss +++ b/app/assets/stylesheets/mixins.scss @@ -35,8 +35,8 @@ @mixin direct-uploads { .cached-image { - max-width: 150px; - max-height: 150px; + max-width: rem-calc(150); + max-height: rem-calc(150); } .progress-bar-placeholder { @@ -49,14 +49,15 @@ .document-attachment, .image-attachment { - padding-left:0; + padding-left: 0; - p{ + p { margin-bottom: 0; } } - input.js-document-attachment, - input.js-image-attachment{ + + .js-document-attachment, + .js-image-attachment { display: none; } } diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index 62bf65d91..87f9838aa 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -310,12 +310,10 @@ .budget-investment-new, .proposal-form, .proposal-edit, -.new_poll_question, -.edit_poll_question { +.poll-question-form { @include direct-uploads; } - // 03. Show participation // ---------------------- diff --git a/app/views/admin/poll/questions/edit.html.erb b/app/views/admin/poll/questions/edit.html.erb index 48998081a..fffc4a399 100644 --- a/app/views/admin/poll/questions/edit.html.erb +++ b/app/views/admin/poll/questions/edit.html.erb @@ -2,4 +2,6 @@

<%= t("admin.questions.edit.title") %>

-<%= render "form", form_url: admin_question_path(@question) %> \ No newline at end of file +
+ <%= render "form", form_url: admin_question_path(@question) %> +
diff --git a/app/views/admin/poll/questions/new.html.erb b/app/views/admin/poll/questions/new.html.erb index 844195920..c91b78016 100644 --- a/app/views/admin/poll/questions/new.html.erb +++ b/app/views/admin/poll/questions/new.html.erb @@ -2,4 +2,6 @@

<%= t("admin.questions.new.title") %>

-<%= render "form", form_url: admin_questions_path %> \ No newline at end of file +
+ <%= render "form", form_url: admin_questions_path %> +
From f44f3f5bc1e64689d1c97e60d0376f7792270a65 Mon Sep 17 00:00:00 2001 From: decabeza Date: Thu, 28 Sep 2017 17:52:28 +0200 Subject: [PATCH 07/16] fixes css to shows error messages correctly --- app/assets/stylesheets/mixins.scss | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/mixins.scss b/app/assets/stylesheets/mixins.scss index a0afec83b..52c07f4f5 100644 --- a/app/assets/stylesheets/mixins.scss +++ b/app/assets/stylesheets/mixins.scss @@ -56,9 +56,16 @@ } } - .js-document-attachment, - .js-image-attachment { - display: none; + .attachment-errors { + + > .js-image-attachment, + > .js-document-attachment { + display: none; + + ~ .error { + display: inline-block; + } + } } } From 1a0467d2c68d1182efc3d141fc7ad8ac8dddae6b Mon Sep 17 00:00:00 2001 From: decabeza Date: Fri, 29 Sep 2017 09:23:05 +0200 Subject: [PATCH 08/16] adds data equalizer watch to prevent js errors --- app/views/budgets/investments/_investment.html.erb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/budgets/investments/_investment.html.erb b/app/views/budgets/investments/_investment.html.erb index b42f8be31..2c6269a3f 100644 --- a/app/views/budgets/investments/_investment.html.erb +++ b/app/views/budgets/investments/_investment.html.erb @@ -88,6 +88,8 @@ <%= investment.formatted_price %>

+ <% else %> +
<% end %> <% end %> From f497227e3f5f85c026c4d5a56117240f415ec45e Mon Sep 17 00:00:00 2001 From: decabeza Date: Mon, 2 Oct 2017 12:24:31 +0200 Subject: [PATCH 09/16] improves layout for polls index view --- app/assets/stylesheets/layout.scss | 12 +++++++ app/assets/stylesheets/participation.scss | 10 ++++-- app/views/polls/_poll_group.html.erb | 41 ++++++++++++++--------- app/views/polls/index.html.erb | 10 ++++-- 4 files changed, 51 insertions(+), 22 deletions(-) diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index 67abd0f1f..44b450779 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -354,6 +354,18 @@ a { vertical-align: top; } +.aling-middle { + vertical-align: middle; +} + +.table { + display: table; +} + +.table-cell { + display: table-cell; +} + // 02. Header // ---------- diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index fbcda0ebb..719a8b229 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -1701,9 +1701,13 @@ } .section-title-divider { - border-bottom: 2px solid $brand; - color: $brand; - margin-bottom: $line-height; + border-bottom: 1px solid #eee; + color: #000; + margin: $line-height 0; + + span { + border-bottom: 1px solid #000; + } } .poll-question { diff --git a/app/views/polls/_poll_group.html.erb b/app/views/polls/_poll_group.html.erb index e3e5c5976..9372aee17 100644 --- a/app/views/polls/_poll_group.html.erb +++ b/app/views/polls/_poll_group.html.erb @@ -33,23 +33,30 @@ <%= t("polls.index.cant_answer") %>
<% end %> -
-
-
<%= poll_dates(poll) %>
+
+
+ +
 
+ +
+
+
<% if poll.questions.count == 1 %> <% poll.questions.each do |question| %> -

<%= link_to question.title, poll %>

+

<%= link_to question.title, poll %>

+ <%= poll_dates(poll) %> <% end %> <% else %> -

<%= link_to poll.name, poll %>

-
    +

    <%= link_to poll.name, poll %>

    + <%= poll_dates(poll) %> +
      <% poll.questions.each do |question| %>
    • <%= link_to question.title, question_path(question) %>
    • <% end %>
    <% end %> <% if poll.geozones.any? %> -

    +

    <%= t("polls.index.geozone_info") %>

    <% end %> @@ -59,16 +66,18 @@ <% end %>
-
- <%= link_to poll, class: "button expanded" do %> - <% if poll.expired? %> - <%= t("polls.index.participate_button_expired") %> - <% elsif poll.incoming? %> - <%= t("polls.index.participate_button_incoming") %> - <% else %> - <%= t("polls.index.participate_button") %> +
+
+ <%= link_to poll, class: "button hollow expanded" do %> + <% if poll.expired? %> + <%= t("polls.index.participate_button_expired") %> + <% elsif poll.incoming? %> + <%= t("polls.index.participate_button_incoming") %> + <% else %> + <%= t("polls.index.participate_button") %> + <% end %> <% end %> - <% end %> +
diff --git a/app/views/polls/index.html.erb b/app/views/polls/index.html.erb index 871b04953..6877cd31d 100644 --- a/app/views/polls/index.html.erb +++ b/app/views/polls/index.html.erb @@ -6,18 +6,22 @@ <%= render "shared/section_header", i18n_namespace: "polls.index.section_header", image: "polls" %>
-
+
<%= render 'shared/filter_subnav', i18n_namespace: "polls.index" %> <% polls_by_geozone_restriction = @polls.group_by(&:geozone_restricted) %> <% if polls_by_geozone_restriction[false].present? %> -

<%= t("polls.index.no_geozone_restricted") %>

+

+ <%= t("polls.index.no_geozone_restricted") %> +

<%= render partial: 'poll_group', locals: {poll_group: polls_by_geozone_restriction[false]} %> <% end %> <% if polls_by_geozone_restriction[true].present? %> -

<%= t("polls.index.geozone_restricted") %>

+

+ <%= t("polls.index.geozone_restricted") %> +

<%= render partial: 'poll_group', locals: {poll_group: polls_by_geozone_restriction[true]} %> <% end %> From b62342280557f7509b4eb3bf933d137b31606eca Mon Sep 17 00:00:00 2001 From: rgarcia Date: Mon, 2 Oct 2017 13:14:58 +0200 Subject: [PATCH 10/16] allows users to change their vote without refreshing the page --- app/models/poll/answer.rb | 2 +- spec/features/polls/polls_spec.rb | 21 +++++++++++++++++++++ spec/models/poll/answer_spec.rb | 27 ++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/app/models/poll/answer.rb b/app/models/poll/answer.rb index a1ff30f0a..cf59cd305 100644 --- a/app/models/poll/answer.rb +++ b/app/models/poll/answer.rb @@ -14,6 +14,6 @@ class Poll::Answer < ActiveRecord::Base scope :by_question, ->(question_id) { where(question_id: question_id) } def record_voter_participation - Poll::Voter.create!(user: author, poll: poll) + Poll::Voter.find_or_create_by!(user: author, poll: poll) end end \ No newline at end of file diff --git a/spec/features/polls/polls_spec.rb b/spec/features/polls/polls_spec.rb index 047c71146..8a90fb4a8 100644 --- a/spec/features/polls/polls_spec.rb +++ b/spec/features/polls/polls_spec.rb @@ -184,6 +184,7 @@ feature 'Polls' do 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) @@ -193,5 +194,25 @@ feature 'Polls' do expect(page).to have_link('Chewbacca') 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 diff --git a/spec/models/poll/answer_spec.rb b/spec/models/poll/answer_spec.rb index 10ccafbb6..157204364 100644 --- a/spec/models/poll/answer_spec.rb +++ b/spec/models/poll/answer_spec.rb @@ -14,17 +14,38 @@ describe Poll::Answer do end 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 - answer = create(:poll_answer) + answer = create(:poll_answer, question: question, author: author, answer: "Yes") expect(answer.poll.voters).to be_blank answer.record_voter_participation - expect(answer.poll.reload.voters.size).to eq(1) - voter = answer.poll.voters.first + 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 + + 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 From 60fb142fff2f6441eda174ae0365e56a9cceb316 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Mon, 2 Oct 2017 13:39:55 +0200 Subject: [PATCH 11/16] adds comprehensive validation specs --- app/models/poll/answer.rb | 3 ++- spec/models/poll/answer_spec.rb | 34 +++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/app/models/poll/answer.rb b/app/models/poll/answer.rb index cf59cd305..c2ea5724b 100644 --- a/app/models/poll/answer.rb +++ b/app/models/poll/answer.rb @@ -8,7 +8,8 @@ class Poll::Answer < ActiveRecord::Base validates :question, presence: true validates :author, 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_question, ->(question_id) { where(question_id: question_id) } diff --git a/spec/models/poll/answer_spec.rb b/spec/models/poll/answer_spec.rb index 157204364..d66cdc18c 100644 --- a/spec/models/poll/answer_spec.rb +++ b/spec/models/poll/answer_spec.rb @@ -3,13 +3,35 @@ require 'rails_helper' describe Poll::Answer 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 From 0147401fbecf797ee1762907f36d6b10666a9371 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Mon, 2 Oct 2017 16:18:08 +0200 Subject: [PATCH 12/16] adds origin to poll voters --- app/models/poll/voter.rb | 7 +++ ...0171002121658_add_origin_to_poll_voters.rb | 5 ++ db/schema.rb | 3 +- spec/factories.rb | 1 + spec/models/poll/voter_spec.rb | 58 +++++++++++++++++++ 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20171002121658_add_origin_to_poll_voters.rb diff --git a/app/models/poll/voter.rb b/app/models/poll/voter.rb index 760096206..abcae7d25 100644 --- a/app/models/poll/voter.rb +++ b/app/models/poll/voter.rb @@ -1,5 +1,8 @@ class Poll class Voter < ActiveRecord::Base + + VALID_ORIGINS = %w{ web booth } + belongs_to :poll belongs_to :user belongs_to :geozone @@ -10,9 +13,13 @@ class Poll validates :user_id, presence: true 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 + scope :web, -> { where(origin: 'web') } + scope :booth, -> { where(origin: 'booth') } + def set_demographic_info return if user.blank? diff --git a/db/migrate/20171002121658_add_origin_to_poll_voters.rb b/db/migrate/20171002121658_add_origin_to_poll_voters.rb new file mode 100644 index 000000000..845c1b774 --- /dev/null +++ b/db/migrate/20171002121658_add_origin_to_poll_voters.rb @@ -0,0 +1,5 @@ +class AddOriginToPollVoters < ActiveRecord::Migration + def change + add_column :poll_voters, :origin, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 500f03540..e862af922 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170927110953) do +ActiveRecord::Schema.define(version: 20171002121658) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -733,6 +733,7 @@ ActiveRecord::Schema.define(version: 20170927110953) do t.integer "answer_id" t.integer "officer_assignment_id" t.integer "user_id" + t.string "origin" end add_index "poll_voters", ["booth_assignment_id"], name: "index_poll_voters_on_booth_assignment_id", using: :btree diff --git a/spec/factories.rb b/spec/factories.rb index b0a287aea..f3d70a529 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -525,6 +525,7 @@ FactoryGirl.define do factory :poll_voter, class: 'Poll::Voter' do poll association :user, :level_two + origin "web" trait :from_booth do association :booth_assignment, factory: :poll_booth_assignment diff --git a/spec/models/poll/voter_spec.rb b/spec/models/poll/voter_spec.rb index c1c248550..f306248dc 100644 --- a/spec/models/poll/voter_spec.rb +++ b/spec/models/poll/voter_spec.rb @@ -83,6 +83,64 @@ describe :voter do expect(voter.errors.messages[:document_number]).to eq(["User has already voted"]) 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 describe "save" do From 085991c624e9ceb5ce15f9606230b0a88ac0c6f3 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Mon, 2 Oct 2017 16:22:31 +0200 Subject: [PATCH 13/16] allows voting only in one origin: booth or web --- app/controllers/officing/voters_controller.rb | 3 +- app/models/poll.rb | 4 + app/models/poll/answer.rb | 2 +- app/views/polls/show.html.erb | 10 +- config/locales/en/general.yml | 1 + config/locales/es/general.yml | 1 + spec/factories.rb | 6 ++ spec/features/polls/voter_spec.rb | 94 +++++++++++++++++++ spec/models/poll/poll_spec.rb | 29 ++++++ spec/support/common_actions.rb | 33 +++++++ 10 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 spec/features/polls/voter_spec.rb diff --git a/app/controllers/officing/voters_controller.rb b/app/controllers/officing/voters_controller.rb index dee1e00bd..a5343f83d 100644 --- a/app/controllers/officing/voters_controller.rb +++ b/app/controllers/officing/voters_controller.rb @@ -12,7 +12,8 @@ class Officing::VotersController < Officing::BaseController @voter = Poll::Voter.new(document_type: @user.document_type, document_number: @user.document_number, user: @user, - poll: @poll) + poll: @poll, + origin: "booth") @voter.save! end diff --git a/app/models/poll.rb b/app/models/poll.rb index 24ffa3a06..78ef2bc90 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -61,6 +61,10 @@ class Poll < ActiveRecord::Base voters.where(document_number: document_number, document_type: document_type).exists? end + def voted_in_booth?(user) + Poll::Voter.where(poll: self, user: user, origin: "booth").exists? + end + def date_range unless starts_at.present? && ends_at.present? && starts_at <= ends_at errors.add(:starts_at, I18n.t('errors.messages.invalid_date_range')) diff --git a/app/models/poll/answer.rb b/app/models/poll/answer.rb index c2ea5724b..01eebd553 100644 --- a/app/models/poll/answer.rb +++ b/app/models/poll/answer.rb @@ -15,6 +15,6 @@ class Poll::Answer < ActiveRecord::Base scope :by_question, ->(question_id) { where(question_id: question_id) } def record_voter_participation - Poll::Voter.find_or_create_by!(user: author, poll: poll) + Poll::Voter.find_or_create_by!(user: author, poll: poll, origin: "web") end end \ No newline at end of file diff --git a/app/views/polls/show.html.erb b/app/views/polls/show.html.erb index 02ab70525..6895397de 100644 --- a/app/views/polls/show.html.erb +++ b/app/views/polls/show.html.erb @@ -31,8 +31,14 @@
- <% @questions.each do |question| %> - <%= render 'polls/questions/question', question: question %> + <% if @poll.voted_in_booth?(current_user) %> +
+ <%= t("polls.show.already_voted_in_booth") %> +
+ <% else %> + <% @questions.each do |question| %> + <%= render 'polls/questions/question', question: question %> + <% end %> <% end %>
diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 29c81c074..67d8eef2c 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -481,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_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: + already_voted_in_booth: "You have already participated in a booth for this poll." dates_title: "Participation dates" cant_answer_not_logged_in: "You must %{signin} or %{signup} to participate." signin: Sign in diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index c5322c84c..cace38212 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -481,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_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: + already_voted_in_booth: "Ya has participado en esta votación en una urna." dates_title: "Fechas de participación" cant_answer_not_logged_in: "Necesitas %{signin} o %{signup} para participar." signin: iniciar sesión diff --git a/spec/factories.rb b/spec/factories.rb index f3d70a529..a67cd2e8e 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -52,6 +52,12 @@ FactoryGirl.define do trait :verified do verified_at Time.current end + + trait :in_census do + document_number "12345678Z" + document_type "1" + verified_at Time.current + end end factory :identity do diff --git a/spec/features/polls/voter_spec.rb b/spec/features/polls/voter_spec.rb new file mode 100644 index 000000000..08bc6f963 --- /dev/null +++ b/spec/features/polls/voter_spec.rb @@ -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 \ No newline at end of file diff --git a/spec/models/poll/poll_spec.rb b/spec/models/poll/poll_spec.rb index ac0cc44ea..5083d7439 100644 --- a/spec/models/poll/poll_spec.rb +++ b/spec/models/poll/poll_spec.rb @@ -138,4 +138,33 @@ describe :poll do 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 diff --git a/spec/support/common_actions.rb b/spec/support/common_actions.rb index 8b8470293..97f05294c 100644 --- a/spec/support/common_actions.rb +++ b/spec/support/common_actions.rb @@ -24,6 +24,17 @@ module CommonActions click_button 'Enter' 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 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") @@ -287,4 +298,26 @@ module CommonActions 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 From 5aa063668fc6fb799cb694e6866e082b101d0123 Mon Sep 17 00:00:00 2001 From: Bertocq Date: Mon, 2 Oct 2017 19:57:02 +0200 Subject: [PATCH 14/16] Remove no longer used befor block with comments --- spec/features/home_spec.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spec/features/home_spec.rb b/spec/features/home_spec.rb index 8b9cf3e4e..cb5349814 100644 --- a/spec/features/home_spec.rb +++ b/spec/features/home_spec.rb @@ -22,11 +22,6 @@ feature "Home" do feature "For signed in users" do - before do - # user = create(:user) - # login_as(user) - end - feature "Recommended" do background do From d401a2cd9272c24d7a094a5f92084008423bdbdc Mon Sep 17 00:00:00 2001 From: Bertocq Date: Mon, 2 Oct 2017 21:16:22 +0200 Subject: [PATCH 15/16] Add default 0 value for Poll Recount amounts --- .../20171002191347_add_default_to_recount_amounts.rb | 7 +++++++ db/schema.rb | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20171002191347_add_default_to_recount_amounts.rb diff --git a/db/migrate/20171002191347_add_default_to_recount_amounts.rb b/db/migrate/20171002191347_add_default_to_recount_amounts.rb new file mode 100644 index 000000000..b90e86aae --- /dev/null +++ b/db/migrate/20171002191347_add_default_to_recount_amounts.rb @@ -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 diff --git a/db/schema.rb b/db/schema.rb index e859a487f..ebcdfe5dc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20171002122312) do +ActiveRecord::Schema.define(version: 20171002191347) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -698,11 +698,11 @@ ActiveRecord::Schema.define(version: 20171002122312) do t.integer "officer_assignment_id" t.text "officer_assignment_id_log", default: "" t.text "author_id_log", default: "" - t.integer "white_amount" + t.integer "white_amount", default: 0 t.text "white_amount_log", default: "" - t.integer "null_amount" + t.integer "null_amount", default: 0 t.text "null_amount_log", default: "" - t.integer "total_amount" + t.integer "total_amount", default: 0 t.text "total_amount_log", default: "" end From 6c998768e8e4a7f8dcd853140d8ceefaca06a946 Mon Sep 17 00:00:00 2001 From: Bertocq Date: Tue, 3 Oct 2017 00:19:12 +0200 Subject: [PATCH 16/16] Fix Poll Recount model spec after default amount value added --- app/models/poll/recount.rb | 8 ++++---- spec/models/poll/recount_spec.rb | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/models/poll/recount.rb b/app/models/poll/recount.rb index 97a909d1f..74a6fe937 100644 --- a/app/models/poll/recount.rb +++ b/app/models/poll/recount.rb @@ -1,6 +1,6 @@ class Poll::Recount < ActiveRecord::Base - VALID_ORIGINS = %w{ web booth letter } + VALID_ORIGINS = %w{web booth letter}.freeze belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id' belongs_to :booth_assignment @@ -22,7 +22,7 @@ class Poll::Recount < ActiveRecord::Base [: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").to_s}" + self["#{amount}_amount_log"] += ":#{send("#{amount}_amount_was")}" amounts_changed = true end @@ -30,7 +30,7 @@ class Poll::Recount < ActiveRecord::Base end def update_officer_author - self.officer_assignment_id_log += ":#{officer_assignment_id_was.to_s}" - self.author_id_log += ":#{author_id_was.to_s}" + self.officer_assignment_id_log += ":#{officer_assignment_id_was}" + self.author_id_log += ":#{author_id_was}" end end diff --git a/spec/models/poll/recount_spec.rb b/spec/models/poll/recount_spec.rb index 1ca0b41eb..bec531d96 100644 --- a/spec/models/poll/recount_spec.rb +++ b/spec/models/poll/recount_spec.rb @@ -17,7 +17,7 @@ describe Poll::Recount do poll_recount.white_amount = 34 poll_recount.save - expect(poll_recount.white_amount_log).to eq(":33:32") + expect(poll_recount.white_amount_log).to eq(":0:33:32") end it "should update null_amount_log if null_amount changes" do @@ -32,7 +32,7 @@ describe Poll::Recount do poll_recount.null_amount = 34 poll_recount.save - expect(poll_recount.null_amount_log).to eq(":33:32") + expect(poll_recount.null_amount_log).to eq(":0:33:32") end it "should update total_amount_log if total_amount changes" do @@ -47,7 +47,7 @@ describe Poll::Recount do poll_recount.total_amount = 34 poll_recount.save - expect(poll_recount.total_amount_log).to eq(":33:32") + expect(poll_recount.total_amount_log).to eq(":0:33:32") end it "should update officer_assignment_id_log if amount changes" do @@ -68,7 +68,7 @@ describe Poll::Recount do poll_recount.officer_assignment = create(:poll_officer_assignment, id: 103) poll_recount.save - expect(poll_recount.white_amount_log).to eq(":33:32") + expect(poll_recount.white_amount_log).to eq(":0:33:32") expect(poll_recount.officer_assignment_id_log).to eq(":101:102") end @@ -78,24 +78,24 @@ describe Poll::Recount do expect(poll_recount.white_amount_log).to eq("") expect(poll_recount.author_id_log).to eq("") - author_A = create(:poll_officer).user - author_B = create(:poll_officer).user - author_C = create(:poll_officer).user + 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 = author_A.id + poll_recount.author_id = first_author.id poll_recount.save! poll_recount.white_amount = 32 - poll_recount.author_id = author_B.id + poll_recount.author_id = second_author.id poll_recount.save! poll_recount.white_amount = 34 - poll_recount.author_id = author_C.id + poll_recount.author_id = third_author.id poll_recount.save! - expect(poll_recount.white_amount_log).to eq(":33:32") - expect(poll_recount.author_id_log).to eq(":#{author_A.id}:#{author_B.id}") + expect(poll_recount.white_amount_log).to eq(":0:33:32") + expect(poll_recount.author_id_log).to eq(":#{first_author.id}:#{second_author.id}:#{third_author.id}") end end