From 7d4936b577ee522f285df2ac85497bab63babfcb Mon Sep 17 00:00:00 2001 From: palomahnhp Date: Sun, 13 Mar 2016 18:29:55 +0100 Subject: [PATCH 0001/1685] track user verification and add statistics of verified users who did not vote proposals --- app/assets/javascripts/application.js | 2 + app/assets/javascripts/tracks.js.coffee | 28 ++++ app/controllers/admin/stats_controller.rb | 4 + app/helpers/tracks_helper.rb | 12 ++ app/models/concerns/verification.rb | 13 +- app/views/admin/stats/show.html.erb | 7 + app/views/layouts/_tracking_data.html.erb | 1 + app/views/layouts/application.html.erb | 1 + app/views/verification/letter/edit.html.erb | 1 + app/views/verification/letter/new.html.erb | 1 + app/views/verification/letter/show.html.erb | 1 + app/views/verification/residence/new.html.erb | 1 + app/views/verification/sms/edit.html.erb | 1 + app/views/verification/sms/new.html.erb | 1 + config/locales/admin.en.yml | 1 + config/locales/admin.es.yml | 1 + db/dev_seeds.rb | 2 +- spec/features/tracks_spec.rb | 134 ++++++++++++++++++ 18 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 app/assets/javascripts/tracks.js.coffee create mode 100644 app/helpers/tracks_helper.rb create mode 100644 app/views/layouts/_tracking_data.html.erb create mode 100644 spec/features/tracks_spec.rb diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index aa27109d9..7bc4b5274 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -41,6 +41,7 @@ //= require registration_form //= require suggest //= require forms +//= require tracks var initialize_modules = function() { App.Comments.initialize(); @@ -57,6 +58,7 @@ var initialize_modules = function() { App.RegistrationForm.initialize(); App.Suggest.initialize(); App.Forms.initialize(); + App.Tracks.initialize(); }; $(function(){ diff --git a/app/assets/javascripts/tracks.js.coffee b/app/assets/javascripts/tracks.js.coffee new file mode 100644 index 000000000..1b6cfe82e --- /dev/null +++ b/app/assets/javascripts/tracks.js.coffee @@ -0,0 +1,28 @@ +App.Tracks = + + tracking_enabled: -> + _paq? + + set_custom_var: (id, name, value, scope) -> + _paq.push(['setCustomVariable', id, name, value, scope]) + _paq.push(['trackPageView']) + + track_event: ($this) -> + category = $this.data('track-event-category') + action = $this.data('track-event-action') + _paq.push(['trackEvent', category, action]) + + initialize: -> + if App.Tracks.tracking_enabled() + $('[data-track-usertype]').each -> + $this = $(this) + usertype = $this.data('track-usertype') + App.Tracks.set_custom_var(1, "usertype", usertype, "visit") + + $('[data-track-event-category]').each -> + $this = $(this) + App.Tracks.track_event($this) + + $('[data-track-click]').on 'click', -> + $this = $(this) + App.Tracks.track_event($this) diff --git a/app/controllers/admin/stats_controller.rb b/app/controllers/admin/stats_controller.rb index ec5c2d19d..f724a054c 100644 --- a/app/controllers/admin/stats_controller.rb +++ b/app/controllers/admin/stats_controller.rb @@ -18,6 +18,10 @@ class Admin::StatsController < Admin::BaseController @verified_users = User.with_hidden.level_two_or_three_verified.count @unverified_users = User.with_hidden.unverified.count @users = User.with_hidden.count + + @user_ids_who_voted_proposals = + ActsAsVotable::Vote.where(votable_type: 'Proposal').pluck(:voter_id).uniq.count + @user_ids_who_didnt_vote_proposals = @verified_users - @user_ids_who_voted_proposals end end diff --git a/app/helpers/tracks_helper.rb b/app/helpers/tracks_helper.rb new file mode 100644 index 000000000..53c110d49 --- /dev/null +++ b/app/helpers/tracks_helper.rb @@ -0,0 +1,12 @@ +module TracksHelper + def track_event(data={}) + track_data = "" + prefix = " data-track-event-" + data.each do |key, value| + track_data = track_data + prefix + key.to_s + '=' + value + " " + end + content_for :track_event do + track_data + end + end +end \ No newline at end of file diff --git a/app/models/concerns/verification.rb b/app/models/concerns/verification.rb index 3520e5b31..c876ef5ed 100644 --- a/app/models/concerns/verification.rb +++ b/app/models/concerns/verification.rb @@ -53,7 +53,18 @@ module Verification def no_phone_available? !verification_sms_sent? end - + + def user_type + case + when level_three_verified? + :level_3_user + when level_two_verified? + :level_2_user + else + :level_1_user + end + end + def sms_code_not_confirmed? !sms_verified? end diff --git a/app/views/admin/stats/show.html.erb b/app/views/admin/stats/show.html.erb index 84abd7be9..93b6be821 100644 --- a/app/views/admin/stats/show.html.erb +++ b/app/views/admin/stats/show.html.erb @@ -76,6 +76,13 @@ <%= t "admin.stats.show.summary.user_level_three" %>
<%= number_with_delimiter(@user_level_three) %>

+ +

+ <%= t "admin.stats.show.summary.verified_users_who_didnt_vote_proposals" %>
+ + <%=number_with_delimiter(@user_ids_who_didnt_vote_proposals)%> + +

diff --git a/app/views/layouts/_tracking_data.html.erb b/app/views/layouts/_tracking_data.html.erb new file mode 100644 index 000000000..a0be1bafa --- /dev/null +++ b/app/views/layouts/_tracking_data.html.erb @@ -0,0 +1 @@ +/> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index ff41ea1ea..e7c5fdf56 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -4,6 +4,7 @@ + <%=render "layouts/tracking_data"%> <%= content_for?(:title) ? yield(:title) : setting['org_name'] %> <%= stylesheet_link_tag "application" %> <%= javascript_include_tag "application", 'data-turbolinks-track' => true %> diff --git a/app/views/verification/letter/edit.html.erb b/app/views/verification/letter/edit.html.erb index c792e219d..5ca194d33 100644 --- a/app/views/verification/letter/edit.html.erb +++ b/app/views/verification/letter/edit.html.erb @@ -1,4 +1,5 @@
+ <%track_event(category: "verification", action: "edit_letter" )%>

diff --git a/app/views/verification/letter/new.html.erb b/app/views/verification/letter/new.html.erb index 130fb106c..9bd6a2ddd 100644 --- a/app/views/verification/letter/new.html.erb +++ b/app/views/verification/letter/new.html.erb @@ -1,4 +1,5 @@

+ <% elsif params[:retired].present? %> +

<%= t("proposals.index.retired_proposals") %> <% end %>

@@ -57,6 +59,7 @@ <%= render 'categories' %> <%= render 'geozones' %> <%= render 'popular' %> + <%= render 'retired' %>
diff --git a/config/locales/en.yml b/config/locales/en.yml index 0df604469..a79ceaca6 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -296,6 +296,8 @@ en: hot_score: most active most_commented: most commented relevance: relevance + retired_proposals: Retired proposals + retired_proposals_link: "Proposals retired by the author (duplicated, unfeasibles, done, etc.)" search_form: button: Search placeholder: Search proposals... diff --git a/config/locales/es.yml b/config/locales/es.yml index c67136e9e..38da0cb2c 100755 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -296,6 +296,8 @@ es: hot_score: Más activas hoy most_commented: Más comentadas relevance: Más relevantes + retired_proposals: Propuestas retiradas + retired_proposals_link: "Propuestas retiradas por sus autores (realizadas, en ejecución, inviables, duplicadas, etc.)" search_form: button: Buscar placeholder: Buscar propuestas... diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index adcaf486c..d770f9d9a 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -430,7 +430,7 @@ feature 'Proposals' do end - context 'Retire a proposal' do + context 'Retired proposals' do scenario 'Retire' do proposal = create(:proposal) login_as(proposal.author) @@ -466,6 +466,34 @@ feature 'Proposals' do expect(page).to_not have_content 'Proposal retired' expect(page).to have_content "can't be blank", count: 2 end + + scenario 'Index do not list retired proposals by default' do + create_featured_proposals + not_retired = create(:proposal) + retired = create(:proposal, retired_at: Time.now) + + visit proposals_path + + expect(page).to have_selector('#proposals .proposal', count: 1) + within('#proposals') do + expect(page).to have_content not_retired.title + expect(page).to_not have_content retired.title + end + end + + scenario 'Index has a link to retired proposals list' do + create_featured_proposals + not_retired = create(:proposal) + retired = create(:proposal, retired_at: Time.now) + + visit proposals_path + + expect(page).to_not have_content retired.title + click_link 'Proposals retired by the author (duplicated, unfeasibles, done, etc.)' + + expect(page).to have_content retired.title + expect(page).to_not have_content not_retired.title + end end scenario 'Update should not be posible if logged user is not the author' do diff --git a/spec/models/proposal_spec.rb b/spec/models/proposal_spec.rb index dddab0fbc..4958204ec 100644 --- a/spec/models/proposal_spec.rb +++ b/spec/models/proposal_spec.rb @@ -758,6 +758,13 @@ describe Proposal do expect(retired.size).to eq(1) expect(retired.first).to eq(@proposal2) end + + it "scope not_retired" do + not_retired = Proposal.not_retired + + expect(not_retired.size).to eq(1) + expect(not_retired.first).to eq(@proposal1) + end end end From ed0a4a85252c6e19a1a66ee55f93c29424cd9416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Fri, 22 Apr 2016 17:51:11 +0200 Subject: [PATCH 0118/1685] adds links to filter retired proposals by reason --- app/controllers/proposals_controller.rb | 1 + app/views/proposals/_retired.html.erb | 9 +++++++- app/views/proposals/index.html.erb | 14 +++++++----- config/locales/en.yml | 9 +++++++- config/locales/es.yml | 9 +++++++- spec/features/proposals_spec.rb | 30 ++++++++++++++++++++++++- 6 files changed, 62 insertions(+), 10 deletions(-) diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index e91d20de9..f778b2ca0 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -25,6 +25,7 @@ class ProposalsController < ApplicationController def index_customization if params[:retired].present? @resources = @resources.retired + @resources = @resources.where(retired_reason: params[:retired]) if Proposal::RETIRE_OPTIONS.include?(params[:retired]) else @resources = @resources.not_retired end diff --git a/app/views/proposals/_retired.html.erb b/app/views/proposals/_retired.html.erb index 73d8a7844..ddf1dc36d 100644 --- a/app/views/proposals/_retired.html.erb +++ b/app/views/proposals/_retired.html.erb @@ -2,5 +2,12 @@

- <%= link_to t("proposals.index.retired_proposals_link"), proposals_path(retired: 1), class: "small" %>
+<% if params[:retired].blank? %> + <%= link_to t("proposals.index.retired_proposals_link"), proposals_path(retired: 'all'), class: "small" %>
+<% else %> + <%= link_to t("proposals.index.retired_links.all"), proposals_path(retired: 'all'), ({class: "small"} unless params[:retired] == 'all') %>
+ <% Proposal::RETIRE_OPTIONS.each do |option| %> + <%= link_to t("proposals.index.retired_links.#{option}"), proposals_path(retired: option), ({class: "small"} unless params[:retired] == option) %>
+ <% end %> +<% end %>

diff --git a/app/views/proposals/index.html.erb b/app/views/proposals/index.html.erb index 065553cce..67ee98f67 100644 --- a/app/views/proposals/index.html.erb +++ b/app/views/proposals/index.html.erb @@ -40,7 +40,7 @@
<% end %> - <%= render "shared/advanced_search", search_path: proposals_path(page: 1)%> + <%= render("shared/advanced_search", search_path: proposals_path(page: 1)) unless params[:retired].present? %> <%= render 'shared/order_links', i18n_namespace: "proposals.index" %> @@ -55,11 +55,13 @@
diff --git a/config/locales/en.yml b/config/locales/en.yml index a79ceaca6..d797bef40 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -297,7 +297,14 @@ en: most_commented: most commented relevance: relevance retired_proposals: Retired proposals - retired_proposals_link: "Proposals retired by the author (duplicated, unfeasibles, done, etc.)" + retired_proposals_link: "Proposals retired by the author" + retired_links: + all: All + duplicated: Duplicated + started: Underway + unfeasible: Unfeasible + done: Done + other: Other search_form: button: Search placeholder: Search proposals... diff --git a/config/locales/es.yml b/config/locales/es.yml index 38da0cb2c..16982ed6c 100755 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -297,7 +297,14 @@ es: most_commented: Más comentadas relevance: Más relevantes retired_proposals: Propuestas retiradas - retired_proposals_link: "Propuestas retiradas por sus autores (realizadas, en ejecución, inviables, duplicadas, etc.)" + retired_proposals_link: "Propuestas retiradas por sus autores" + retired_links: + all: Todas + duplicated: Duplicadas + started: Empezadas + unfeasible: Inviables + done: Hechas + other: Otras search_form: button: Buscar placeholder: Buscar propuestas... diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index d770f9d9a..4a3ea58a1 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -489,11 +489,39 @@ feature 'Proposals' do visit proposals_path expect(page).to_not have_content retired.title - click_link 'Proposals retired by the author (duplicated, unfeasibles, done, etc.)' + click_link 'Proposals retired by the author' expect(page).to have_content retired.title expect(page).to_not have_content not_retired.title end + + scenario 'Retired proposals index interface elements' do + visit proposals_path(retired: 'all') + + expect(page).to_not have_content 'Advanced search' + expect(page).to_not have_content 'Categories' + expect(page).to_not have_content 'Districts' + end + + scenario 'Retired proposals index has links to filter by retired_reason' do + unfeasible = create(:proposal, retired_at: Time.now, retired_reason: 'unfeasible') + duplicated = create(:proposal, retired_at: Time.now, retired_reason: 'duplicated') + + visit proposals_path(retired: 'all') + + expect(page).to have_content unfeasible.title + expect(page).to have_content duplicated.title + expect(page).to have_link 'Duplicated' + expect(page).to have_link 'Underway' + expect(page).to have_link 'Unfeasible' + expect(page).to have_link 'Done' + expect(page).to have_link 'Other' + + click_link 'Unfeasible' + + expect(page).to have_content unfeasible.title + expect(page).to_not have_content duplicated.title + end end scenario 'Update should not be posible if logged user is not the author' do From 5b4a7b8cf83d4286767a84f481e24dc54a419b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Fri, 22 Apr 2016 17:58:23 +0200 Subject: [PATCH 0119/1685] adds link to explanation --- app/views/proposals/show.html.erb | 3 ++- config/locales/en.yml | 3 ++- config/locales/es.yml | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/views/proposals/show.html.erb b/app/views/proposals/show.html.erb index 7d1c23e59..8fc01b7b4 100644 --- a/app/views/proposals/show.html.erb +++ b/app/views/proposals/show.html.erb @@ -24,7 +24,7 @@

<%= @proposal.title %>

<% if @proposal.retired? %>
- <%= t("proposals.show.retired_warning") %> + <%= t("proposals.show.retired_warning") %> <%= link_to t("proposals.show.retired_warning_link_to_explanation"), "#retired_explanation" %>
<% elsif @proposal.conflictive? %>
@@ -79,6 +79,7 @@

<%= @proposal.question %>

<% if @proposal.retired? %> +

<%= t('proposals.show.retired') %>: <%= t("proposals.retire_options.#{@proposal.retired_reason}") unless @proposal.retired_reason == 'other' %>

<%= simple_format text_with_links(@proposal.retired_explanation), {}, sanitize: false %> <% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index d797bef40..8d9b23541 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -358,7 +358,8 @@ en: edit_proposal_link: Edit flag: This proposal has been flagged as inappropriate by several users. login_to_comment: You must %{signin} or %{signup} to leave a comment. - retired_warning: "The author considers this proposal should not receive more supports. check the explanation before voting for it." + retired_warning: "The author considers this proposal should not receive more supports." + retired_warning_link_to_explanation: Read the explanation before voting for it. retired: Proposal retired by the author share: Share update: diff --git a/config/locales/es.yml b/config/locales/es.yml index 16982ed6c..93e685326 100755 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -358,7 +358,8 @@ es: edit_proposal_link: Editar propuesta flag: Esta propuesta ha sido marcada como inapropiada por varios usuarios. login_to_comment: Necesitas %{signin} o %{signup} para comentar. - retired_warning: "El autor de esta propuesta considera que ya no debe seguir recogiendo apoyos. Revisa su explicación antes de apoyarla." + retired_warning: "El autor de esta propuesta considera que ya no debe seguir recogiendo apoyos." + retired_warning_link_to_explanation: Revisa su explicación antes de apoyarla. retired: Propuesta retirada por el autor share: Compartir update: From f079bdac8a00a6c608d3c239e8b1496afaf42df2 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Cabeza Date: Sat, 23 Apr 2016 00:40:28 +0200 Subject: [PATCH 0120/1685] Improves styles for retire proposals --- app/assets/stylesheets/layout.scss | 22 ++++++++++++++++------ app/assets/stylesheets/participation.scss | 4 ++++ app/views/proposals/_retired.html.erb | 14 +++++++------- app/views/proposals/retire_form.html.erb | 21 +++++++++++---------- app/views/proposals/show.html.erb | 14 +++++++++----- app/views/users/_proposals.html.erb | 6 +++--- 6 files changed, 50 insertions(+), 31 deletions(-) diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index fdaf2dd30..2040a02ce 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -545,7 +545,7 @@ footer { // 04. Tags // - - - - - - - - - - - - - - - - - - - - - - - - - -.tags a , .tag-cloud a, .categories a, .geozone a { +.tags a , .tag-cloud a, .categories a, .geozone a, .sidebar-links a { background: #ececec; border-radius: rem-calc(6); color: $text; @@ -1730,9 +1730,12 @@ table { border: 0; td { - padding-left: $line-height*1.5; position: relative; - word-break: break-all; + + &:first-child { + padding-left: $line-height*1.5; + width: 80%; + } &:before { color: $brand; @@ -1753,9 +1756,16 @@ table { top: 14px; } - &.activity-proposals td:first-child:before { - content: "h"; - top: 18px; + &.activity-proposals { + + td:first-child:before { + content: "h"; + top: 18px; + } + + .retired { + text-decoration: line-through; + } } &.activity-investment-projects td:first-child:before { diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index 8ede20c2b..7ceaf7b99 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -343,6 +343,10 @@ word-wrap: break-word; } + .callout.proposal-retired { + font-size: $base-font-size; + } + .social-share-full .social-share-button { display:inline; } diff --git a/app/views/proposals/_retired.html.erb b/app/views/proposals/_retired.html.erb index ddf1dc36d..4ab1aba98 100644 --- a/app/views/proposals/_retired.html.erb +++ b/app/views/proposals/_retired.html.erb @@ -1,13 +1,13 @@ -

<% if params[:retired].blank? %> - <%= link_to t("proposals.index.retired_proposals_link"), proposals_path(retired: 'all'), class: "small" %>
+

<%= link_to t("proposals.index.retired_proposals_link"), proposals_path(retired: 'all'), class: "small" %>

<% else %> - <%= link_to t("proposals.index.retired_links.all"), proposals_path(retired: 'all'), ({class: "small"} unless params[:retired] == 'all') %>
- <% Proposal::RETIRE_OPTIONS.each do |option| %> - <%= link_to t("proposals.index.retired_links.#{option}"), proposals_path(retired: option), ({class: "small"} unless params[:retired] == option) %>
- <% end %> + <% end %> -

diff --git a/app/views/proposals/retire_form.html.erb b/app/views/proposals/retire_form.html.erb index 293e523bb..d56277cb3 100644 --- a/app/views/proposals/retire_form.html.erb +++ b/app/views/proposals/retire_form.html.erb @@ -2,33 +2,34 @@
-
- <%= link_to @proposal.title, @proposal %> -
+

<%= t("proposals.retire_form.title") %>

-

<%= t("proposals.retire_form.title") %>

+

<%= link_to @proposal.title, @proposal %>

-
+
<%= t("proposals.retire_form.warning") %>
<%= form_for(@proposal, url: retire_proposal_path(@proposal)) do |f| %> <%= render 'shared/errors', resource: @proposal %>
- -
+
<%= f.label :retired_reason, t("proposals.retire_form.retired_reason_label") %> <%= f.select :retired_reason, retire_proposals_options, {include_blank: t("proposals.retire_form.retired_reason_blank"), label: false} %>
+
-
+
+
<%= f.label :retired_explanation, t("proposals.retire_form.retired_explanation_label") %> <%= f.text_area :retired_explanation, rows: 4, maxlength: 500, label: false, placeholder: t('proposals.retire_form.retired_explanation_placeholder') %>
+
-
- <%= f.submit(class: "button", value: t("proposals.retire_form.submit_button")) %> +
+
+ <%= f.submit(class: "button expanded", value: t("proposals.retire_form.submit_button")) %>
<% end %> diff --git a/app/views/proposals/show.html.erb b/app/views/proposals/show.html.erb index 8fc01b7b4..c319c1409 100644 --- a/app/views/proposals/show.html.erb +++ b/app/views/proposals/show.html.erb @@ -23,8 +23,11 @@

<%= @proposal.title %>

<% if @proposal.retired? %> -
- <%= t("proposals.show.retired_warning") %> <%= link_to t("proposals.show.retired_warning_link_to_explanation"), "#retired_explanation" %> +
+ + <%= t("proposals.show.retired_warning") %>
+ <%= link_to t("proposals.show.retired_warning_link_to_explanation"), "#retired_explanation" %> +
<% elsif @proposal.conflictive? %>
@@ -79,9 +82,10 @@

<%= @proposal.question %>

<% if @proposal.retired? %> - -

<%= t('proposals.show.retired') %>: <%= t("proposals.retire_options.#{@proposal.retired_reason}") unless @proposal.retired_reason == 'other' %>

- <%= simple_format text_with_links(@proposal.retired_explanation), {}, sanitize: false %> +
+

<%= t('proposals.show.retired') %>: <%= t("proposals.retire_options.#{@proposal.retired_reason}") unless @proposal.retired_reason == 'other' %>

+ <%= simple_format text_with_links(@proposal.retired_explanation), {}, sanitize: false %> +
<% end %> <%= render 'shared/tags', taggable: @proposal %> diff --git a/app/views/users/_proposals.html.erb b/app/views/users/_proposals.html.erb index c3aa55ed1..9ec1368bd 100644 --- a/app/views/users/_proposals.html.erb +++ b/app/views/users/_proposals.html.erb @@ -2,13 +2,13 @@ <% @proposals.each do |proposal| %> - <%= link_to proposal.title, proposal, proposal.retired? ? {class: 'delete'} : {} %> + <%= link_to proposal.title, proposal, proposal.retired? ? {class: 'retired'} : {} %>
<%= proposal.summary %> - + <% if proposal.retired? %> - <%= t('users.show.retired') %> + <%= t('users.show.retired') %> <% else %> <%= link_to t('users.show.retire'), retire_form_proposal_path(proposal), From a49624b6ad5ccc793164bc7ace379566e4da953b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Sun, 24 Apr 2016 21:56:43 +0200 Subject: [PATCH 0121/1685] adds social settings to dev_seeds --- db/dev_seeds.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/db/dev_seeds.rb b/db/dev_seeds.rb index 5a97a3aec..e78e73546 100644 --- a/db/dev_seeds.rb +++ b/db/dev_seeds.rb @@ -15,6 +15,10 @@ Setting.create(key: 'proposal_code_prefix', value: 'MAD') Setting.create(key: 'votes_for_proposal_success', value: '100') Setting.create(key: 'comments_body_max_length', value: '1000') +Setting.create(key: 'twitter_handle', value: '@consul_dev') +Setting.create(key: 'twitter_hashtag', value: '#consul_dev') +Setting.create(key: 'facebook_handle', value: 'consul') +Setting.create(key: 'youtube_handle', value: 'consul') Setting.create(key: 'blog_url', value: '/blog') Setting.create(key: 'url', value: 'http://localhost:3000') Setting.create(key: 'org_name', value: 'Consul') From a45e112e654c59bc6284d5f67c89d2c53c2e9dc4 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Cabeza Date: Mon, 25 Apr 2016 11:12:52 +0200 Subject: [PATCH 0122/1685] Adds styles to admin spending proposals summary --- app/assets/stylesheets/admin.scss | 12 ++++++++++++ app/views/admin/spending_proposals/index.html.erb | 8 +++++--- app/views/admin/spending_proposals/summary.html.erb | 11 ++++++++--- config/locales/en.yml | 1 + config/locales/es.yml | 1 + 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index 1ccd7c880..7f05b47f8 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -354,6 +354,18 @@ body.admin { .investment-projects-list.medium-9 { width: 100%; } + + .investment-projects-summary { + + th { + text-align: center; + width: 33%; + + &:first-child { + text-align: left; + } + } + } } .admin-content .select-geozone { diff --git a/app/views/admin/spending_proposals/index.html.erb b/app/views/admin/spending_proposals/index.html.erb index 86dad6bbd..cd30f121d 100644 --- a/app/views/admin/spending_proposals/index.html.erb +++ b/app/views/admin/spending_proposals/index.html.erb @@ -1,4 +1,8 @@ -

<%= t("admin.spending_proposals.index.title") %>

+<%= link_to t("admin.spending_proposals.index.summary_link"), + summary_admin_spending_proposals_path, + class: "button float-right" %> + +

<%= t("admin.spending_proposals.index.title") %>

<%= form_tag admin_spending_proposals_path, method: :get, enforce_utf8: false do %> @@ -36,8 +40,6 @@
<%= render 'shared/filter_subnav', i18n_namespace: "admin.spending_proposals.index" %> -<%= link_to t("admin.spending_proposals.index.summary_link"), - summary_admin_spending_proposals_path %>

<%= page_entries_info @spending_proposals %>

diff --git a/app/views/admin/spending_proposals/summary.html.erb b/app/views/admin/spending_proposals/summary.html.erb index 825b30983..64b07e0ea 100644 --- a/app/views/admin/spending_proposals/summary.html.erb +++ b/app/views/admin/spending_proposals/summary.html.erb @@ -1,6 +1,11 @@ +<%= link_to admin_spending_proposals_path, class: "back" do %> + + <%= t("shared.back") %> +<% end %> +

<%= t("admin.spending_proposals.summary.title") %>

- +
@@ -8,8 +13,8 @@ <% @spending_proposals.each do |geozone, price| %> - - + + <% end %>
<%= t("admin.spending_proposals.summary.geozone_name") %> <%= t("admin.spending_proposals.summary.count_for_geozone") %> <%= t("admin.spending_proposals.summary.cost_for_geozone") %>
<%= geozone.present? ? geozone.name : t("geozones.none") %><%= spending_proposal_count_for_geozone(geozone) %><%= number_to_currency(price) %><%= spending_proposal_count_for_geozone(geozone) %><%= number_to_currency(price) %>
\ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index b5899e63a..441c0048e 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -361,6 +361,7 @@ en: to: 'To' author_info: author_deleted: User deleted + back: Back check: Select check_all: All check_none: None diff --git a/config/locales/es.yml b/config/locales/es.yml index f1241bb15..02da179b1 100755 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -361,6 +361,7 @@ es: to: 'Hasta' author_info: author_deleted: Usuario eliminado + back: Volver check: Seleccionar check_all: Todos check_none: Ninguno From 91199cda77f9ae4f528c421cd7a25849b3ba162a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Mon, 25 Apr 2016 11:44:33 +0200 Subject: [PATCH 0123/1685] removes capybara warning messages --- spec/features/comments/debates_spec.rb | 2 +- spec/features/comments/proposals_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/comments/debates_spec.rb b/spec/features/comments/debates_spec.rb index b8e7295a7..d80b08bc0 100644 --- a/spec/features/comments/debates_spec.rb +++ b/spec/features/comments/debates_spec.rb @@ -32,7 +32,7 @@ feature 'Commenting debates' do expect(page).to have_content first_child.body expect(page).to have_content second_child.body - expect(page).to have_link "Go back to #{debate.title}", debate_path(debate) + expect(page).to have_link "Go back to #{debate.title}", href: debate_path(debate) end scenario 'Collapsable comments', :js do diff --git a/spec/features/comments/proposals_spec.rb b/spec/features/comments/proposals_spec.rb index d7a3dbc95..53b1006c3 100644 --- a/spec/features/comments/proposals_spec.rb +++ b/spec/features/comments/proposals_spec.rb @@ -32,7 +32,7 @@ feature 'Commenting proposals' do expect(page).to have_content first_child.body expect(page).to have_content second_child.body - expect(page).to have_link "Go back to #{proposal.title}", proposal_path(proposal) + expect(page).to have_link "Go back to #{proposal.title}", href: proposal_path(proposal) end scenario 'Collapsable comments', :js do From c1f5db1f1e35d6912782c4d34e600c7ed5332fd0 Mon Sep 17 00:00:00 2001 From: kikito Date: Mon, 25 Apr 2016 14:55:59 +0200 Subject: [PATCH 0124/1685] Fixes issue when evaluating feasible sps - the explanation should be required only for unfeasible ones --- app/models/spending_proposal.rb | 7 ++++++- spec/models/spending_proposal_spec.rb | 10 +++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/app/models/spending_proposal.rb b/app/models/spending_proposal.rb index d2c2be34c..723cfa7e2 100644 --- a/app/models/spending_proposal.rb +++ b/app/models/spending_proposal.rb @@ -16,7 +16,7 @@ class SpendingProposal < ActiveRecord::Base validates :title, presence: true validates :author, presence: true validates :description, presence: true - validates_presence_of :feasible_explanation, if: :valuation_finished? + validates_presence_of :feasible_explanation, if: :feasible_explanation_required? validates :title, length: { in: 4..SpendingProposal.title_max_length } validates :description, length: { maximum: SpendingProposal.description_max_length } @@ -100,6 +100,10 @@ class SpendingProposal < ActiveRecord::Base valuation_finished end + def feasible_explanation_required? + valuation_finished? && unfeasible? + end + def total_votes cached_votes_up + physical_votes end @@ -139,4 +143,5 @@ class SpendingProposal < ActiveRecord::Base valuation_finished.feasible end + end diff --git a/spec/models/spending_proposal_spec.rb b/spec/models/spending_proposal_spec.rb index 7a5e2050b..68ca93535 100644 --- a/spec/models/spending_proposal_spec.rb +++ b/spec/models/spending_proposal_spec.rb @@ -49,8 +49,16 @@ describe SpendingProposal do expect(spending_proposal).to be_valid end - it "should not be valid if valuation finished" do + it "should be valid if valuation finished and feasible" do spending_proposal.feasible_explanation = "" + spending_proposal.feasible = true + spending_proposal.valuation_finished = true + expect(spending_proposal).to be_valid + end + + it "should not be valid if valuation finished and unfeasible" do + spending_proposal.feasible_explanation = "" + spending_proposal.feasible = false spending_proposal.valuation_finished = true expect(spending_proposal).to_not be_valid end From 62745136db6a4daffb9cb120575e99b2d18989fa Mon Sep 17 00:00:00 2001 From: kikito Date: Mon, 25 Apr 2016 15:14:44 +0200 Subject: [PATCH 0125/1685] Fixes capistrano setup mismatch --- config/deploy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/deploy.rb b/config/deploy.rb index 19d559986..6c1af4b9d 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -1,5 +1,5 @@ # config valid only for current version of Capistrano -lock '3.4.0' +lock '3.4.1' def deploysecret(key) @deploy_secrets_yml ||= YAML.load_file('config/deploy-secrets.yml')[fetch(:stage).to_s] From 198f6c96bdbff1e8256a1a0f53d6d63c7d4960cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Mon, 25 Apr 2016 17:59:42 +0200 Subject: [PATCH 0126/1685] adds & refactors specs for featured debates --- spec/features/debates_spec.rb | 46 +++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index 9db200f11..0db455401 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -1009,42 +1009,52 @@ feature 'Debates' do end end - scenario 'Mark debate as featured' do + scenario 'Matk/Unmark a debate as featured' do admin = create(:administrator) login_as(admin.user) - - debate1 = create(:debate) - debate2 = create(:debate, featured_at: Time.now) - - visit debate_path(debate1) - expect(page).to have_content("Featured") - visit debate_path(debate2) - expect(page).to have_content("Unmark featured") + debate = create(:debate) - end + visit debates_path + expect(page).to_not have_content 'Featured' + + click_link debate.title + + click_link 'Featured' + + visit debates_path + expect(page).to have_content 'Featured' + within('#featured-debates') do + expect(page).to have_content debate.title + end + + visit debate_path(debate) + click_link 'Unmark featured' + + expect(page).to_not have_content 'Featured' + end - scenario 'Show featured debates' do + scenario 'Index include featured debates' do admin = create(:administrator) login_as(admin.user) - + debate1 = create(:debate, featured_at: Time.now) debate2 = create(:debate) - + visit debates_path expect(page).to have_content("Featured") - end + end - scenario 'Dont show featured debates' do + scenario 'Index do not show featured debates if none is marked as featured' do admin = create(:administrator) login_as(admin.user) - + debate1 = create(:debate) debate2 = create(:debate) - + visit debates_path expect(page).to_not have_content("Featured") - end + end end From 11208ebb0561566493586388eeb704f931d1ef65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Mon, 25 Apr 2016 18:12:40 +0200 Subject: [PATCH 0127/1685] removes unused css class --- app/views/proposals/_retired.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/proposals/_retired.html.erb b/app/views/proposals/_retired.html.erb index 4ab1aba98..280265d87 100644 --- a/app/views/proposals/_retired.html.erb +++ b/app/views/proposals/_retired.html.erb @@ -5,9 +5,9 @@

<%= link_to t("proposals.index.retired_proposals_link"), proposals_path(retired: 'all'), class: "small" %>

<% else %> <% end %> From 296f41b1ed809d768b4d75da0ff37ddee1a64f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Mon, 25 Apr 2016 18:19:03 +0200 Subject: [PATCH 0128/1685] changes copy --- config/locales/es.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/locales/es.yml b/config/locales/es.yml index 82b7d59d1..d2d01e407 100755 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -264,9 +264,9 @@ es: submit_button: Retirar propuesta retire_options: duplicated: Duplicada - started: Ejecutándose + started: En ejecución unfeasible: Inviable - done: Hecha + done: Realizada other: Otra form: geozone: "Ámbito de actuación" @@ -301,9 +301,9 @@ es: retired_links: all: Todas duplicated: Duplicadas - started: Empezadas + started: En ejecución unfeasible: Inviables - done: Hechas + done: Realizadas other: Otras search_form: button: Buscar From 6e8a310ee1d6058e15ebd6e3420d336764b3d835 Mon Sep 17 00:00:00 2001 From: kikito Date: Mon, 25 Apr 2016 18:33:18 +0200 Subject: [PATCH 0129/1685] Sorts spending proposals by votes and creation in admin --- app/controllers/admin/spending_proposals_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/spending_proposals_controller.rb b/app/controllers/admin/spending_proposals_controller.rb index bd139dc9a..9826ab17f 100644 --- a/app/controllers/admin/spending_proposals_controller.rb +++ b/app/controllers/admin/spending_proposals_controller.rb @@ -7,7 +7,7 @@ class Admin::SpendingProposalsController < Admin::BaseController load_and_authorize_resource def index - @spending_proposals = SpendingProposal.scoped_filter(params, @current_filter).order(created_at: :desc).page(params[:page]) + @spending_proposals = SpendingProposal.scoped_filter(params, @current_filter).order(cached_votes_up: :desc, created_at: :desc).page(params[:page]) end def show From 73ffd3e18920705f71462ebdaf61a8b47eae2485 Mon Sep 17 00:00:00 2001 From: kikito Date: Mon, 25 Apr 2016 18:35:28 +0200 Subject: [PATCH 0130/1685] adds feasibility column to sp admin --- app/views/admin/spending_proposals/index.html.erb | 4 ++++ config/locales/admin.en.yml | 4 ++++ config/locales/admin.es.yml | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/app/views/admin/spending_proposals/index.html.erb b/app/views/admin/spending_proposals/index.html.erb index cd30f121d..5bbcee57f 100644 --- a/app/views/admin/spending_proposals/index.html.erb +++ b/app/views/admin/spending_proposals/index.html.erb @@ -29,6 +29,7 @@ label: false, class: "js-submit-on-change" } %>
+
<%= select_tag :tag_name, options_for_select(spending_proposal_tags_select_options, params[:tag_name]), @@ -69,6 +70,9 @@ <%= geozone_name(spending_proposal) %> + + <%= t("admin.spending_proposals.index.feasibility.#{spending_proposal.feasibility}", price: spending_proposal.price) %> + <% end %> diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index d24991654..2f4fe46a7 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -168,6 +168,10 @@ en: no_admin_assigned: No admin assigned no_valuators_assigned: No valuators assigned summary_link: "Summary" + feasibility: + feasible: "Feasible (%{price})" + not_feasible: "Not feasible" + undefined: "Undefined" show: assigned_admin: Assigned administrator assigned_valuators: Assigned valuators diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index b5466a080..e93eb4902 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -168,6 +168,10 @@ es: no_admin_assigned: Sin admin asignado no_valuators_assigned: Sin evaluador summary_link: "Resumen" + feasibility: + feasible: "Viable (%{price})" + not_feasible: "Inviable" + undefined: "Sin definir" show: assigned_admin: Administrador asignado assigned_valuators: Evaluadores asignados From 13aa83f2774a197ccd06c032c923654749ab1210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Mon, 25 Apr 2016 18:53:27 +0200 Subject: [PATCH 0131/1685] updates dependencies --- Gemfile | 2 +- Gemfile.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index ab00df68e..001eb4c38 100644 --- a/Gemfile +++ b/Gemfile @@ -44,7 +44,7 @@ gem 'paranoia' gem 'rinku', require: 'rails_rinku' gem 'savon' gem 'dalli' -gem 'rollbar', '~> 2.8.0' +gem 'rollbar', '~> 2.10.0' gem 'delayed_job_active_record', '~> 4.1.0' gem 'daemons' gem 'devise-async' diff --git a/Gemfile.lock b/Gemfile.lock index 12cb537d3..4e6b1aa80 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -126,7 +126,7 @@ GEM tins (~> 1.6.0) daemons (1.2.3) dalli (2.7.6) - database_cleaner (1.5.2) + database_cleaner (1.5.3) debug_inspector (0.0.2) delayed_job (4.1.1) activesupport (>= 3.0, < 5.0) @@ -231,7 +231,7 @@ GEM mime-types-data (3.2016.0221) mini_portile2 (2.0.0) minitest (5.8.4) - multi_json (1.11.2) + multi_json (1.11.3) multi_xml (0.5.5) multipart-post (2.0.0) net-scp (1.2.1) @@ -323,7 +323,7 @@ GEM responders (2.1.2) railties (>= 4.2.0, < 5.1) rinku (1.7.3) - rollbar (2.8.3) + rollbar (2.10.0) multi_json rspec (3.4.0) rspec-core (~> 3.4.0) @@ -488,7 +488,7 @@ DEPENDENCIES redcarpet responders rinku - rollbar (~> 2.8.0) + rollbar (~> 2.10.0) rspec-rails (~> 3.3) sass-rails (~> 5.0, >= 5.0.4) savon From 1c92ac4089d65006878d662623c9364185d37820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Tue, 26 Apr 2016 10:20:07 +0200 Subject: [PATCH 0132/1685] adds new filter 'All' to admin sps index --- app/controllers/admin/spending_proposals_controller.rb | 2 +- config/locales/admin.en.yml | 1 + config/locales/admin.es.yml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/admin/spending_proposals_controller.rb b/app/controllers/admin/spending_proposals_controller.rb index 9826ab17f..3c7f0c78d 100644 --- a/app/controllers/admin/spending_proposals_controller.rb +++ b/app/controllers/admin/spending_proposals_controller.rb @@ -2,7 +2,7 @@ class Admin::SpendingProposalsController < Admin::BaseController include FeatureFlags feature_flag :spending_proposals - has_filters %w{valuation_open without_admin managed valuating valuation_finished}, only: :index + has_filters %w{valuation_open without_admin managed valuating valuation_finished all}, only: :index load_and_authorize_resource diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index 3a04b8a6a..01b485b5b 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -165,6 +165,7 @@ en: managed: Managed valuating: Under valuation valuation_finished: Valuation finished + all: All title: Investment projects for participatory budgeting assigned_admin: Assigned administrator no_admin_assigned: No admin assigned diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index 16dd2373a..10ffdf22d 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -165,6 +165,7 @@ es: managed: Gestionando valuating: En evaluación valuation_finished: Evaluación finalizada + all: Todas title: Propuestas de inversión para presupuestos participativos assigned_admin: Administrador asignado no_admin_assigned: Sin admin asignado From d5e3c9ac3c2f3bd9d6df74b8612d2f6d3ae6e0a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Tue, 26 Apr 2016 10:30:31 +0200 Subject: [PATCH 0133/1685] adds specs for new filter --- spec/features/admin/spending_proposals_spec.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spec/features/admin/spending_proposals_spec.rb b/spec/features/admin/spending_proposals_spec.rb index a28feded4..118c66d26 100644 --- a/spec/features/admin/spending_proposals_spec.rb +++ b/spec/features/admin/spending_proposals_spec.rb @@ -194,7 +194,8 @@ feature 'Admin spending proposals' do 'without_admin' => 'Without assigned admin', 'managed' => 'Managed', 'valuating' => 'Under valuation', - 'valuation_finished' => 'Valuation finished'} + 'valuation_finished' => 'Valuation finished', + 'all' => 'All'} visit admin_spending_proposals_path @@ -253,6 +254,10 @@ feature 'Admin spending proposals' do expect(page).to_not have_content("Ongoing valuation") expect(page).to have_content("Old idea") + + visit admin_spending_proposals_path(filter: 'all') + expect(page).to have_content("Ongoing valuation") + expect(page).to have_content("Old idea") end scenario "Filtering by tag" do From 23e325896f4579b28810bdd3a15c51a23cba3be7 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Tue, 26 Apr 2016 11:12:07 +0200 Subject: [PATCH 0134/1685] displays error on failed update --- .../admin/spending_proposals_controller.rb | 21 ++++++++++++++++--- .../features/admin/spending_proposals_spec.rb | 14 +++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/app/controllers/admin/spending_proposals_controller.rb b/app/controllers/admin/spending_proposals_controller.rb index bd139dc9a..bdcfb9a62 100644 --- a/app/controllers/admin/spending_proposals_controller.rb +++ b/app/controllers/admin/spending_proposals_controller.rb @@ -14,9 +14,9 @@ class Admin::SpendingProposalsController < Admin::BaseController end def edit - @admins = Administrator.includes(:user).all - @valuators = Valuator.includes(:user).all.order("description ASC").order("users.email ASC") - @tags = ActsAsTaggableOn::Tag.spending_proposal_tags + load_admins + load_valuators + load_tags end def update @@ -24,6 +24,9 @@ class Admin::SpendingProposalsController < Admin::BaseController redirect_to admin_spending_proposal_path(@spending_proposal, SpendingProposal.filter_params(params)), notice: t("flash.actions.update.spending_proposal") else + load_admins + load_valuators + load_tags render :edit end end @@ -38,4 +41,16 @@ class Admin::SpendingProposalsController < Admin::BaseController params.require(:spending_proposal).permit(:title, :description, :external_url, :geozone_id, :association_name, :administrator_id, :tag_list, valuator_ids: []) end + def load_admins + @admins = Administrator.includes(:user).all + end + + def load_valuators + @valuators = Valuator.includes(:user).all.order("description ASC").order("users.email ASC") + end + + def load_tags + @tags = ActsAsTaggableOn::Tag.spending_proposal_tags + end + end diff --git a/spec/features/admin/spending_proposals_spec.rb b/spec/features/admin/spending_proposals_spec.rb index a28feded4..0ca1edd45 100644 --- a/spec/features/admin/spending_proposals_spec.rb +++ b/spec/features/admin/spending_proposals_spec.rb @@ -423,6 +423,20 @@ feature 'Admin spending proposals' do end end + scenario "Errors on update" do + spending_proposal = create(:spending_proposal) + create(:geozone, name: "Barbate") + + visit admin_spending_proposal_path(spending_proposal) + click_link 'Edit' + + fill_in 'spending_proposal_title', with: '' + + click_button 'Update' + + expect(page).to have_content "can't be blank" + end + end context 'Summary' do From 5dd4d2a80a3342c4a2e048b29f0fc02d67740627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Tue, 26 Apr 2016 11:18:01 +0200 Subject: [PATCH 0135/1685] improves spec scopes css element search to the main area, ignoring sidebar --- spec/features/debates_spec.rb | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/spec/features/debates_spec.rb b/spec/features/debates_spec.rb index 0db455401..5efb48406 100644 --- a/spec/features/debates_spec.rb +++ b/spec/features/debates_spec.rb @@ -1009,21 +1009,27 @@ feature 'Debates' do end end - scenario 'Matk/Unmark a debate as featured' do + scenario 'Mark/Unmark a debate as featured' do admin = create(:administrator) login_as(admin.user) debate = create(:debate) visit debates_path - expect(page).to_not have_content 'Featured' + within('#debates') do + expect(page).to_not have_content 'Featured' + end click_link debate.title click_link 'Featured' visit debates_path - expect(page).to have_content 'Featured' + + within('#debates') do + expect(page).to have_content 'Featured' + end + within('#featured-debates') do expect(page).to have_content debate.title end @@ -1031,7 +1037,9 @@ feature 'Debates' do visit debate_path(debate) click_link 'Unmark featured' - expect(page).to_not have_content 'Featured' + within('#debates') do + expect(page).to_not have_content 'Featured' + end end @@ -1043,7 +1051,9 @@ feature 'Debates' do debate2 = create(:debate) visit debates_path - expect(page).to have_content("Featured") + within('#debates') do + expect(page).to have_content("Featured") + end end @@ -1055,6 +1065,8 @@ feature 'Debates' do debate2 = create(:debate) visit debates_path - expect(page).to_not have_content("Featured") + within('#debates') do + expect(page).to_not have_content("Featured") + end end end From 7320d17bea01b9b652a3b8668ab4bceed45c6b70 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Cabeza Date: Tue, 26 Apr 2016 13:04:57 +0200 Subject: [PATCH 0136/1685] Moves back links inside a partial --- app/views/debates/edit.html.erb | 5 +---- app/views/debates/new.html.erb | 6 ++---- app/views/debates/show.html.erb | 6 ++---- app/views/pages/faq.html.erb | 5 +---- app/views/pages/how_it_works.html.erb | 5 +---- app/views/pages/how_to_use.html.erb | 5 +---- app/views/pages/participation.html.erb | 5 +---- app/views/pages/participation_facts.html.erb | 6 +----- app/views/pages/participation_world.html.erb | 5 +---- app/views/pages/proposals_info.html.erb | 6 +----- app/views/pages/spending_proposals_info.html.erb | 5 +---- app/views/proposals/edit.html.erb | 5 +---- app/views/proposals/new.html.erb | 6 ++---- app/views/proposals/show.html.erb | 6 ++---- app/views/proposals/summary.html.erb | 6 +----- app/views/shared/_back_link.html.erb | 4 ++++ app/views/spending_proposals/new.html.erb | 6 ++---- app/views/users/registrations/delete_form.html.erb | 5 +---- app/views/users/registrations/edit.html.erb | 5 +---- app/views/valuation/spending_proposals/show.html.erb | 4 +--- config/locales/en.yml | 2 +- 21 files changed, 29 insertions(+), 79 deletions(-) create mode 100644 app/views/shared/_back_link.html.erb diff --git a/app/views/debates/edit.html.erb b/app/views/debates/edit.html.erb index 34a7f70df..eea353438 100644 --- a/app/views/debates/edit.html.erb +++ b/app/views/debates/edit.html.erb @@ -1,10 +1,7 @@
- <%= link_to debates_path, class: "back" do %> - - <%= t("debates.edit.back_link") %> - <% end %> + <%= render "shared/back_link" %>
<%= link_to t("debates.edit.show_link"), @debate %> diff --git a/app/views/debates/new.html.erb b/app/views/debates/new.html.erb index 34821a4fd..65d47bbcd 100644 --- a/app/views/debates/new.html.erb +++ b/app/views/debates/new.html.erb @@ -1,10 +1,8 @@
- <%= link_to debates_path, class: "back" do %> - - <%= t("debates.new.back_link") %> - <% end %> + <%= render "shared/back_link" %> +

<%= t("debates.new.start_new") %>

<%= t("debates.new.info", diff --git a/app/views/debates/show.html.erb b/app/views/debates/show.html.erb index cfce656a2..9625ab42d 100644 --- a/app/views/debates/show.html.erb +++ b/app/views/debates/show.html.erb @@ -3,10 +3,8 @@
- <%= link_to :back, class: "back" do %> - - <%= t("debates.show.back_link") %> - <% end %> + <%= render "shared/back_link" %> + <% if current_user && @debate.editable_by?(current_user) %> <%= link_to edit_debate_path(@debate), class: 'edit-debate button success small float-right' do %> diff --git a/app/views/pages/faq.html.erb b/app/views/pages/faq.html.erb index 0dcd09a68..3806cb22f 100644 --- a/app/views/pages/faq.html.erb +++ b/app/views/pages/faq.html.erb @@ -1,9 +1,6 @@
-
- +
\ No newline at end of file diff --git a/app/views/admin/budgets/show.html.erb b/app/views/admin/budgets/show.html.erb new file mode 100644 index 000000000..20185b2ba --- /dev/null +++ b/app/views/admin/budgets/show.html.erb @@ -0,0 +1,12 @@ +
+
+

<%= @budget.name %>

+ + <%= simple_format(text_with_links(@budget.description), {}, sanitize: false) %> + +

+ <%= t('admin.budgets.show.phase') %>: <%= t("budget.phase.#{@budget.phase}") %> | + <%= t('admin.budgets.show.currency') %>: <%= @budget.currency_symbol %> +

+
+
\ No newline at end of file diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index d55d24726..812e1a45c 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -87,6 +87,9 @@ en: table_heading: Heading table_amount: Amount table_geozone: Scope of operation + show: + phase: Current phase + currency: Currency comments: index: filter: Filter diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index 8ed57d4d8..1afc01ef2 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -87,6 +87,9 @@ es: table_heading: Partida table_amount: Cantidad table_geozone: Ámbito de actuación + show: + phase: Fase actual + currency: Divisa comments: index: filter: Filtro diff --git a/spec/features/admin/budgets_spec.rb b/spec/features/admin/budgets_spec.rb index c684d8a55..f38d2c9f5 100644 --- a/spec/features/admin/budgets_spec.rb +++ b/spec/features/admin/budgets_spec.rb @@ -55,7 +55,6 @@ feature 'Admin budgets' do expect(page).to_not have_content(budget5.name) end - scenario 'Current filter is properly highlighted' do filters_links = {'open' => 'Open', 'finished' => 'Finished'} @@ -78,6 +77,7 @@ feature 'Admin budgets' do end context 'New' do + scenario 'Create budget' do visit admin_budgets_path click_link 'Create new' From 9abf6e155888148752707eb7c7eb320ece4c1337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Fri, 29 Jul 2016 15:13:28 +0200 Subject: [PATCH 0449/1685] updates dependencies bullet, coveralls, faker, uglifier --- Gemfile.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5ccd7f8ba..5f35de786 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -67,7 +67,7 @@ GEM bcrypt (3.1.11) browser (2.2.0) builder (3.2.2) - bullet (5.1.1) + bullet (5.2.0) activesupport (>= 3.0.0) uniform_notifier (~> 1.10.0) byebug (9.0.5) @@ -114,12 +114,12 @@ GEM execjs coffee-script-source (1.10.0) concurrent-ruby (1.0.2) - coveralls (0.8.14) + coveralls (0.8.15) json (>= 1.8, < 3) simplecov (~> 0.12.0) term-ansicolor (~> 1.3) thor (~> 0.19.1) - tins (~> 1.6.0) + tins (>= 1.6.0, < 2) daemons (1.2.3) dalli (2.7.6) database_cleaner (1.5.3) @@ -156,7 +156,7 @@ GEM factory_girl_rails (4.7.0) factory_girl (~> 4.7.0) railties (>= 3.0.0) - faker (1.6.5) + faker (1.6.6) i18n (~> 0.5) faraday (0.9.2) multipart-post (>= 1.2, < 3) @@ -396,7 +396,7 @@ GEM thread (0.2.2) thread_safe (0.3.5) tilt (2.0.5) - tins (1.6.0) + tins (1.11.0) tolk (1.9.3) rails (>= 4.0, < 4.3) safe_yaml (>= 0.8.6) @@ -408,7 +408,7 @@ GEM tilt (>= 1.4, < 3) tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (3.0.0) + uglifier (3.0.1) execjs (>= 0.3.0, < 3) unicorn (5.1.0) kgio (~> 2.6) From c4768e380d01efbbac3d63a52f86fb49861b2abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Sat, 30 Jul 2016 09:56:13 +0200 Subject: [PATCH 0450/1685] saves querys --- app/views/shared/_admin_login_items.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/shared/_admin_login_items.html.erb b/app/views/shared/_admin_login_items.html.erb index 6ba10bbca..013320f38 100644 --- a/app/views/shared/_admin_login_items.html.erb +++ b/app/views/shared/_admin_login_items.html.erb @@ -5,13 +5,13 @@ <% end %> - <% if current_user.moderator? || current_user.administrator? %> + <% if current_user.administrator? || current_user.moderator? %>
  • <%= link_to t("layouts.header.moderation"), moderation_root_path %>
  • <% end %> - <% if feature?(:spending_proposals) && (current_user.valuator? || current_user.administrator?) %> + <% if feature?(:spending_proposals) && (current_user.administrator? || current_user.valuator?) %>
  • <%= link_to t("layouts.header.valuation"), valuation_root_path %>
  • From 99b9c3867ed80fb8ba60300e5b09867bd52d923f Mon Sep 17 00:00:00 2001 From: rgarcia Date: Fri, 29 Jul 2016 18:01:44 +0200 Subject: [PATCH 0451/1685] adds pending spec --- spec/features/emails_spec.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/features/emails_spec.rb b/spec/features/emails_spec.rb index 429d74738..94c70df4f 100644 --- a/spec/features/emails_spec.rb +++ b/spec/features/emails_spec.rb @@ -229,6 +229,9 @@ feature 'Emails' do expect(email).to have_body_text(/#{account_path}/) end + xscenario "Delete all Notifications included in the digest after email sent" do + end + end context "User invites" do From 9d9bf488fccae054ce7c49c307861628a5c140d0 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Tue, 2 Aug 2016 20:35:33 +0200 Subject: [PATCH 0452/1685] does not create notifications for blocked or erased users --- app/models/proposal.rb | 2 +- app/models/user.rb | 1 + spec/features/proposal_notifications_spec.rb | 38 +++++++++++++++++ spec/models/proposal_spec.rb | 44 ++++++++++++++++++++ spec/models/user_spec.rb | 28 +++++++++++++ 5 files changed, 112 insertions(+), 1 deletion(-) diff --git a/app/models/proposal.rb b/app/models/proposal.rb index 7d2bddb30..9a92a8d18 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -99,7 +99,7 @@ class Proposal < ActiveRecord::Base end def voters - votes_for.voters + User.active.where(id: votes_for.voters) end def editable? diff --git a/app/models/user.rb b/app/models/user.rb index 4bb09c4a0..60bc2364a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -53,6 +53,7 @@ class User < ActiveRecord::Base scope :for_render, -> { includes(:organization) } scope :by_document, -> (document_type, document_number) { where(document_type: document_type, document_number: document_number) } scope :email_digest, -> { where(email_digest: true) } + scope :active, -> { where(erased_at: nil) } before_validation :clean_document_number diff --git a/spec/features/proposal_notifications_spec.rb b/spec/features/proposal_notifications_spec.rb index 6092289f0..a10e41a7d 100644 --- a/spec/features/proposal_notifications_spec.rb +++ b/spec/features/proposal_notifications_spec.rb @@ -24,6 +24,44 @@ feature 'Proposal Notifications' do expect(page).to have_content "Please share it with others so we can make it happen!" end + scenario "Send a notification (Active voter)" do + author = create(:user) + proposal = create(:proposal, author: author) + + voter = create(:user, :level_two) + create(:vote, voter: voter, votable: proposal) + + create_proposal_notification(proposal) + + expect(Notification.count).to eq(1) + end + + scenario "Send a notification (Blocked voter)" do + author = create(:user) + proposal = create(:proposal, author: author) + + voter = create(:user, :level_two) + create(:vote, voter: voter, votable: proposal) + voter.block + + create_proposal_notification(proposal) + + expect(Notification.count).to eq(0) + end + + scenario "Send a notification (Erased voter)" do + author = create(:user) + proposal = create(:proposal, author: author) + + voter = create(:user, :level_two) + create(:vote, voter: voter, votable: proposal) + voter.erase + + create_proposal_notification(proposal) + + expect(Notification.count).to eq(0) + end + scenario "Show notifications" do proposal = create(:proposal) notification1 = create(:proposal_notification, proposal: proposal, title: "Hey guys", body: "Just wanted to let you know that...") diff --git a/spec/models/proposal_spec.rb b/spec/models/proposal_spec.rb index 4958204ec..247cd9e66 100644 --- a/spec/models/proposal_spec.rb +++ b/spec/models/proposal_spec.rb @@ -367,6 +367,50 @@ describe Proposal do end end + describe "voters" do + + it "returns users that have voted for the proposal" do + proposal = create(:proposal) + voter1 = create(:user, :level_two) + voter2 = create(:user, :level_two) + voter3 = create(:user, :level_two) + + create(:vote, voter: voter1, votable: proposal) + create(:vote, voter: voter2, votable: proposal) + + expect(proposal.voters).to include(voter1) + expect(proposal.voters).to include(voter2) + expect(proposal.voters).to_not include(voter3) + end + + it "does not return users that have been erased" do + proposal = create(:proposal) + voter1 = create(:user, :level_two) + voter2 = create(:user, :level_two) + + create(:vote, voter: voter1, votable: proposal) + create(:vote, voter: voter2, votable: proposal) + voter2.erase + + expect(proposal.voters).to include(voter1) + expect(proposal.voters).to_not include(voter2) + end + + it "does not return users that have been blocked" do + proposal = create(:proposal) + voter1 = create(:user, :level_two) + voter2 = create(:user, :level_two) + + create(:vote, voter: voter1, votable: proposal) + create(:vote, voter: voter2, votable: proposal) + voter2.block + + expect(proposal.voters).to include(voter1) + expect(proposal.voters).to_not include(voter2) + end + + end + describe "search" do context "attributes" do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index d54f3a42e..b6084a971 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -325,6 +325,34 @@ describe User do end + describe "scopes" do + + describe "active" do + + it "returns users that have not been erased" do + user1 = create(:user, erased_at: nil) + user2 = create(:user, erased_at: nil) + user3 = create(:user, erased_at: Time.now) + + expect(User.active).to include(user1) + expect(User.active).to include(user2) + expect(User.active).to_not include(user3) + end + + it "returns users that have not been blocked" do + user1 = create(:user) + user2 = create(:user) + user3 = create(:user) + user3.block + + expect(User.active).to include(user1) + expect(User.active).to include(user2) + expect(User.active).to_not include(user3) + end + + end + end + describe "self.search" do it "find users by email" do user1 = create(:user, email: "larry@consul.dev") From 6281af2a7d9aa490c5cd2af64a54c1402ce1d946 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 3 Aug 2016 19:33:23 +0200 Subject: [PATCH 0453/1685] adds emailed_at attribute to notifications --- .../20160803154011_add_emailed_at_to_notifications.rb | 5 +++++ db/schema.rb | 11 ++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20160803154011_add_emailed_at_to_notifications.rb diff --git a/db/migrate/20160803154011_add_emailed_at_to_notifications.rb b/db/migrate/20160803154011_add_emailed_at_to_notifications.rb new file mode 100644 index 000000000..83e38b00f --- /dev/null +++ b/db/migrate/20160803154011_add_emailed_at_to_notifications.rb @@ -0,0 +1,5 @@ +class AddEmailedAtToNotifications < ActiveRecord::Migration + def change + add_column :notifications, :emailed_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 6932611e4..becde4f8a 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: 20160617172616) do +ActiveRecord::Schema.define(version: 20160803154011) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -251,10 +251,11 @@ ActiveRecord::Schema.define(version: 20160617172616) do add_index "moderators", ["user_id"], name: "index_moderators_on_user_id", using: :btree create_table "notifications", force: :cascade do |t| - t.integer "user_id" - t.integer "notifiable_id" - t.string "notifiable_type" - t.integer "counter", default: 1 + t.integer "user_id" + t.integer "notifiable_id" + t.string "notifiable_type" + t.integer "counter", default: 1 + t.datetime "emailed_at" end add_index "notifications", ["user_id"], name: "index_notifications_on_user_id", using: :btree From b087fe8fb78598cea3df6424d49f117b9eab5d95 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 3 Aug 2016 19:33:37 +0200 Subject: [PATCH 0454/1685] refactors email digest --- app/mailers/mailer.rb | 4 ++-- app/models/notification.rb | 8 +++++--- lib/email_digest.rb | 21 +++++++++++++++------ lib/tasks/emails.rake | 6 ++++-- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/app/mailers/mailer.rb b/app/mailers/mailer.rb index ad87359af..25c019857 100644 --- a/app/mailers/mailer.rb +++ b/app/mailers/mailer.rb @@ -60,8 +60,8 @@ class Mailer < ApplicationMailer end end - def proposal_notification_digest(user) - @notifications = user.notifications.where(notifiable_type: "ProposalNotification") + def proposal_notification_digest(user, notifications) + @notifications = notifications with_user(user) do mail(to: user.email, subject: t('mailers.proposal_notification_digest.title', org_name: Setting['org_name'])) diff --git a/app/models/notification.rb b/app/models/notification.rb index 9695c1b01..c6c32eb8d 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -2,9 +2,11 @@ class Notification < ActiveRecord::Base belongs_to :user, counter_cache: true belongs_to :notifiable, polymorphic: true - scope :unread, -> { all } - scope :recent, -> { order(id: :desc) } - scope :for_render, -> { includes(:notifiable) } + scope :unread, -> { all } + scope :recent, -> { order(id: :desc) } + scope :not_emailed, -> { where(emailed_at: nil) } + scope :for_render, -> { includes(:notifiable) } + def timestamp notifiable.created_at diff --git a/lib/email_digest.rb b/lib/email_digest.rb index 90838f78f..0b4d796db 100644 --- a/lib/email_digest.rb +++ b/lib/email_digest.rb @@ -1,13 +1,22 @@ class EmailDigest - def initialize + attr_accessor :user, :notifications + + def initialize(user) + @user = user end - def create - User.email_digest.each do |user| - if user.notifications.where(notifiable_type: "ProposalNotification").any? - Mailer.proposal_notification_digest(user).deliver_later - end + def notifications + user.notifications.not_emailed.where(notifiable_type: "ProposalNotification").to_a + end + + def pending_notifications? + notifications.any? + end + + def deliver + if pending_notifications? + Mailer.proposal_notification_digest(user, notifications).deliver_later end end diff --git a/lib/tasks/emails.rake b/lib/tasks/emails.rake index 6670264a5..7c76b20c8 100644 --- a/lib/tasks/emails.rake +++ b/lib/tasks/emails.rake @@ -2,8 +2,10 @@ namespace :emails do desc "Sends email digest of proposal notifications to each user" task digest: :environment do - email_digest = EmailDigest.new - email_digest.create + User.email_digest.find_each do |user| + email_digest = EmailDigest.new(user) + email_digest.deliver + end end end From 0faff2f01c2c62e9d75e4ded293428c0f8c26f75 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 3 Aug 2016 19:33:43 +0200 Subject: [PATCH 0455/1685] adds specs --- spec/lib/email_digests_spec.rb | 92 +++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/spec/lib/email_digests_spec.rb b/spec/lib/email_digests_spec.rb index 6fc6eef53..244d1270a 100644 --- a/spec/lib/email_digests_spec.rb +++ b/spec/lib/email_digests_spec.rb @@ -2,8 +2,96 @@ require 'rails_helper' describe EmailDigest do - describe "create" do - pending "only send unread notifications" + describe "notifications" do + + it "returns notifications for a user" do + user1 = create(:user) + user2 = create(:user) + + proposal_notification = create(:proposal_notification) + notification1 = create(:notification, notifiable: proposal_notification, user: user1) + notification2 = create(:notification, notifiable: proposal_notification, user: user2) + + email_digest = EmailDigest.new(user1) + + expect(email_digest.notifications).to include(notification1) + expect(email_digest.notifications).to_not include(notification2) + end + + it "returns only proposal notifications" do + user = create(:user) + + proposal_notification = create(:proposal_notification) + comment = create(:comment) + + notification1 = create(:notification, notifiable: proposal_notification, user: user) + notification2 = create(:notification, notifiable: comment, user: user) + + email_digest = EmailDigest.new(user) + + expect(email_digest.notifications).to include(notification1) + expect(email_digest.notifications).to_not include(notification2) + end + + end + + describe "pending_notifications?" do + + it "returns true when notifications have not been emailed" do + user = create(:user) + + proposal_notification = create(:proposal_notification) + notification = create(:notification, notifiable: proposal_notification, user: user) + + email_digest = EmailDigest.new(user) + expect(email_digest.pending_notifications?).to be + end + + it "returns false when notifications have been emailed" do + user = create(:user) + + proposal_notification = create(:proposal_notification) + notification = create(:notification, notifiable: proposal_notification, user: user, emailed_at: Time.now) + + email_digest = EmailDigest.new(user) + expect(email_digest.pending_notifications?).to_not be + end + + it "returns false when there are no notifications for a user" do + user = create(:user) + email_digest = EmailDigest.new(user) + expect(email_digest.pending_notifications?).to_not be + end + + end + + describe "deliver" do + + it "delivers email if notifications pending" do + user = create(:user) + + proposal_notification = create(:proposal_notification) + notification = create(:notification, notifiable: proposal_notification, user: user) + + email_digest = EmailDigest.new(user) + email_digest.deliver + + email = open_last_email + expect(email).to have_subject("Proposal notifications in Consul") + end + + it "does not deliver email if no notifications pending" do + user = create(:user) + + proposal_notification = create(:proposal_notification) + notification = create(:notification, notifiable: proposal_notification, user: user, emailed_at: Time.now) + + email_digest = EmailDigest.new(user) + email_digest.deliver + + expect(all_emails.count).to eq(0) + end + end end \ No newline at end of file From 63274dfe08f8ebe259fce31382f4fb77890d9de0 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 3 Aug 2016 19:48:43 +0200 Subject: [PATCH 0456/1685] marks notifications as emailed after rake --- lib/email_digest.rb | 8 ++++++-- lib/tasks/emails.rake | 1 + spec/lib/email_digests_spec.rb | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/email_digest.rb b/lib/email_digest.rb index 0b4d796db..209014dcc 100644 --- a/lib/email_digest.rb +++ b/lib/email_digest.rb @@ -7,7 +7,7 @@ class EmailDigest end def notifications - user.notifications.not_emailed.where(notifiable_type: "ProposalNotification").to_a + user.notifications.not_emailed.where(notifiable_type: "ProposalNotification") end def pending_notifications? @@ -16,8 +16,12 @@ class EmailDigest def deliver if pending_notifications? - Mailer.proposal_notification_digest(user, notifications).deliver_later + Mailer.proposal_notification_digest(user, notifications.to_a).deliver_later end end + def mark_as_emailed + notifications.update_all(emailed_at: Time.now) + end + end \ No newline at end of file diff --git a/lib/tasks/emails.rake b/lib/tasks/emails.rake index 7c76b20c8..ffadebf05 100644 --- a/lib/tasks/emails.rake +++ b/lib/tasks/emails.rake @@ -5,6 +5,7 @@ namespace :emails do User.email_digest.find_each do |user| email_digest = EmailDigest.new(user) email_digest.deliver + email_digest.mark_as_emailed end end diff --git a/spec/lib/email_digests_spec.rb b/spec/lib/email_digests_spec.rb index 244d1270a..d03ea91fd 100644 --- a/spec/lib/email_digests_spec.rb +++ b/spec/lib/email_digests_spec.rb @@ -94,4 +94,27 @@ describe EmailDigest do end + describe "mark_as_emailed" do + + it "marks notifications as emailed" do + user = create(:user) + + proposal_notification = create(:proposal_notification) + notification1 = create(:notification, notifiable: proposal_notification, user: user) + notification2 = create(:notification, notifiable: proposal_notification, user: user) + + expect(notification1.emailed_at).to_not be + expect(notification2.emailed_at).to_not be + + email_digest = EmailDigest.new(user) + email_digest.mark_as_emailed + + notification1.reload + notification2.reload + expect(notification1.emailed_at).to be + expect(notification2.emailed_at).to be + end + + end + end \ No newline at end of file From 5bd7fdb26369f59410dc71204af7069e74cd6925 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 3 Aug 2016 20:05:08 +0200 Subject: [PATCH 0457/1685] fixes specs --- spec/features/emails_spec.rb | 11 +++++++---- spec/lib/email_digests_spec.rb | 15 +++++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/spec/features/emails_spec.rb b/spec/features/emails_spec.rb index 94c70df4f..a9569e9b2 100644 --- a/spec/features/emails_spec.rb +++ b/spec/features/emails_spec.rb @@ -201,8 +201,9 @@ feature 'Emails' do notification2 = create_proposal_notification(proposal2) notification3 = create_proposal_notification(proposal3) - email_digest = EmailDigest.new - email_digest.create + email_digest = EmailDigest.new(user) + email_digest.deliver + email_digest.mark_as_emailed email = open_last_email expect(email).to have_subject("Proposal notifications in Consul") @@ -227,9 +228,11 @@ feature 'Emails' do expect(email).to_not have_body_text(proposal3.title) expect(email).to have_body_text(/#{account_path}/) - end - xscenario "Delete all Notifications included in the digest after email sent" do + notification1.reload + notification2.reload + expect(notification1.emailed_at).to be + expect(notification2.emailed_at).to be end end diff --git a/spec/lib/email_digests_spec.rb b/spec/lib/email_digests_spec.rb index d03ea91fd..ae2122793 100644 --- a/spec/lib/email_digests_spec.rb +++ b/spec/lib/email_digests_spec.rb @@ -73,6 +73,7 @@ describe EmailDigest do proposal_notification = create(:proposal_notification) notification = create(:notification, notifiable: proposal_notification, user: user) + reset_mailer email_digest = EmailDigest.new(user) email_digest.deliver @@ -86,6 +87,7 @@ describe EmailDigest do proposal_notification = create(:proposal_notification) notification = create(:notification, notifiable: proposal_notification, user: user, emailed_at: Time.now) + reset_mailer email_digest = EmailDigest.new(user) email_digest.deliver @@ -97,22 +99,27 @@ describe EmailDigest do describe "mark_as_emailed" do it "marks notifications as emailed" do - user = create(:user) + user1 = create(:user) + user2 = create(:user) proposal_notification = create(:proposal_notification) - notification1 = create(:notification, notifiable: proposal_notification, user: user) - notification2 = create(:notification, notifiable: proposal_notification, user: user) + notification1 = create(:notification, notifiable: proposal_notification, user: user1) + notification2 = create(:notification, notifiable: proposal_notification, user: user1) + notification3 = create(:notification, notifiable: proposal_notification, user: user2) expect(notification1.emailed_at).to_not be expect(notification2.emailed_at).to_not be + expect(notification3.emailed_at).to_not be - email_digest = EmailDigest.new(user) + email_digest = EmailDigest.new(user1) email_digest.mark_as_emailed notification1.reload notification2.reload + notification3.reload expect(notification1.emailed_at).to be expect(notification2.emailed_at).to be + expect(notification3.emailed_at).to_not be end end From 64a614c67f2ce55e815980df5bd989879945e131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Wed, 3 Aug 2016 20:20:52 +0200 Subject: [PATCH 0458/1685] adds geozone helper to map ids and names --- app/helpers/geozones_helper.rb | 5 +++++ spec/helpers/geozones_helper_spec.rb | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/app/helpers/geozones_helper.rb b/app/helpers/geozones_helper.rb index bfc5f9105..ce03e0579 100644 --- a/app/helpers/geozones_helper.rb +++ b/app/helpers/geozones_helper.rb @@ -8,4 +8,9 @@ module GeozonesHelper Geozone.all.order(name: :asc).collect { |g| [ g.name, g.id ] } end + def geozone_name_from_id(g_id) + @all_geozones ||= Geozone.all.collect{ |g| [ g.id, g.name ] }.to_h + @all_geozones[g_id] || t("geozones.none") + end + end diff --git a/spec/helpers/geozones_helper_spec.rb b/spec/helpers/geozones_helper_spec.rb index 605a774a6..0c0c13d70 100644 --- a/spec/helpers/geozones_helper_spec.rb +++ b/spec/helpers/geozones_helper_spec.rb @@ -31,4 +31,19 @@ describe GeozonesHelper do end end + describe "#geozone_name_from_id" do + + it "returns geozone name if present" do + g1 = create(:geozone, name: "AAA") + g2 = create(:geozone, name: "BBB") + + expect(geozone_name_from_id(g1.id)).to eq "AAA" + expect(geozone_name_from_id(g2.id)).to eq "BBB" + end + + it "returns default string for no geozone if geozone is blank" do + expect(geozone_name_from_id(nil)).to eq "All city" + end + end + end From 0f7e23bec49a2494dce28c771a0b521ea549111e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Wed, 3 Aug 2016 20:23:41 +0200 Subject: [PATCH 0459/1685] adds budget's groups & headings to admin --- .../admin/budget_groups_controller.rb | 15 ++++ .../admin/budget_headings_controller.rb | 16 ++++ app/controllers/admin/budgets_controller.rb | 1 + app/models/abilities/administrator.rb | 4 +- app/views/admin/budget_groups/create.js.erb | 2 + app/views/admin/budget_headings/create.js.erb | 2 + app/views/admin/budgets/_group.html.erb | 76 +++++++++++++++++++ app/views/admin/budgets/_groups.html.erb | 34 +++++++++ app/views/admin/budgets/new.html.erb | 2 +- app/views/admin/budgets/show.html.erb | 4 + config/locales/admin.en.yml | 9 ++- config/locales/admin.es.yml | 9 ++- spec/features/admin/budgets_spec.rb | 54 +++++++++++++ 13 files changed, 220 insertions(+), 8 deletions(-) create mode 100644 app/controllers/admin/budget_groups_controller.rb create mode 100644 app/controllers/admin/budget_headings_controller.rb create mode 100644 app/views/admin/budget_groups/create.js.erb create mode 100644 app/views/admin/budget_headings/create.js.erb create mode 100644 app/views/admin/budgets/_group.html.erb create mode 100644 app/views/admin/budgets/_groups.html.erb diff --git a/app/controllers/admin/budget_groups_controller.rb b/app/controllers/admin/budget_groups_controller.rb new file mode 100644 index 000000000..18f5a6b12 --- /dev/null +++ b/app/controllers/admin/budget_groups_controller.rb @@ -0,0 +1,15 @@ +class Admin::BudgetGroupsController < Admin::BaseController + + def create + @budget = Budget.find params[:budget_id] + @budget.groups.create(budget_group_params) + @groups = @budget.groups.includes(:headings) + end + + private + + def budget_group_params + params.require(:budget_group).permit(:name) + end + +end \ No newline at end of file diff --git a/app/controllers/admin/budget_headings_controller.rb b/app/controllers/admin/budget_headings_controller.rb new file mode 100644 index 000000000..3c8ccafa0 --- /dev/null +++ b/app/controllers/admin/budget_headings_controller.rb @@ -0,0 +1,16 @@ +class Admin::BudgetHeadingsController < Admin::BaseController + + def create + @budget = Budget.find params[:budget_id] + @budget_group = @budget.groups.find params[:budget_group_id] + @budget_group.headings.create(budget_heading_params) + @headings = @budget_group.headings + end + + private + + def budget_heading_params + params.require(:budget_heading).permit(:name, :price, :geozone_id) + end + +end \ No newline at end of file diff --git a/app/controllers/admin/budgets_controller.rb b/app/controllers/admin/budgets_controller.rb index 2e8a28fe6..144b43a7f 100644 --- a/app/controllers/admin/budgets_controller.rb +++ b/app/controllers/admin/budgets_controller.rb @@ -9,6 +9,7 @@ class Admin::BudgetsController < Admin::BaseController end def show + @budget = Budget.includes(groups: :headings).find(params[:id]) end def new diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index 65f97db2e..f3f0b8f9b 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -42,7 +42,9 @@ module Abilities can [:read, :update, :valuate, :destroy, :summary], SpendingProposal - can [:read, :create, :update], Budget + can [:index, :read, :new, :create, :update, :destroy], Budget + can [:read, :create, :update, :destroy], Budget::Group + can [:read, :create, :update, :destroy], Budget::Heading can [:hide, :update], Budget::Investment can :valuate, Budget::Investment, budget: { valuating: true } can :create, Budget::ValuatorAssignment diff --git a/app/views/admin/budget_groups/create.js.erb b/app/views/admin/budget_groups/create.js.erb new file mode 100644 index 000000000..cb926a7c6 --- /dev/null +++ b/app/views/admin/budget_groups/create.js.erb @@ -0,0 +1,2 @@ +$("#<%= dom_id(@budget) %>_groups").html('<%= j render("admin/budgets/groups", groups: @groups) %>'); +App.Forms.toggleLink(); \ No newline at end of file diff --git a/app/views/admin/budget_headings/create.js.erb b/app/views/admin/budget_headings/create.js.erb new file mode 100644 index 000000000..5d8eefb2d --- /dev/null +++ b/app/views/admin/budget_headings/create.js.erb @@ -0,0 +1,2 @@ +$("#<%= dom_id(@budget_group) %>").html('<%= j render("admin/budgets/group", group: @budget_group, headings: @headings) %>'); +App.Forms.toggleLink(); \ No newline at end of file diff --git a/app/views/admin/budgets/_group.html.erb b/app/views/admin/budgets/_group.html.erb new file mode 100644 index 000000000..3660fa0c1 --- /dev/null +++ b/app/views/admin/budgets/_group.html.erb @@ -0,0 +1,76 @@ +
    + + + + + + + <% if headings.blank? %> + + + + + <% else %> + + + + + + + + <% end %> + + + + + + + + <% headings.each do |heading| %> + + + + + + <% end %> + + +
    + <%= group.name %> + <%= link_to t("admin.budgets.form.add_heading"), "#", class: "button float-right js-toggle-link", data: { "toggle-selector" => "#group-#{group.id}-new-heading-form" } %> +
    +
    + <%= t("admin.budgets.form.no_heading") %> +
    +
    <%= t("admin.budgets.form.table_heading") %><%= t("admin.budgets.form.table_amount") %><%= t("admin.budgets.form.table_geozone") %>
    + <%= heading.name %> + + <%= heading.price %> + + <%= geozone_name_from_id heading.geozone_id %> +
    +
    \ No newline at end of file diff --git a/app/views/admin/budgets/_groups.html.erb b/app/views/admin/budgets/_groups.html.erb new file mode 100644 index 000000000..ba785ee0c --- /dev/null +++ b/app/views/admin/budgets/_groups.html.erb @@ -0,0 +1,34 @@ +
    +

    <%= t('admin.budgets.show.groups') %>

    + <% if groups.blank? %> +
    + <%= t("admin.budgets.form.no_groups") %> + <%= link_to t("admin.budgets.form.add_group"), "#", + class: "js-toggle-link", + data: { "toggle-selector" => "#new-group-form" } %> +
    + <% else %> + <%= link_to t("admin.budgets.form.add_group"), "#", class: "button float-right js-toggle-link", data: { "toggle-selector" => "#new-group-form" } %> + <% end %> + + <%= form_for [:admin, @budget, Budget::Group.new], html: {id: "new-group-form", style: "display:none"}, remote: true do |f| %> +
    + + + + <%= f.text_field :name, + label: false, + maxlength: 50, + placeholder: t("admin.budgets.form.group") %> +
    + <%= f.submit t("admin.budgets.form.create_group"), class: "button success" %> +
    +
    + <% end %> + + <% groups.each do |group| %> +
    + <%= render "admin/budgets/group", group: group, headings: group.headings %> +
    + <% end %> +
    \ No newline at end of file diff --git a/app/views/admin/budgets/new.html.erb b/app/views/admin/budgets/new.html.erb index 019ca460f..9ca0f34a5 100644 --- a/app/views/admin/budgets/new.html.erb +++ b/app/views/admin/budgets/new.html.erb @@ -23,7 +23,7 @@ <%= f.select :currency_symbol, budget_currency_symbol_select_options, {label: false} %>
    - " class="button success"> + <%= f.submit t("admin.budgets.new.create"), class: "button success" %> <% end %>
    \ No newline at end of file diff --git a/app/views/admin/budgets/show.html.erb b/app/views/admin/budgets/show.html.erb index 20185b2ba..847aa2f60 100644 --- a/app/views/admin/budgets/show.html.erb +++ b/app/views/admin/budgets/show.html.erb @@ -9,4 +9,8 @@ <%= t('admin.budgets.show.currency') %>: <%= @budget.currency_symbol %>

    +
    + +
    + <%= render "groups", groups: @budget.groups %>
    \ No newline at end of file diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index 812e1a45c..d8154efc1 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -74,7 +74,13 @@ en: description: Description phase: Phase currency: Currency + show: + phase: Current phase + currency: Currency + groups: Groups of budget headings + form: group: Group's name + no_groups: No groups created yet. Each user will be able to vote in only one heading per group. add_group: Add new group create_group: Create group heading: Heading's name @@ -87,9 +93,6 @@ en: table_heading: Heading table_amount: Amount table_geozone: Scope of operation - show: - phase: Current phase - currency: Currency comments: index: filter: Filter diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index 1afc01ef2..1d4ead16b 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -74,7 +74,13 @@ es: description: Descripción phase: Fase currency: Divisa + show: + phase: Fase actual + currency: Divisa + groups: Grupos de partidas presupuestarias + form: group: Nombre del grupo + no_groups: No hay grupos creados todavía. Cada usuario podrá votar en una sola partida de cada grupo. add_group: Añadir nuevo grupo create_group: Crear grupo heading: Nombre de la partida @@ -87,9 +93,6 @@ es: table_heading: Partida table_amount: Cantidad table_geozone: Ámbito de actuación - show: - phase: Fase actual - currency: Divisa comments: index: filter: Filtro diff --git a/spec/features/admin/budgets_spec.rb b/spec/features/admin/budgets_spec.rb index f38d2c9f5..123ca43e8 100644 --- a/spec/features/admin/budgets_spec.rb +++ b/spec/features/admin/budgets_spec.rb @@ -101,4 +101,58 @@ feature 'Admin budgets' do end end + + context 'Manage groups and headings' do + + scenario 'Create group', :js do + create(:budget, name: 'Yearly participatory budget') + + visit admin_budgets_path + click_link 'Yearly participatory budget' + + expect(page).to have_content 'No groups created yet.' + + click_link 'Add new group' + + fill_in 'budget_group_name', with: 'General improvments' + click_button 'Create group' + + expect(page).to have_content 'Yearly participatory budget' + expect(page).to_not have_content 'No groups created yet.' + + visit admin_budgets_path + click_link 'Yearly participatory budget' + + expect(page).to have_content 'Yearly participatory budget' + expect(page).to_not have_content 'No groups created yet.' + end + + scenario 'Create heading', :js do + budget = create(:budget, name: 'Yearly participatory budget') + group = create(:budget_group, budget: budget, name: 'Districts improvments') + + visit admin_budget_path(budget) + + within("#budget_group_#{group.id}") do + expect(page).to have_content 'This group has no assigned heading.' + click_link 'Add heading' + + fill_in 'budget_heading_name', with: 'District 9 reconstruction' + fill_in 'budget_heading_price', with: '6785' + click_button 'Save heading' + end + + expect(page).to_not have_content 'This group has no assigned heading.' + + visit admin_budget_path(budget) + within("#budget_group_#{group.id}") do + expect(page).to_not have_content 'This group has no assigned heading.' + + expect(page).to have_content 'District 9 reconstruction' + expect(page).to have_content '6785' + expect(page).to have_content 'All city' + end + end + + end end \ No newline at end of file From 3b5e0b55c0e6ea9c5d127f5ed5391156bc576347 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 3 Aug 2016 20:45:36 +0200 Subject: [PATCH 0460/1685] tries to fix flacky spec --- spec/features/notifications_spec.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/spec/features/notifications_spec.rb b/spec/features/notifications_spec.rb index e16dedf37..1c47ca44f 100644 --- a/spec/features/notifications_spec.rb +++ b/spec/features/notifications_spec.rb @@ -151,7 +151,7 @@ feature "Notifications" do context "Proposal notification" do - scenario "Voters should receive a notification", :js do + scenario "Voters should receive a notification", :js, :focus do author = create(:user) user1 = create(:user) @@ -180,9 +180,10 @@ feature "Notifications" do find(".icon-notification").click + notification_for_user1 = Notification.where(user: user1).first expect(page).to have_css ".notification", count: 1 expect(page).to have_content "There is one new notification on #{proposal.title}" - expect(page).to have_xpath "//a[@href='#{notification_path(Notification.last)}']" + expect(page).to have_xpath "//a[@href='#{notification_path(notification_for_user1)}']" logout login_as user2 @@ -190,9 +191,10 @@ feature "Notifications" do find(".icon-notification").click + notification_for_user2 = Notification.where(user: user2).first expect(page).to have_css ".notification", count: 1 expect(page).to have_content "There is one new notification on #{proposal.title}" - expect(page).to have_xpath "//a[@href='#{notification_path(Notification.first)}']" + expect(page).to have_xpath "//a[@href='#{notification_path(notification_for_user2)}']" logout login_as user3 From 4f4a5b68e50fc518aaeb4cd3fde3d29f91434765 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 3 Aug 2016 20:50:37 +0200 Subject: [PATCH 0461/1685] runs all spec file --- spec/features/notifications_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/notifications_spec.rb b/spec/features/notifications_spec.rb index 1c47ca44f..2504a6032 100644 --- a/spec/features/notifications_spec.rb +++ b/spec/features/notifications_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature "Notifications" do +feature "Notifications", :focus do let(:author) { create :user } let(:user) { create :user } let(:debate) { create :debate, author: author } @@ -151,7 +151,7 @@ feature "Notifications" do context "Proposal notification" do - scenario "Voters should receive a notification", :js, :focus do + scenario "Voters should receive a notification", :js do author = create(:user) user1 = create(:user) From 24bc8cca20773098435ff227b4d36792e9b1acb6 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 3 Aug 2016 20:56:33 +0200 Subject: [PATCH 0462/1685] runs all specs --- spec/features/notifications_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/notifications_spec.rb b/spec/features/notifications_spec.rb index 2504a6032..5fbc51736 100644 --- a/spec/features/notifications_spec.rb +++ b/spec/features/notifications_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature "Notifications", :focus do +feature "Notifications" do let(:author) { create :user } let(:user) { create :user } let(:debate) { create :debate, author: author } From c84108ae601ccc4058573bfb2a3f83779fe13f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Fri, 12 Aug 2016 13:41:51 +0200 Subject: [PATCH 0463/1685] updates rails version (security fix) --- Gemfile | 2 +- Gemfile.lock | 62 ++++++++++++++++++++++++++-------------------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Gemfile b/Gemfile index 8646567dc..3f3119770 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ source 'https://rubygems.org' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '4.2.7' +gem 'rails', '4.2.7.1' # Use PostgreSQL gem 'pg' # Use SCSS for stylesheets diff --git a/Gemfile.lock b/Gemfile.lock index 5f35de786..103ec214d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,36 +1,36 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (4.2.7) - actionpack (= 4.2.7) - actionview (= 4.2.7) - activejob (= 4.2.7) + actionmailer (4.2.7.1) + actionpack (= 4.2.7.1) + actionview (= 4.2.7.1) + activejob (= 4.2.7.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.7) - actionview (= 4.2.7) - activesupport (= 4.2.7) + actionpack (4.2.7.1) + actionview (= 4.2.7.1) + activesupport (= 4.2.7.1) rack (~> 1.6) rack-test (~> 0.6.2) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.7) - activesupport (= 4.2.7) + actionview (4.2.7.1) + activesupport (= 4.2.7.1) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - activejob (4.2.7) - activesupport (= 4.2.7) + activejob (4.2.7.1) + activesupport (= 4.2.7.1) globalid (>= 0.3.0) - activemodel (4.2.7) - activesupport (= 4.2.7) + activemodel (4.2.7.1) + activesupport (= 4.2.7.1) builder (~> 3.1) - activerecord (4.2.7) - activemodel (= 4.2.7) - activesupport (= 4.2.7) + activerecord (4.2.7.1) + activemodel (= 4.2.7.1) + activesupport (= 4.2.7.1) arel (~> 6.0) - activesupport (4.2.7) + activesupport (4.2.7.1) i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) @@ -174,7 +174,7 @@ GEM rspec (~> 3.0) ruby-progressbar (~> 1.4) geocoder (1.3.7) - globalid (0.3.6) + globalid (0.3.7) activesupport (>= 4.1.0) groupdate (3.0.1) activesupport (>= 3) @@ -290,16 +290,16 @@ GEM rack rack-test (0.6.3) rack (>= 1.0) - rails (4.2.7) - actionmailer (= 4.2.7) - actionpack (= 4.2.7) - actionview (= 4.2.7) - activejob (= 4.2.7) - activemodel (= 4.2.7) - activerecord (= 4.2.7) - activesupport (= 4.2.7) + rails (4.2.7.1) + actionmailer (= 4.2.7.1) + actionpack (= 4.2.7.1) + actionview (= 4.2.7.1) + activejob (= 4.2.7.1) + activemodel (= 4.2.7.1) + activerecord (= 4.2.7.1) + activesupport (= 4.2.7.1) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.7) + railties (= 4.2.7.1) sprockets-rails rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) @@ -309,9 +309,9 @@ GEM rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - railties (4.2.7) - actionpack (= 4.2.7) - activesupport (= 4.2.7) + railties (4.2.7.1) + actionpack (= 4.2.7.1) + activesupport (= 4.2.7.1) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) raindrops (0.16.0) @@ -485,7 +485,7 @@ DEPENDENCIES pg_search poltergeist quiet_assets - rails (= 4.2.7) + rails (= 4.2.7.1) redcarpet responders rinku From 345e34d4229d05cb783c4ad8ed35febc41bf6681 Mon Sep 17 00:00:00 2001 From: kikito Date: Mon, 29 Aug 2016 16:49:52 +0200 Subject: [PATCH 0464/1685] adds ckeditor config --- config/initializers/ckeditor.rb | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 config/initializers/ckeditor.rb diff --git a/config/initializers/ckeditor.rb b/config/initializers/ckeditor.rb new file mode 100644 index 000000000..58e119048 --- /dev/null +++ b/config/initializers/ckeditor.rb @@ -0,0 +1,4 @@ +Ckeditor.setup do |config| + config.assets_languages = I18n.available_locales.map(&:to_s) + config.assets_plugins = [] +end From 7ad4a212296caccd47495fa856c4877b1213edc3 Mon Sep 17 00:00:00 2001 From: kikito Date: Tue, 30 Aug 2016 12:05:46 +0200 Subject: [PATCH 0465/1685] Tries to make ckeditor work correctly with the asset pipeline Reference: https://github.com/galetahub/ckeditor/issues/519 --- app/assets/javascripts/application.js | 2 +- app/assets/javascripts/ckeditor/loader.js.erb | 3 +++ config/initializers/assets.rb | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 app/assets/javascripts/ckeditor/loader.js.erb diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index ca79ceb8b..7fb92b5e3 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -16,7 +16,7 @@ //= require jquery-ui/datepicker-es //= require foundation //= require turbolinks -//= require ckeditor/init +//= require ckeditor/loader //= require_directory ./ckeditor //= require social-share-button //= require initial diff --git a/app/assets/javascripts/ckeditor/loader.js.erb b/app/assets/javascripts/ckeditor/loader.js.erb new file mode 100644 index 000000000..66e1d8347 --- /dev/null +++ b/app/assets/javascripts/ckeditor/loader.js.erb @@ -0,0 +1,3 @@ +//= require ckeditor/init + +CKEDITOR.config.customConfig = '<%= javascript_path 'ckeditor/config.js' %>'; diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 942ba99c8..e5fc916f0 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -9,7 +9,7 @@ Rails.application.config.assets.version = '1.0' # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. # Rails.application.config.assets.precompile += %w( search.js ) -Rails.application.config.assets.precompile += %w( ckeditor/* ) +Rails.application.config.assets.precompile += %w( ckeditor/config.js ) Rails.application.config.assets.precompile += %w( ie_lt9.js ) Rails.application.config.assets.precompile += %w( stat_graphs.js ) Rails.application.config.assets.precompile += %w( print.css ) From fb31a4782f8eed7009db30f51c2a69627c9b3025 Mon Sep 17 00:00:00 2001 From: kikito Date: Tue, 30 Aug 2016 18:26:51 +0200 Subject: [PATCH 0466/1685] downgrades sprockets to 3.6.3 to avoid warnings --- Gemfile | 3 +++ Gemfile.lock | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 3f3119770..1819992d3 100644 --- a/Gemfile +++ b/Gemfile @@ -19,6 +19,9 @@ gem 'jquery-ui-rails' # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks gem 'turbolinks' +# Fix sprockets on the +gem 'sprockets', '~> 3.6.3' + gem 'devise', '~> 3.5.7' # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' diff --git a/Gemfile.lock b/Gemfile.lock index 103ec214d..121d7b86e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -375,7 +375,7 @@ GEM spring (1.7.2) spring-commands-rspec (1.0.4) spring (>= 0.9.1) - sprockets (3.7.0) + sprockets (3.6.3) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-es6 (0.9.0) @@ -496,6 +496,7 @@ DEPENDENCIES social-share-button spring spring-commands-rspec + sprockets (~> 3.6.3) tolk turbolinks turnout From f24886560b2f6636fc5cd958ecbb04a6e2909aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Thu, 1 Sep 2016 12:46:43 +0200 Subject: [PATCH 0467/1685] removes unused i18n entry --- config/locales/admin.en.yml | 1 - config/locales/admin.es.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index d8154efc1..78a3a6d6c 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -89,7 +89,6 @@ en: save_heading: Save heading no_heading: This group has no assigned heading. geozone: Scope of operation - no_geozone: Does not apply table_heading: Heading table_amount: Amount table_geozone: Scope of operation diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index 1d4ead16b..496a0208d 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -89,7 +89,6 @@ es: save_heading: Guardar partida no_heading: Este grupo no tiene ninguna partida asignada. geozone: Ámbito de actuación - no_geozone: No aplica table_heading: Partida table_amount: Cantidad table_geozone: Ámbito de actuación From e28c5c5010ea30a6a81b680264eae42fa7afb960 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Thu, 28 Jul 2016 14:06:40 +0200 Subject: [PATCH 0468/1685] fixes specs --- spec/features/budget/investments_spec.rb | 72 ++++++++++++------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/spec/features/budget/investments_spec.rb b/spec/features/budget/investments_spec.rb index 9209618d5..4093bcb5a 100644 --- a/spec/features/budget/investments_spec.rb +++ b/spec/features/budget/investments_spec.rb @@ -2,12 +2,12 @@ require 'rails_helper' feature 'Budget Investments' do - let(:author) { create(:user, :level_two, username: 'Isabel') } - let(:budget) { create(:budget) } - let(:group) { create(:budget_group, budget: budget) } + let(:author) { create(:user, :level_two, username: 'Isabel') } + let(:budget) { create(:budget) } + let(:group) { create(:budget_group, budget: budget) } + let(:heading) { create(:budget_heading, group: group) } scenario 'Index' do - heading = create(:budget_heading, group: group) investments = [create(:budget_investment, heading: heading), create(:budget_investment, heading: heading), create(:budget_investment, :feasible, heading: heading)] unfeasible_investment = create(:budget_investment, :unfeasible, heading: heading) @@ -25,9 +25,9 @@ feature 'Budget Investments' do context("Search") do scenario 'Search by text' do - investment1 = create(:budget_investment, budget: budget, title: "Get Schwifty") - investment2 = create(:budget_investment, budget: budget, title: "Schwifty Hello") - investment3 = create(:budget_investment, budget: budget, title: "Do not show me") + investment1 = create(:budget_investment, heading: heading, title: "Get Schwifty") + investment2 = create(:budget_investment, heading: heading, title: "Schwifty Hello") + investment3 = create(:budget_investment, heading: heading, title: "Do not show me") visit budget_investments_path(budget_id: budget.id) @@ -48,10 +48,10 @@ feature 'Budget Investments' do context("Filters") do scenario 'by unfeasibility' do - investment1 = create(:budget_investment, :unfeasible, budget: budget, valuation_finished: true) - investment2 = create(:budget_investment, :feasible, budget: budget) - investment3 = create(:budget_investment, budget: budget) - investment4 = create(:budget_investment, :feasible, budget: budget) + investment1 = create(:budget_investment, :unfeasible, heading: heading, valuation_finished: true) + investment2 = create(:budget_investment, :feasible, heading: heading) + investment3 = create(:budget_investment, heading: heading) + investment4 = create(:budget_investment, :feasible, heading: heading) visit budget_investments_path(budget_id: budget.id, unfeasible: 1) @@ -99,7 +99,7 @@ feature 'Budget Investments' do scenario 'Random order maintained with pagination', :js do per_page = Kaminari.config.default_per_page - (per_page + 2).times { create(:budget_investment, budget: budget) } + (per_page + 2).times { create(:budget_investment, heading: heading) } visit budget_investments_path(budget_id: budget.id) @@ -116,9 +116,9 @@ feature 'Budget Investments' do end scenario 'Proposals are ordered by confidence_score', :js do - create(:budget_investment, budget: budget, title: 'Best proposal').update_column(:confidence_score, 10) - create(:budget_investment, budget: budget, title: 'Worst proposal').update_column(:confidence_score, 2) - create(:budget_investment, budget: budget, title: 'Medium proposal').update_column(:confidence_score, 5) + create(:budget_investment, heading: heading, title: 'Best proposal').update_column(:confidence_score, 10) + create(:budget_investment, heading: heading, title: 'Worst proposal').update_column(:confidence_score, 2) + create(:budget_investment, heading: heading, title: 'Medium proposal').update_column(:confidence_score, 5) visit budget_investments_path(budget_id: budget.id) click_link 'highest rated' @@ -135,10 +135,10 @@ feature 'Budget Investments' do end - xscenario 'Create with invisible_captcha honeypot field' do + scenario 'Create with invisible_captcha honeypot field' do login_as(author) - visit new_budget_investment_path(budget_id: budget.id) + fill_in 'investment_title', with: 'I am a bot' fill_in 'investment_subtitle', with: 'This is the honeypot' fill_in 'investment_description', with: 'This is the description' @@ -203,7 +203,7 @@ feature 'Budget Investments' do user = create(:user) login_as(user) - investment = create(:budget_investment, heading: create(:budget_heading), budget: budget) + investment = create(:budget_investment, heading: create(:budget_heading), heading: heading) visit budget_investment_path(budget_id: budget.id, id: investment.id) @@ -223,7 +223,7 @@ feature 'Budget Investments' do investment = create(:budget_investment, :feasible, :finished, - budget: budget, + heading: heading, price: 16, price_explanation: 'Every wheel is 4 euros, so total is 16') @@ -240,7 +240,7 @@ feature 'Budget Investments' do investment = create(:budget_investment, :unfeasible, :finished, - budget: budget, + heading: heading, unfeasibility_explanation: 'Local government is not competent in this matter') visit budget_investment_path(budget_id: budget.id, id: investment.id) @@ -254,7 +254,7 @@ feature 'Budget Investments' do xscenario "Admin cannot destroy spending proposals" do admin = create(:administrator) user = create(:user, :level_two) - investment = create(:budget_investment, budget: budget, author: user) + investment = create(:budget_investment, heading: heading, author: user) login_as(admin.user) visit user_path(user) @@ -270,7 +270,7 @@ feature 'Budget Investments' do scenario "Spending proposal created by a User" do user = create(:user) - user_investment = create(:budget_investment, budget: budget) + user_investment = create(:budget_investment, heading: heading) visit budget_investment_path(budget_id: budget.id, id: user_investment.id) expect(page).to_not have_css "is-forum" @@ -291,8 +291,8 @@ feature 'Budget Investments' do xscenario "Index" do user = create(:user, :level_two) - sp1 = create(:budget_investment, :feasible, :finished, budget: budget, price: 10000) - sp2 = create(:budget_investment, :feasible, :finished, budget: budget, price: 20000) + sp1 = create(:budget_investment, :feasible, :finished, heading: heading, price: 10000) + sp2 = create(:budget_investment, :feasible, :finished, heading: heading, price: 20000) login_as(user) visit root_path @@ -313,9 +313,9 @@ feature 'Budget Investments' do end xscenario 'Order by cost (only in phase3)' do - create(:budget_investment, :feasible, :finished, budget: budget, title: 'Build a nice house', price: 1000).update_column(:confidence_score, 10) - create(:budget_investment, :feasible, :finished, budget: budget, title: 'Build an ugly house', price: 1000).update_column(:confidence_score, 5) - create(:budget_investment, :feasible, :finished, budget: budget, title: 'Build a skyscraper', price: 20000) + create(:budget_investment, :feasible, :finished, heading: heading, title: 'Build a nice house', price: 1000).update_column(:confidence_score, 10) + create(:budget_investment, :feasible, :finished, heading: heading, title: 'Build an ugly house', price: 1000).update_column(:confidence_score, 5) + create(:budget_investment, :feasible, :finished, heading: heading, title: 'Build a skyscraper', price: 20000) visit budget_investments_path(budget_id: budget.id) @@ -333,7 +333,7 @@ feature 'Budget Investments' do scenario "Show" do user = create(:user, :level_two) - sp1 = create(:budget_investment, :feasible, :finished, budget: budget, price: 10000) + sp1 = create(:budget_investment, :feasible, :finished, heading: heading, price: 10000) login_as(user) visit root_path @@ -353,15 +353,15 @@ feature 'Budget Investments' do carabanchel = create(:geozone, name: "Carabanchel") new_york = create(:geozone, name: "New York") - carabanchel_heading = create(:budget_heading, budget: budget, geozone: carabanchel, name: carabanchel.name) - new_york_heading = create(:budget_heading, budget: budget, geozone: new_york, name: new_york.name) + carabanchel_heading = create(:budget_heading, heading: heading, geozone: carabanchel, name: carabanchel.name) + new_york_heading = create(:budget_heading, heading: heading, geozone: new_york, name: new_york.name) - sp1 = create(:budget_investment, :feasible, :finished, budget: budget, price: 1, heading: nil) - sp2 = create(:budget_investment, :feasible, :finished, budget: budget, price: 10, heading: nil) - sp3 = create(:budget_investment, :feasible, :finished, budget: budget, price: 100, heading: nil) - sp4 = create(:budget_investment, :feasible, :finished, budget: budget, price: 1000, heading: carabanchel_heading) - sp5 = create(:budget_investment, :feasible, :finished, budget: budget, price: 10000, heading: carabanchel_heading) - sp6 = create(:budget_investment, :feasible, :finished, budget: budget, price: 100000, heading: new_york_heading) + sp1 = create(:budget_investment, :feasible, :finished, heading: heading, price: 1, heading: nil) + sp2 = create(:budget_investment, :feasible, :finished, heading: heading, price: 10, heading: nil) + sp3 = create(:budget_investment, :feasible, :finished, heading: heading, price: 100, heading: nil) + sp4 = create(:budget_investment, :feasible, :finished, heading: heading, price: 1000, heading: carabanchel_heading) + sp5 = create(:budget_investment, :feasible, :finished, heading: heading, price: 10000, heading: carabanchel_heading) + sp6 = create(:budget_investment, :feasible, :finished, heading: heading, price: 100000, heading: new_york_heading) login_as(user) visit root_path From 9003655cccb7a55bdece9d063d9a26bd940165e6 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Fri, 2 Sep 2016 13:10:10 +0200 Subject: [PATCH 0469/1685] removes duplicate views --- app/views/budget/budgets/_budget.html.erb | 3 - app/views/budget/budgets/index.html.erb | 1 - .../budget/investments/_investment.html.erb | 3 - app/views/budget/investments/index.html.erb | 2 - spec/features/budget/investments_spec.rb | 413 ------------------ 5 files changed, 422 deletions(-) delete mode 100644 app/views/budget/budgets/_budget.html.erb delete mode 100644 app/views/budget/budgets/index.html.erb delete mode 100644 app/views/budget/investments/_investment.html.erb delete mode 100644 app/views/budget/investments/index.html.erb delete mode 100644 spec/features/budget/investments_spec.rb diff --git a/app/views/budget/budgets/_budget.html.erb b/app/views/budget/budgets/_budget.html.erb deleted file mode 100644 index a88d9d181..000000000 --- a/app/views/budget/budgets/_budget.html.erb +++ /dev/null @@ -1,3 +0,0 @@ -
    -
    <%= budget.name %>
    -
    \ No newline at end of file diff --git a/app/views/budget/budgets/index.html.erb b/app/views/budget/budgets/index.html.erb deleted file mode 100644 index a7f13b347..000000000 --- a/app/views/budget/budgets/index.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= render @budgets %> \ No newline at end of file diff --git a/app/views/budget/investments/_investment.html.erb b/app/views/budget/investments/_investment.html.erb deleted file mode 100644 index 40d534067..000000000 --- a/app/views/budget/investments/_investment.html.erb +++ /dev/null @@ -1,3 +0,0 @@ -
    -
    <%= investment.title %>
    -
    diff --git a/app/views/budget/investments/index.html.erb b/app/views/budget/investments/index.html.erb deleted file mode 100644 index 95f9db31d..000000000 --- a/app/views/budget/investments/index.html.erb +++ /dev/null @@ -1,2 +0,0 @@ -hello budgets! -<%= render partial: 'investment', collection: @investments %> \ No newline at end of file diff --git a/spec/features/budget/investments_spec.rb b/spec/features/budget/investments_spec.rb deleted file mode 100644 index 4093bcb5a..000000000 --- a/spec/features/budget/investments_spec.rb +++ /dev/null @@ -1,413 +0,0 @@ -require 'rails_helper' - -feature 'Budget Investments' do - - let(:author) { create(:user, :level_two, username: 'Isabel') } - let(:budget) { create(:budget) } - let(:group) { create(:budget_group, budget: budget) } - let(:heading) { create(:budget_heading, group: group) } - - scenario 'Index' do - investments = [create(:budget_investment, heading: heading), create(:budget_investment, heading: heading), create(:budget_investment, :feasible, heading: heading)] - unfeasible_investment = create(:budget_investment, :unfeasible, heading: heading) - - visit budget_investments_path(budget_id: budget.id) - - expect(page).to have_selector('#budget-investments .budget-investment', count: 3) - investments.each do |investment| - within('#budget-investments') do - expect(page).to have_content investment.title - expect(page).to have_css("a[href='#{budget_investment_path(budget_id: budget.id, id: investment.id)}']", text: investment.title) - expect(page).to_not have_content(unfeasible_investment.title) - end - end - end - - context("Search") do - scenario 'Search by text' do - investment1 = create(:budget_investment, heading: heading, title: "Get Schwifty") - investment2 = create(:budget_investment, heading: heading, title: "Schwifty Hello") - investment3 = create(:budget_investment, heading: heading, title: "Do not show me") - - visit budget_investments_path(budget_id: budget.id) - - within(".expanded #search_form") do - fill_in "search", with: "Schwifty" - click_button "Search" - end - - within("#budget-investments") do - expect(page).to have_css('.budget-investment', count: 2) - - expect(page).to have_content(investment1.title) - expect(page).to have_content(investment2.title) - expect(page).to_not have_content(investment3.title) - end - end - end - - context("Filters") do - scenario 'by unfeasibility' do - investment1 = create(:budget_investment, :unfeasible, heading: heading, valuation_finished: true) - investment2 = create(:budget_investment, :feasible, heading: heading) - investment3 = create(:budget_investment, heading: heading) - investment4 = create(:budget_investment, :feasible, heading: heading) - - visit budget_investments_path(budget_id: budget.id, unfeasible: 1) - - within("#budget-investments") do - expect(page).to have_css('.budget-investment', count: 1) - - expect(page).to have_content(investment1.title) - expect(page).to_not have_content(investment2.title) - expect(page).to_not have_content(investment3.title) - expect(page).to_not have_content(investment4.title) - end - end - end - - context("Orders") do - - scenario "Default order is random" do - per_page = Kaminari.config.default_per_page - (per_page + 2).times { create(:budget_investment) } - - visit budget_investments_path(budget_id: budget.id) - order = all(".budget-investment h3").collect {|i| i.text } - - visit budget_investments_path(budget_id: budget.id) - new_order = eq(all(".budget-investment h3").collect {|i| i.text }) - - expect(order).to_not eq(new_order) - end - - scenario "Random order after another order" do - per_page = Kaminari.config.default_per_page - (per_page + 2).times { create(:budget_investment) } - - visit budget_investments_path(budget_id: budget.id) - click_link "highest rated" - click_link "random" - - order = all(".budget-investment h3").collect {|i| i.text } - - visit budget_investments_path(budget_id: budget.id) - new_order = eq(all(".budget-investment h3").collect {|i| i.text }) - - expect(order).to_not eq(new_order) - end - - scenario 'Random order maintained with pagination', :js do - per_page = Kaminari.config.default_per_page - (per_page + 2).times { create(:budget_investment, heading: heading) } - - visit budget_investments_path(budget_id: budget.id) - - order = all(".budget-investment h3").collect {|i| i.text } - - click_link 'Next' - expect(page).to have_content "You're on page 2" - - click_link 'Previous' - expect(page).to have_content "You're on page 1" - - new_order = all(".budget-investment h3").collect {|i| i.text } - expect(order).to eq(new_order) - end - - scenario 'Proposals are ordered by confidence_score', :js do - create(:budget_investment, heading: heading, title: 'Best proposal').update_column(:confidence_score, 10) - create(:budget_investment, heading: heading, title: 'Worst proposal').update_column(:confidence_score, 2) - create(:budget_investment, heading: heading, title: 'Medium proposal').update_column(:confidence_score, 5) - - visit budget_investments_path(budget_id: budget.id) - click_link 'highest rated' - expect(page).to have_selector('a.active', text: 'highest rated') - - within '#budget-investments' do - expect('Best proposal').to appear_before('Medium proposal') - expect('Medium proposal').to appear_before('Worst proposal') - end - - expect(current_url).to include('order=confidence_score') - expect(current_url).to include('page=1') - end - - end - - scenario 'Create with invisible_captcha honeypot field' do - login_as(author) - visit new_budget_investment_path(budget_id: budget.id) - - fill_in 'investment_title', with: 'I am a bot' - fill_in 'investment_subtitle', with: 'This is the honeypot' - fill_in 'investment_description', with: 'This is the description' - select 'All city', from: 'investment_heading_id' - check 'investment_terms_of_service' - - click_button 'Create' - - expect(page.status_code).to eq(200) - expect(page.html).to be_empty - expect(current_path).to eq(budget_investments_path(budget_id: budget.id)) - end - - xscenario 'Create spending proposal too fast' do - allow(InvisibleCaptcha).to receive(:timestamp_threshold).and_return(Float::INFINITY) - - login_as(author) - - visit new_budget_investments_path(budget_id: budget.id) - fill_in 'investment_title', with: 'I am a bot' - fill_in 'investment_description', with: 'This is the description' - select 'All city', from: 'investment_heading_id' - check 'investment_terms_of_service' - - click_button 'Create' - - expect(page).to have_content 'Sorry, that was too quick! Please resubmit' - expect(current_path).to eq(new_budget_investment_path(budget_id: budget.id)) - end - - xscenario 'Create notice' do - login_as(author) - - visit new_budget_investment_path(budget_id: budget.id) - fill_in 'investment_title', with: 'Build a skyscraper' - fill_in 'investment_description', with: 'I want to live in a high tower over the clouds' - fill_in 'investment_external_url', with: 'http://http://skyscraperpage.com/' - select 'All city', from: 'investment_heading_id' - check 'investment_terms_of_service' - - click_button 'Create' - - expect(page).to_not have_content 'Investment project created successfully' - expect(page).to have_content '1 error' - - within "#notice" do - click_link 'My activity' - end - - expect(page).to have_content 'Investment project created successfully' - end - - xscenario 'Errors on create' do - login_as(author) - - visit new_budget_investment_path(budget_id: budget.id) - click_button 'Create' - expect(page).to have_content error_message - end - - scenario "Show" do - user = create(:user) - login_as(user) - - investment = create(:budget_investment, heading: create(:budget_heading), heading: heading) - - visit budget_investment_path(budget_id: budget.id, id: investment.id) - - expect(page).to have_content(investment.title) - expect(page).to have_content(investment.description) - expect(page).to have_content(investment.author.name) - expect(page).to have_content(investment.heading.name) - within("#investment_code") do - expect(page).to have_content(investment.id) - end - end - - scenario "Show (feasible spending proposal)" do - user = create(:user) - login_as(user) - - investment = create(:budget_investment, - :feasible, - :finished, - heading: heading, - price: 16, - price_explanation: 'Every wheel is 4 euros, so total is 16') - - visit budget_investment_path(budget_id: budget.id, id: investment.id) - - expect(page).to have_content("Price explanation") - expect(page).to have_content(investment.price_explanation) - end - - scenario "Show (unfeasible spending proposal)" do - user = create(:user) - login_as(user) - - investment = create(:budget_investment, - :unfeasible, - :finished, - heading: heading, - unfeasibility_explanation: 'Local government is not competent in this matter') - - visit budget_investment_path(budget_id: budget.id, id: investment.id) - - expect(page).to have_content("Unfeasibility explanation") - expect(page).to have_content(investment.unfeasibility_explanation) - end - - context "Destroy" do - - xscenario "Admin cannot destroy spending proposals" do - admin = create(:administrator) - user = create(:user, :level_two) - investment = create(:budget_investment, heading: heading, author: user) - - login_as(admin.user) - visit user_path(user) - - within("#investment_#{investment.id}") do - expect(page).to_not have_link "Delete" - end - end - - end - - context "Badge" do - - scenario "Spending proposal created by a User" do - user = create(:user) - user_investment = create(:budget_investment, heading: heading) - - visit budget_investment_path(budget_id: budget.id, id: user_investment.id) - expect(page).to_not have_css "is-forum" - - visit budget_investments_path(budget_id: budget.id, id: user_investment.id) - within "#budget_investment_#{user_investment.id}" do - expect(page).to_not have_css "is-forum" - end - end - - end - - context "Phase 3 - Final Voting" do - - background do - budget.update(phase: "balloting") - end - - xscenario "Index" do - user = create(:user, :level_two) - sp1 = create(:budget_investment, :feasible, :finished, heading: heading, price: 10000) - sp2 = create(:budget_investment, :feasible, :finished, heading: heading, price: 20000) - - login_as(user) - visit root_path - - first(:link, "Participatory budgeting").click - click_link budget.name - click_link "No Heading" - - within("#budget_investment_#{sp1.id}") do - expect(page).to have_content sp1.title - expect(page).to have_content "€10,000" - end - - within("#budget_investment_#{sp2.id}") do - expect(page).to have_content sp2.title - expect(page).to have_content "€20,000" - end - end - - xscenario 'Order by cost (only in phase3)' do - create(:budget_investment, :feasible, :finished, heading: heading, title: 'Build a nice house', price: 1000).update_column(:confidence_score, 10) - create(:budget_investment, :feasible, :finished, heading: heading, title: 'Build an ugly house', price: 1000).update_column(:confidence_score, 5) - create(:budget_investment, :feasible, :finished, heading: heading, title: 'Build a skyscraper', price: 20000) - - visit budget_investments_path(budget_id: budget.id) - - click_link 'by price' - expect(page).to have_selector('a.active', text: 'by price') - - within '#budget-investments' do - expect('Build a skyscraper').to appear_before('Build a nice house') - expect('Build a nice house').to appear_before('Build an ugly house') - end - - expect(current_url).to include('order=price') - expect(current_url).to include('page=1') - end - - scenario "Show" do - user = create(:user, :level_two) - sp1 = create(:budget_investment, :feasible, :finished, heading: heading, price: 10000) - - login_as(user) - visit root_path - - first(:link, "Participatory budgeting").click - click_link budget.name - click_link "No Heading" - - click_link sp1.title - - expect(page).to have_content "€10,000" - end - - xscenario "Confirm", :js do - user = create(:user, :level_two) - - carabanchel = create(:geozone, name: "Carabanchel") - new_york = create(:geozone, name: "New York") - - carabanchel_heading = create(:budget_heading, heading: heading, geozone: carabanchel, name: carabanchel.name) - new_york_heading = create(:budget_heading, heading: heading, geozone: new_york, name: new_york.name) - - sp1 = create(:budget_investment, :feasible, :finished, heading: heading, price: 1, heading: nil) - sp2 = create(:budget_investment, :feasible, :finished, heading: heading, price: 10, heading: nil) - sp3 = create(:budget_investment, :feasible, :finished, heading: heading, price: 100, heading: nil) - sp4 = create(:budget_investment, :feasible, :finished, heading: heading, price: 1000, heading: carabanchel_heading) - sp5 = create(:budget_investment, :feasible, :finished, heading: heading, price: 10000, heading: carabanchel_heading) - sp6 = create(:budget_investment, :feasible, :finished, heading: heading, price: 100000, heading: new_york_heading) - - login_as(user) - visit root_path - - first(:link, "Participatory budgeting").click - click_link budget.name - click_link "No Heading" - - add_to_ballot(sp1) - add_to_ballot(sp2) - - first(:link, "Participatory budgeting").click - - click_link budget.name - click_link carabanchel.name - - add_to_ballot(sp4) - add_to_ballot(sp5) - - click_link "Check my ballot" - - expect(page).to have_content "You can change your vote at any time until the close of this phase" - - within("#city_wide") do - expect(page).to have_content sp1.title - expect(page).to have_content sp1.price - - expect(page).to have_content sp2.title - expect(page).to have_content sp2.price - - expect(page).to_not have_content sp3.title - expect(page).to_not have_content sp3.price - end - - within("#district_wide") do - expect(page).to have_content sp4.title - expect(page).to have_content "$1,000" - - expect(page).to have_content sp5.title - expect(page).to have_content "$10,000" - - expect(page).to_not have_content sp6.title - expect(page).to_not have_content "$100,000" - end - end - - end - -end From 521b3e1a666832d95a085d6bf3cd811839f5254d Mon Sep 17 00:00:00 2001 From: rgarcia Date: Fri, 2 Sep 2016 13:10:26 +0200 Subject: [PATCH 0470/1685] refactors specs file structure --- spec/features/budgets/budgets_spec.rb | 25 +- spec/features/budgets/investments_spec.rb | 413 ++++++++++++++++++++++ spec/features/budgets_spec.rb | 21 -- 3 files changed, 427 insertions(+), 32 deletions(-) create mode 100644 spec/features/budgets/investments_spec.rb delete mode 100644 spec/features/budgets_spec.rb diff --git a/spec/features/budgets/budgets_spec.rb b/spec/features/budgets/budgets_spec.rb index 58ee92d0c..14c0d7318 100644 --- a/spec/features/budgets/budgets_spec.rb +++ b/spec/features/budgets/budgets_spec.rb @@ -2,17 +2,20 @@ require 'rails_helper' feature 'Budgets' do - xscenario "Index" do - budget1 = create(:budget) - budget2 = create(:budget) - budget3 = create(:budget) - + scenario 'Index' do + budgets = create_list(:budget, 3) visit budgets_path - - expect(page).to have_css ".budget", count: 3 - expect(page).to have_content budget1.name - expect(page).to have_content budget2.name - expect(page).to have_content budget3.name + budgets.each {|budget| expect(page).to have_link(budget.name)} end -end + scenario 'Show' do + budget = create(:budget) + group = create(:budget_group, budget: budget) + heading = create(:budget_heading, group: group) + + visit budget_path(budget) + + expect(page).to have_content(budget.name) + expect(page).to have_content(heading.name) + end +end \ No newline at end of file diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb new file mode 100644 index 000000000..c3aa0107b --- /dev/null +++ b/spec/features/budgets/investments_spec.rb @@ -0,0 +1,413 @@ +require 'rails_helper' + +feature 'Budget Investments' do + + let(:author) { create(:user, :level_two, username: 'Isabel') } + let(:budget) { create(:budget) } + let(:group) { create(:budget_group, budget: budget) } + let(:heading) { create(:budget_heading, group: group) } + + scenario 'Index' do + investments = [create(:budget_investment, heading: heading), create(:budget_investment, heading: heading), create(:budget_investment, :feasible, heading: heading)] + unfeasible_investment = create(:budget_investment, :unfeasible, heading: heading) + + visit budget_investments_path(budget_id: budget.id) + + expect(page).to have_selector('#budget-investments .budget-investment', count: 3) + investments.each do |investment| + within('#budget-investments') do + expect(page).to have_content investment.title + expect(page).to have_css("a[href='#{budget_investment_path(budget_id: budget.id, id: investment.id)}']", text: investment.title) + expect(page).to_not have_content(unfeasible_investment.title) + end + end + end + + context("Search") do + scenario 'Search by text' do + investment1 = create(:budget_investment, heading: heading, title: "Get Schwifty") + investment2 = create(:budget_investment, heading: heading, title: "Schwifty Hello") + investment3 = create(:budget_investment, heading: heading, title: "Do not show me") + + visit budget_investments_path(budget_id: budget.id) + + within(".expanded #search_form") do + fill_in "search", with: "Schwifty" + click_button "Search" + end + + within("#budget-investments") do + expect(page).to have_css('.budget-investment', count: 2) + + expect(page).to have_content(investment1.title) + expect(page).to have_content(investment2.title) + expect(page).to_not have_content(investment3.title) + end + end + end + + context("Filters") do + scenario 'by unfeasibility' do + investment1 = create(:budget_investment, :unfeasible, heading: heading, valuation_finished: true) + investment2 = create(:budget_investment, :feasible, heading: heading) + investment3 = create(:budget_investment, heading: heading) + investment4 = create(:budget_investment, :feasible, heading: heading) + + visit budget_investments_path(budget_id: budget.id, unfeasible: 1) + + within("#budget-investments") do + expect(page).to have_css('.budget-investment', count: 1) + + expect(page).to have_content(investment1.title) + expect(page).to_not have_content(investment2.title) + expect(page).to_not have_content(investment3.title) + expect(page).to_not have_content(investment4.title) + end + end + end + + context("Orders") do + + scenario "Default order is random" do + per_page = Kaminari.config.default_per_page + (per_page + 2).times { create(:budget_investment) } + + visit budget_investments_path(budget_id: budget.id) + order = all(".budget-investment h3").collect {|i| i.text } + + visit budget_investments_path(budget_id: budget.id) + new_order = eq(all(".budget-investment h3").collect {|i| i.text }) + + expect(order).to_not eq(new_order) + end + + scenario "Random order after another order" do + per_page = Kaminari.config.default_per_page + (per_page + 2).times { create(:budget_investment) } + + visit budget_investments_path(budget_id: budget.id) + click_link "highest rated" + click_link "random" + + order = all(".budget-investment h3").collect {|i| i.text } + + visit budget_investments_path(budget_id: budget.id) + new_order = eq(all(".budget-investment h3").collect {|i| i.text }) + + expect(order).to_not eq(new_order) + end + + scenario 'Random order maintained with pagination', :js do + per_page = Kaminari.config.default_per_page + (per_page + 2).times { create(:budget_investment, heading: heading) } + + visit budget_investments_path(budget_id: budget.id) + + order = all(".budget-investment h3").collect {|i| i.text } + + click_link 'Next' + expect(page).to have_content "You're on page 2" + + click_link 'Previous' + expect(page).to have_content "You're on page 1" + + new_order = all(".budget-investment h3").collect {|i| i.text } + expect(order).to eq(new_order) + end + + scenario 'Proposals are ordered by confidence_score', :js do + create(:budget_investment, heading: heading, title: 'Best proposal').update_column(:confidence_score, 10) + create(:budget_investment, heading: heading, title: 'Worst proposal').update_column(:confidence_score, 2) + create(:budget_investment, heading: heading, title: 'Medium proposal').update_column(:confidence_score, 5) + + visit budget_investments_path(budget_id: budget.id) + click_link 'highest rated' + expect(page).to have_selector('a.active', text: 'highest rated') + + within '#budget-investments' do + expect('Best proposal').to appear_before('Medium proposal') + expect('Medium proposal').to appear_before('Worst proposal') + end + + expect(current_url).to include('order=confidence_score') + expect(current_url).to include('page=1') + end + + end + + xscenario 'Create with invisible_captcha honeypot field' do + login_as(author) + visit new_budget_investment_path(budget_id: budget.id) + + fill_in 'investment_title', with: 'I am a bot' + fill_in 'investment_subtitle', with: 'This is the honeypot' + fill_in 'investment_description', with: 'This is the description' + select 'All city', from: 'investment_heading_id' + check 'investment_terms_of_service' + + click_button 'Create' + + expect(page.status_code).to eq(200) + expect(page.html).to be_empty + expect(current_path).to eq(budget_investments_path(budget_id: budget.id)) + end + + xscenario 'Create spending proposal too fast' do + allow(InvisibleCaptcha).to receive(:timestamp_threshold).and_return(Float::INFINITY) + + login_as(author) + + visit new_budget_investments_path(budget_id: budget.id) + fill_in 'investment_title', with: 'I am a bot' + fill_in 'investment_description', with: 'This is the description' + select 'All city', from: 'investment_heading_id' + check 'investment_terms_of_service' + + click_button 'Create' + + expect(page).to have_content 'Sorry, that was too quick! Please resubmit' + expect(current_path).to eq(new_budget_investment_path(budget_id: budget.id)) + end + + xscenario 'Create notice' do + login_as(author) + + visit new_budget_investment_path(budget_id: budget.id) + fill_in 'investment_title', with: 'Build a skyscraper' + fill_in 'investment_description', with: 'I want to live in a high tower over the clouds' + fill_in 'investment_external_url', with: 'http://http://skyscraperpage.com/' + select 'All city', from: 'investment_heading_id' + check 'investment_terms_of_service' + + click_button 'Create' + + expect(page).to_not have_content 'Investment project created successfully' + expect(page).to have_content '1 error' + + within "#notice" do + click_link 'My activity' + end + + expect(page).to have_content 'Investment project created successfully' + end + + xscenario 'Errors on create' do + login_as(author) + + visit new_budget_investment_path(budget_id: budget.id) + click_button 'Create' + expect(page).to have_content error_message + end + + scenario "Show" do + user = create(:user) + login_as(user) + + investment = create(:budget_investment, heading: heading) + + visit budget_investment_path(budget_id: budget.id, id: investment.id) + + expect(page).to have_content(investment.title) + expect(page).to have_content(investment.description) + expect(page).to have_content(investment.author.name) + expect(page).to have_content(investment.heading.name) + within("#investment_code") do + expect(page).to have_content(investment.id) + end + end + + scenario "Show (feasible spending proposal)" do + user = create(:user) + login_as(user) + + investment = create(:budget_investment, + :feasible, + :finished, + heading: heading, + price: 16, + price_explanation: 'Every wheel is 4 euros, so total is 16') + + visit budget_investment_path(budget_id: budget.id, id: investment.id) + + expect(page).to have_content("Price explanation") + expect(page).to have_content(investment.price_explanation) + end + + scenario "Show (unfeasible spending proposal)" do + user = create(:user) + login_as(user) + + investment = create(:budget_investment, + :unfeasible, + :finished, + heading: heading, + unfeasibility_explanation: 'Local government is not competent in this matter') + + visit budget_investment_path(budget_id: budget.id, id: investment.id) + + expect(page).to have_content("Unfeasibility explanation") + expect(page).to have_content(investment.unfeasibility_explanation) + end + + context "Destroy" do + + xscenario "Admin cannot destroy spending proposals" do + admin = create(:administrator) + user = create(:user, :level_two) + investment = create(:budget_investment, heading: heading, author: user) + + login_as(admin.user) + visit user_path(user) + + within("#investment_#{investment.id}") do + expect(page).to_not have_link "Delete" + end + end + + end + + context "Badge" do + + scenario "Spending proposal created by a User" do + user = create(:user) + user_investment = create(:budget_investment, heading: heading) + + visit budget_investment_path(budget_id: budget.id, id: user_investment.id) + expect(page).to_not have_css "is-forum" + + visit budget_investments_path(budget_id: budget.id, id: user_investment.id) + within "#budget_investment_#{user_investment.id}" do + expect(page).to_not have_css "is-forum" + end + end + + end + + context "Phase 3 - Final Voting" do + + background do + budget.update(phase: "balloting") + end + + xscenario "Index" do + user = create(:user, :level_two) + sp1 = create(:budget_investment, :feasible, :finished, heading: heading, price: 10000) + sp2 = create(:budget_investment, :feasible, :finished, heading: heading, price: 20000) + + login_as(user) + visit root_path + + first(:link, "Participatory budgeting").click + click_link budget.name + click_link "No Heading" + + within("#budget_investment_#{sp1.id}") do + expect(page).to have_content sp1.title + expect(page).to have_content "€10,000" + end + + within("#budget_investment_#{sp2.id}") do + expect(page).to have_content sp2.title + expect(page).to have_content "€20,000" + end + end + + xscenario 'Order by cost (only in phase3)' do + create(:budget_investment, :feasible, :finished, heading: heading, title: 'Build a nice house', price: 1000).update_column(:confidence_score, 10) + create(:budget_investment, :feasible, :finished, heading: heading, title: 'Build an ugly house', price: 1000).update_column(:confidence_score, 5) + create(:budget_investment, :feasible, :finished, heading: heading, title: 'Build a skyscraper', price: 20000) + + visit budget_investments_path(budget_id: budget.id) + + click_link 'by price' + expect(page).to have_selector('a.active', text: 'by price') + + within '#budget-investments' do + expect('Build a skyscraper').to appear_before('Build a nice house') + expect('Build a nice house').to appear_before('Build an ugly house') + end + + expect(current_url).to include('order=price') + expect(current_url).to include('page=1') + end + + scenario "Show" do + user = create(:user, :level_two) + sp1 = create(:budget_investment, :feasible, :finished, heading: heading, price: 10000) + + login_as(user) + visit root_path + + first(:link, "Participatory budgeting").click + click_link budget.name + click_link "No Heading" + + click_link sp1.title + + expect(page).to have_content "€10,000" + end + + xscenario "Confirm", :js do + user = create(:user, :level_two) + + carabanchel = create(:geozone, name: "Carabanchel") + new_york = create(:geozone, name: "New York") + + carabanchel_heading = create(:budget_heading, heading: heading, geozone: carabanchel, name: carabanchel.name) + new_york_heading = create(:budget_heading, heading: heading, geozone: new_york, name: new_york.name) + + sp1 = create(:budget_investment, :feasible, :finished, price: 1, heading: nil) + sp2 = create(:budget_investment, :feasible, :finished, price: 10, heading: nil) + sp3 = create(:budget_investment, :feasible, :finished, price: 100, heading: nil) + sp4 = create(:budget_investment, :feasible, :finished, price: 1000, heading: carabanchel_heading) + sp5 = create(:budget_investment, :feasible, :finished, price: 10000, heading: carabanchel_heading) + sp6 = create(:budget_investment, :feasible, :finished, price: 100000, heading: new_york_heading) + + login_as(user) + visit root_path + + first(:link, "Participatory budgeting").click + click_link budget.name + click_link "No Heading" + + add_to_ballot(sp1) + add_to_ballot(sp2) + + first(:link, "Participatory budgeting").click + + click_link budget.name + click_link carabanchel.name + + add_to_ballot(sp4) + add_to_ballot(sp5) + + click_link "Check my ballot" + + expect(page).to have_content "You can change your vote at any time until the close of this phase" + + within("#city_wide") do + expect(page).to have_content sp1.title + expect(page).to have_content sp1.price + + expect(page).to have_content sp2.title + expect(page).to have_content sp2.price + + expect(page).to_not have_content sp3.title + expect(page).to_not have_content sp3.price + end + + within("#district_wide") do + expect(page).to have_content sp4.title + expect(page).to have_content "$1,000" + + expect(page).to have_content sp5.title + expect(page).to have_content "$10,000" + + expect(page).to_not have_content sp6.title + expect(page).to_not have_content "$100,000" + end + end + + end + +end diff --git a/spec/features/budgets_spec.rb b/spec/features/budgets_spec.rb deleted file mode 100644 index 64f135dec..000000000 --- a/spec/features/budgets_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'rails_helper' - -feature 'Budgets' do - - scenario 'Index' do - budgets = create_list(:budget, 3) - visit budgets_path - budgets.each {|budget| expect(page).to have_link(budget.name)} - end - - scenario 'Show' do - budget = create(:budget) - group = create(:budget_group, budget: budget) - heading = create(:budget_heading, group: group) - - visit budget_path(budget) - - expect(page).to have_content(budget.name) - expect(page).to have_content(heading.name) - end -end From 1c8290faa9196aa32f2cdc6895a734e0814f786c Mon Sep 17 00:00:00 2001 From: rgarcia Date: Fri, 2 Sep 2016 13:46:12 +0200 Subject: [PATCH 0471/1685] refactors budget translations --- app/views/budgets/ballots/_ballot.html.erb | 12 +- .../budgets/ballots/_investment.html.erb | 2 +- .../ballots/_investment_for_sidebar.html.erb | 2 +- app/views/budgets/ballots/_remove.html.erb | 2 +- config/locales/budgets.en.yml | 106 ++++++++++++++++++ config/locales/budgets.es.yml | 106 ++++++++++++++++++ config/locales/en.yml | 94 ---------------- config/locales/es.yml | 94 ---------------- 8 files changed, 221 insertions(+), 197 deletions(-) create mode 100644 config/locales/budgets.en.yml create mode 100644 config/locales/budgets.es.yml diff --git a/app/views/budgets/ballots/_ballot.html.erb b/app/views/budgets/ballots/_ballot.html.erb index 5189de92b..a3b0d22f3 100644 --- a/app/views/budgets/ballots/_ballot.html.erb +++ b/app/views/budgets/ballots/_ballot.html.erb @@ -18,7 +18,7 @@ <% end %>

    - <%= t("ballots.show.remaining_city_html", + <%= t("budgets.ballots.show.remaining_city_html", amount_city: format_price(@ballot.amount_available(nil))) %>

    @@ -52,7 +52,7 @@ <% else %>

    <%= t("budgets.ballots.show.zero") %>
    - <%= link_to t("ballots.show.city_link"), + <%= link_to t("budgets.ballots.show.city_link"), investments_path(geozone: 'all'), data: { no_turbolink: true } %>

    @@ -66,7 +66,7 @@

    - <%= t("ballots.show.district_wide") %> + <%= t("budgets.ballots.show.district_wide") %> <% if @ballot.geozone.present? %> (<%= @ballot.geozone.name %>) @@ -75,13 +75,13 @@

    <% if @ballot.geozone.present? %>

    - <%= t("ballots.show.amount_spent") %> + <%= t("budgets.ballots.show.amount_spent") %> <%= format_price(district_wide_amount_spent(@ballot)) %>

    <% else %>

    - <%= t("ballots.show.zero") %>
    - <%= link_to t("budget.ballots.show.districts_link"), select_district_path %> + <%= t("budgets.ballots.show.zero") %>
    + <%= link_to t("budgets.ballots.show.districts_link"), select_district_path %>

    <% end %> diff --git a/app/views/budgets/ballots/_investment.html.erb b/app/views/budgets/ballots/_investment.html.erb index 93c934bd5..af78b4168 100644 --- a/app/views/budgets/ballots/_investment.html.erb +++ b/app/views/budgets/ballots/_investment.html.erb @@ -4,7 +4,7 @@ <% if @budget.balloting? %> <%= link_to ballot_line_path(id: investment.id), - title: t('ballots.show.remove'), + title: t('budgets.ballots.show.remove'), class: "remove-investment-project", method: :delete, remote: true do %> diff --git a/app/views/budgets/ballots/_investment_for_sidebar.html.erb b/app/views/budgets/ballots/_investment_for_sidebar.html.erb index c0bde5d34..c229cc93b 100644 --- a/app/views/budgets/ballots/_investment_for_sidebar.html.erb +++ b/app/views/budgets/ballots/_investment_for_sidebar.html.erb @@ -5,7 +5,7 @@ <% if @budget.balloting? %> <%= link_to ballot_line_path(id: investment.id, investments_ids: investment_ids), - title: t('ballots.show.remove'), + title: t('budgets.ballots.show.remove'), class: "remove-investment-project", method: :delete, remote: true do %> diff --git a/app/views/budgets/ballots/_remove.html.erb b/app/views/budgets/ballots/_remove.html.erb index a02ac9966..5511e60c7 100644 --- a/app/views/budgets/ballots/_remove.html.erb +++ b/app/views/budgets/ballots/_remove.html.erb @@ -8,7 +8,7 @@

    <% if @budget.balloting? %> - <%= link_to t('ballots.show.remove'), + <%= link_to t('budgets.ballots.show.remove'), ballot_line_path(id: investment.id, investments_ids: investment_ids), class: "delete small expanded", diff --git a/config/locales/budgets.en.yml b/config/locales/budgets.en.yml new file mode 100644 index 000000000..ae8c6b08a --- /dev/null +++ b/config/locales/budgets.en.yml @@ -0,0 +1,106 @@ +en: + budgets: + ballots: + show: + amount_spent: "pending translation" + city_wide: "pending translation" + districts_link: "pending translation" + remaining_district_html: "pending translation" + social_share: "pending translation" + title: "pending translation" + voted_html: "pending translation" + voted_info_html: "pending translation" + zero: "pending translation" + budget: + phase: + on_hold: On hold + accepting: Accepting proposals + selecting: Selecting + balloting: Balloting + finished: Finished + headings: + none: Whole City + all: All scopes + index: + name: Budget's name + phase: Phase + title: Participatory budgets + investments: + form: + association_name_label: 'If you propose in name of an assocation or collective add the name here' + association_name: 'Association name' + description: Description + external_url: Link to additional documentation + heading: Choose if a proposed citywide or district + submit_buttons: + create: Create + new: Create + title: Investment title + index: + available: "Available:" + title: Participatory budgeting + unfeasible: Unfeasible investment projects + unfeasible_text: "The proposals must meet a number of criteria (legality, concreteness, be the responsibility of the city, not exceed the limit of the budget; %{definitions}) to be declared viable and reach the stage of final vote. All proposals don't meet these criteria are marked as unfeasible and published in the following list, along with its report of infeasibility." + unfeasible_text_definitions: see definitions here + by_heading: "Investment projects with scope: %{heading}" + search_form: + button: Search + placeholder: Investment projects... + title: Search + search_results: + one: " containing the term '%{search_term}'" + other: " containing the term '%{search_term}'" + sidebar: + back: Back to select page + district: District + my_ballot: My ballot + remember_city: You can also vote %{city} investment projects. + remember_city_link_html: city-wide + remember_district: You can also vote investment projects for %{district}. + remember_district_link_html: a district + voted_html: + one: "You voted one proposal with a cost of %{amount_spent}" + other: "You voted %{count} proposals with a cost of %{amount_spent}" + voted_info: You can change your vote at any time until the close of this phase. No need to spend all the money available. + votes: Supports remaining + votes_district: "You can only vote in the district %{district}" + zero: You have not voted any investment project. + orders: + random: random + confidence_score: highest rated + price: by price + new: + back_link: Back + more_info: "Important, not to be ruled out your proposal must comply:" + recommendation_one: See the %{requirements}. + recommendation_one_link: requirements to be met by a proposal + recommendation_three: Try to go into details when describing your spending proposal so the reviewing team undertands your points. + recommendation_two: Each proposal must be submitted separately. You can make as many want. + recommendations_title: How to create a spending proposal + start_new: Create spending proposal + show: + author_deleted: User deleted + price_explanation: Price explanation + unfeasibility_explanation: Unfeasibility explanation + code: 'Investment project code:' + share: Share + wrong_price_format: Only integer numbers + investment: + title: Investment project + add: Add + already_added: You have already added this investment project + already_supported: You have already supported this. Share it! + forum: District discussion space + support_title: Support this project + supports: + one: 1 support + other: "%{count} supports" + zero: No supports + vote: Vote + header: + check_ballot: Check my ballot + different_heading_active: You have active votes in another district. + show: + heading: Heading + price: Price + no_heading: No Heading \ No newline at end of file diff --git a/config/locales/budgets.es.yml b/config/locales/budgets.es.yml new file mode 100644 index 000000000..667b39617 --- /dev/null +++ b/config/locales/budgets.es.yml @@ -0,0 +1,106 @@ +es: + budgets: + ballots: + show: + amount_spent: "pending translation" + city_wide: "pending translation" + districts_link: "pending translation" + remaining_district_html: "pending translation" + social_share: "pending translation" + title: "pending translation" + voted_html: "pending translation" + voted_info_html: "pending translation" + zero: "pending translation" + budget: + phase: + on_hold: En pausa + accepting: Aceptando propuestas + selecting: Fase de selección + balloting: Fase de Votación + finished: Terminado + headings: + none: Toda la ciudad + all: Todos los ámbitos + index: + name: Nombre del presupuesto + phase: Fase + title: Presupuestos participativos + investments: + form: + association_name_label: 'Si propones en nombre de una asociación o colectivo añade el nombre aquí' + association_name: 'Nombre de la asociación' + description: Descripción detallada + external_url: Enlace a documentación adicional + heading: "Elige si es una propuesta para toda la ciudad o para un distrito" + submit_buttons: + create: Crear + new: Crear + title: Título de la propuesta de inversión + index: + available: "Disponible:" + title: Presupuestos participativos + unfeasible: Propuestas de inversión no viables + unfeasible_text: Las propuestas presentadas deben cumplir una serie de criterios (legalidad, concreción, ser competencia del Ayuntamiento, no superar el tope del presupuesto; %{definitions}) para ser declaradas viables y llegar hasta la fase de votación final. Todas las propuestas que no cumplen estos criterios son marcadas como inviables y publicadas en la siguiente lista, junto con su informe de inviabilidad. + unfeasible_text_definitions: ver definiciones aquí + by_heading: "Propuestas de inversión con ámbito: %{heading}" + search_form: + button: Buscar + placeholder: Propuestas de inversión... + title: Buscar + search_results: + one: " que contiene '%{search_term}'" + other: " que contienen '%{search_term}'" + sidebar: + back: Volver a página de selección + district: Distrito + my_ballot: Mis votos + remember_city: Además puedes votar propuestas de inversión para %{city}. + remember_city_link_html: toda la ciudad + remember_district: Además puedes votar propuestas de inversión para %{district}. + remember_district_link_html: un distrito + voted_html: + one: "Has votado una propuesta por un valor de %{amount_spent}" + other: "Has votado %{count} propuestas por un valor de %{amount_spent}" + voted_info: Puedes cambiar tus votos en cualquier momento hasta el cierre de esta fase. No hace falta que gastes todo el dinero disponible. + votes: Apoyos restantes + votes_district: "Solo puedes votar en el distrito %{district}" + zero: "Todavía no has votado ninguna propuesta de inversión." + orders: + random: Aleatorias + confidence_score: Mejor valoradas + price: Por coste + new: + more_info: "¿Cómo funcionan los presupuestos participativos?" + recommendation_one: Consulta los %{requirements}. + recommendation_one_link: requisitos que debe cumplir una propuesta + recommendation_three: Intenta detallar lo máximo posible la propuesta para que el equipo de gobierno encargado de estudiarla tenga las menor dudas posibles. + recommendation_two: Cualquier propuesta o comentario que implique acciones ilegales será eliminada. + recommendations_title: Cómo crear una propuesta de inversión + start_new: Crear una propuesta de inversión + back_link: Volver + show: + author_deleted: Usuario eliminado + price_explanation: Informe de coste + unfeasibility_explanation: Informe de inviabilidad + code: 'Código propuesta de gasto:' + share: Compartir + wrong_price_format: Solo puede incluir caracteres numéricos + investment: + title: Propuesta de inversión + add: Añadir + already_added: "Ya has añadido esta propuesta de inversión" + already_supported: Ya has apoyado este proyecto. ¡Compártelo! + forum: Espacio de debate distrital + support_title: Apoyar este proyecto + supports: + one: 1 apoyo + other: "%{count} apoyos" + zero: Sin apoyos + vote: Votar + header: + check_ballot: Revisar mis votos + different_heading_active: Ya apoyaste propuestas de otro distrito. + show: + heading: Partida + price: Cantidad + no_heading: Sin línea \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index d20c69885..58d4c9492 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -33,13 +33,6 @@ en: application: close: Close menu: Menu - budget: - phase: - on_hold: On hold - accepting: Accepting proposals - selecting: Selecting - balloting: Balloting - finished: Finished comments: comment: admin: Administrator @@ -447,93 +440,6 @@ en: facebook: Facebook twitter: Twitter youtube: YouTube - budget: - headings: - none: Whole City - all: All scopes - index: - name: Budget's name - phase: Phase - title: Participatory budgets - investments: - form: - association_name_label: 'If you propose in name of an assocation or collective add the name here' - association_name: 'Association name' - description: Description - external_url: Link to additional documentation - heading: Choose if a proposed citywide or district - submit_buttons: - create: Create - new: Create - title: Investment title - index: - available: "Available:" - title: Participatory budgeting - unfeasible: Unfeasible investment projects - unfeasible_text: "The proposals must meet a number of criteria (legality, concreteness, be the responsibility of the city, not exceed the limit of the budget; %{definitions}) to be declared viable and reach the stage of final vote. All proposals don't meet these criteria are marked as unfeasible and published in the following list, along with its report of infeasibility." - unfeasible_text_definitions: see definitions here - by_heading: "Investment projects with scope: %{heading}" - search_form: - button: Search - placeholder: Investment projects... - title: Search - search_results: - one: " containing the term '%{search_term}'" - other: " containing the term '%{search_term}'" - sidebar: - back: Back to select page - district: District - my_ballot: My ballot - remember_city: You can also vote %{city} investment projects. - remember_city_link_html: city-wide - remember_district: You can also vote investment projects for %{district}. - remember_district_link_html: a district - voted_html: - one: "You voted one proposal with a cost of %{amount_spent}" - other: "You voted %{count} proposals with a cost of %{amount_spent}" - voted_info: You can change your vote at any time until the close of this phase. No need to spend all the money available. - votes: Supports remaining - votes_district: "You can only vote in the district %{district}" - zero: You have not voted any investment project. - orders: - random: random - confidence_score: highest rated - price: by price - new: - back_link: Back - more_info: "Important, not to be ruled out your proposal must comply:" - recommendation_one: See the %{requirements}. - recommendation_one_link: requirements to be met by a proposal - recommendation_three: Try to go into details when describing your spending proposal so the reviewing team undertands your points. - recommendation_two: Each proposal must be submitted separately. You can make as many want. - recommendations_title: How to create a spending proposal - start_new: Create spending proposal - show: - author_deleted: User deleted - price_explanation: Price explanation - unfeasibility_explanation: Unfeasibility explanation - code: 'Investment project code:' - share: Share - wrong_price_format: Only integer numbers - investment: - title: Investment project - add: Add - already_added: You have already added this investment project - already_supported: You have already supported this. Share it! - forum: District discussion space - support_title: Support this project - supports: - one: 1 support - other: "%{count} supports" - zero: No supports - vote: Vote - header: - check_ballot: Check my ballot - different_heading_active: You have active votes in another district. - show: - heading: Heading - price: Price - no_heading: No Heading spending_proposals: form: association_name_label: 'If you propose in name of an assocation or collective add the name here' diff --git a/config/locales/es.yml b/config/locales/es.yml index 62b1f8059..5e3f28507 100755 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -33,13 +33,6 @@ es: application: close: Cerrar menu: Menú - budget: - phase: - on_hold: En pausa - accepting: Aceptando propuestas - selecting: Fase de selección - balloting: Fase de Votación - finished: Terminado comments: comment: admin: Administrador @@ -447,93 +440,6 @@ es: facebook: Facebook twitter: Twitter youtube: YouTube - budget: - headings: - none: Toda la ciudad - all: Todos los ámbitos - index: - name: Nombre del presupuesto - phase: Fase - title: Presupuestos participativos - investments: - form: - association_name_label: 'Si propones en nombre de una asociación o colectivo añade el nombre aquí' - association_name: 'Nombre de la asociación' - description: Descripción detallada - external_url: Enlace a documentación adicional - heading: "Elige si es una propuesta para toda la ciudad o para un distrito" - submit_buttons: - create: Crear - new: Crear - title: Título de la propuesta de inversión - index: - available: "Disponible:" - title: Presupuestos participativos - unfeasible: Propuestas de inversión no viables - unfeasible_text: Las propuestas presentadas deben cumplir una serie de criterios (legalidad, concreción, ser competencia del Ayuntamiento, no superar el tope del presupuesto; %{definitions}) para ser declaradas viables y llegar hasta la fase de votación final. Todas las propuestas que no cumplen estos criterios son marcadas como inviables y publicadas en la siguiente lista, junto con su informe de inviabilidad. - unfeasible_text_definitions: ver definiciones aquí - by_heading: "Propuestas de inversión con ámbito: %{heading}" - search_form: - button: Buscar - placeholder: Propuestas de inversión... - title: Buscar - search_results: - one: " que contiene '%{search_term}'" - other: " que contienen '%{search_term}'" - sidebar: - back: Volver a página de selección - district: Distrito - my_ballot: Mis votos - remember_city: Además puedes votar propuestas de inversión para %{city}. - remember_city_link_html: toda la ciudad - remember_district: Además puedes votar propuestas de inversión para %{district}. - remember_district_link_html: un distrito - voted_html: - one: "Has votado una propuesta por un valor de %{amount_spent}" - other: "Has votado %{count} propuestas por un valor de %{amount_spent}" - voted_info: Puedes cambiar tus votos en cualquier momento hasta el cierre de esta fase. No hace falta que gastes todo el dinero disponible. - votes: Apoyos restantes - votes_district: "Solo puedes votar en el distrito %{district}" - zero: "Todavía no has votado ninguna propuesta de inversión." - orders: - random: Aleatorias - confidence_score: Mejor valoradas - price: Por coste - new: - more_info: "¿Cómo funcionan los presupuestos participativos?" - recommendation_one: Consulta los %{requirements}. - recommendation_one_link: requisitos que debe cumplir una propuesta - recommendation_three: Intenta detallar lo máximo posible la propuesta para que el equipo de gobierno encargado de estudiarla tenga las menor dudas posibles. - recommendation_two: Cualquier propuesta o comentario que implique acciones ilegales será eliminada. - recommendations_title: Cómo crear una propuesta de inversión - start_new: Crear una propuesta de inversión - back_link: Volver - show: - author_deleted: Usuario eliminado - price_explanation: Informe de coste - unfeasibility_explanation: Informe de inviabilidad - code: 'Código propuesta de gasto:' - share: Compartir - wrong_price_format: Solo puede incluir caracteres numéricos - investment: - title: Propuesta de inversión - add: Añadir - already_added: "Ya has añadido esta propuesta de inversión" - already_supported: Ya has apoyado este proyecto. ¡Compártelo! - forum: Espacio de debate distrital - support_title: Apoyar este proyecto - supports: - one: 1 apoyo - other: "%{count} apoyos" - zero: Sin apoyos - vote: Votar - header: - check_ballot: Revisar mis votos - different_heading_active: Ya apoyaste propuestas de otro distrito. - show: - heading: Partida - price: Cantidad - no_heading: Sin línea spending_proposals: form: association_name_label: 'Si propones en nombre de una asociación o colectivo añade el nombre aquí' From 9570d79ee02e214678936b137d783c1635c1f07b Mon Sep 17 00:00:00 2001 From: rgarcia Date: Fri, 2 Sep 2016 13:46:32 +0200 Subject: [PATCH 0472/1685] ignores missing and unused budget i18n keys --- config/i18n-tasks.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index e24d3af0c..7df6f7f9e 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -94,6 +94,8 @@ search: # - 'errors.messages.{accepted,blank,invalid,too_short,too_long}' # - '{devise,simple_form}.*' ignore_missing: + - 'budget.*' + - 'budgets.*' - 'unauthorized.*' - 'activerecord.errors.models.proposal_notification.*' - 'activerecord.errors.models.direct_message.*' @@ -104,6 +106,8 @@ ignore_missing: ## Consider these keys used: ignore_unused: + - 'budget.*' + - 'budgets.*' - 'activerecord.*' - 'activemodel.*' - 'unauthorized.*' From ee2e0b864f6efbd9fbb143a7e7bac48f48cfe775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Mon, 5 Sep 2016 11:56:53 +0200 Subject: [PATCH 0473/1685] denormalizes investments --- db/migrate/20160905092539_denormalize_investments.rb | 6 ++++++ db/schema.rb | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20160905092539_denormalize_investments.rb diff --git a/db/migrate/20160905092539_denormalize_investments.rb b/db/migrate/20160905092539_denormalize_investments.rb new file mode 100644 index 000000000..d28291c4e --- /dev/null +++ b/db/migrate/20160905092539_denormalize_investments.rb @@ -0,0 +1,6 @@ +class DenormalizeInvestments < ActiveRecord::Migration + def change + add_column :budget_investments, :budget_id, :integer, index: true + add_column :budget_investments, :group_id, :integer, index: true + end +end diff --git a/db/schema.rb b/db/schema.rb index ff2a0f590..982f850d3 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: 20160803154011) do +ActiveRecord::Schema.define(version: 20160905092539) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -139,6 +139,8 @@ ActiveRecord::Schema.define(version: 20160803154011) do t.datetime "updated_at", null: false t.integer "heading_id" t.string "responsible_name" + t.integer "budget_id" + t.integer "group_id" end add_index "budget_investments", ["administrator_id"], name: "index_budget_investments_on_administrator_id", using: :btree @@ -210,10 +212,10 @@ ActiveRecord::Schema.define(version: 20160803154011) do t.string "visit_id" t.datetime "hidden_at" t.integer "flags_count", default: 0 + t.datetime "ignored_flag_at" t.integer "cached_votes_total", default: 0 t.integer "cached_votes_up", default: 0 t.integer "cached_votes_down", default: 0 - t.datetime "ignored_flag_at" t.integer "comments_count", default: 0 t.datetime "confirmed_hide_at" t.integer "cached_anonymous_votes_total", default: 0 From 6d06a59403aecc18e15b539c0cf2f093df9aa35f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baza=CC=81n?= Date: Mon, 5 Sep 2016 13:01:46 +0200 Subject: [PATCH 0474/1685] uses direct associations when managing investments --- app/models/budget/investment.rb | 18 +++++------------- spec/factories.rb | 4 +++- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 890175035..f76d1f68e 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -12,6 +12,8 @@ class Budget belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id' belongs_to :heading + belongs_to :group + belongs_to :budget belongs_to :administrator has_many :valuator_assignments, dependent: :destroy @@ -58,16 +60,14 @@ class Budget end def self.scoped_filter(params, current_filter) - results = budget.investments - if params[:max_for_no_heading].present? || params[:max_per_heading].present? - results = limit_results(results, budget, params[:max_per_heading].to_i, params[:max_for_no_heading].to_i) - end + results = Investment.where(budget_id: params[:budget_id]) + results = results.where(group_id: params[:group_id]) if params[:group_id].present? results = results.by_heading(params[:heading_id]) if params[:heading_id].present? results = results.by_admin(params[:administrator_id]) if params[:administrator_id].present? results = results.by_tag(params[:tag_name]) if params[:tag_name].present? results = results.by_valuator(params[:valuator_id]) if params[:valuator_id].present? results = results.send(current_filter) if current_filter.present? - results.includes(:heading, administrator: :user, valuators: :user) + results.includes(:heading, :group, :budget, administrator: :user, valuators: :user) end def self.limit_results(results, budget, max_per_heading, max_for_no_heading) @@ -114,14 +114,6 @@ class Budget where(heading_id: heading == 'all' ? nil : heading.presence) end - def budget - heading.group.budget - end - - def budget=(resource) - heading.group.budget = resource - end - def undecided? feasibility == "undecided" end diff --git a/spec/factories.rb b/spec/factories.rb index db694b4ce..243e3a928 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -223,7 +223,9 @@ FactoryGirl.define do factory :budget_investment, class: 'Budget::Investment' do sequence(:title) { |n| "Budget Investment #{n} title" } - association :heading, factory: :budget_heading + budget + group { create :budget_group, budget: budget } + heading { create :budget_heading, group: group } association :author, factory: :user description 'Spend money on this' price 10 From 40cdeb568ed2fa9bf28d9fd4c05c168b77efbea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Mon, 5 Sep 2016 13:11:57 +0200 Subject: [PATCH 0475/1685] adds missing associations to dev_seeds --- db/dev_seeds.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/db/dev_seeds.rb b/db/dev_seeds.rb index 7e8a6a54b..16be19f67 100644 --- a/db/dev_seeds.rb +++ b/db/dev_seeds.rb @@ -330,6 +330,8 @@ tags = Faker::Lorem.words(10) investment = Budget::Investment.create!( author: User.reorder("RANDOM()").first, heading: heading, + group: heading.group, + budget: heading.group.budget, title: Faker::Lorem.sentence(3).truncate(60), external_url: Faker::Internet.url, description: "

    #{Faker::Lorem.paragraphs.join('

    ')}

    ", From 3964988bb11c736e635162c936fff921c372b7cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Mon, 5 Sep 2016 13:50:25 +0200 Subject: [PATCH 0476/1685] fixes specs updates investment to have group_id & budget_id --- spec/features/budgets/investments_spec.rb | 56 +++++++++++---------- spec/models/abilities/administrator_spec.rb | 10 +--- spec/models/abilities/common_spec.rb | 12 ++--- spec/models/abilities/valuator_spec.rb | 10 +--- spec/models/budget/investment_spec.rb | 26 +++++----- 5 files changed, 50 insertions(+), 64 deletions(-) diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index c3aa0107b..cdf8694bc 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -8,8 +8,8 @@ feature 'Budget Investments' do let(:heading) { create(:budget_heading, group: group) } scenario 'Index' do - investments = [create(:budget_investment, heading: heading), create(:budget_investment, heading: heading), create(:budget_investment, :feasible, heading: heading)] - unfeasible_investment = create(:budget_investment, :unfeasible, heading: heading) + investments = [create(:budget_investment, budget: budget, group: group, heading: heading), create(:budget_investment, budget: budget, group: group, heading: heading), create(:budget_investment, :feasible, budget: budget, group: group, heading: heading)] + unfeasible_investment = create(:budget_investment, :unfeasible, budget: budget, group: group, heading: heading) visit budget_investments_path(budget_id: budget.id) @@ -25,9 +25,9 @@ feature 'Budget Investments' do context("Search") do scenario 'Search by text' do - investment1 = create(:budget_investment, heading: heading, title: "Get Schwifty") - investment2 = create(:budget_investment, heading: heading, title: "Schwifty Hello") - investment3 = create(:budget_investment, heading: heading, title: "Do not show me") + investment1 = create(:budget_investment, budget: budget, group: group, heading: heading, title: "Get Schwifty") + investment2 = create(:budget_investment, budget: budget, group: group, heading: heading, title: "Schwifty Hello") + investment3 = create(:budget_investment, budget: budget, group: group, heading: heading, title: "Do not show me") visit budget_investments_path(budget_id: budget.id) @@ -48,10 +48,10 @@ feature 'Budget Investments' do context("Filters") do scenario 'by unfeasibility' do - investment1 = create(:budget_investment, :unfeasible, heading: heading, valuation_finished: true) - investment2 = create(:budget_investment, :feasible, heading: heading) - investment3 = create(:budget_investment, heading: heading) - investment4 = create(:budget_investment, :feasible, heading: heading) + investment1 = create(:budget_investment, :unfeasible, budget: budget, group: group, heading: heading, valuation_finished: true) + investment2 = create(:budget_investment, :feasible, budget: budget, group: group, heading: heading) + investment3 = create(:budget_investment, budget: budget, group: group, heading: heading) + investment4 = create(:budget_investment, :feasible, budget: budget, group: group, heading: heading) visit budget_investments_path(budget_id: budget.id, unfeasible: 1) @@ -99,7 +99,7 @@ feature 'Budget Investments' do scenario 'Random order maintained with pagination', :js do per_page = Kaminari.config.default_per_page - (per_page + 2).times { create(:budget_investment, heading: heading) } + (per_page + 2).times { create(:budget_investment, budget: budget, group: group, heading: heading) } visit budget_investments_path(budget_id: budget.id) @@ -116,9 +116,9 @@ feature 'Budget Investments' do end scenario 'Proposals are ordered by confidence_score', :js do - create(:budget_investment, heading: heading, title: 'Best proposal').update_column(:confidence_score, 10) - create(:budget_investment, heading: heading, title: 'Worst proposal').update_column(:confidence_score, 2) - create(:budget_investment, heading: heading, title: 'Medium proposal').update_column(:confidence_score, 5) + create(:budget_investment, budget: budget, group: group, heading: heading, title: 'Best proposal').update_column(:confidence_score, 10) + create(:budget_investment, budget: budget, group: group, heading: heading, title: 'Worst proposal').update_column(:confidence_score, 2) + create(:budget_investment, budget: budget, group: group, heading: heading, title: 'Medium proposal').update_column(:confidence_score, 5) visit budget_investments_path(budget_id: budget.id) click_link 'highest rated' @@ -203,7 +203,7 @@ feature 'Budget Investments' do user = create(:user) login_as(user) - investment = create(:budget_investment, heading: heading) + investment = create(:budget_investment, budget: budget, group: group, heading: heading) visit budget_investment_path(budget_id: budget.id, id: investment.id) @@ -223,6 +223,8 @@ feature 'Budget Investments' do investment = create(:budget_investment, :feasible, :finished, + budget: budget, + group: group, heading: heading, price: 16, price_explanation: 'Every wheel is 4 euros, so total is 16') @@ -240,6 +242,8 @@ feature 'Budget Investments' do investment = create(:budget_investment, :unfeasible, :finished, + budget: budget, + group: group, heading: heading, unfeasibility_explanation: 'Local government is not competent in this matter') @@ -254,7 +258,7 @@ feature 'Budget Investments' do xscenario "Admin cannot destroy spending proposals" do admin = create(:administrator) user = create(:user, :level_two) - investment = create(:budget_investment, heading: heading, author: user) + investment = create(:budget_investment, budget: budget, group: group, heading: heading, author: user) login_as(admin.user) visit user_path(user) @@ -270,7 +274,7 @@ feature 'Budget Investments' do scenario "Spending proposal created by a User" do user = create(:user) - user_investment = create(:budget_investment, heading: heading) + user_investment = create(:budget_investment, budget: budget, group: group, heading: heading) visit budget_investment_path(budget_id: budget.id, id: user_investment.id) expect(page).to_not have_css "is-forum" @@ -291,8 +295,8 @@ feature 'Budget Investments' do xscenario "Index" do user = create(:user, :level_two) - sp1 = create(:budget_investment, :feasible, :finished, heading: heading, price: 10000) - sp2 = create(:budget_investment, :feasible, :finished, heading: heading, price: 20000) + sp1 = create(:budget_investment, :feasible, :finished, budget: budget, group: group, heading: heading, price: 10000) + sp2 = create(:budget_investment, :feasible, :finished, budget: budget, group: group, heading: heading, price: 20000) login_as(user) visit root_path @@ -313,9 +317,9 @@ feature 'Budget Investments' do end xscenario 'Order by cost (only in phase3)' do - create(:budget_investment, :feasible, :finished, heading: heading, title: 'Build a nice house', price: 1000).update_column(:confidence_score, 10) - create(:budget_investment, :feasible, :finished, heading: heading, title: 'Build an ugly house', price: 1000).update_column(:confidence_score, 5) - create(:budget_investment, :feasible, :finished, heading: heading, title: 'Build a skyscraper', price: 20000) + create(:budget_investment, :feasible, :finished, budget: budget, group: group, heading: heading, title: 'Build a nice house', price: 1000).update_column(:confidence_score, 10) + create(:budget_investment, :feasible, :finished, budget: budget, group: group, heading: heading, title: 'Build an ugly house', price: 1000).update_column(:confidence_score, 5) + create(:budget_investment, :feasible, :finished, budget: budget, group: group, heading: heading, title: 'Build a skyscraper', price: 20000) visit budget_investments_path(budget_id: budget.id) @@ -333,7 +337,7 @@ feature 'Budget Investments' do scenario "Show" do user = create(:user, :level_two) - sp1 = create(:budget_investment, :feasible, :finished, heading: heading, price: 10000) + sp1 = create(:budget_investment, :feasible, :finished, budget: budget, group: group, heading: heading, price: 10000) login_as(user) visit root_path @@ -354,14 +358,14 @@ feature 'Budget Investments' do new_york = create(:geozone, name: "New York") carabanchel_heading = create(:budget_heading, heading: heading, geozone: carabanchel, name: carabanchel.name) - new_york_heading = create(:budget_heading, heading: heading, geozone: new_york, name: new_york.name) + new_york_heading = create(:budget_heading, heading: heading, geozone: new_york, name: new_york.name) sp1 = create(:budget_investment, :feasible, :finished, price: 1, heading: nil) sp2 = create(:budget_investment, :feasible, :finished, price: 10, heading: nil) sp3 = create(:budget_investment, :feasible, :finished, price: 100, heading: nil) - sp4 = create(:budget_investment, :feasible, :finished, price: 1000, heading: carabanchel_heading) - sp5 = create(:budget_investment, :feasible, :finished, price: 10000, heading: carabanchel_heading) - sp6 = create(:budget_investment, :feasible, :finished, price: 100000, heading: new_york_heading) + sp4 = create(:budget_investment, :feasible, :finished, price: 1000, budget: budget, group: group, heading: carabanchel_heading) + sp5 = create(:budget_investment, :feasible, :finished, price: 10000, budget: budget, group: group, heading: carabanchel_heading) + sp6 = create(:budget_investment, :feasible, :finished, price: 100000, budget: budget, group: group, heading: new_york_heading) login_as(user) visit root_path diff --git a/spec/models/abilities/administrator_spec.rb b/spec/models/abilities/administrator_spec.rb index d2313dea5..8170d3434 100644 --- a/spec/models/abilities/administrator_spec.rb +++ b/spec/models/abilities/administrator_spec.rb @@ -65,13 +65,7 @@ describe "Abilities::Administrator" do it { should be_able_to(:update, Budget::Investment) } it { should be_able_to(:hide, Budget::Investment) } - it { should be_able_to(:valuate, create(:budget_investment, - heading: create(:budget_heading, - group: create(:budget_group, - budget: create(:budget, valuating: true))))) } - it { should_not be_able_to(:valuate, create(:budget_investment, - heading: create(:budget_heading, - group: create(:budget_group, - budget: create(:budget, valuating: false))))) } + it { should be_able_to(:valuate, create(:budget_investment, budget: create(:budget, valuating: true))) } + it { should_not be_able_to(:valuate, create(:budget_investment, budget: create(:budget, valuating: false))) } end diff --git a/spec/models/abilities/common_spec.rb b/spec/models/abilities/common_spec.rb index a115d36c2..2a30d44a5 100644 --- a/spec/models/abilities/common_spec.rb +++ b/spec/models/abilities/common_spec.rb @@ -12,16 +12,10 @@ describe "Abilities::Common" do let(:accepting_budget) { create(:budget, phase: 'accepting') } let(:selecting_budget) { create(:budget, phase: 'selecting') } let(:balloting_budget) { create(:budget, phase: 'balloting') } - let(:accepting_budget_group) { create(:budget_group, budget: accepting_budget) } - let(:selecting_budget_group) { create(:budget_group, budget: selecting_budget) } - let(:balloting_budget_group) { create(:budget_group, budget: balloting_budget) } - let(:accepting_budget_heading) { create(:budget_heading, group: accepting_budget_group) } - let(:selecting_budget_heading) { create(:budget_heading, group: selecting_budget_group) } - let(:balloting_budget_heading) { create(:budget_heading, group: balloting_budget_group) } - let(:investment_in_accepting_budget) { create(:budget_investment, heading: accepting_budget_heading) } - let(:investment_in_selecting_budget) { create(:budget_investment, heading: selecting_budget_heading) } - let(:investment_in_balloting_budget) { create(:budget_investment, heading: balloting_budget_heading) } + let(:investment_in_accepting_budget) { create(:budget_investment, budget: accepting_budget) } + let(:investment_in_selecting_budget) { create(:budget_investment, budget: selecting_budget) } + let(:investment_in_balloting_budget) { create(:budget_investment, budget: balloting_budget) } let(:ballot_in_accepting_budget) { create(:budget_ballot, budget: accepting_budget) } let(:ballot_in_selecting_budget) { create(:budget_ballot, budget: selecting_budget) } let(:ballot_in_balloting_budget) { create(:budget_ballot, budget: balloting_budget) } diff --git a/spec/models/abilities/valuator_spec.rb b/spec/models/abilities/valuator_spec.rb index add938a9d..9fa285f19 100644 --- a/spec/models/abilities/valuator_spec.rb +++ b/spec/models/abilities/valuator_spec.rb @@ -7,16 +7,10 @@ describe "Abilities::Valuator" do let(:valuator) { create(:valuator) } let(:non_assigned_investment) { create(:budget_investment) } - let(:assigned_investment) { create(:budget_investment, - heading: create(:budget_heading, - group: create(:budget_group, - budget: create(:budget, valuating: true)))) } + let(:assigned_investment) { create(:budget_investment, budget: create(:budget, valuating: true)) } before(:each) { assigned_investment.valuators << valuator } - let(:assigned_investment_not_valuating) { create(:budget_investment, - heading: create(:budget_heading, - group: create(:budget_group, - budget: create(:budget, valuating: false)))) } + let(:assigned_investment_not_valuating) { create(:budget_investment, budget: create(:budget, valuating: false)) } before(:each) { assigned_investment_not_valuating.valuators << valuator } it { should be_able_to(:read, SpendingProposal) } diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb index d3dbf0d0b..6b98025ad 100644 --- a/spec/models/budget/investment_spec.rb +++ b/spec/models/budget/investment_spec.rb @@ -194,7 +194,7 @@ describe Budget::Investment do let(:heading) { create(:budget_heading, group: group) } let(:user) { create(:user, :level_two) } let(:luser) { create(:user) } - let(:district_sp) { create(:budget_investment, heading: heading) } + let(:district_sp) { create(:budget_investment, budget: budget, group: group, heading: heading) } describe '#reason_for_not_being_selectable_by' do it "rejects not logged in users" do @@ -271,13 +271,13 @@ describe Budget::Investment do b = create(:budget, :selecting) g = create(:budget_group, budget: b) h = create(:budget_heading, group: g) - sp = create(:budget_investment, heading: h) + i = create(:budget_investment, budget: b, group: g, heading: h) - sp.register_selection(create(:user, :level_two)) - expect(sp.total_votes).to eq(1) + i.register_selection(create(:user, :level_two)) + expect(i.total_votes).to eq(1) - sp.physical_votes = 10 - expect(sp.total_votes).to eq(11) + i.physical_votes = 10 + expect(i.total_votes).to eq(11) end end @@ -301,7 +301,7 @@ describe Budget::Investment do let(:user) { create(:user, :level_two) } let(:luser) { create(:user) } let(:ballot) { create(:budget_ballot, budget: budget) } - let(:investment) { create(:budget_investment, heading: heading) } + let(:investment) { create(:budget_investment, budget: budget, group: group, heading: heading) } describe '#reason_for_not_being_ballotable_by' do it "rejects not logged in users" do @@ -338,8 +338,8 @@ describe Budget::Investment do california = create(:budget_heading, group: group) new_york = create(:budget_heading, group: group) - inv1 = create(:budget_investment, :feasible, heading: california) - inv2 = create(:budget_investment, :feasible, heading: new_york) + inv1 = create(:budget_investment, :feasible, budget: budget, group: group, heading: california) + inv2 = create(:budget_investment, :feasible, budget: budget, group: group, heading: new_york) b = create(:budget_ballot, user: user, budget: budget) b.add_investment inv1 @@ -348,10 +348,10 @@ describe Budget::Investment do it "rejects proposals with price higher than current available money" do budget.phase = "balloting" - distritos = create(:budget_group, budget: budget) - carabanchel = create(:budget_heading, group: distritos, price: 35) - inv1 = create(:budget_investment, :feasible, heading: carabanchel, price: 30) - inv2 = create(:budget_investment, :feasible, heading: carabanchel, price: 10) + districts = create(:budget_group, budget: budget) + carabanchel = create(:budget_heading, group: districts, price: 35) + inv1 = create(:budget_investment, :feasible, budget: budget, group: districts, heading: carabanchel, price: 30) + inv2 = create(:budget_investment, :feasible, budget: budget, group: districts, heading: carabanchel, price: 10) ballot = create(:budget_ballot, user: user, budget: budget) ballot.add_investment inv1 From b0358e48671ddd23e4fd04c32e3b9994540b6e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Mon, 5 Sep 2016 17:50:58 +0200 Subject: [PATCH 0477/1685] adds index of investments with filters to admin --- .../admin/budget_investments_controller.rb | 15 + app/helpers/budget_groups_helper.rb | 7 + .../admin/budget_investments/index.html.erb | 76 +++++ .../admin/budget_investments/show.html.erb | 1 + app/views/admin/budgets/index.html.erb | 5 +- config/i18n-tasks.yml | 1 + config/locales/activerecord.es.yml | 3 + config/locales/admin.en.yml | 22 ++ config/locales/admin.es.yml | 22 ++ config/routes.rb | 2 + .../features/admin/budget_investments_spec.rb | 298 ++++++++++++++++++ spec/features/admin/budgets_spec.rb | 7 +- 12 files changed, 456 insertions(+), 3 deletions(-) create mode 100644 app/controllers/admin/budget_investments_controller.rb create mode 100644 app/helpers/budget_groups_helper.rb create mode 100644 app/views/admin/budget_investments/index.html.erb create mode 100644 app/views/admin/budget_investments/show.html.erb create mode 100644 spec/features/admin/budget_investments_spec.rb diff --git a/app/controllers/admin/budget_investments_controller.rb b/app/controllers/admin/budget_investments_controller.rb new file mode 100644 index 000000000..bf15ee7f6 --- /dev/null +++ b/app/controllers/admin/budget_investments_controller.rb @@ -0,0 +1,15 @@ +class Admin::BudgetInvestmentsController < Admin::BaseController + + has_filters %w{valuation_open without_admin managed valuating valuation_finished all}, only: :index + + def index + @budget = Budget.includes(:groups).find params[:budget_id] + @investments = @budget.investments.scoped_filter(params, @current_filter).order(cached_votes_up: :desc, created_at: :desc).page(params[:page]) + end + + def show + @budget = Budget.includes(:groups).find params[:budget_id] + @investment = @budget.investments.find params[:id] + end + +end \ No newline at end of file diff --git a/app/helpers/budget_groups_helper.rb b/app/helpers/budget_groups_helper.rb new file mode 100644 index 000000000..d36a992d9 --- /dev/null +++ b/app/helpers/budget_groups_helper.rb @@ -0,0 +1,7 @@ +module BudgetGroupsHelper + + def budget_group_select_options(groups) + groups.map {|group| [group.name, group.id]} + end + +end \ No newline at end of file diff --git a/app/views/admin/budget_investments/index.html.erb b/app/views/admin/budget_investments/index.html.erb new file mode 100644 index 000000000..31ad2298a --- /dev/null +++ b/app/views/admin/budget_investments/index.html.erb @@ -0,0 +1,76 @@ +

    <%= @budget.name %> - <%= t("admin.budget_investments.index.title") %>

    + +
    + <%= form_tag admin_budget_budget_investments_path(budget: @budget), method: :get, enforce_utf8: false do %> +
    + <%= select_tag :administrator_id, + options_for_select(admin_select_options, params[:administrator_id]), + { prompt: t("admin.budget_investments.index.administrator_filter_all"), + label: false, + class: "js-submit-on-change" } %> +
    + +
    + <%= select_tag :valuator_id, + options_for_select(valuator_select_options, params[:valuator_id]), + { prompt: t("admin.budget_investments.index.valuator_filter_all"), + label: false, + class: "js-submit-on-change" } %> +
    + +
    + <%= select_tag :group_id, + options_for_select(budget_group_select_options(@budget.groups), params[:group_id]), + { prompt: t("admin.budget_investments.index.group_filter_all"), + label: false, + class: "js-submit-on-change" } %> +
    + +
    + <%= select_tag :tag_name, + options_for_select(spending_proposal_tags_select_options, params[:tag_name]), + { prompt: t("admin.budget_investments.index.tags_filter_all"), + label: false, + class: "js-submit-on-change" } %> +
    + <% end %> +
    + +<%= render 'shared/filter_subnav', i18n_namespace: "admin.budget_investments.index" %> + +

    <%= page_entries_info @investments %>

    + + + <% @investments.each do |investment| %> + + + + + + + + + <% end %> +
    + <%= investment.id %> + + <%= link_to investment.title, admin_budget_budget_investment_path(budget_id: @budget.id, id: investment.id), Budget::Investment.filter_params(params) %> + + <% if investment.administrator.present? %> + <%= investment.administrator.name %> + <% else %> + <%= t("admin.budget_investments.index.no_admin_assigned") %> + <% end %> + + <% if investment.valuators.size == 0 %> + <%= t("admin.budget_investments.index.no_valuators_assigned") %> + <% else %> + <%= investment.valuators.collect(&:description_or_name).join(', ') %> + <% end %> + + <%= investment.group.name %> + + <%= t("admin.budget_investments.index.feasibility.#{investment.feasibility}", price: investment.price) %> +
    + +<%= paginate @investments %> \ No newline at end of file diff --git a/app/views/admin/budget_investments/show.html.erb b/app/views/admin/budget_investments/show.html.erb new file mode 100644 index 000000000..a142a388d --- /dev/null +++ b/app/views/admin/budget_investments/show.html.erb @@ -0,0 +1 @@ +<%= @investment.title %> \ No newline at end of file diff --git a/app/views/admin/budgets/index.html.erb b/app/views/admin/budgets/index.html.erb index 193b6a7ef..d4de771db 100644 --- a/app/views/admin/budgets/index.html.erb +++ b/app/views/admin/budgets/index.html.erb @@ -13,11 +13,14 @@ <% @budgets.each do |budget| %> - <%= link_to budget.name, admin_budget_path(budget) %> + <%= link_to budget.name, admin_budget_budget_investments_path(budget_id: budget.id) %> <%= t("budget.phase.#{budget.phase}") %> + + <%= link_to t("admin.budgets.index.info_link"), admin_budget_path(budget) %> + <% end %> diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 7df6f7f9e..161ed6dfd 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -117,6 +117,7 @@ ignore_unused: - 'admin.debates.index.filter*' - 'admin.proposals.index.filter*' - 'admin.budgets.index.filter*' + - 'admin.budget_investments.index.filter*' - 'admin.spending_proposals.index.filter*' - 'admin.organizations.index.filter*' - 'admin.users.index.filter*' diff --git a/config/locales/activerecord.es.yml b/config/locales/activerecord.es.yml index ccd0240e8..c7c811801 100644 --- a/config/locales/activerecord.es.yml +++ b/config/locales/activerecord.es.yml @@ -7,6 +7,9 @@ es: budget: one: "Presupuesto participativo" other: "Presupuestos participativos" + budget/investment: + one: "Propuesta de inversión" + other: "Propuestas de inversión" comment: one: "Comentario" other: "Comentarios" diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index 78a3a6d6c..61845a164 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -62,6 +62,7 @@ en: index: title: Participatory budgets new_link: Create new + info_link: Info filters: open: Open finished: Finished @@ -92,6 +93,27 @@ en: table_heading: Heading table_amount: Amount table_geozone: Scope of operation + budget_investments: + index: + group_filter_all: All voting groups + administrator_filter_all: All administrators + valuator_filter_all: All valuators + tags_filter_all: All tags + filters: + valuation_open: Open + without_admin: Without assigned admin + managed: Managed + valuating: Under valuation + valuation_finished: Valuation finished + all: All + title: Investment projects + assigned_admin: Assigned administrator + no_admin_assigned: No admin assigned + no_valuators_assigned: No valuators assigned + feasibility: + feasible: "Feasible (%{price})" + not_feasible: "Not feasible" + undefined: "Undefined" comments: index: filter: Filter diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index 496a0208d..7d2417480 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -62,6 +62,7 @@ es: index: title: Presupuestos participativos new_link: Crear nuevo + info_link: Info filters: open: Abiertos finished: Terminados @@ -92,6 +93,27 @@ es: table_heading: Partida table_amount: Cantidad table_geozone: Ámbito de actuación + budget_investments: + index: + group_filter_all: Todos los grupos + administrator_filter_all: Todos los administradores + valuator_filter_all: Todos los evaluadores + tags_filter_all: Todas las etiquetas + filters: + valuation_open: Abiertas + without_admin: Sin administrador + managed: Gestionando + valuating: En evaluación + valuation_finished: Evaluación finalizada + all: Todas + title: Propuestas de inversión + assigned_admin: Administrador asignado + no_admin_assigned: Sin admin asignado + no_valuators_assigned: Sin evaluador + feasibility: + feasible: "Viable (%{price})" + not_feasible: "Inviable" + undefined: "Sin definir" comments: index: filter: Filtro diff --git a/config/routes.rb b/config/routes.rb index 92f3d6c22..278153a19 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -161,6 +161,8 @@ Rails.application.routes.draw do resources :budget_headings do end end + + resources :budget_investments, only: [:index, :show] end resources :banners, only: [:index, :new, :create, :edit, :update, :destroy] do diff --git a/spec/features/admin/budget_investments_spec.rb b/spec/features/admin/budget_investments_spec.rb new file mode 100644 index 000000000..3c5e611c5 --- /dev/null +++ b/spec/features/admin/budget_investments_spec.rb @@ -0,0 +1,298 @@ +require 'rails_helper' + +feature 'Admin budget investments' do + + background do + admin = create(:administrator) + login_as(admin.user) + + @budget = create(:budget) + end + + context "Index" do + + scenario 'Displaying investmentss' do + budget_investment = create(:budget_investment, budget: @budget) + visit admin_budget_budget_investments_path(budget_id: @budget.id) + expect(page).to have_content(budget_investment.title) + end + + scenario 'Displaying assignments info' do + budget_investment1 = create(:budget_investment, budget: @budget) + budget_investment2 = create(:budget_investment, budget: @budget) + budget_investment3 = create(:budget_investment, budget: @budget) + + valuator1 = create(:valuator, user: create(:user, username: 'Olga'), description: 'Valuator Olga') + valuator2 = create(:valuator, user: create(:user, username: 'Miriam'), description: 'Valuator Miriam') + admin = create(:administrator, user: create(:user, username: 'Gema')) + + budget_investment1.valuators << valuator1 + budget_investment2.valuator_ids = [valuator1.id, valuator2.id] + budget_investment3.update({administrator_id: admin.id}) + + visit admin_budget_budget_investments_path(budget_id: @budget.id) + + within("#budget_investment_#{budget_investment1.id}") do + expect(page).to have_content("No admin assigned") + expect(page).to have_content("Valuator Olga") + end + + within("#budget_investment_#{budget_investment2.id}") do + expect(page).to have_content("No admin assigned") + expect(page).to have_content("Valuator Olga") + expect(page).to have_content("Valuator Miriam") + end + + within("#budget_investment_#{budget_investment3.id}") do + expect(page).to have_content("Gema") + expect(page).to have_content("No valuators assigned") + end + end + + scenario "Filtering by budget group", :js do + group1 = create(:budget_group, name: "Street improvments", budget: @budget) + group2 = create(:budget_group, name: "Parks", budget: @budget) + + create(:budget_investment, title: "Realocate visitors", budget: @budget, group: group1) + create(:budget_investment, title: "Destroy the city", budget: @budget, group: group2) + + visit admin_budget_budget_investments_path(budget_id: @budget.id) + + expect(page).to have_link("Realocate visitors") + expect(page).to have_link("Destroy the city") + + select "Parks", from: "group_id" + + expect(page).to have_link("Destroy the city") + expect(page).to_not have_link("Realocate visitors") + + select "All voting groups", from: "group_id" + + expect(page).to have_link("Realocate visitors") + expect(page).to have_link("Destroy the city") + + select "Street improvments", from: "group_id" + + expect(page).to_not have_link("Destroy the city") + expect(page).to have_link("Realocate visitors") + + # click_link("Realocate visitors") + # click_link("Back") + + # expect(page).to_not have_link("Destroy the city") + # expect(page).to have_link("Realocate visitors") + + # click_link("Realocate visitors") + # click_link("Edit classification") + # expect(page).to have_button("Update") + # click_link("Back") + # expect(page).to_not have_button("Update") + # click_link("Back") + + # expect(page).to_not have_link("Destroy the city") + # expect(page).to have_link("Realocate visitors") + end + + scenario "Filtering by admin", :js do + user = create(:user, username: 'Admin 1') + administrator = create(:administrator, user: user) + + create(:budget_investment, title: "Realocate visitors", budget: @budget, administrator: administrator) + create(:budget_investment, title: "Destroy the city", budget: @budget) + + visit admin_budget_budget_investments_path(budget_id: @budget.id) + expect(page).to have_link("Realocate visitors") + expect(page).to have_link("Destroy the city") + + select "Admin 1", from: "administrator_id" + + expect(page).to have_content('There is 1 investment') + expect(page).to_not have_link("Destroy the city") + expect(page).to have_link("Realocate visitors") + + select "All administrators", from: "administrator_id" + + expect(page).to have_content('There are 2 investments') + expect(page).to have_link("Destroy the city") + expect(page).to have_link("Realocate visitors") + + select "Admin 1", from: "administrator_id" + expect(page).to have_content('There is 1 investment') + + # click_link("Realocate visitors") + # click_link("Back") + + # expect(page).to have_content('There is 1 investment') + # expect(page).to_not have_link("Destroy the city") + # expect(page).to have_link("Realocate visitors") + + # click_link("Realocate visitors") + # click_link("Edit classification") + # expect(page).to have_button("Update") + # click_link("Back") + # expect(page).to_not have_button("Update") + # click_link("Back") + + # expect(page).to have_content('There is 1 investment') + # expect(page).to_not have_link("Destroy the city") + # expect(page).to have_link("Realocate visitors") + end + + scenario "Filtering by valuator", :js do + user = create(:user) + valuator = create(:valuator, user: user, description: 'Valuator 1') + + budget_investment = create(:budget_investment, title: "Realocate visitors", budget: @budget) + budget_investment.valuators << valuator + + create(:budget_investment, title: "Destroy the city", budget: @budget) + + visit admin_budget_budget_investments_path(budget_id: @budget.id) + expect(page).to have_link("Realocate visitors") + expect(page).to have_link("Destroy the city") + + select "Valuator 1", from: "valuator_id" + + expect(page).to have_content('There is 1 investment') + expect(page).to_not have_link("Destroy the city") + expect(page).to have_link("Realocate visitors") + + select "All valuators", from: "valuator_id" + + expect(page).to have_content('There are 2 investments') + expect(page).to have_link("Destroy the city") + expect(page).to have_link("Realocate visitors") + + select "Valuator 1", from: "valuator_id" + expect(page).to have_content('There is 1 investment') + # click_link("Realocate visitors") + # click_link("Back") + + # expect(page).to have_content('There is 1 investment') + # expect(page).to_not have_link("Destroy the city") + # expect(page).to have_link("Realocate visitors") + + # click_link("Realocate visitors") + # click_link("Edit classification") + # expect(page).to have_button("Update") + # click_link("Back") + # expect(page).to_not have_button("Update") + # click_link("Back") + + # expect(page).to have_content('There is 1 investment') + # expect(page).to_not have_link("Destroy the city") + # expect(page).to have_link("Realocate visitors") + end + + scenario "Current filter is properly highlighted" do + filters_links = {'valuation_open' => 'Open', + 'without_admin' => 'Without assigned admin', + 'managed' => 'Managed', + 'valuating' => 'Under valuation', + 'valuation_finished' => 'Valuation finished', + 'all' => 'All'} + + visit admin_budget_budget_investments_path(budget_id: @budget.id) + + expect(page).to_not have_link(filters_links.values.first) + filters_links.keys.drop(1).each { |filter| expect(page).to have_link(filters_links[filter]) } + + filters_links.each_pair do |current_filter, link| + visit admin_budget_budget_investments_path(budget_id: @budget.id, filter: current_filter) + + expect(page).to_not have_link(link) + + (filters_links.keys - [current_filter]).each do |filter| + expect(page).to have_link(filters_links[filter]) + end + end + end + + scenario "Filtering by assignment status" do + assigned = create(:budget_investment, title: "Assigned idea", budget: @budget, administrator: create(:administrator)) + valuating = create(:budget_investment, title: "Evaluating...", budget: @budget) + valuating.valuators << create(:valuator) + + visit admin_budget_budget_investments_path(budget_id: @budget.id, filter: 'valuation_open') + + expect(page).to have_content("Assigned idea") + expect(page).to have_content("Evaluating...") + + visit admin_budget_budget_investments_path(budget_id: @budget.id, filter: 'without_admin') + + expect(page).to have_content("Evaluating...") + expect(page).to_not have_content("Assigned idea") + + visit admin_budget_budget_investments_path(budget_id: @budget.id, filter: 'managed') + + expect(page).to have_content("Assigned idea") + expect(page).to_not have_content("Evaluating...") + end + + scenario "Filtering by valuation status" do + valuating = create(:budget_investment, budget: @budget, title: "Ongoing valuation") + valuated = create(:budget_investment, budget: @budget, title: "Old idea", valuation_finished: true) + valuating.valuators << create(:valuator) + valuated.valuators << create(:valuator) + + visit admin_budget_budget_investments_path(budget_id: @budget.id, filter: 'valuation_open') + + expect(page).to have_content("Ongoing valuation") + expect(page).to_not have_content("Old idea") + + visit admin_budget_budget_investments_path(budget_id: @budget.id, filter: 'valuating') + + expect(page).to have_content("Ongoing valuation") + expect(page).to_not have_content("Old idea") + + visit admin_budget_budget_investments_path(budget_id: @budget.id, filter: 'valuation_finished') + + expect(page).to_not have_content("Ongoing valuation") + expect(page).to have_content("Old idea") + + visit admin_budget_budget_investments_path(budget_id: @budget.id, filter: 'all') + expect(page).to have_content("Ongoing valuation") + expect(page).to have_content("Old idea") + end + + scenario "Filtering by tag" do + create(:budget_investment, budget: @budget, title: 'Educate the children', tag_list: 'Education') + create(:budget_investment, budget: @budget, title: 'More schools', tag_list: 'Education') + create(:budget_investment, budget: @budget, title: 'More hospitals', tag_list: 'Health') + + visit admin_budget_budget_investments_path(budget_id: @budget.id) + + expect(page).to have_css(".budget_investment", count: 3) + expect(page).to have_content("Educate the children") + expect(page).to have_content("More schools") + expect(page).to have_content("More hospitals") + + visit admin_budget_budget_investments_path(budget_id: @budget.id, tag_name: 'Education') + + expect(page).to_not have_content("More hospitals") + expect(page).to have_css(".budget_investment", count: 2) + expect(page).to have_content("Educate the children") + expect(page).to have_content("More schools") + + # click_link("Educate the children") + # click_link("Back") + + # expect(page).to_not have_content("More hospitals") + # expect(page).to have_content("Educate the children") + # expect(page).to have_content("More schools") + + # click_link("Educate the children") + # click_link("Edit classification") + # expect(page).to have_button("Update") + # click_link("Back") + # expect(page).to_not have_button("Update") + # click_link("Back") + + # expect(page).to_not have_content("More hospitals") + # expect(page).to have_content("Educate the children") + # expect(page).to have_content("More schools") + end + + end + +end \ No newline at end of file diff --git a/spec/features/admin/budgets_spec.rb b/spec/features/admin/budgets_spec.rb index 123ca43e8..a87cd741a 100644 --- a/spec/features/admin/budgets_spec.rb +++ b/spec/features/admin/budgets_spec.rb @@ -105,10 +105,13 @@ feature 'Admin budgets' do context 'Manage groups and headings' do scenario 'Create group', :js do - create(:budget, name: 'Yearly participatory budget') + budget = create(:budget, name: 'Yearly participatory budget') visit admin_budgets_path - click_link 'Yearly participatory budget' + + within("#budget_#{budget.id}") do + click_link 'Info' + end expect(page).to have_content 'No groups created yet.' From 31ef3f4c9815e8d2c5bd641c711f15ec990fb454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Tue, 6 Sep 2016 17:03:35 +0200 Subject: [PATCH 0478/1685] adds heading filter to index --- app/helpers/budget_groups_helper.rb | 7 -- app/helpers/budget_headings_helper.rb | 7 ++ app/models/budget/investment.rb | 2 +- .../admin/budget_investments/index.html.erb | 10 +- config/locales/admin.en.yml | 2 +- config/locales/admin.es.yml | 2 +- .../features/admin/budget_investments_spec.rb | 92 +++++++++++-------- 7 files changed, 69 insertions(+), 53 deletions(-) delete mode 100644 app/helpers/budget_groups_helper.rb create mode 100644 app/helpers/budget_headings_helper.rb diff --git a/app/helpers/budget_groups_helper.rb b/app/helpers/budget_groups_helper.rb deleted file mode 100644 index d36a992d9..000000000 --- a/app/helpers/budget_groups_helper.rb +++ /dev/null @@ -1,7 +0,0 @@ -module BudgetGroupsHelper - - def budget_group_select_options(groups) - groups.map {|group| [group.name, group.id]} - end - -end \ No newline at end of file diff --git a/app/helpers/budget_headings_helper.rb b/app/helpers/budget_headings_helper.rb new file mode 100644 index 000000000..cb042f796 --- /dev/null +++ b/app/helpers/budget_headings_helper.rb @@ -0,0 +1,7 @@ +module BudgetHeadingsHelper + + def budget_heading_select_options(budget) + budget.headings.map {|heading| [heading.name, heading.id]} + end + +end \ No newline at end of file diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index f76d1f68e..56ae67d41 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -56,7 +56,7 @@ class Budget before_validation :set_responsible_name def self.filter_params(params) - params.select{|x,_| %w{heading_id administrator_id tag_name valuator_id}.include? x.to_s } + params.select{|x,_| %w{heading_id group_id administrator_id tag_name valuator_id}.include? x.to_s } end def self.scoped_filter(params, current_filter) diff --git a/app/views/admin/budget_investments/index.html.erb b/app/views/admin/budget_investments/index.html.erb index 31ad2298a..5aff40115 100644 --- a/app/views/admin/budget_investments/index.html.erb +++ b/app/views/admin/budget_investments/index.html.erb @@ -19,9 +19,9 @@
    - <%= select_tag :group_id, - options_for_select(budget_group_select_options(@budget.groups), params[:group_id]), - { prompt: t("admin.budget_investments.index.group_filter_all"), + <%= select_tag :heading_id, + options_for_select(budget_heading_select_options(@budget), params[:heading_id]), + { prompt: t("admin.budget_investments.index.heading_filter_all"), label: false, class: "js-submit-on-change" } %>
    @@ -47,7 +47,7 @@ <%= investment.id %> - <%= link_to investment.title, admin_budget_budget_investment_path(budget_id: @budget.id, id: investment.id), Budget::Investment.filter_params(params) %> + <%= link_to investment.title, admin_budget_budget_investment_path(budget_id: @budget.id, id: investment.id, params: Budget::Investment.filter_params(params)) %> <% if investment.administrator.present? %> @@ -64,7 +64,7 @@ <% end %> - <%= investment.group.name %> + <%= investment.heading.name %> <%= t("admin.budget_investments.index.feasibility.#{investment.feasibility}", price: investment.price) %> diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index 61845a164..4a9abf7d3 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -95,7 +95,7 @@ en: table_geozone: Scope of operation budget_investments: index: - group_filter_all: All voting groups + heading_filter_all: All headings administrator_filter_all: All administrators valuator_filter_all: All valuators tags_filter_all: All tags diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index 7d2417480..3600c2448 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -95,7 +95,7 @@ es: table_geozone: Ámbito de actuación budget_investments: index: - group_filter_all: Todos los grupos + heading_filter_all: Todas las partidas administrator_filter_all: Todos los administradores valuator_filter_all: Todos los evaluadores tags_filter_all: Todas las etiquetas diff --git a/spec/features/admin/budget_investments_spec.rb b/spec/features/admin/budget_investments_spec.rb index 3c5e611c5..ad08ee634 100644 --- a/spec/features/admin/budget_investments_spec.rb +++ b/spec/features/admin/budget_investments_spec.rb @@ -49,45 +49,61 @@ feature 'Admin budget investments' do end end - scenario "Filtering by budget group", :js do - group1 = create(:budget_group, name: "Street improvments", budget: @budget) + scenario "Filtering by budget heading", :js do + group1 = create(:budget_group, name: "Streets", budget: @budget) group2 = create(:budget_group, name: "Parks", budget: @budget) - create(:budget_investment, title: "Realocate visitors", budget: @budget, group: group1) - create(:budget_investment, title: "Destroy the city", budget: @budget, group: group2) + group1_heading1 = create(:budget_heading, group: group1, name: "Main Avenue") + group1_heading2 = create(:budget_heading, group: group1, name: "Mercy Street") + group2_heading1 = create(:budget_heading, group: group2, name: "Central Park") + + create(:budget_investment, title: "Realocate visitors", budget: @budget, group: group1, heading: group1_heading1) + create(:budget_investment, title: "Change name", budget: @budget, group: group1, heading: group1_heading2) + create(:budget_investment, title: "Plant trees", budget: @budget, group: group2, heading: group2_heading1) visit admin_budget_budget_investments_path(budget_id: @budget.id) expect(page).to have_link("Realocate visitors") - expect(page).to have_link("Destroy the city") + expect(page).to have_link("Change name") + expect(page).to have_link("Plant trees") - select "Parks", from: "group_id" + select "Central Park", from: "heading_id" - expect(page).to have_link("Destroy the city") expect(page).to_not have_link("Realocate visitors") + expect(page).to_not have_link("Change name") + expect(page).to have_link("Plant trees") - select "All voting groups", from: "group_id" + select "All headings", from: "heading_id" expect(page).to have_link("Realocate visitors") - expect(page).to have_link("Destroy the city") + expect(page).to have_link("Change name") + expect(page).to have_link("Plant trees") - select "Street improvments", from: "group_id" + select "Main Avenue", from: "heading_id" - expect(page).to_not have_link("Destroy the city") expect(page).to have_link("Realocate visitors") + expect(page).to_not have_link("Change name") + expect(page).to_not have_link("Plant trees") - # click_link("Realocate visitors") - # click_link("Back") + select "Mercy Street", from: "heading_id" - # expect(page).to_not have_link("Destroy the city") - # expect(page).to have_link("Realocate visitors") + expect(page).to_not have_link("Realocate visitors") + expect(page).to have_link("Change name") + expect(page).to_not have_link("Plant trees") + + click_link("Change name") + click_link("Go back") + + expect(page).to_not have_link("Realocate visitors") + expect(page).to have_link("Change name") + expect(page).to_not have_link("Plant trees") # click_link("Realocate visitors") # click_link("Edit classification") # expect(page).to have_button("Update") - # click_link("Back") + # click_link("Go back") # expect(page).to_not have_button("Update") - # click_link("Back") + # click_link("Go back") # expect(page).to_not have_link("Destroy the city") # expect(page).to have_link("Realocate visitors") @@ -119,19 +135,19 @@ feature 'Admin budget investments' do select "Admin 1", from: "administrator_id" expect(page).to have_content('There is 1 investment') - # click_link("Realocate visitors") - # click_link("Back") + click_link("Realocate visitors") + click_link("Go back") - # expect(page).to have_content('There is 1 investment') - # expect(page).to_not have_link("Destroy the city") - # expect(page).to have_link("Realocate visitors") + expect(page).to have_content('There is 1 investment') + expect(page).to_not have_link("Destroy the city") + expect(page).to have_link("Realocate visitors") # click_link("Realocate visitors") # click_link("Edit classification") # expect(page).to have_button("Update") - # click_link("Back") + # click_link("Go back") # expect(page).to_not have_button("Update") - # click_link("Back") + # click_link("Go back") # expect(page).to have_content('There is 1 investment') # expect(page).to_not have_link("Destroy the city") @@ -165,19 +181,19 @@ feature 'Admin budget investments' do select "Valuator 1", from: "valuator_id" expect(page).to have_content('There is 1 investment') - # click_link("Realocate visitors") - # click_link("Back") + click_link("Realocate visitors") + click_link("Go back") - # expect(page).to have_content('There is 1 investment') - # expect(page).to_not have_link("Destroy the city") - # expect(page).to have_link("Realocate visitors") + expect(page).to have_content('There is 1 investment') + expect(page).to_not have_link("Destroy the city") + expect(page).to have_link("Realocate visitors") # click_link("Realocate visitors") # click_link("Edit classification") # expect(page).to have_button("Update") - # click_link("Back") + # click_link("Go back") # expect(page).to_not have_button("Update") - # click_link("Back") + # click_link("Go back") # expect(page).to have_content('There is 1 investment') # expect(page).to_not have_link("Destroy the city") @@ -274,19 +290,19 @@ feature 'Admin budget investments' do expect(page).to have_content("Educate the children") expect(page).to have_content("More schools") - # click_link("Educate the children") - # click_link("Back") + click_link("Educate the children") + click_link("Go back") - # expect(page).to_not have_content("More hospitals") - # expect(page).to have_content("Educate the children") - # expect(page).to have_content("More schools") + expect(page).to_not have_content("More hospitals") + expect(page).to have_content("Educate the children") + expect(page).to have_content("More schools") # click_link("Educate the children") # click_link("Edit classification") # expect(page).to have_button("Update") - # click_link("Back") + # click_link("Go back") # expect(page).to_not have_button("Update") - # click_link("Back") + # click_link("Go back") # expect(page).to_not have_content("More hospitals") # expect(page).to have_content("Educate the children") From 65428126479b86926191c1c02a630fcc383da2c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Tue, 6 Sep 2016 17:04:31 +0200 Subject: [PATCH 0479/1685] adds simple investment show view to admin valuators info is missing --- .../admin/budget_investments_controller.rb | 14 ++++-- .../_written_by_author.html.erb | 36 +++++++++++++ .../admin/budget_investments/show.html.erb | 50 ++++++++++++++++++- config/locales/admin.en.yml | 15 ++++++ config/locales/admin.es.yml | 15 ++++++ 5 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 app/views/admin/budget_investments/_written_by_author.html.erb diff --git a/app/controllers/admin/budget_investments_controller.rb b/app/controllers/admin/budget_investments_controller.rb index bf15ee7f6..10342081c 100644 --- a/app/controllers/admin/budget_investments_controller.rb +++ b/app/controllers/admin/budget_investments_controller.rb @@ -1,15 +1,21 @@ class Admin::BudgetInvestmentsController < Admin::BaseController + before_action :load_budget, only: [:index, :show] + has_filters %w{valuation_open without_admin managed valuating valuation_finished all}, only: :index def index - @budget = Budget.includes(:groups).find params[:budget_id] - @investments = @budget.investments.scoped_filter(params, @current_filter).order(cached_votes_up: :desc, created_at: :desc).page(params[:page]) + @investments = Budget::Investment.scoped_filter(params, @current_filter).order(cached_votes_up: :desc, created_at: :desc).page(params[:page]) end def show - @budget = Budget.includes(:groups).find params[:budget_id] - @investment = @budget.investments.find params[:id] + @investment = Budget::Investment.where(budget_id: @budget.id).find params[:id] end + private + + def load_budget + @budget = Budget.includes(:groups).find params[:budget_id] + end + end \ No newline at end of file diff --git a/app/views/admin/budget_investments/_written_by_author.html.erb b/app/views/admin/budget_investments/_written_by_author.html.erb new file mode 100644 index 000000000..b2c46c6f5 --- /dev/null +++ b/app/views/admin/budget_investments/_written_by_author.html.erb @@ -0,0 +1,36 @@ +
    + <%= t "admin.budget_investments.show.info", budget_name: @budget.name, group_name: @investment.group.name, id: @investment.id %> +
    + +
    +

    <%= @investment.title %>

    + +
    +
    +

    : <%= @investment.group.name %>"> + <%= t("admin.budget_investments.show.heading") %>: + <%= @investment.heading.name %> +

    +
    + +
    +

    + <%= t("admin.budget_investments.show.by") %>: + <%= link_to @investment.author.name, admin_user_path(@investment.author) %> +

    +
    + +
    +

    + <%= t("admin.budget_investments.show.sent") %>: + <%= l @investment.created_at, format: :datetime %> +

    +
    + +
    + +<% if @investment.external_url.present? %> +

    <%= text_with_links @investment.external_url %> 

    +<% end %> + +<%= safe_html_with_links @investment.description %> diff --git a/app/views/admin/budget_investments/show.html.erb b/app/views/admin/budget_investments/show.html.erb index a142a388d..47e66bc37 100644 --- a/app/views/admin/budget_investments/show.html.erb +++ b/app/views/admin/budget_investments/show.html.erb @@ -1 +1,49 @@ -<%= @investment.title %> \ No newline at end of file +<%= link_to admin_budget_budget_investments_path(Budget::Investment.filter_params(params)), data: {no_turbolink: true} do %> + <%= t("shared.back") %> +<% end %> + +<%= render 'written_by_author' %> + +<%= link_to t("admin.budget_investments.show.edit"), + admin_budget_budget_investment_path(@budget, @investment, + Budget::Investment.filter_params(params)) %> + +
    + +

    <%= t("admin.budget_investments.show.classification") %>

    + +

    <%= t("admin.budget_investments.show.assigned_admin") %>: + <%= @investment.administrator.try(:name_and_email) || t("admin.budget_investments.show.undefined") %> +

    + +

    + <%= t("admin.budget_investments.show.tags") %>: + + <%= @investment.tags.pluck(:name).join(', ') %> +

    + +

    + <%= t("admin.budget_investments.show.assigned_valuators") %>: + <% if @investment.valuators.any? %> + <%= @investment.valuators.collect(&:name_and_email).join(', ') %> + <% else %> + <%= t("admin.budget_investments.show.undefined") %> + <% end %> +

    + +

    + <%= link_to t("admin.budget_investments.show.edit_classification"), + edit_admin_spending_proposal_path(@investment, + {anchor: 'classification'}.merge(Budget::Investment.filter_params(params))) %> +

    + +
    + +

    <%= t("admin.budget_investments.show.dossier") %>

    + +<%# render 'valuation/budget_investments/written_by_valuators' %> + +

    + <%= link_to t("admin.budget_investments.show.edit_dossier"), edit_valuation_spending_proposal_path(@investment) %> +

    + diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index 4a9abf7d3..9b5e7c19c 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -114,6 +114,21 @@ en: feasible: "Feasible (%{price})" not_feasible: "Not feasible" undefined: "Undefined" + show: + assigned_admin: Assigned administrator + assigned_valuators: Assigned valuators + classification: Clasification + info: "%{budget_name} - Group: %{group_name} - Investment project %{id}" + edit: Edit + edit_classification: Edit classification + by: By + sent: Sent + group: Grupo + heading: Partida + dossier: Dossier + edit_dossier: Edit dossier + tags: Tags + undefined: Undefined comments: index: filter: Filter diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index 3600c2448..4f4536950 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -114,6 +114,21 @@ es: feasible: "Viable (%{price})" not_feasible: "Inviable" undefined: "Sin definir" + show: + assigned_admin: Administrador asignado + assigned_valuators: Evaluadores asignados + classification: Clasificación + info: "%{budget_name} - Grupo: %{group_name} - Propuesta de inversión %{id}" + edit: Editar + edit_classification: Editar clasificación + by: Autor + sent: Fecha + group: Grupo + heading: Partida + dossier: Informe + edit_dossier: Editar informe + tags: Etiquetas + undefined: Sin definir comments: index: filter: Filtro From 2e6328d50235f4673df3b549860581fbc11a01b1 Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Tue, 6 Sep 2016 18:21:15 +0200 Subject: [PATCH 0480/1685] fixes a few typos --- config/locales/pages.es.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/locales/pages.es.yml b/config/locales/pages.es.yml index c9f282a4f..3876e8a1b 100644 --- a/config/locales/pages.es.yml +++ b/config/locales/pages.es.yml @@ -33,13 +33,13 @@ es: Tanto los hilos, como los comentarios podrán ser valorados por cualquiera, de tal manera que será la propia ciudadanía, y nadie en su nombre, la que decida cuáles son los temas más importantes en cada momento. Estos serán presentados en la portada del espacio, pudiendo por supuesto accederse a todos los demás temas en páginas posteriores, o usando otros criterios de ordenación (los temas con más comentarios, los más nuevos, los más controvertidos, etc.). - Cada uno de los trabajadores del Ayuntamiento tiene un usuario propio, que será resaltado como tal, permitiendo que participen en los debates al mismo nivel que todos los demás ciudadanos. Esto permitirá crear espacios de comunicación directos entre unos y otros, evitando los inconvenientes que implica la comunicación medidada, y respondiendo a un planteamiento claro por parte del nuevo gobierno por el cual el Ayuntamiento trabaja para la ciudadanía, y ante ella debe responder. + Cada uno de los trabajadores del Ayuntamiento tiene un usuario propio, que será resaltado como tal, permitiendo que participen en los debates al mismo nivel que todos los demás ciudadanos. Esto permitirá crear espacios de comunicación directos entre unos y otros, evitando los inconvenientes que implica la comunicación mediada, y respondiendo a un planteamiento claro por parte del nuevo gobierno por el cual el Ayuntamiento trabaja para la ciudadanía, y ante ella debe responder. ## I.I. Espacio de propuestas - En este espacio, cualquier persona puede proponer una iniciativa con la intención de recabar los suficientes apoyos como para que la idea pase a ser consultada a toda la ciudadanía con caracter vinculante. + En este espacio, cualquier persona puede proponer una iniciativa con la intención de recabar los suficientes apoyos como para que la idea pase a ser consultada a toda la ciudadanía con carácter vinculante. Las propuestas pueden ser apoyadas por ciudadanos empadronados que hayan verificado su cuenta en la plataforma de participación, de tal manera que será la propia ciudadanía, y nadie en su nombre, la que decida cuáles son las propuestas que merecen la pena ser llevadas a cabo. - Una vez que una propuesta alcance una cantidad de apoyos equivalente al 2% del censo, automaticamente pasa a ser estudiada por un grupo de trabajo del Ayuntamiento y pasará a la siguiente fase de consulta popular, en la que la ciudadanía votará si se lleva a cabo o no. El plazo máximo para recabar los apoyos necesarios será de 12 meses. + Una vez que una propuesta alcance una cantidad de apoyos equivalente al 2% del censo, automáticamente pasa a ser estudiada por un grupo de trabajo del Ayuntamiento y pasará a la siguiente fase de consulta popular, en la que la ciudadanía votará si se lleva a cabo o no. El plazo máximo para recabar los apoyos necesarios será de 12 meses. how_to_use: text: |- Utilízalo en tu municipio libremente o ayúdanos a mejorarlo, es software libre. From bdfd3269078bdf3724b490f85d46036e57912dcc Mon Sep 17 00:00:00 2001 From: kikito Date: Wed, 7 Sep 2016 11:53:24 +0200 Subject: [PATCH 0481/1685] implements some parts of the spending proposals importer --- lib/spending_proposals_importer.rb | 61 ++++++++++++++++++++ spec/lib/spending_proposals_importer_spec.rb | 57 ++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 lib/spending_proposals_importer.rb create mode 100644 spec/lib/spending_proposals_importer_spec.rb diff --git a/lib/spending_proposals_importer.rb b/lib/spending_proposals_importer.rb new file mode 100644 index 000000000..f879dcae7 --- /dev/null +++ b/lib/spending_proposals_importer.rb @@ -0,0 +1,61 @@ +class SpendingProposalsImporter + + def import(sp) + # feasibility + # unfeasibility_explanation + # heading_id + # valuator_assignments_count + # hidden_at + # comments_count + # group_id + # budget_id + # duration + + # comments + + budget = Budget.last || Budget.create!(name: Date.today.year.to_s, currency_symbol: "€") + + group = nil + heading = nil + + if sp.geozone_id.present? + group = budget.groups.find_or_create_by!(name: "Barrios") + heading = group.headings.find_or_create_by!(name: sp.geozone.name, price: 10000000) + else + group = budget.groups.find_or_create_by!(name: "Toda la ciudad") + heading = group.headings.find_or_create_by!(name: "Toda la ciudad", price: 10000000) + end + + feasibility = case sp.feasible + when FalseClass + 'unfeasible' + when TrueClass + 'feasible' + else + 'undecided' + end + + Budget::Investment.create!( + heading_id: heading.id, + author_id: sp.author_id, + administrator_id: sp.administrator_id, + title: sp.title, + description: sp.description, + external_url: sp.external_url, + price: sp.price, + price_explanation: sp.price_explanation, + internal_comments: sp.internal_comments, + feasibility: feasibility, + valuation_finished: sp.valuation_finished, + price_first_year: sp.price_first_year, + cached_votes_up: sp.cached_votes_up, + physical_votes: sp.physical_votes, + created_at: sp.created_at, + updated_at: sp.updated_at, + responsible_name: sp.responsible_name, + terms_of_service: "1" + ) + end + +end + diff --git a/spec/lib/spending_proposals_importer_spec.rb b/spec/lib/spending_proposals_importer_spec.rb new file mode 100644 index 000000000..1b424722f --- /dev/null +++ b/spec/lib/spending_proposals_importer_spec.rb @@ -0,0 +1,57 @@ +require 'rails_helper' + +describe SpendingProposalsImporter do + + let(:importer) { SpendingProposalsImporter.new } + + describe '#import' do + it "Imports a city spending proposal" do + sp = create(:spending_proposal) + + expect { importer.import(sp) }.to change{ Budget::Investment.count }.from(0).to(1) + + inv = Budget::Investment.last + + expect(inv.author).to eq(sp.author) + expect(inv.title).to eq(sp.title) + expect(inv.heading.name).to eq("Toda la ciudad") + expect(inv.heading.group.name).to eq("Toda la ciudad") + end + + it "Imports a city spending proposal" do + sp = create(:spending_proposal, geozone: create(:geozone, name: "Bel Air")) + + expect { importer.import(sp) }.to change{ Budget::Investment.count }.from(0).to(1) + + inv = Budget::Investment.last + + expect(inv.author).to eq(sp.author) + expect(inv.title).to eq(sp.title) + expect(inv.heading.name).to eq("Bel Air") + expect(inv.heading.group.name).to eq("Barrios") + end + + it "Uses existing budgets, headings and groups instead of creating new ones" do + sp1 = create(:spending_proposal, geozone: create(:geozone, name: "Bel Air")) + sp2 = create(:spending_proposal, geozone: create(:geozone, name: "Bel Air")) + + expect { importer.import(sp1) }.to change{ Budget::Investment.count }.from(0).to(1) + expect { importer.import(sp2) }.to change{ Budget::Investment.count }.from(1).to(2) + + inv1 = Budget::Investment.first + inv2 = Budget::Investment.last + + expect(inv2.heading).to eq(inv1.heading) + end + + it "Imports feasibility correctly" do + sp = create(:spending_proposal) + feasible = create(:spending_proposal, feasible: true) + unfeasible = create(:spending_proposal, feasible: false) + + expect(importer.import(sp).feasibility).to eq('undecided') + expect(importer.import(feasible).feasibility).to eq('feasible') + expect(importer.import(unfeasible).feasibility).to eq('unfeasible') + end + end +end From 3d5f7f207c81f9f7daef865b7d1896c918e1ac9f Mon Sep 17 00:00:00 2001 From: Jaime Iniesta Date: Wed, 7 Sep 2016 11:58:10 +0200 Subject: [PATCH 0482/1685] no need to db:create here --- README.md | 1 - README_ES.md | 1 - 2 files changed, 2 deletions(-) diff --git a/README.md b/README.md index 27162bfd7..f376dfded 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ cd consul bundle install cp config/database.yml.example config/database.yml cp config/secrets.yml.example config/secrets.yml -rake db:create bin/rake db:setup bin/rake db:dev_seed RAILS_ENV=test rake db:setup diff --git a/README_ES.md b/README_ES.md index d8c394680..7c7720ee7 100644 --- a/README_ES.md +++ b/README_ES.md @@ -32,7 +32,6 @@ cd consul bundle install cp config/database.yml.example config/database.yml cp config/secrets.yml.example config/secrets.yml -rake db:create bin/rake db:setup bin/rake db:dev_seed RAILS_ENV=test rake db:setup From b8dffc6137740e816d93de8d8811594229129c64 Mon Sep 17 00:00:00 2001 From: kikito Date: Wed, 7 Sep 2016 12:01:04 +0200 Subject: [PATCH 0483/1685] refactor some tests to their own test in importer --- spec/lib/spending_proposals_importer_spec.rb | 34 ++++++++++++-------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/spec/lib/spending_proposals_importer_spec.rb b/spec/lib/spending_proposals_importer_spec.rb index 1b424722f..88d60b360 100644 --- a/spec/lib/spending_proposals_importer_spec.rb +++ b/spec/lib/spending_proposals_importer_spec.rb @@ -5,12 +5,25 @@ describe SpendingProposalsImporter do let(:importer) { SpendingProposalsImporter.new } describe '#import' do + + it "Creates the budget if it doesn't exist" do + sp = create(:spending_proposal) + expect { importer.import(sp) }.to change{ Budget.count }.from(0).to(1) + importer.import(create(:spending_proposal)) + expect(Budget.count).to eq(1) + end + + it "Creates the and returns investments" do + inv = nil + sp = create(:spending_proposal) + expect { inv = importer.import(sp) }.to change{ Budget::Investment.count }.from(0).to(1) + expect(inv).to be_kind_of(Budget::Investment) + end + it "Imports a city spending proposal" do sp = create(:spending_proposal) - expect { importer.import(sp) }.to change{ Budget::Investment.count }.from(0).to(1) - - inv = Budget::Investment.last + inv = importer.import(sp) expect(inv.author).to eq(sp.author) expect(inv.title).to eq(sp.title) @@ -21,9 +34,7 @@ describe SpendingProposalsImporter do it "Imports a city spending proposal" do sp = create(:spending_proposal, geozone: create(:geozone, name: "Bel Air")) - expect { importer.import(sp) }.to change{ Budget::Investment.count }.from(0).to(1) - - inv = Budget::Investment.last + inv = importer.import(sp) expect(inv.author).to eq(sp.author) expect(inv.title).to eq(sp.title) @@ -35,18 +46,15 @@ describe SpendingProposalsImporter do sp1 = create(:spending_proposal, geozone: create(:geozone, name: "Bel Air")) sp2 = create(:spending_proposal, geozone: create(:geozone, name: "Bel Air")) - expect { importer.import(sp1) }.to change{ Budget::Investment.count }.from(0).to(1) - expect { importer.import(sp2) }.to change{ Budget::Investment.count }.from(1).to(2) - - inv1 = Budget::Investment.first - inv2 = Budget::Investment.last + inv1 = importer.import(sp1) + inv2 = importer.import(sp2) expect(inv2.heading).to eq(inv1.heading) end it "Imports feasibility correctly" do - sp = create(:spending_proposal) - feasible = create(:spending_proposal, feasible: true) + sp = create(:spending_proposal) + feasible = create(:spending_proposal, feasible: true) unfeasible = create(:spending_proposal, feasible: false) expect(importer.import(sp).feasibility).to eq('undecided') From a527de4f9224dc67a6da675a9d980f2dcc5de7b2 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Cabeza Date: Wed, 7 Sep 2016 12:43:12 +0200 Subject: [PATCH 0484/1685] Adds proposal ballots controller and views --- .../proposal_ballots_controller.rb | 8 ++ .../_featured_successfull_proposal.html.erb | 3 + .../_successfull_proposal.html.erb | 13 +++ app/views/proposal_ballots/index.html.erb | 36 ++++++++ config/routes.rb | 2 + db/schema.rb | 87 +++++++++++++++++++ 6 files changed, 149 insertions(+) create mode 100644 app/controllers/proposal_ballots_controller.rb create mode 100644 app/views/proposal_ballots/_featured_successfull_proposal.html.erb create mode 100644 app/views/proposal_ballots/_successfull_proposal.html.erb create mode 100644 app/views/proposal_ballots/index.html.erb diff --git a/app/controllers/proposal_ballots_controller.rb b/app/controllers/proposal_ballots_controller.rb new file mode 100644 index 000000000..4e3e99671 --- /dev/null +++ b/app/controllers/proposal_ballots_controller.rb @@ -0,0 +1,8 @@ +class ProposalBallotsController < ApplicationController + skip_authorization_check + + def index + @proposal_ballots = Proposal.successfull.sort_by_confidence_score + end + +end diff --git a/app/views/proposal_ballots/_featured_successfull_proposal.html.erb b/app/views/proposal_ballots/_featured_successfull_proposal.html.erb new file mode 100644 index 000000000..97754ce9c --- /dev/null +++ b/app/views/proposal_ballots/_featured_successfull_proposal.html.erb @@ -0,0 +1,3 @@ +
    +

    <%= link_to proposal.title, proposal_ballots_path %>

    +
    diff --git a/app/views/proposal_ballots/_successfull_proposal.html.erb b/app/views/proposal_ballots/_successfull_proposal.html.erb new file mode 100644 index 000000000..3a8c2a557 --- /dev/null +++ b/app/views/proposal_ballots/_successfull_proposal.html.erb @@ -0,0 +1,13 @@ +
    +

    <%= link_to proposal.title, proposal %>

    +

    <%= proposal.question %>

    +
    + <% if proposal.author.hidden? || proposal.author.erased? %> + <%= t("proposals.show.author_deleted") %> + <% else %> + <%= proposal.author.name %> + <% end %> +  •  + <%= t("proposals.proposal.supports", count: proposal.total_votes) %> +
    +
    diff --git a/app/views/proposal_ballots/index.html.erb b/app/views/proposal_ballots/index.html.erb new file mode 100644 index 000000000..6206a856c --- /dev/null +++ b/app/views/proposal_ballots/index.html.erb @@ -0,0 +1,36 @@ +
    +
    +
    +

    + <%= t("proposal_ballots.title") %> +

    +

    + <%= t("proposal_ballots.description_html", + supports: Setting['votes_for_proposal_success'].to_i).html_safe %> +

    +
    + +
    +

     <%= t("proposal_ballots.date_title") %>

    +

    <%= t("proposal_ballots.date") %>

    +
    +
    +
    + +
    +
    +
    + <% if @proposal_ballots.present? %> +
    + <% @proposal_ballots.each do |proposal_for_vote| %> + <%= render "successfull_proposal", proposal: proposal_for_vote %> + <% end %> +
    + <% else %> +

    + <%= t("proposal_ballots.nothing_to_vote") %> +

    + <% end %> +
    +
    +
    diff --git a/config/routes.rb b/config/routes.rb index 4f3eb94ec..df1a7c6fb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -61,6 +61,8 @@ Rails.application.routes.draw do end end + resources :proposal_ballots, only: [:index] + resources :comments, only: [:create, :show], shallow: true do member do post :vote diff --git a/db/schema.rb b/db/schema.rb index becde4f8a..6124f31d0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -78,6 +78,91 @@ ActiveRecord::Schema.define(version: 20160803154011) do add_index "banners", ["hidden_at"], name: "index_banners_on_hidden_at", using: :btree + create_table "budget_ballot_lines", force: :cascade do |t| + t.integer "ballot_id" + t.integer "investment_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "budget_id" + t.integer "group_id" + t.integer "heading_id" + end + + add_index "budget_ballot_lines", ["ballot_id"], name: "index_budget_ballot_lines_on_ballot_id", using: :btree + add_index "budget_ballot_lines", ["investment_id"], name: "index_budget_ballot_lines_on_investment_id", using: :btree + + create_table "budget_ballots", force: :cascade do |t| + t.integer "user_id" + t.integer "budget_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "budget_groups", force: :cascade do |t| + t.integer "budget_id" + t.string "name", limit: 50 + end + + add_index "budget_groups", ["budget_id"], name: "index_budget_groups_on_budget_id", using: :btree + + create_table "budget_headings", force: :cascade do |t| + t.integer "budget_id" + t.integer "geozone_id" + t.string "name", limit: 50 + t.integer "price", limit: 8 + end + + create_table "budget_investments", force: :cascade do |t| + t.integer "author_id" + t.integer "administrator_id" + t.string "title" + t.text "description" + t.string "external_url" + t.integer "price", limit: 8 + t.string "feasibility", limit: 15, default: "undecided" + t.text "price_explanation" + t.text "unfeasibility_explanation" + t.text "internal_comments" + t.boolean "valuation_finished", default: false + t.integer "valuator_assignments_count", default: 0 + t.integer "price_first_year", limit: 8 + t.string "duration" + t.datetime "hidden_at" + t.integer "cached_votes_up", default: 0 + t.integer "comments_count", default: 0 + t.integer "confidence_score", default: 0, null: false + t.integer "physical_votes", default: 0 + t.tsvector "tsv" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "heading_id" + t.string "responsible_name" + end + + add_index "budget_investments", ["administrator_id"], name: "index_budget_investments_on_administrator_id", using: :btree + add_index "budget_investments", ["author_id"], name: "index_budget_investments_on_author_id", using: :btree + add_index "budget_investments", ["heading_id"], name: "index_budget_investments_on_heading_id", using: :btree + add_index "budget_investments", ["tsv"], name: "index_budget_investments_on_tsv", using: :gin + + create_table "budget_valuator_assignments", force: :cascade do |t| + t.integer "valuator_id" + t.integer "investment_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "budget_valuator_assignments", ["investment_id"], name: "index_budget_valuator_assignments_on_investment_id", using: :btree + + create_table "budgets", force: :cascade do |t| + t.string "name", limit: 30 + t.text "description" + t.string "currency_symbol", limit: 10 + t.string "phase", limit: 15, default: "on_hold" + t.boolean "valuating", default: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "campaigns", force: :cascade do |t| t.string "name" t.string "track_id" @@ -378,6 +463,7 @@ ActiveRecord::Schema.define(version: 20160803154011) do t.integer "proposals_count", default: 0 t.integer "spending_proposals_count", default: 0 t.string "kind" + t.integer "budget/investments_count", default: 0 end add_index "tags", ["debates_count"], name: "index_tags_on_debates_count", using: :btree @@ -484,6 +570,7 @@ ActiveRecord::Schema.define(version: 20160803154011) do t.integer "user_id" t.string "description" t.integer "spending_proposals_count", default: 0 + t.integer "budget_investments_count", default: 0 end add_index "valuators", ["user_id"], name: "index_valuators_on_user_id", using: :btree From b107790039bddd175eb98df13be7b03089832792 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Cabeza Date: Wed, 7 Sep 2016 12:46:29 +0200 Subject: [PATCH 0485/1685] Adds links, texts and i18n --- app/controllers/proposals_controller.rb | 5 +++++ app/models/proposal.rb | 5 +++++ app/views/proposals/_proposal.html.erb | 24 ++++++++++++++++++------ app/views/proposals/index.html.erb | 16 ++++++++++++++-- app/views/proposals/show.html.erb | 18 +++++++++++++----- app/views/shared/_subnavigation.html.erb | 3 +++ config/locales/en.yml | 10 ++++++++++ config/locales/es.yml | 10 ++++++++++ 8 files changed, 78 insertions(+), 13 deletions(-) diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index 578395ab3..898ad9949 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -28,6 +28,7 @@ class ProposalsController < ApplicationController def index_customization load_retired load_featured + load_proposal_ballots end def vote @@ -97,4 +98,8 @@ class ProposalsController < ApplicationController end end + def load_proposal_ballots + @proposal_ballots = Proposal.successfull.sort_by_confidence_score + end + end diff --git a/app/models/proposal.rb b/app/models/proposal.rb index 9a92a8d18..4c3cc9e40 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -47,6 +47,7 @@ class Proposal < ActiveRecord::Base scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)} scope :retired, -> { where.not(retired_at: nil) } scope :not_retired, -> { where(retired_at: nil) } + scope :successfull, -> { where("cached_votes_up + physical_votes >= ?", Proposal.votes_needed_for_success)} def to_param "#{id}-#{title}".parameterize @@ -155,6 +156,10 @@ class Proposal < ActiveRecord::Base Setting['votes_for_proposal_success'].to_i end + def successfull? + total_votes >= Proposal.votes_needed_for_success + end + def notifications proposal_notifications end diff --git a/app/views/proposals/_proposal.html.erb b/app/views/proposals/_proposal.html.erb index 70c2b9c89..464710493 100644 --- a/app/views/proposals/_proposal.html.erb +++ b/app/views/proposals/_proposal.html.erb @@ -1,10 +1,12 @@ -
    +
    Proposal.votes_needed_for_success) %>" + data-type="proposal">
    +
    - <% cache [locale_and_user_status(proposal), 'index', proposal, proposal.author] do %> <%= t("proposals.proposal.proposal") %> @@ -50,11 +52,21 @@
    -
    - <%= render 'votes', - { proposal: proposal, vote_url: vote_proposal_path(proposal, value: 'yes') } %> +
    + <% if proposal.successfull? %> +
    +

    + <%= t("proposal_ballots.successfull", + voting: link_to(t("proposal_ballots.voting"), proposal_ballots_path)).html_safe %> +

    +
    + <% else %> +
    + <%= render 'votes', + { proposal: proposal, vote_url: vote_proposal_path(proposal, value: 'yes') } %> +
    + <% end %>
    -
    diff --git a/app/views/proposals/index.html.erb b/app/views/proposals/index.html.erb index 6f6516890..ff9c23d08 100644 --- a/app/views/proposals/index.html.erb +++ b/app/views/proposals/index.html.erb @@ -30,8 +30,20 @@ <% if has_banners %> <%= render "shared/banner" %> <% end %> - - <% if @featured_proposals.present? %> + + <% if @proposal_ballots.present? %> + + <% elsif @featured_proposals.present? %> - -
    -
    - - -
    - -
    - - -
    - + <%= f.submit t("admin.polls.#{admin_submit_action(@poll)}.submit_button"), + class: "button success expanded" %>
    <% end %> \ No newline at end of file diff --git a/app/views/admin/poll/polls/edit.html.erb b/app/views/admin/poll/polls/edit.html.erb index 0158655a5..cf131203f 100644 --- a/app/views/admin/poll/polls/edit.html.erb +++ b/app/views/admin/poll/polls/edit.html.erb @@ -1,37 +1,5 @@ <%= render 'shared/back_link' %>

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

    -<%= render "form" %> - - - \ No newline at end of file +<%= render "form" %> \ No newline at end of file diff --git a/spec/features/admin/poll/polls_spec.rb b/spec/features/admin/poll/polls_spec.rb index 8d130e67a..bab7b5847 100644 --- a/spec/features/admin/poll/polls_spec.rb +++ b/spec/features/admin/poll/polls_spec.rb @@ -30,7 +30,6 @@ feature 'Admin polls' do Poll.all.each do |poll| within("#poll_#{poll.id}") do expect(page).to have_content poll.name -#expect(page).to have_content "Status/Dates" - Hardcoded end end expect(page).to_not have_content "There are no polls" @@ -43,8 +42,6 @@ feature 'Admin polls' do click_link poll.name expect(page).to have_content poll.name -#expect(page).to have_content "Status/Dates" - Hardcoded -#expect(page).to have_content "REFNUM" - Hardcoded end scenario "Create" do @@ -52,12 +49,9 @@ feature 'Admin polls' do click_link "Create poll" fill_in "poll_name", with: "Upcoming poll" -#fill_in reference_number - Hardcoded -#fill_in open_date - Hardcoded -#fill_in close_date - Hardcoded click_button "Create poll" - expect(page).to have_content "Poll created successfully" + expect(page).to have_content "Poll created successfully" expect(page).to have_content "Upcoming poll" end @@ -66,14 +60,11 @@ feature 'Admin polls' do visit admin_poll_path(poll) click_link "Edit" -save_and_open_page - fill_in "poll_name", with: "Next Poll" -#fill_in reference_number - Hardcoded -#fill_in open_date - Hardcoded -#fill_in close_date - Hardcoded - click_button "Update poll" - expect(page).to have_content "Poll updated successfully" + fill_in "poll_name", with: "Next Poll" + click_button "Update poll" + + expect(page).to have_content "Poll updated successfully" expect(page).to have_content "Next Poll" end From 78c6a30424df21f6743b8812ac7445a23d3594a3 Mon Sep 17 00:00:00 2001 From: Marcia Date: Tue, 27 Sep 2016 13:07:06 +0200 Subject: [PATCH 0589/1685] optimize code --- app/models/user.rb | 6 ++ .../initializers/devise_security_extension.rb | 81 +++++-------------- config/locales/devise.en.yml | 2 +- .../locales/devise.security_extension.de.yml | 16 ---- .../locales/devise.security_extension.en.yml | 16 ---- .../locales/devise.security_extension.it.yml | 10 --- lib/tasks/users.rake | 8 ++ spec/features/users_auth_spec.rb | 15 ++++ 8 files changed, 49 insertions(+), 105 deletions(-) delete mode 100644 config/locales/devise.security_extension.de.yml delete mode 100644 config/locales/devise.security_extension.en.yml delete mode 100644 config/locales/devise.security_extension.it.yml diff --git a/app/models/user.rb b/app/models/user.rb index 633610d9d..1c9ace227 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -57,6 +57,8 @@ before_validation :clean_document_number + before_create :set_password_changed_at + # Get the existing user by email if the provider gives us a verified email. def self.first_or_initialize_for_oauth(auth) oauth_email = auth.info.email @@ -240,6 +242,10 @@ true end + def set_password_changed_at + set_password_changed_at = created_at + end + def ability @ability ||= Ability.new(self) end diff --git a/config/initializers/devise_security_extension.rb b/config/initializers/devise_security_extension.rb index 83b88200e..b38393b75 100644 --- a/config/initializers/devise_security_extension.rb +++ b/config/initializers/devise_security_extension.rb @@ -10,7 +10,7 @@ Devise.setup do |config| # config.password_regex = /(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])/ # How many passwords to keep in archive - # config.password_archiving_count = 5 + #config.password_archiving_count = 5 # Deny old password (true, false, count) # config.deny_old_passwords = true @@ -18,7 +18,6 @@ Devise.setup do |config| # enable email validation for :secure_validatable. (true, false, validation_options) # dependency: need an email validator like rails_email_validator # config.email_validation = true - # captcha integration for recover form # config.captcha_for_recover = true @@ -42,20 +41,22 @@ module Devise module Models module PasswordExpirable def need_change_password? - if self.administrator? - #is administrator - if self.expire_password_after.is_a? Fixnum or self.expire_password_after.is_a? Float - self.password_changed_at.nil? or self.password_changed_at < self.expire_password_after.ago - else - #not change password - false - end - else - #It is not an administrator - false + if password_change? + password_expired? + else + false end end - end + + def password_change? + self.administrator? && password_expired? + end + + def password_expired? + self.password_changed_at < self.expire_password_after.ago + end + + end #module PasswordExpirable module SecureValidatable def self.included(base) @@ -63,24 +64,11 @@ module Devise assert_secure_validations_api!(base) base.class_eval do - # validate login in a strict way if not yet validated - unless devise_validation_enabled? - validates :email, :presence => true, :if => :email_required? - validates :email, :uniqueness => true, :allow_blank => true, :if => :email_changed? # check uniq for email ever - validates :password, :presence => true, :length => password_length, :confirmation => true, :if => :password_required? - end - - # extra validations - #validates :password, :format => { :with => password_regex, :message => :password_format }, :if => :password_required? - # don't allow use same password + validate :current_equal_password_validation end end - def self.assert_secure_validations_api!(base) - raise "Could not use SecureValidatable on #{base}" unless base.respond_to?(:validates) - end - def current_equal_password_validation if !self.new_record? && !self.encrypted_password_change.nil? && !self.erased? dummy = self.class.new @@ -90,38 +78,7 @@ module Devise end end - protected + end #module SecureValidatable - # Checks whether a password is needed or not. For validations only. - # Passwords are always required if it's a new record, or if the password - # or confirmation are being set somewhere. - def password_required? - !persisted? || !password.nil? || !password_confirmation.nil? - end - - def email_required? - true - end - - module ClassMethods - Devise::Models.config(self, :password_regex, :password_length, :email_validation) - - private - def has_uniqueness_validation_of_login? - validators.any? do |validator| - validator.kind_of?(ActiveRecord::Validations::UniquenessValidator) && - validator.attributes.include?(login_attribute) - end - end - - def login_attribute - authentication_keys[0] - end - - def devise_validation_enabled? - self.ancestors.map(&:to_s).include? 'Devise::Models::Validatable' - end - end - end - end -end \ No newline at end of file + end #module Models +end #module Devise \ No newline at end of file diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml index f031d62b5..29bc0a620 100755 --- a/config/locales/devise.en.yml +++ b/config/locales/devise.en.yml @@ -4,7 +4,7 @@ en: devise: password_expired: expire_password: "Password expired" - change_required: "Your password has expired" + change_required: "Your password is expired" change_password: "Change your password" new_password: "New password" updated: "Password successfully updated" diff --git a/config/locales/devise.security_extension.de.yml b/config/locales/devise.security_extension.de.yml deleted file mode 100644 index cad39d9b7..000000000 --- a/config/locales/devise.security_extension.de.yml +++ /dev/null @@ -1,16 +0,0 @@ -de: - errors: - messages: - taken_in_past: "wurde bereits in der Vergangenheit verwendet!" - equal_to_current_password: "darf nicht dem aktuellen Passwort entsprechen!" - password_format: "müssen große, kleine Buchstaben und Ziffern enthalten" - devise: - invalid_captcha: "Die Captchaeingabe ist nicht gültig!" - paranoid_verify: - code_required: "Bitte geben Sie den Code unser Support-Team zur Verfügung gestellt" - password_expired: - updated: "Das neue Passwort wurde übernommen." - change_required: "Ihr Passwort ist abgelaufen. Bitte vergeben sie ein neues Passwort!" - failure: - session_limited: 'Ihre Anmeldedaten wurden in einem anderen Browser genutzt. Bitte melden Sie sich erneut an, um in diesem Browser fortzufahren.' - expired: 'Ihr Account ist aufgrund zu langer Inaktiviät abgelaufen. Bitte kontaktieren Sie den Administrator.' diff --git a/config/locales/devise.security_extension.en.yml b/config/locales/devise.security_extension.en.yml deleted file mode 100644 index e73d6e245..000000000 --- a/config/locales/devise.security_extension.en.yml +++ /dev/null @@ -1,16 +0,0 @@ -en: - errors: - messages: - taken_in_past: "was used previously." - equal_to_current_password: "must be different than the current password." - password_format: "must contain big, small letters and digits" - devise: - invalid_captcha: "The captcha input was invalid." - paranoid_verify: - code_required: "Please enter the code our support team provided" - password_expired: - updated: "Your new password is saved." - change_required: "Your password is expired. Please renew your password." - failure: - session_limited: 'Your login credentials were used in another browser. Please sign in again to continue in this browser.' - expired: 'Your account has expired due to inactivity. Please contact the site administrator.' diff --git a/config/locales/devise.security_extension.it.yml b/config/locales/devise.security_extension.it.yml deleted file mode 100644 index 646ae4ea0..000000000 --- a/config/locales/devise.security_extension.it.yml +++ /dev/null @@ -1,10 +0,0 @@ -it: - errors: - messages: - taken_in_past: "e' stata gia' utilizzata in passato!" - equal_to_current_password: " deve essere differente dalla password corrente!" - devise: - invalid_captcha: "Il captcha inserito non e' valido!" - password_expired: - updated: "La tua nuova password e' stata salvata." - change_required: "La tua password e' scaduta. Si prega di rinnovarla!" \ No newline at end of file diff --git a/lib/tasks/users.rake b/lib/tasks/users.rake index efbeeaa94..98fcae5d2 100644 --- a/lib/tasks/users.rake +++ b/lib/tasks/users.rake @@ -76,4 +76,12 @@ namespace :users do task remove_erased_identities: :environment do Identity.joins(:user).where('users.erased_at IS NOT NULL').destroy_all end + + desc "Update password changed at for existing users" + task update_password_changed_at: :environment do + User.all.each do |user| + user.update(password_changed_at:user.created_at) + end + end + end diff --git a/spec/features/users_auth_spec.rb b/spec/features/users_auth_spec.rb index 1b365f16d..f16772fd4 100644 --- a/spec/features/users_auth_spec.rb +++ b/spec/features/users_auth_spec.rb @@ -322,4 +322,19 @@ feature 'Users' do expect(page).to_not have_content "Your password is expired" end + scenario 'Admin with password expired trying to use same password' do + user = create(:user, password_changed_at: Time.now - 1.year, password: '123456789') + admin = create(:administrator, user: user) + login_as(admin.user) + visit root_path + expect(page).to have_content "Your password is expired" + fill_in 'user_current_password', with: 'judgmentday' + fill_in 'user_password', with: '123456789' + fill_in 'user_password_confirmation', with: '123456789' + click_button 'Change your password' + expect(page).to have_content "must be different than the current password." + #expect(page).to have_content "You can not use the same password. Please choose another one." + end + + end From 042cb14dbdbf198d65e825d9c0310d41f07a795a Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 28 Sep 2016 11:53:46 +0200 Subject: [PATCH 0590/1685] moves poll spec to poll folder --- spec/models/{ => poll}/poll_spec.rb | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename spec/models/{ => poll}/poll_spec.rb (100%) diff --git a/spec/models/poll_spec.rb b/spec/models/poll/poll_spec.rb similarity index 100% rename from spec/models/poll_spec.rb rename to spec/models/poll/poll_spec.rb From f3ad806c8b1433eda70c5076f8cea89f99e20c44 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 28 Sep 2016 11:54:29 +0200 Subject: [PATCH 0591/1685] updates dev seeds with booths --- db/dev_seeds.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/db/dev_seeds.rb b/db/dev_seeds.rb index beb1d815f..2fe812ea5 100644 --- a/db/dev_seeds.rb +++ b/db/dev_seeds.rb @@ -341,4 +341,8 @@ puts "Creating polls" 3.times.each_with_index do |i| Poll.create(name: "Poll #{i}") +end + +10.times.each_with_index do |i| + Poll::Booth.create(name: "Booth #{i}", poll: Poll.all.sample) end \ No newline at end of file From 7db3683c27f1b6f9a56a2b1429463fca80d98b64 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 28 Sep 2016 11:55:11 +0200 Subject: [PATCH 0592/1685] adds consistency to syntax --- app/views/admin/poll/polls/index.html.erb | 2 +- config/routes.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/poll/polls/index.html.erb b/app/views/admin/poll/polls/index.html.erb index 2954e44b8..b4c18d21b 100644 --- a/app/views/admin/poll/polls/index.html.erb +++ b/app/views/admin/poll/polls/index.html.erb @@ -4,7 +4,7 @@ new_admin_poll_path, class: "button success float-right" %> -<% if Poll.any? %> +<% if @polls.any? %> diff --git a/config/routes.rb b/config/routes.rb index 070823d63..f682ab529 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -177,7 +177,7 @@ Rails.application.routes.draw do get :search, on: :collection end - scope module: 'poll' do + scope module: :poll do resources :officers do get :search, on: :collection end From 2c3127b6bd74916420cb70e30f39b3e0bf879a9c Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 28 Sep 2016 11:56:19 +0200 Subject: [PATCH 0593/1685] adds booth backend for index, show, create and edit actions --- .../admin/poll/booths_controller.rb | 31 +++- app/models/abilities/administrator.rb | 5 +- app/models/poll/booth.rb | 2 + app/views/admin/poll/booths/_form.html.erb | 20 +++ app/views/admin/poll/booths/edit.html.erb | 29 +--- app/views/admin/poll/booths/index.html.erb | 49 +++--- app/views/admin/poll/booths/new.html.erb | 29 +--- app/views/admin/poll/booths/show.html.erb | 13 +- app/views/admin/poll/polls/show.html.erb | 4 +- config/locales/admin.en.yml | 4 +- config/locales/responders.en.yml | 2 + config/locales/responders.es.yml | 3 + .../20160926090107_add_location_to_booths.rb | 5 + db/schema.rb | 11 +- spec/factories.rb | 1 + spec/features/admin/poll/booths_spec.rb | 146 ++++++++++++++++++ spec/models/abilities/administrator_spec.rb | 3 + spec/models/poll/booth_spec.rb | 16 ++ 18 files changed, 288 insertions(+), 85 deletions(-) create mode 100644 app/views/admin/poll/booths/_form.html.erb create mode 100644 db/migrate/20160926090107_add_location_to_booths.rb create mode 100644 spec/features/admin/poll/booths_spec.rb create mode 100644 spec/models/poll/booth_spec.rb diff --git a/app/controllers/admin/poll/booths_controller.rb b/app/controllers/admin/poll/booths_controller.rb index 9b1e62f8f..95057ce2f 100644 --- a/app/controllers/admin/poll/booths_controller.rb +++ b/app/controllers/admin/poll/booths_controller.rb @@ -1,5 +1,8 @@ class Admin::Poll::BoothsController < Admin::BaseController - skip_authorization_check + load_and_authorize_resource :poll + load_and_authorize_resource class: 'Poll::Booth', through: :poll + + before_action :load_polls, only: :index def index end @@ -10,7 +13,33 @@ class Admin::Poll::BoothsController < Admin::BaseController def new end + def create + if @booth.save + redirect_to admin_poll_booth_path(@poll, @booth), notice: t("flash.actions.create.poll_booth") + else + render :new + end + end + def edit end + def update + if @booth.update(booth_params) + redirect_to admin_poll_booth_path(@poll, @booth), notice: t("flash.actions.update.poll_booth") + else + render :edit + end + end + + private + + def booth_params + params.require(:poll_booth).permit(:name, :location) + end + + def load_polls + @polls = Poll.all + end + end \ No newline at end of file diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index bd74e1be9..a0e040ab3 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -40,12 +40,13 @@ module Abilities can [:search, :create, :index, :destroy], ::Manager can [:search, :create, :index, :destroy], ::Poll::Officer - can [:manage], Poll - can :manage, Annotation can [:read, :update, :destroy, :summary], SpendingProposal can [:search, :edit, :update, :create, :index, :destroy], Banner + + can [:manage], Poll + can [:manage], Poll::Booth end end end diff --git a/app/models/poll/booth.rb b/app/models/poll/booth.rb index a05f3d547..eb7d81b8c 100644 --- a/app/models/poll/booth.rb +++ b/app/models/poll/booth.rb @@ -2,5 +2,7 @@ class Poll class Booth < ActiveRecord::Base belongs_to :poll has_many :voters + + validates :name, presence: true end end \ No newline at end of file diff --git a/app/views/admin/poll/booths/_form.html.erb b/app/views/admin/poll/booths/_form.html.erb new file mode 100644 index 000000000..31d60c0f0 --- /dev/null +++ b/app/views/admin/poll/booths/_form.html.erb @@ -0,0 +1,20 @@ +
    +
    + <%= f.text_field :name, + placeholder: t('admin.booths.new.name'), + label: t("admin.booths.new.name") %> +
    + +
    + <%= f.text_field :location, + placeholder: t("admin.booths.new.location"), + label: t("admin.booths.new.location") %> +
    +
    + +
    +
    + <%= f.submit t("admin.booths.#{admin_submit_action(@booth)}.submit_button"), + class: "button success expanded" %> +
    +
    \ No newline at end of file diff --git a/app/views/admin/poll/booths/edit.html.erb b/app/views/admin/poll/booths/edit.html.erb index e48db9cdd..23d825b91 100644 --- a/app/views/admin/poll/booths/edit.html.erb +++ b/app/views/admin/poll/booths/edit.html.erb @@ -1,28 +1,7 @@ <%= render 'shared/back_link' %> -

    <%= t("admin.booths.edit.title") %>: <%= t("admin.booths.edit.subtitle") %>

    +

    <%= t("admin.booths.edit.title", poll: @poll.name) %>: <%= t("admin.booths.edit.subtitle") %>

    -
    -
    -
    - - -
    - -
    - - -
    - -
    - - "> -
    -
    - -
    -
    - -
    -
    - +<%= form_for @booth, url: admin_poll_booth_path(@poll, @booth) do |f| %> + <%= render "form", f: f %> +<% end %> diff --git a/app/views/admin/poll/booths/index.html.erb b/app/views/admin/poll/booths/index.html.erb index 918479f38..b3733670d 100644 --- a/app/views/admin/poll/booths/index.html.erb +++ b/app/views/admin/poll/booths/index.html.erb @@ -1,22 +1,27 @@

    <%= t("admin.booths.index.title") %>

    -
    -
    - -
    - - -

    <%= t("admin.booths.index.title_list") %>

    - - -
    - <%= t("admin.booths.index.no_booths") %> +
    + <%= form_tag '', method: :get do %> + <%= select_tag "poll_id", + options_for_select(@polls.collect {|poll| + [poll.name, admin_poll_booths_path(poll)] + }), + prompt: t("admin.booths.index.select_poll"), + class: "js-location-changer" %> + <% end %>
    - -<%= link_to t("admin.booths.index.add_booth"), new_admin_poll_booth_path, class: "button success" %> +

    <%= t("admin.booths.index.title_list", poll: @poll.name) %>

    + +<% if @booths.empty? %> +
    + <%= t("admin.booths.index.no_booths") %> +
    +<% end %> + +<%= link_to t("admin.booths.index.add_booth"), + new_admin_poll_booth_path, + class: "button success" %>
    <%= t("admin.polls.index.name") %>
    @@ -26,23 +31,25 @@ - - + <% @booths.each do |booth| %> + - + <% end %>
     
    - <%= link_to "Urna Moncloa (REFNUM)", "booths/1" %> + <%= link_to booth.name, admin_poll_booth_path(@poll, booth) %> - C/ Isaac Peral, 25. 28003, Madrid + <%= booth.location %> N <%= t("admin.booths.index.officers") %> - <%= link_to t("admin.actions.edit"), "booths/1/edit", class: "button hollow" %> + <%= link_to t("admin.actions.edit"), + edit_admin_poll_booth_path(@poll, booth), + class: "button hollow" %>
    diff --git a/app/views/admin/poll/booths/new.html.erb b/app/views/admin/poll/booths/new.html.erb index e83d2f47c..cffcfab72 100644 --- a/app/views/admin/poll/booths/new.html.erb +++ b/app/views/admin/poll/booths/new.html.erb @@ -1,28 +1,7 @@ <%= render 'shared/back_link' %> -

    <%= t("admin.booths.new.title") %>: <%= t("admin.booths.new.subtitle") %>

    +

    <%= t("admin.booths.new.title", poll: @poll.name) %>: <%= t("admin.booths.new.subtitle") %>

    -
    -
    -
    - - -
    - -
    - - -
    - -
    - - "> -
    -
    - -
    -
    - -
    -
    -
    +<%= form_for @booth, url: admin_poll_booths_path(@poll) do |f| %> + <%= render "form", f: f %> +<% end %> \ No newline at end of file diff --git a/app/views/admin/poll/booths/show.html.erb b/app/views/admin/poll/booths/show.html.erb index 34e1a4465..55f7d5504 100644 --- a/app/views/admin/poll/booths/show.html.erb +++ b/app/views/admin/poll/booths/show.html.erb @@ -1,10 +1,17 @@ <%= render 'shared/back_link' %>
    -

    Urna Moncloa (REFNUM)

    -<%= link_to t("admin.actions.edit"), "1/edit", class: "button hollow float-right" %> +

    + <%= @booth.name %> +

    +<%= link_to t("admin.actions.edit"), + edit_admin_poll_booth_path(@poll, @booth), + class: "button hollow float-right" %> -

    <%= t("admin.booths.show.location") %>: C/ Isaac Peral, 25. 28003, Madrid

    +

    + <%= t("admin.booths.show.location") %>: + <%= @booth.location %> +

    <%= t("admin.booths.show.officers_list") %>

    diff --git a/app/views/admin/poll/polls/show.html.erb b/app/views/admin/poll/polls/show.html.erb index 1b0d1e198..17248d4b9 100644 --- a/app/views/admin/poll/polls/show.html.erb +++ b/app/views/admin/poll/polls/show.html.erb @@ -5,7 +5,9 @@ <%= @poll.name %> -<%= link_to t("admin.actions.edit"), edit_admin_poll_path(@poll), class: "button hollow float-right" %> +<%= link_to t("admin.actions.edit"), + edit_admin_poll_path(@poll), + class: "button hollow float-right" %>

    (REFNUM)

    Próximamente (15/12/2016 - 15/02/2017)

    diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index bb8093b03..db4cf34ca 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -174,7 +174,7 @@ en: close_date: "Close date" submit_button: "Update poll" show: - no_booths: "There is no booths in this poll." + no_booths: "There are no booths in this poll." add_booth: "Add booth" booths_title: "List of booths" name: "Name" @@ -184,7 +184,7 @@ en: title: "List of booths" select_poll: "Select a poll" title_list: "List of booths of poll %{poll}" - no_booths: "There is no booths in this poll." + no_booths: "There are no booths in this poll." add_booth: "Add booth" name: "Name" location: "Location" diff --git a/config/locales/responders.en.yml b/config/locales/responders.en.yml index 422a59e0c..68d77b0d2 100755 --- a/config/locales/responders.en.yml +++ b/config/locales/responders.en.yml @@ -7,6 +7,7 @@ en: debate: "Debate created successfully." direct_message: "You message has been sent successfully." poll: "Poll created successfully." + poll_booth: "Booth created successfully." proposal: "Proposal created successfully." proposal_notification: "Your message has been sent correctly." spending_proposal: "Spending proposal created successfully. You can access it from %{activity}" @@ -16,6 +17,7 @@ en: notice: "%{resource_name} updated successfully." debate: "Debate updated successfully." poll: "Poll updated successfully." + poll_booth: "Booth updated successfully." proposal: "Proposal updated successfully." spending_proposal: "Investment project updated succesfully." destroy: diff --git a/config/locales/responders.es.yml b/config/locales/responders.es.yml index c9292b187..105b00903 100644 --- a/config/locales/responders.es.yml +++ b/config/locales/responders.es.yml @@ -7,6 +7,7 @@ es: debate: "Debate creado correctamente." direct_message: "Tu mensaje ha sido enviado correctamente." poll: "Votación presencial creada correctamente." + poll_booth: "Urna creada correctamente." proposal: "Propuesta creada correctamente." proposal_notification: "Tu message ha sido enviado correctamente." spending_proposal: "Propuesta de inversión creada correctamente. Puedes acceder a ella desde %{activity}" @@ -16,6 +17,8 @@ es: notice: "%{resource_name} actualizado correctamente." debate: "Debate actualizado correctamente." proposal: "Propuesta actualizada correctamente." + poll: "Votación presencial actualizada correctamente." + poll_booth: "Urna actualizada correctamente." spending_proposal: "Propuesta de inversión actualizada correctamente." destroy: spending_proposal: "Propuesta de inversión eliminada." \ No newline at end of file diff --git a/db/migrate/20160926090107_add_location_to_booths.rb b/db/migrate/20160926090107_add_location_to_booths.rb new file mode 100644 index 000000000..146f55d41 --- /dev/null +++ b/db/migrate/20160926090107_add_location_to_booths.rb @@ -0,0 +1,5 @@ +class AddLocationToBooths < ActiveRecord::Migration + def change + add_column :poll_booths, :location, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 205fc5f21..493dfbe3a 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: 20160914172535) do +ActiveRecord::Schema.define(version: 20160926090107) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -273,6 +273,11 @@ ActiveRecord::Schema.define(version: 20160914172535) do create_table "poll_booths", force: :cascade do |t| t.string "name" t.integer "poll_id" + t.string "location" + end + + create_table "poll_officers", force: :cascade do |t| + t.integer "user_id" end create_table "poll_voters", force: :cascade do |t| @@ -281,10 +286,6 @@ ActiveRecord::Schema.define(version: 20160914172535) do t.string "document_type" end - create_table "poll_officers", force: :cascade do |t| - t.integer "user_id" - end - create_table "polls", force: :cascade do |t| t.string "name" end diff --git a/spec/factories.rb b/spec/factories.rb index ac7bb379b..f7e09b7e8 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -269,6 +269,7 @@ FactoryGirl.define do factory :poll_booth, class: 'Poll::Booth' do sequence(:name) { |n| "Booth #{n}" } + sequence(:location) { |n| "Street #{n}" } poll end diff --git a/spec/features/admin/poll/booths_spec.rb b/spec/features/admin/poll/booths_spec.rb new file mode 100644 index 000000000..ad46c67fb --- /dev/null +++ b/spec/features/admin/poll/booths_spec.rb @@ -0,0 +1,146 @@ +require 'rails_helper' + +feature 'Admin booths' do + + let!(:poll) { create(:poll) } + + background do + admin = create(:administrator) + login_as(admin.user) + end + + scenario 'Index empty' do + visit admin_root_path + + within('#side_menu') do + click_link "Booths" + end + + expect(page).to have_content "There are no booths in this poll" + end + + scenario 'No link to booths when no polls' do + Poll.destroy_all + + visit admin_root_path + + within('#side_menu') do + expect(page).to_not have_link "Booths" + end + end + + scenario 'Index' do + 3.times { create(:poll_booth, poll: poll) } + + visit admin_root_path + + within('#side_menu') do + click_link "Booths" + end + + expect(page).to have_css ".booth", count: 3 + + booths = Poll::Booth.all + booths.each do |booth| + within("#booth_#{booth.id}") do + expect(page).to have_content booth.name + expect(page).to have_content booth.location + end + end + expect(page).to_not have_content "There are no booths" + end + + scenario "Index default to last poll" do + poll1 = create(:poll) + poll2 = create(:poll) + + booth1 = create(:poll_booth, poll: poll1) + booth2 = create(:poll_booth, poll: poll2) + + visit admin_root_path + + within('#side_menu') do + click_link "Booths" + end + + expect(page).to have_css ".booth", count: 1 + expect(page).to have_content booth2.name + expect(page).to_not have_content booth1.name + end + + scenario "Index select poll", :js do + poll1 = create(:poll) + poll2 = create(:poll) + + booth1 = create(:poll_booth, poll: poll1) + booth2 = create(:poll_booth, poll: poll2) + + visit admin_root_path + + within('#side_menu') do + click_link "Booths" + end + + select poll1.name, from: "poll_id" + + expect(page).to have_content "List of booths of poll #{poll1.name}" + expect(page).to have_css ".booth", count: 1 + expect(page).to have_content booth1.name + expect(page).to_not have_content booth2.name + end + + scenario 'Show' do + booth = create(:poll_booth, poll: poll) + + visit admin_poll_booths_path(poll) + click_link booth.name + + expect(page).to have_content booth.name + expect(page).to have_content booth.location + end + + scenario "Create" do + visit admin_poll_booths_path(poll) + click_link "Add booth" + + expect(page).to have_content "Poll #{poll.name}" + + fill_in "poll_booth_name", with: "Upcoming booth" + fill_in "poll_booth_location", with: "39th Street, number 2, ground floor" + click_button "Create booth" + + expect(page).to have_content "Booth created successfully" + expect(page).to have_content "Upcoming booth" + expect(page).to have_content "39th Street, number 2, ground floor" + end + + scenario "Edit" do + booth = create(:poll_booth, poll: poll) + + visit admin_poll_booths_path(poll) + + click_link "Edit" + + expect(page).to have_content "Poll #{poll.name}" + + fill_in "poll_booth_name", with: "Next booth" + fill_in "poll_booth_location", with: "40th Street, number 1, firts floor" + click_button "Update booth" + + expect(page).to have_content "Booth updated successfully" + expect(page).to have_content "Next booth" + expect(page).to have_content "40th Street, number 1, firts floor" + end + + scenario 'Edit from index' do + booth = create(:poll_booth, poll: poll) + visit admin_poll_booths_path(poll) + + within("#booth_#{booth.id}") do + click_link "Edit" + end + + expect(current_path).to eq(edit_admin_poll_booth_path(poll, booth)) + end + +end \ No newline at end of file diff --git a/spec/models/abilities/administrator_spec.rb b/spec/models/abilities/administrator_spec.rb index f9ed7a0c5..04fd199f0 100644 --- a/spec/models/abilities/administrator_spec.rb +++ b/spec/models/abilities/administrator_spec.rb @@ -56,4 +56,7 @@ describe "Abilities::Administrator" do it { should be_able_to(:update, SpendingProposal) } it { should be_able_to(:valuate, SpendingProposal) } it { should be_able_to(:destroy, SpendingProposal) } + + it { should be_able_to(:manage, Poll) } + it { should be_able_to(:manage, Poll::Booth) } end diff --git a/spec/models/poll/booth_spec.rb b/spec/models/poll/booth_spec.rb new file mode 100644 index 000000000..2fabb9c12 --- /dev/null +++ b/spec/models/poll/booth_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' + +describe :booth do + + let(:booth) { build(:poll_booth) } + + it "should be valid" do + expect(booth).to be_valid + end + + it "should not be valid without a name" do + booth.name = nil + expect(booth).to_not be_valid + end + +end \ No newline at end of file From a8ea86fae1f84f7ff39a542146b3609ec8eb6e7f Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 28 Sep 2016 11:56:48 +0200 Subject: [PATCH 0594/1685] removes unused attributes from poll show --- app/views/admin/poll/polls/_poll.html.erb | 4 ---- app/views/admin/poll/polls/show.html.erb | 2 -- 2 files changed, 6 deletions(-) diff --git a/app/views/admin/poll/polls/_poll.html.erb b/app/views/admin/poll/polls/_poll.html.erb index 4128ad222..d90fed14a 100644 --- a/app/views/admin/poll/polls/_poll.html.erb +++ b/app/views/admin/poll/polls/_poll.html.erb @@ -4,10 +4,6 @@ <%= link_to poll.name, admin_poll_path(poll) %>
    - - Próximamente -
    (15/12/2016 - 15/02/2017) - <%= link_to t("admin.actions.edit"), edit_admin_poll_path(poll), diff --git a/app/views/admin/poll/polls/show.html.erb b/app/views/admin/poll/polls/show.html.erb index 17248d4b9..8a02ebfd7 100644 --- a/app/views/admin/poll/polls/show.html.erb +++ b/app/views/admin/poll/polls/show.html.erb @@ -9,8 +9,6 @@ edit_admin_poll_path(@poll), class: "button hollow float-right" %> -

    (REFNUM)

    -

    Próximamente (15/12/2016 - 15/02/2017)

    <%= link_to t("admin.polls.show.add_booth"), "#", class: "button success" %> From e97e7e20dc27339ea932ff148ce59022ab72ca44 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 28 Sep 2016 12:01:58 +0200 Subject: [PATCH 0595/1685] maintains poll date and status in index for demo --- app/views/admin/poll/polls/_poll.html.erb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/views/admin/poll/polls/_poll.html.erb b/app/views/admin/poll/polls/_poll.html.erb index d90fed14a..4128ad222 100644 --- a/app/views/admin/poll/polls/_poll.html.erb +++ b/app/views/admin/poll/polls/_poll.html.erb @@ -4,6 +4,10 @@ <%= link_to poll.name, admin_poll_path(poll) %> + + Próximamente +
    (15/12/2016 - 15/02/2017) + <%= link_to t("admin.actions.edit"), edit_admin_poll_path(poll), From 6387d281578bd00cd7b9f10a5e10ec3cd8379910 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 28 Sep 2016 12:34:24 +0200 Subject: [PATCH 0596/1685] adds booth info to poll show --- app/views/admin/poll/booths/_booth.html.erb | 18 +++++++ app/views/admin/poll/booths/index.html.erb | 21 +------- app/views/admin/poll/polls/show.html.erb | 55 +++++++++------------ config/locales/admin.en.yml | 1 + config/locales/admin.es.yml | 1 + spec/features/admin/poll/polls_spec.rb | 44 ++++++++++++++++- 6 files changed, 88 insertions(+), 52 deletions(-) create mode 100644 app/views/admin/poll/booths/_booth.html.erb diff --git a/app/views/admin/poll/booths/_booth.html.erb b/app/views/admin/poll/booths/_booth.html.erb new file mode 100644 index 000000000..ff1683867 --- /dev/null +++ b/app/views/admin/poll/booths/_booth.html.erb @@ -0,0 +1,18 @@ + + + + <%= link_to booth.name, admin_poll_booth_path(@poll, booth) %> + + + + <%= booth.location %> + + + N <%= t("admin.booths.index.officers") %> + + + <%= link_to t("admin.actions.edit"), + edit_admin_poll_booth_path(@poll, booth), + class: "button hollow" %> + + \ No newline at end of file diff --git a/app/views/admin/poll/booths/index.html.erb b/app/views/admin/poll/booths/index.html.erb index b3733670d..d2a9a7e5a 100644 --- a/app/views/admin/poll/booths/index.html.erb +++ b/app/views/admin/poll/booths/index.html.erb @@ -20,7 +20,7 @@ <% end %> <%= link_to t("admin.booths.index.add_booth"), - new_admin_poll_booth_path, + new_admin_poll_booth_path(@poll), class: "button success" %> @@ -32,24 +32,7 @@ <% @booths.each do |booth| %> - - - - - - + <%= render partial: "booth", locals: { booth: booth } %> <% end %>
    - - <%= link_to booth.name, admin_poll_booth_path(@poll, booth) %> - - - <%= booth.location %> - - N <%= t("admin.booths.index.officers") %> - - <%= link_to t("admin.actions.edit"), - edit_admin_poll_booth_path(@poll, booth), - class: "button hollow" %> -
    diff --git a/app/views/admin/poll/polls/show.html.erb b/app/views/admin/poll/polls/show.html.erb index 8a02ebfd7..bed01af41 100644 --- a/app/views/admin/poll/polls/show.html.erb +++ b/app/views/admin/poll/polls/show.html.erb @@ -9,37 +9,28 @@ edit_admin_poll_path(@poll), class: "button hollow float-right" %> -<%= link_to t("admin.polls.show.add_booth"), "#", class: "button success" %> +<%= link_to t("admin.polls.show.add_booth"), + new_admin_poll_booth_path(@poll), + class: "button success" %> - -
    - <%= t("admin.polls.show.no_booths") %> -
    - +<% if @poll.booths.empty? %> +
    + <%= t("admin.polls.show.no_booths") %> +
    +<% else %> +

    <%= t("admin.polls.show.booths_title") %>

    -

    <%= t("admin.polls.show.booths_title") %>

    - - - - - - - - - <%= @poll.booths.each do |booth| %> - - - - - - <% end %> - -
    <%= t("admin.polls.show.name") %><%= t("admin.polls.show.location") %> 
    - - <%= link_to "Urna Moncloa (REFNUM)", "#" %> - - - C/ Isaac Peral, 25. 28003, Madrid - - <%= link_to t("admin.actions.edit"), "#", class: "button hollow" %> -
    + + + + + + + + + <% @poll.booths.each do |booth| %> + <%= render partial: "admin/poll/booths/booth", locals: { booth: booth } %> + <% end %> + +
    <%= t("admin.polls.show.name") %><%= t("admin.polls.show.location") %><%= t("admin.polls.show.officers") %> 
    +<% end %> \ No newline at end of file diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index db4cf34ca..ef294262d 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -179,6 +179,7 @@ en: booths_title: "List of booths" name: "Name" location: "Location" + officers: "Officers" booths: index: title: "List of booths" diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index 6023da712..48dfe2959 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -179,6 +179,7 @@ es: booths_title: "Listado de urnas" name: "Nombre" location: "Ubicación" + officers: "Presidentes de mesa" booths: index: title: "Lista de urnas" diff --git a/spec/features/admin/poll/polls_spec.rb b/spec/features/admin/poll/polls_spec.rb index bab7b5847..80f875567 100644 --- a/spec/features/admin/poll/polls_spec.rb +++ b/spec/features/admin/poll/polls_spec.rb @@ -27,7 +27,8 @@ feature 'Admin polls' do expect(page).to have_css ".poll", count: 3 - Poll.all.each do |poll| + polls = Poll.all + polls.each do |poll| within("#poll_#{poll.id}") do expect(page).to have_content poll.name end @@ -79,4 +80,45 @@ feature 'Admin polls' do expect(current_path).to eq(edit_admin_poll_path(poll)) end + context "Booths" do + + context "Poll show" do + + scenario "No booths" do + poll = create(:poll) + visit admin_poll_path(poll) + + expect(page).to have_content "There are no booths in this poll." + end + + scenario "Booth list" do + poll = create(:poll) + 3.times { create(:poll_booth, poll: poll) } + + visit admin_poll_path(poll) + + expect(page).to have_css ".booth", count: 3 + + booths = Poll::Booth.all + booths.each do |booth| + within("#booth_#{booth.id}") do + expect(page).to have_content booth.name + expect(page).to have_content booth.location + end + end + expect(page).to_not have_content "There are no booths" + end + + scenario "Add booth" do + poll = create(:poll) + visit admin_poll_path(poll) + + click_link "Add booth" + + expect(current_path).to eq(new_admin_poll_booth_path(poll)) + expect(page).to have_content poll.name + end + end + end + end \ No newline at end of file From 527b734e0ebae60f30c76e03e7a5082eacdad0a4 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Wed, 28 Sep 2016 18:39:01 +0200 Subject: [PATCH 0597/1685] assigns officers to booths --- .../admin/poll/booths_controller.rb | 3 +- app/helpers/officers_helper.rb | 7 + app/models/poll/booth.rb | 2 + app/models/poll/officing_booth.rb | 6 + app/views/admin/poll/booths/show.html.erb | 40 +++--- config/locales/admin.en.yml | 2 +- .../20160928113143_create_officing_booths.rb | 9 ++ db/schema.rb | 9 +- spec/factories.rb | 5 + spec/features/admin/poll/officers_spec.rb | 129 +++++++++++++++++- 10 files changed, 185 insertions(+), 27 deletions(-) create mode 100644 app/helpers/officers_helper.rb create mode 100644 app/models/poll/officing_booth.rb create mode 100644 db/migrate/20160928113143_create_officing_booths.rb diff --git a/app/controllers/admin/poll/booths_controller.rb b/app/controllers/admin/poll/booths_controller.rb index 95057ce2f..1d05ddab5 100644 --- a/app/controllers/admin/poll/booths_controller.rb +++ b/app/controllers/admin/poll/booths_controller.rb @@ -8,6 +8,7 @@ class Admin::Poll::BoothsController < Admin::BaseController end def show + @officers = Poll::Officer.all end def new @@ -35,7 +36,7 @@ class Admin::Poll::BoothsController < Admin::BaseController private def booth_params - params.require(:poll_booth).permit(:name, :location) + params.require(:poll_booth).permit(:name, :location, officer_ids: []) end def load_polls diff --git a/app/helpers/officers_helper.rb b/app/helpers/officers_helper.rb new file mode 100644 index 000000000..f29bcf728 --- /dev/null +++ b/app/helpers/officers_helper.rb @@ -0,0 +1,7 @@ +module OfficersHelper + + def officer_label(officer) + truncate([officer.name, officer.email].compact.join(' - '), length: 100) + end + +end \ No newline at end of file diff --git a/app/models/poll/booth.rb b/app/models/poll/booth.rb index eb7d81b8c..74c4c3edb 100644 --- a/app/models/poll/booth.rb +++ b/app/models/poll/booth.rb @@ -2,6 +2,8 @@ class Poll class Booth < ActiveRecord::Base belongs_to :poll has_many :voters + has_many :officing_booths, dependent: :destroy + has_many :officers, through: :officing_booths validates :name, presence: true end diff --git a/app/models/poll/officing_booth.rb b/app/models/poll/officing_booth.rb new file mode 100644 index 000000000..f0a64721a --- /dev/null +++ b/app/models/poll/officing_booth.rb @@ -0,0 +1,6 @@ +class Poll + class OfficingBooth < ActiveRecord::Base + belongs_to :officer + belongs_to :booth + end +end diff --git a/app/views/admin/poll/booths/show.html.erb b/app/views/admin/poll/booths/show.html.erb index 55f7d5504..cce704d2c 100644 --- a/app/views/admin/poll/booths/show.html.erb +++ b/app/views/admin/poll/booths/show.html.erb @@ -15,34 +15,32 @@

    <%= t("admin.booths.show.officers_list") %>

    - -
    - <%= t("admin.booths.show.no_officers") %> -
    - - -<%= link_to t("admin.booths.show.assign_officer"), "#", class: "button success" %> +<% if @booth.officers.empty? %> +
    + <%= t("admin.booths.show.no_officers") %> +
    +<% end %>
    - - <%# f.label :valuator_ids, t("admin.spending_proposals.edit.assigned_valuators") %> + <%= form_for @booth, url: admin_poll_booth_path(@poll, @booth) do |f| %> - <%# f.collection_check_boxes :valuator_ids, @valuators, :id, :email do |b| %> - <%# b.label(title: valuator_label(b.object)) { b.check_box + truncate(b.object.description_or_email, length: 60) } %> - <%# end %> + <%= f.label :officer_ids, t("admin.spending_proposals.edit.assigned_valuators") %> + <%= f.collection_check_boxes :officer_ids, @officers, :id, :email do |b| %> + <% b.label { b.check_box + truncate(officer_label(b.object), length: 60) } %> + <% end %> + + <%= f.submit t("admin.booths.show.assign_officer"), class: "button success" %> + <% end %>
    - - <%# @officers.each do |officer| %> - +
    + <% @booth.officers.each do |officer| %> + - <%# end %> + <% end %>
    - <%# officer.name %> - Admin + <%= officer.name %> - admin@consul.dev - <%# officer.email %> + <%= officer.email %> <%= link_to t('admin.poll_officers.officer.delete'), "#", class: "button hollow alert" %> @@ -53,5 +51,5 @@ %>
    \ No newline at end of file diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index ef294262d..c4a94a86e 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -208,7 +208,7 @@ en: location: "Location" assign_officer: "Assign officer" officers_list: "List of officers" - no_officers: "There is no officers in this booth." + no_officers: "There are no officers assigned to this booth" officials: edit: destroy: Remove 'Official' status diff --git a/db/migrate/20160928113143_create_officing_booths.rb b/db/migrate/20160928113143_create_officing_booths.rb new file mode 100644 index 000000000..00483fe00 --- /dev/null +++ b/db/migrate/20160928113143_create_officing_booths.rb @@ -0,0 +1,9 @@ +class CreateOfficingBooths < ActiveRecord::Migration + def change + create_table :poll_officing_booths do |t| + t.belongs_to :officer + t.belongs_to :booth + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 493dfbe3a..98be0a56f 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: 20160926090107) do +ActiveRecord::Schema.define(version: 20160928113143) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -280,6 +280,13 @@ ActiveRecord::Schema.define(version: 20160926090107) do t.integer "user_id" end + create_table "poll_officing_booths", force: :cascade do |t| + t.integer "officer_id" + t.integer "booth_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "poll_voters", force: :cascade do |t| t.integer "booth_id" t.string "document_number" diff --git a/spec/factories.rb b/spec/factories.rb index f7e09b7e8..92fefba11 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -267,6 +267,11 @@ FactoryGirl.define do user end + factory :officing_booth, class: 'Poll::OfficingBooth' do + association :officer, factory: :poll_officer + association :booth, factory: :poll_booth + end + factory :poll_booth, class: 'Poll::Booth' do sequence(:name) { |n| "Booth #{n}" } sequence(:location) { |n| "Street #{n}" } diff --git a/spec/features/admin/poll/officers_spec.rb b/spec/features/admin/poll/officers_spec.rb index ed9ec545d..981b17f13 100644 --- a/spec/features/admin/poll/officers_spec.rb +++ b/spec/features/admin/poll/officers_spec.rb @@ -1,12 +1,13 @@ require 'rails_helper' feature 'Admin poll officers' do + background do @admin = create(:administrator) @user = create(:user, username: 'Pedro Jose Garcia') @officer = create(:poll_officer) login_as(@admin.user) - visit admin_poll_officers_path + visit admin_officers_path end scenario 'Index' do @@ -15,7 +16,7 @@ feature 'Admin poll officers' do expect(page).to_not have_content @user.name end - scenario 'Create poll officer', :js do + scenario 'Create', :js do fill_in 'email', with: @user.email click_button 'Search' @@ -26,11 +27,133 @@ feature 'Admin poll officers' do end end - scenario 'Delete poll officer' do + scenario 'Delete' do click_link 'Delete' within("#officers") do expect(page).to_not have_content @officer.name end end + + context "Booth" do + + scenario 'No officers assigned to booth' do + poll = create(:poll) + booth = create(:poll_booth, poll: poll) + + visit admin_poll_booth_path(poll, booth) + + within("#assigned_officers") do + expect(page).to have_css ".officer", count: 0 + end + + expect(page).to have_content "There are no officers assigned to this booth" + end + + scenario "Assigned to booth" do + john = create(:poll_officer) + isabel = create(:poll_officer) + eve = create(:poll_officer) + + poll = create(:poll) + booth = create(:poll_booth, poll: poll) + + officing_booth1 = create(:officing_booth, officer: john, booth: booth) + officing_booth2 = create(:officing_booth, officer: isabel, booth: booth) + + visit admin_poll_booth_path(poll, booth) + + within("#assigned_officers") do + expect(page).to have_css ".officer", count: 2 + expect(page).to have_content john.name + expect(page).to have_content isabel.name + + expect(page).to_not have_content eve.name + end + + expect(page).to_not have_content "There are no officers assigned to this booth" + end + + scenario 'Assign to booth' do + john = create(:poll_officer) + isabel = create(:poll_officer) + + poll = create(:poll) + booth = create(:poll_booth, poll: poll) + + visit admin_poll_booth_path(poll, booth) + + check "#{john.name} - #{john.email}" + click_button "Assign officer" + + expect(page).to have_content "Booth updated successfully." + within("#assigned_officers") do + expect(page).to have_css ".officer", count: 1 + expect(page).to have_content john.name + end + end + + scenario "Unassign from booth" do + john = create(:poll_officer) + isabel = create(:poll_officer) + + poll = create(:poll) + booth = create(:poll_booth, poll: poll) + + officing_booth = create(:officing_booth, officer: john, booth: booth) + officing_booth = create(:officing_booth, officer: isabel, booth: booth) + + visit admin_poll_booth_path(poll, booth) + + uncheck "#{john.name} - #{john.email}" + click_button "Assign officer" + + expect(page).to have_content "Booth updated successfully." + within("#assigned_officers") do + expect(page).to have_css ".officer", count: 1 + expect(page).to have_content isabel.name + + expect(page).to_not have_content john.name + end + end + + scenario "Assigned multiple officers to different booths" do + john = create(:poll_officer) + isabel = create(:poll_officer) + eve = create(:poll_officer) + peter = create(:poll_officer) + + poll1 = create(:poll) + poll2 = create(:poll) + + booth1 = create(:poll_booth, poll: poll1) + booth2 = create(:poll_booth, poll: poll1) + booth3 = create(:poll_booth, poll: poll2) + + officing_booth = create(:officing_booth, officer: john, booth: booth1) + officing_booth = create(:officing_booth, officer: isabel, booth: booth1) + officing_booth = create(:officing_booth, officer: eve, booth: booth2) + officing_booth = create(:officing_booth, officer: peter, booth: booth3) + + visit admin_poll_booth_path(poll1, booth1) + within("#assigned_officers") do + expect(page).to have_css ".officer", count: 2 + expect(page).to have_content john.name + expect(page).to have_content isabel.name + end + + visit admin_poll_booth_path(poll1, booth2) + within("#assigned_officers") do + expect(page).to have_css ".officer", count: 1 + expect(page).to have_content eve.name + end + + visit admin_poll_booth_path(poll2, booth3) + within("#assigned_officers") do + expect(page).to have_css ".officer", count: 1 + expect(page).to have_content peter.name + end + end + end + end \ No newline at end of file From 1e87810593c37659a2b3d388a4c1760c175b0569 Mon Sep 17 00:00:00 2001 From: Marcia Date: Thu, 29 Sep 2016 14:34:37 +0200 Subject: [PATCH 0598/1685] improves expired password view --- app/models/user.rb | 4 ++-- app/views/devise/password_expired/show.html.erb | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 1c9ace227..75367dbe1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,8 +2,8 @@ include Verification - devise :password_expirable, :secure_validatable, :database_authenticatable, :registerable, :confirmable, - :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :async + devise :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, + :trackable, :validatable, :omniauthable, :async, :password_expirable, :secure_validatable acts_as_voter acts_as_paranoid column: :hidden_at diff --git a/app/views/devise/password_expired/show.html.erb b/app/views/devise/password_expired/show.html.erb index 0c750dd1e..33dc82f71 100644 --- a/app/views/devise/password_expired/show.html.erb +++ b/app/views/devise/password_expired/show.html.erb @@ -1,7 +1,6 @@

    <%= t("devise.password_expired.expire_password") %>

    <%= form_for(resource, :as => resource_name, :url => [resource_name, :password_expired], :html => { :method => :put }) do |f| %> - <%= devise_error_messages! %> <%= f.password_field :current_password %>

    From 1f72c5cc74ea1cfcb147e1bb58e5bf495a21af00 Mon Sep 17 00:00:00 2001 From: Marcia Date: Fri, 30 Sep 2016 10:10:20 +0200 Subject: [PATCH 0599/1685] improves expired password view --- config/initializers/devise_security_extension.rb | 13 ++++--------- db/migrate/20160901104320_add_password_expired.rb~ | 4 ---- spec/features/users_auth_spec.rb | 1 - 3 files changed, 4 insertions(+), 14 deletions(-) delete mode 100644 db/migrate/20160901104320_add_password_expired.rb~ diff --git a/config/initializers/devise_security_extension.rb b/config/initializers/devise_security_extension.rb index b38393b75..5b13fc905 100644 --- a/config/initializers/devise_security_extension.rb +++ b/config/initializers/devise_security_extension.rb @@ -55,16 +55,13 @@ module Devise def password_expired? self.password_changed_at < self.expire_password_after.ago end - - end #module PasswordExpirable + end module SecureValidatable def self.included(base) base.extend ClassMethods assert_secure_validations_api!(base) - base.class_eval do - validate :current_equal_password_validation end end @@ -77,8 +74,6 @@ module Devise self.errors.add(:password, :equal_to_current_password) if dummy.valid_password?(self.password) end end - - end #module SecureValidatable - - end #module Models -end #module Devise \ No newline at end of file + end + end +end \ No newline at end of file diff --git a/db/migrate/20160901104320_add_password_expired.rb~ b/db/migrate/20160901104320_add_password_expired.rb~ deleted file mode 100644 index ac3a48f49..000000000 --- a/db/migrate/20160901104320_add_password_expired.rb~ +++ /dev/null @@ -1,4 +0,0 @@ -class AddPasswordExpired < ActiveRecord::Migration - def change - end -end diff --git a/spec/features/users_auth_spec.rb b/spec/features/users_auth_spec.rb index f16772fd4..bd58eabe0 100644 --- a/spec/features/users_auth_spec.rb +++ b/spec/features/users_auth_spec.rb @@ -333,7 +333,6 @@ feature 'Users' do fill_in 'user_password_confirmation', with: '123456789' click_button 'Change your password' expect(page).to have_content "must be different than the current password." - #expect(page).to have_content "You can not use the same password. Please choose another one." end From 263bef42bc467e8000581717849138b9de817fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baza=CC=81n?= Date: Mon, 3 Oct 2016 14:36:05 +0200 Subject: [PATCH 0600/1685] updates dependencies all minor upgrades --- Gemfile.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index bf37a7091..8d891d8cd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -51,7 +51,7 @@ GEM safely_block (>= 0.1.1) user_agent_parser uuidtools - airbrussh (1.0.2) + airbrussh (1.1.1) sshkit (>= 1.6.1, != 1.7.0) akami (1.3.1) gyoku (>= 0.4.0) @@ -70,7 +70,7 @@ GEM bullet (5.2.0) activesupport (>= 3.0.0) uniform_notifier (~> 1.10.0) - byebug (9.0.5) + byebug (9.0.6) cancancan (1.15.0) capistrano (3.5.0) airbrussh (>= 1.0.0) @@ -81,7 +81,7 @@ GEM capistrano-bundler (1.1.4) capistrano (~> 3.1) sshkit (~> 1.2) - capistrano-harrow (0.5.2) + capistrano-harrow (0.5.3) capistrano-rails (1.1.7) capistrano (~> 3.1) capistrano-bundler (~> 1.1) @@ -120,7 +120,7 @@ GEM term-ansicolor (~> 1.3) thor (~> 0.19.1) tins (>= 1.6.0, < 2) - daemons (1.2.3) + daemons (1.2.4) dalli (2.7.6) database_cleaner (1.5.3) debug_inspector (0.0.2) @@ -176,7 +176,7 @@ GEM geocoder (1.3.7) globalid (0.3.7) activesupport (>= 4.1.0) - groupdate (3.0.1) + groupdate (3.0.2) activesupport (>= 3) gyoku (1.3.1) builder (>= 2.1.2) @@ -228,14 +228,14 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) mini_portile2 (2.1.0) - minitest (5.9.0) + minitest (5.9.1) multi_json (1.12.1) multi_xml (0.5.5) multipart-post (2.0.0) net-scp (1.2.1) net-ssh (>= 2.6.5) net-ssh (3.2.0) - newrelic_rpm (3.16.0.318) + newrelic_rpm (3.16.3.323) nokogiri (1.6.8) mini_portile2 (~> 2.1.0) pkg-config (~> 1.1.7) @@ -315,7 +315,7 @@ GEM rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) raindrops (0.16.0) - rake (11.2.2) + rake (11.3.0) redcarpet (3.3.4) referer-parser (0.3.0) request_store (1.3.1) @@ -328,7 +328,7 @@ GEM rspec-core (~> 3.5.0) rspec-expectations (~> 3.5.0) rspec-mocks (~> 3.5.0) - rspec-core (3.5.1) + rspec-core (3.5.4) rspec-support (~> 3.5.0) rspec-expectations (3.5.0) diff-lcs (>= 1.2.0, < 2.0) @@ -336,7 +336,7 @@ GEM rspec-mocks (3.5.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.5.0) - rspec-rails (3.5.1) + rspec-rails (3.5.2) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) @@ -386,7 +386,7 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) - sshkit (1.11.1) + sshkit (1.11.3) net-scp (>= 1.1.2) net-ssh (>= 2.8.0) term-ansicolor (1.3.2) @@ -408,7 +408,7 @@ GEM tilt (>= 1.4, < 3) tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (3.0.1) + uglifier (3.0.2) execjs (>= 0.3.0, < 3) unicorn (5.1.0) kgio (~> 2.6) @@ -506,4 +506,4 @@ DEPENDENCIES whenever BUNDLED WITH - 1.12.5 + 1.13.1 From 407c6e022d8e2aa1b37e095df0d1dffa139832d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baza=CC=81n?= Date: Mon, 3 Oct 2016 14:40:06 +0200 Subject: [PATCH 0601/1685] updates capistrano-rails --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 83a3bddbd..ff0ded14e 100644 --- a/Gemfile +++ b/Gemfile @@ -79,7 +79,7 @@ group :development, :test do gem 'i18n-tasks' gem 'capistrano', '3.5.0', require: false gem "capistrano-bundler", '1.1.4', require: false - gem "capistrano-rails", '1.1.7', require: false + gem "capistrano-rails", '1.1.8', require: false gem "capistrano-rvm", require: false gem 'capistrano3-delayed-job', '~> 1.0' gem "bullet" diff --git a/Gemfile.lock b/Gemfile.lock index 8d891d8cd..8ca495b1b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -82,7 +82,7 @@ GEM capistrano (~> 3.1) sshkit (~> 1.2) capistrano-harrow (0.5.3) - capistrano-rails (1.1.7) + capistrano-rails (1.1.8) capistrano (~> 3.1) capistrano-bundler (~> 1.1) capistrano-rvm (0.1.2) @@ -447,7 +447,7 @@ DEPENDENCIES cancancan capistrano (= 3.5.0) capistrano-bundler (= 1.1.4) - capistrano-rails (= 1.1.7) + capistrano-rails (= 1.1.8) capistrano-rvm capistrano3-delayed-job (~> 1.0) capybara From ac6b75e8f916db499cd6af4a74d442ba751fb194 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Tue, 4 Oct 2016 18:38:10 +0200 Subject: [PATCH 0602/1685] updates image url for error pages --- public/404.html | 2 +- public/422.html | 2 +- public/500.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/404.html b/public/404.html index 5d519fb70..cc6820bba 100644 --- a/public/404.html +++ b/public/404.html @@ -5,7 +5,7 @@