From 8fc302cb46588699977321648146a2754e2ac113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Fri, 4 Mar 2016 17:26:50 +0100 Subject: [PATCH 01/17] valuators can manage spending proposals --- app/models/abilities/administrator.rb | 1 + spec/models/abilities/valuator_spec.rb | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 spec/models/abilities/valuator_spec.rb diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index 6bf2b0b53..49184c447 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -4,6 +4,7 @@ module Abilities def initialize(user) self.merge Abilities::Moderation.new(user) + self.merge Abilities::Valuator.new(user) can :restore, Comment cannot :restore, Comment, hidden_at: nil diff --git a/spec/models/abilities/valuator_spec.rb b/spec/models/abilities/valuator_spec.rb new file mode 100644 index 000000000..d9542220d --- /dev/null +++ b/spec/models/abilities/valuator_spec.rb @@ -0,0 +1,10 @@ +require 'rails_helper' +require 'cancan/matchers' + +describe "Abilities::Valuator" do + subject(:ability) { Ability.new(user) } + let(:user) { valuator.user } + let(:valuator) { create(:valuator) } + + it { should be_able_to(:manage, SpendingProposal) } +end From cd58ae85f843038b190c5ca011db76883e53d030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Fri, 4 Mar 2016 17:37:25 +0100 Subject: [PATCH 02/17] adds by_valuator search method to SpendingProposal --- app/models/spending_proposal.rb | 5 +++++ spec/models/spending_proposal_spec.rb | 32 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/app/models/spending_proposal.rb b/app/models/spending_proposal.rb index 48473640c..cceac00c1 100644 --- a/app/models/spending_proposal.rb +++ b/app/models/spending_proposal.rb @@ -34,6 +34,7 @@ class SpendingProposal < ActiveRecord::Base results = self results = results.by_geozone(params[:geozone_id]) if params[:geozone_id].present? results = results.by_administrator(params[:administrator_id]) if params[:administrator_id].present? + results = results.by_valuator(params[:valuator_id]) if params[:valuator_id].present? results = results.send(current_filter) if current_filter.present? results.for_render end @@ -50,6 +51,10 @@ class SpendingProposal < ActiveRecord::Base where(administrator_id: administrator.presence) end + def self.by_valuator(valuator) + joins(:valuation_assignments).includes(:valuators).where("valuation_assignments.valuator_id = ?", valuator.presence) + end + def feasibility case feasible when true diff --git a/spec/models/spending_proposal_spec.rb b/spec/models/spending_proposal_spec.rb index a3800e85c..9ed96da59 100644 --- a/spec/models/spending_proposal_spec.rb +++ b/spec/models/spending_proposal_spec.rb @@ -61,6 +61,38 @@ describe SpendingProposal do end end + describe "by_administrator" do + it "should return spending proposals assigned to specific administrator" do + spending_proposal1 = create(:spending_proposal, administrator_id: 33) + spending_proposal2 = create(:spending_proposal) + + by_administrator = SpendingProposal.by_administrator(33) + + expect(by_administrator.size).to eq(1) + expect(by_administrator.first).to eq(spending_proposal1) + end + end + + describe "by_valuator" do + it "should return spending proposals assigned to specific valuator" do + spending_proposal1 = create(:spending_proposal) + spending_proposal2 = create(:spending_proposal) + spending_proposal3 = create(:spending_proposal) + + valuator1 = create(:valuator) + valuator2 = create(:valuator) + + spending_proposal1.valuators << valuator1 + spending_proposal2.valuators << valuator2 + spending_proposal3.valuators << [valuator1, valuator2] + + by_valuator = SpendingProposal.by_valuator(valuator1.id) + + expect(by_valuator.size).to eq(2) + expect(by_valuator.sort).to eq([spending_proposal1,spending_proposal3].sort) + end + end + describe "scopes" do describe "valuation_open" do it "should return all spending proposals with false valuation_finished" do From 0160ed816cb7b88af437ee6f8a4e5c55d0e810db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Fri, 4 Mar 2016 17:39:56 +0100 Subject: [PATCH 03/17] adds valuation namespace --- app/controllers/valuation/base_controller.rb | 15 +++++++++++++++ config/locales/en.yml | 1 + config/locales/es.yml | 1 + config/routes.rb | 10 ++++++++++ 4 files changed, 27 insertions(+) create mode 100644 app/controllers/valuation/base_controller.rb diff --git a/app/controllers/valuation/base_controller.rb b/app/controllers/valuation/base_controller.rb new file mode 100644 index 000000000..fb42fb694 --- /dev/null +++ b/app/controllers/valuation/base_controller.rb @@ -0,0 +1,15 @@ +class Valuation::BaseController < ApplicationController + layout 'admin' + + before_action :authenticate_user! + before_action :verify_valuator + + skip_authorization_check + + private + + def verify_valuator + raise CanCan::AccessDenied unless current_user.try(:valuator?) || current_user.try(:administrator?) + end + +end diff --git a/config/locales/en.yml b/config/locales/en.yml index 5514d2401..e3f51219c 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -190,6 +190,7 @@ en: locale: 'Language:' logo: Madrid moderation: Moderation + valuation: Valuation more_information: More information my_account_link: My account my_activity_link: My activity diff --git a/config/locales/es.yml b/config/locales/es.yml index bf256fa13..e8c65c08a 100755 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -190,6 +190,7 @@ es: locale: 'Idioma:' logo: Madrid moderation: Moderar + valuation: Evaluación more_information: Más información my_account_link: Mi cuenta my_activity_link: Mi actividad diff --git a/config/routes.rb b/config/routes.rb index e743e29d7..2e1cbce68 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -208,6 +208,16 @@ Rails.application.routes.draw do end end + namespace :valuation do + root to: "spending_proposals#index" + + resources :spending_proposals, only: [:index, :show] do + member do + patch :valuate + end + end + end + namespace :management do root to: "dashboard#index" From ac9eaec9d94ec5cb50b4f23dc0001b65809baa6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baza=CC=81n?= Date: Fri, 4 Mar 2016 17:52:27 +0100 Subject: [PATCH 04/17] adds spending proposals index to valuation filters included: valuation_open, valuating, valuation_finished search by geozone & by valuator --- .../spending_proposals_controller.rb | 12 ++ app/helpers/valuation_helper.rb | 11 ++ app/views/valuation/_menu.html.erb | 17 +++ .../spending_proposals/index.html.erb | 63 ++++++++ config/locales/valuation.en.yml | 21 +++ config/locales/valuation.es.yml | 21 +++ .../valuation/spending_proposals_spec.rb | 143 ++++++++++++++++++ 7 files changed, 288 insertions(+) create mode 100644 app/controllers/valuation/spending_proposals_controller.rb create mode 100644 app/helpers/valuation_helper.rb create mode 100644 app/views/valuation/_menu.html.erb create mode 100644 app/views/valuation/spending_proposals/index.html.erb create mode 100644 config/locales/valuation.en.yml create mode 100644 config/locales/valuation.es.yml create mode 100644 spec/features/valuation/spending_proposals_spec.rb diff --git a/app/controllers/valuation/spending_proposals_controller.rb b/app/controllers/valuation/spending_proposals_controller.rb new file mode 100644 index 000000000..ac502334d --- /dev/null +++ b/app/controllers/valuation/spending_proposals_controller.rb @@ -0,0 +1,12 @@ +class Valuation::SpendingProposalsController < Valuation::BaseController + include FeatureFlags + feature_flag :spending_proposals + + has_filters %w{valuation_open valuating valuation_finished}, only: :index + + load_resource + + def index + @spending_proposals = SpendingProposal.search(params, @current_filter).order(created_at: :desc).page(params[:page]) + end +end diff --git a/app/helpers/valuation_helper.rb b/app/helpers/valuation_helper.rb new file mode 100644 index 000000000..becd29abb --- /dev/null +++ b/app/helpers/valuation_helper.rb @@ -0,0 +1,11 @@ +module ValuationHelper + + def valuator_select_options(valuator=nil) + if valuator.present? + Valuator.where.not(id: valuator.id).order('users.username asc').includes(:user).collect { |v| [ v.name, v.id ] }.prepend([valuator.name, valuator.id]) + else + Valuator.all.order('users.username asc').includes(:user).collect { |v| [ v.name, v.id ] } + end + end + +end \ No newline at end of file diff --git a/app/views/valuation/_menu.html.erb b/app/views/valuation/_menu.html.erb new file mode 100644 index 000000000..76f6ff434 --- /dev/null +++ b/app/views/valuation/_menu.html.erb @@ -0,0 +1,17 @@ + diff --git a/app/views/valuation/spending_proposals/index.html.erb b/app/views/valuation/spending_proposals/index.html.erb new file mode 100644 index 000000000..f7e8d4ba6 --- /dev/null +++ b/app/views/valuation/spending_proposals/index.html.erb @@ -0,0 +1,63 @@ +

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

+ +
+ <%= form_tag valuation_spending_proposals_path, method: :get, enforce_utf8: false do %> +
+ <%= select_tag :geozone_id, + options_for_select(geozone_select_options.unshift([t("geozones.none"), "all"]), params[:geozone_id]), + { prompt: t("valuation.spending_proposals.index.geozone_filter_all"), + label: false, + class: "js-submit-on-change" } %> +
+
+ <%= select_tag :valuator_id, + options_for_select(valuator_select_options(current_user.valuator), params[:valuator_id]), + { prompt: t("valuation.spending_proposals.index.valuator_filter_all"), + label: false, + class: "js-submit-on-change" } %> +
+ <% end %> +
+ +<%= render 'shared/filter_subnav', i18n_namespace: "valuation.spending_proposals.index" %> + +

<%= page_entries_info @spending_proposals %>

+ + + <% @spending_proposals.each do |spending_proposal| %> + + + + + + + + <% end %> +
+ <%= spending_proposal.id %> + + <%= link_to spending_proposal.title, spending_proposal_path(spending_proposal) %> + + <% if spending_proposal.administrator.present? %> + <%= spending_proposal.administrator.name %> + <% else %> + <%= t("valuation.spending_proposals.index.no_admin_assigned") %> + <% end %> + + <% case spending_proposal.valuators.size %> + <% when 0 %> + <%= t("valuation.spending_proposals.index.no_valuators_assigned") %> + <% when 1 %> + + <%= spending_proposal.valuators.first.name %> + + <% else %> + + <%= t('valuation.spending_proposals.index.valuators_assigned', count: spending_proposal.valuators.size) %> + + <% end %> + + <%= geozone_name(spending_proposal) %> +
+ +<%= paginate @spending_proposals %> \ No newline at end of file diff --git a/config/locales/valuation.en.yml b/config/locales/valuation.en.yml new file mode 100644 index 000000000..8d5c0f3ed --- /dev/null +++ b/config/locales/valuation.en.yml @@ -0,0 +1,21 @@ +--- +en: + valuation: + menu: + title: Valuation + spending_proposals: Spending proposals + spending_proposals: + index: + geozone_filter_all: All zones + valuator_filter_all: All valuators + filters: + valuation_open: Open + valuating: Under valuation + valuation_finished: Valuation finished + title: Investment projects for participatory budgeting + admin_assigned: Assigned administrator + no_admin_assigned: No admin assigned + valuators_assigned: + one: Assigned valuator + other: "%{count} valuators assigned" + no_valuators_assigned: No valuators assigned \ No newline at end of file diff --git a/config/locales/valuation.es.yml b/config/locales/valuation.es.yml new file mode 100644 index 000000000..ca65fd82a --- /dev/null +++ b/config/locales/valuation.es.yml @@ -0,0 +1,21 @@ +--- +es: + valuation: + menu: + title: Evaluación + spending_proposals: Propuestas de inversión + spending_proposals: + index: + geozone_filter_all: Todos los ámbitos de actuación + valuator_filter_all: Todos los evaluadores + filters: + valuation_open: Abiertas + valuating: En evaluación + valuation_finished: Evaluación finalizada + title: Propuestas de inversión para presupuestos participativos + admin_assigned: Administrador asignado + no_admin_assigned: Sin admin asignado + valuators_assigned: + one: Evaluador asignado + other: "%{count} evaluadores asignados" + no_valuators_assigned: Sin evaluador \ No newline at end of file diff --git a/spec/features/valuation/spending_proposals_spec.rb b/spec/features/valuation/spending_proposals_spec.rb new file mode 100644 index 000000000..ae0c7df7a --- /dev/null +++ b/spec/features/valuation/spending_proposals_spec.rb @@ -0,0 +1,143 @@ +require 'rails_helper' + +feature 'Valuation spending proposals' do + + background do + valuator = create(:valuator) + login_as(valuator.user) + end + + scenario 'Disabled with a feature flag' do + Setting['feature.spending_proposals'] = nil + expect{ visit valuation_spending_proposals_path }.to raise_exception(FeatureFlags::FeatureDisabled) + end + + scenario 'Index shows spending proposals' do + spending_proposal = create(:spending_proposal) + visit valuation_spending_proposals_path + + expect(page).to have_content(spending_proposal.title) + end + + scenario 'Index shows assignments info' do + spending_proposal1 = create(:spending_proposal) + spending_proposal2 = create(:spending_proposal) + spending_proposal3 = create(:spending_proposal) + + valuator1 = create(:valuator, user: create(:user, username: 'Olga')) + valuator2 = create(:valuator, user: create(:user, username: 'Miriam')) + admin = create(:administrator, user: create(:user, username: 'Gema')) + + spending_proposal1.valuators << valuator1 + spending_proposal2.valuator_ids = [valuator1.id, valuator2.id] + spending_proposal3.update({administrator_id: admin.id}) + + visit valuation_spending_proposals_path + + within("#spending_proposal_#{spending_proposal1.id}") do + expect(page).to have_content("No admin assigned") + expect(page).to have_content("Olga") + end + + within("#spending_proposal_#{spending_proposal2.id}") do + expect(page).to have_content("No admin assigned") + expect(page).to have_content("2 valuators assigned") + end + + within("#spending_proposal_#{spending_proposal3.id}") do + expect(page).to have_content("Gema") + expect(page).to have_content("No valuators assigned") + end + end + + scenario "Index filtering by geozone", :js do + geozone = create(:geozone, name: "District 9") + create(:spending_proposal, title: "Realocate visitors", geozone: geozone) + create(:spending_proposal, title: "Destroy the city") + + visit valuation_spending_proposals_path + expect(page).to have_link("Realocate visitors") + expect(page).to have_link("Destroy the city") + + select "District 9", from: "geozone_id" + + expect(page).to have_link("Realocate visitors") + expect(page).to_not have_link("Destroy the city") + + select "All city", from: "geozone_id" + + expect(page).to have_link("Destroy the city") + expect(page).to_not have_link("Realocate visitors") + + select "All zones", from: "geozone_id" + expect(page).to have_link("Realocate visitors") + expect(page).to have_link("Destroy the city") + end + + scenario "Index filtering by valuator", :js do + user = create(:user, username: 'Karnak') + valuator = create(:valuator, user: user) + + spending = create(:spending_proposal, title: "Realocate visitors") + spending.valuators << valuator + create(:spending_proposal, title: "Destroy the city") + + visit valuation_spending_proposals_path + expect(page).to have_link("Realocate visitors") + expect(page).to have_link("Destroy the city") + + select "Karnak", from: "valuator_id" + + expect(page).to have_link("Realocate visitors") + expect(page).to_not have_link("Destroy the city") + + select "All valuators", from: "valuator_id" + + expect(page).to 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', + 'valuating' => 'Under valuation', + 'valuation_finished' => 'Valuation finished'} + + visit valuation_spending_proposals_path + + 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 valuation_spending_proposals_path(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 "Index filtering by valuation status" do + valuating = create(:spending_proposal, title: "Ongoing valuation") + valuated = create(:spending_proposal, title: "Old idea", valuation_finished: true) + valuating.valuators << create(:valuator) + valuated.valuators << create(:valuator) + + visit valuation_spending_proposals_path(filter: 'valuation_open') + + expect(page).to have_content("Ongoing valuation") + expect(page).to_not have_content("Old idea") + + visit valuation_spending_proposals_path(filter: 'valuating') + + expect(page).to have_content("Ongoing valuation") + expect(page).to_not have_content("Old idea") + + visit valuation_spending_proposals_path(filter: 'valuation_finished') + + expect(page).to_not have_content("Ongoing valuation") + expect(page).to have_content("Old idea") + end + +end From da855207d3fc4240a6605c3dc9b6a6456a8d51f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baza=CC=81n?= Date: Fri, 4 Mar 2016 18:29:20 +0100 Subject: [PATCH 05/17] adds valuation links and access specs --- app/views/shared/_admin_login_items.html.erb | 6 ++ config/i18n-tasks.yml | 2 + spec/features/admin_spec.rb | 38 ++++------ spec/features/moderation_spec.rb | 39 +++++++++- spec/features/valuation_spec.rb | 78 ++++++++++++++++++++ 5 files changed, 138 insertions(+), 25 deletions(-) create mode 100644 spec/features/valuation_spec.rb diff --git a/app/views/shared/_admin_login_items.html.erb b/app/views/shared/_admin_login_items.html.erb index 2636f3a73..304c04fb0 100644 --- a/app/views/shared/_admin_login_items.html.erb +++ b/app/views/shared/_admin_login_items.html.erb @@ -10,4 +10,10 @@ <%= link_to t("layouts.header.moderation"), moderation_root_path %> <% end %> + + <% if current_user.valuator? || current_user.administrator? %> +
  • + <%= link_to t("layouts.header.valuation"), valuation_root_path %> +
  • + <% end %> <% end %> diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index e003e2842..c5e88d8dd 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -24,6 +24,7 @@ data: - config/locales/%{locale}.yml - config/locales/admin.%{locale}.yml - config/locales/moderation.%{locale}.yml + - config/locales/valuation.%{locale}.yml - config/locales/management.%{locale}.yml - config/locales/verification.%{locale}.yml - config/locales/mailers.%{locale}.yml @@ -122,6 +123,7 @@ ignore_unused: - 'moderation.proposals.index.order*' - 'moderation.debates.index.filter*' - 'moderation.debates.index.order*' + - 'valuation.spending_proposals.index.filter*' - 'users.show.filters.*' - 'debates.index.select_order' - 'debates.index.orders.*' diff --git a/spec/features/admin_spec.rb b/spec/features/admin_spec.rb index 644c20f9d..87c60355b 100644 --- a/spec/features/admin_spec.rb +++ b/spec/features/admin_spec.rb @@ -6,10 +6,6 @@ feature 'Admin' do create(:administrator, user: user) user end - let(:moderator) do - create(:moderator, user: user) - user - end scenario 'Access as regular user is not authorized' do login_as(user) @@ -21,7 +17,18 @@ feature 'Admin' do end scenario 'Access as a moderator is not authorized' do - login_as(moderator) + create(:moderator, user: user) + login_as(user) + visit admin_root_path + + expect(current_path).not_to eq(admin_root_path) + expect(current_path).to eq(proposals_path) + expect(page).to have_content "You do not have permission to access this page" + end + + scenario 'Access as a valuator is not authorized' do + create(:valuator, user: user) + login_as(user) visit admin_root_path expect(current_path).not_to eq(admin_root_path) @@ -42,15 +49,8 @@ feature 'Admin' do visit root_path expect(page).to have_link('Administration') - expect(page).to_not have_link('Moderator') - end - - scenario "Moderation access links" do - login_as(moderator) - visit root_path - expect(page).to have_link('Moderation') - expect(page).to_not have_link('Administration') + expect(page).to have_link('Valuation') end scenario 'Admin dashboard' do @@ -62,17 +62,7 @@ feature 'Admin' do expect(current_path).to eq(admin_root_path) expect(page).to have_css('#admin_menu') expect(page).to_not have_css('#moderation_menu') - end - - scenario 'Moderation dashboard' do - login_as(moderator) - visit root_path - - click_link 'Moderation' - - expect(current_path).to eq(moderation_root_path) - expect(page).to have_css('#moderation_menu') - expect(page).to_not have_css('#admin_menu') + expect(page).to_not have_css('#valuation_menu') end context 'Tags' do diff --git a/spec/features/moderation_spec.rb b/spec/features/moderation_spec.rb index c13a23461..12eb07358 100644 --- a/spec/features/moderation_spec.rb +++ b/spec/features/moderation_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Admin' do +feature 'Moderation' do let(:user) { create(:user) } scenario 'Access as regular user is not authorized' do @@ -15,6 +15,20 @@ feature 'Admin' do expect(page).to have_content "You do not have permission to access this page" end + scenario 'Access as valuator is not authorized' do + create(:valuator, user: user) + + login_as(user) + visit root_path + + expect(page).to_not have_link("Moderation") + visit moderation_root_path + + expect(current_path).not_to eq(moderation_root_path) + expect(current_path).to eq(proposals_path) + expect(page).to have_content "You do not have permission to access this page" + end + scenario 'Access as a moderator is authorized' do create(:moderator, user: user) @@ -41,4 +55,27 @@ feature 'Admin' do expect(page).to_not have_content "You do not have permission to access this page" end + scenario "Moderation access links" do + create(:moderator, user: user) + login_as(user) + visit root_path + + expect(page).to have_link('Moderation') + expect(page).to_not have_link('Administration') + expect(page).to_not have_link('Valuation') + end + + scenario 'Moderation dashboard' do + create(:moderator, user: user) + login_as(user) + visit root_path + + click_link 'Moderation' + + expect(current_path).to eq(moderation_root_path) + expect(page).to have_css('#moderation_menu') + expect(page).to_not have_css('#admin_menu') + expect(page).to_not have_css('#valuation_menu') + end + end diff --git a/spec/features/valuation_spec.rb b/spec/features/valuation_spec.rb new file mode 100644 index 000000000..571a4323f --- /dev/null +++ b/spec/features/valuation_spec.rb @@ -0,0 +1,78 @@ +require 'rails_helper' + +feature 'Valuation' do + let(:user) { create(:user) } + + scenario 'Access as regular user is not authorized' do + login_as(user) + visit root_path + + expect(page).to_not have_link("Valuation") + visit valuation_root_path + + expect(current_path).not_to eq(valuation_root_path) + expect(current_path).to eq(proposals_path) + expect(page).to have_content "You do not have permission to access this page" + end + + scenario 'Access as moderator is not authorized' do + create(:moderator, user: user) + login_as(user) + visit root_path + + expect(page).to_not have_link("Valuation") + visit valuation_root_path + + expect(current_path).not_to eq(valuation_root_path) + expect(current_path).to eq(proposals_path) + expect(page).to have_content "You do not have permission to access this page" + end + + scenario 'Access as a valuator is authorized' do + create(:valuator, user: user) + login_as(user) + visit root_path + + expect(page).to have_link("Valuation") + click_on "Valuation" + + expect(current_path).to eq(valuation_root_path) + expect(page).to_not have_content "You do not have permission to access this page" + end + + scenario 'Access as an administrator is authorized' do + create(:administrator, user: user) + login_as(user) + visit root_path + + expect(page).to have_link("Valuation") + click_on "Valuation" + + expect(current_path).to eq(valuation_root_path) + expect(page).to_not have_content "You do not have permission to access this page" + end + + scenario "Valuation access links" do + create(:valuator, user: user) + login_as(user) + visit root_path + + expect(page).to have_link('Valuation') + expect(page).to_not have_link('Administration') + expect(page).to_not have_link('Moderation') + end + + scenario 'Valuation dashboard' do + create(:valuator, user: user) + login_as(user) + visit root_path + + click_link 'Valuation' + + expect(current_path).to eq(valuation_root_path) + expect(page).to have_css('#valuation_menu') + expect(page).to_not have_css('#admin_menu') + expect(page).to_not have_css('#moderation_menu') + end + +end From b3486ede8be39773e04365d750f6784930dfbe9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Fri, 4 Mar 2016 20:43:30 +0100 Subject: [PATCH 06/17] adds valuation's spending proposal show --- .../spending_proposals_controller.rb | 2 +- .../spending_proposals/index.html.erb | 2 +- .../spending_proposals/show.html.erb | 74 +++++++++++++++++++ config/locales/valuation.en.yml | 22 +++++- config/locales/valuation.es.yml | 22 +++++- .../valuation/spending_proposals_spec.rb | 31 ++++++++ 6 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 app/views/valuation/spending_proposals/show.html.erb diff --git a/app/controllers/valuation/spending_proposals_controller.rb b/app/controllers/valuation/spending_proposals_controller.rb index ac502334d..21389d4a2 100644 --- a/app/controllers/valuation/spending_proposals_controller.rb +++ b/app/controllers/valuation/spending_proposals_controller.rb @@ -4,7 +4,7 @@ class Valuation::SpendingProposalsController < Valuation::BaseController has_filters %w{valuation_open valuating valuation_finished}, only: :index - load_resource + load_and_authorize_resource def index @spending_proposals = SpendingProposal.search(params, @current_filter).order(created_at: :desc).page(params[:page]) diff --git a/app/views/valuation/spending_proposals/index.html.erb b/app/views/valuation/spending_proposals/index.html.erb index f7e8d4ba6..5aa486677 100644 --- a/app/views/valuation/spending_proposals/index.html.erb +++ b/app/views/valuation/spending_proposals/index.html.erb @@ -30,7 +30,7 @@ <%= spending_proposal.id %> - <%= link_to spending_proposal.title, spending_proposal_path(spending_proposal) %> + <%= link_to spending_proposal.title, valuation_spending_proposal_path(spending_proposal) %> <% if spending_proposal.administrator.present? %> diff --git a/app/views/valuation/spending_proposals/show.html.erb b/app/views/valuation/spending_proposals/show.html.erb new file mode 100644 index 000000000..cc0c8bca6 --- /dev/null +++ b/app/views/valuation/spending_proposals/show.html.erb @@ -0,0 +1,74 @@ +<%= link_to t("valuation.spending_proposals.show.back"), :back, class: 'back' %> +

    <%= t("valuation.spending_proposals.show.heading") %> <%= @spending_proposal.id %>

    +

    <%= @spending_proposal.title %>

    + +<%= safe_html_with_links @spending_proposal.description %> + +<% if @spending_proposal.external_url.present? %> +

    <%= text_with_links @spending_proposal.external_url %>

    +<% end %> + +

    <%= t("valuation.spending_proposals.show.info") %>

    + +

    <%= t("valuation.spending_proposals.show.by") %>: + <%= link_to @spending_proposal.author.name, user_path(@spending_proposal.author) %> +

    + +<% if @spending_proposal.association_name.present? %> +

    <%= t("valuation.spending_proposals.show.association_name") %>: + <%= @spending_proposal.association_name %> +

    +<% end %> + +

    <%= t("valuation.spending_proposals.show.geozone") %>: + <%= geozone_name(@spending_proposal) %> +

    + +

    <%= t("valuation.spending_proposals.show.sent") %>: + <%= l @spending_proposal.created_at, format: :datetime %> +

    + +

    <%= t("valuation.spending_proposals.show.responsibles") %>

    + +

    <%= t("valuation.spending_proposals.show.assigned_admin") %>: + <% if @spending_proposal.administrator.present? %> + <%= @spending_proposal.administrator.name %> (<%= @spending_proposal.administrator.email %>) + <% else %> + <%= t("valuation.spending_proposals.show.undefined") %> + <% end %> +

    + +

    <%= t("valuation.spending_proposals.show.assigned_valuators") %>:

    +
    +
      + <% @spending_proposal.valuators.each do |valuator| %> +
    • <%= valuator.name %> (<%= valuator.email %>)
    • + <% end %> + + <% if @spending_proposal.valuators.empty? %> +
    • <%= t("valuation.spending_proposals.show.undefined") %>
    • + <% end %> +
    +
    + + +

    <%= t("valuation.spending_proposals.show.dossier") %>

    + +

    <%= t("valuation.spending_proposals.show.price") %> (<%= t("valuation.spending_proposals.show.currency") %>): + <%= @spending_proposal.price.present? ? @spending_proposal.price : t("valuation.spending_proposals.show.undefined") %> +

    +<%= simple_format(safe_html_with_links(@spending_proposal.price_explanation.html_safe), {}, sanitize: false) if @spending_proposal.price_explanation.present? %> + +

    <%= t("valuation.spending_proposals.show.feasibility") %>: + <%= t("valuation.spending_proposals.show.#{@spending_proposal.feasibility}") %> +

    +<%= simple_format(safe_html_with_links(@spending_proposal.feasible_explanation.html_safe), {}, sanitize: false) if @spending_proposal.feasible_explanation.present? %> + +<% if @spending_proposal.valuation_finished %> +

    <%= t("valuation.spending_proposals.show.valuation_finished") %> +<% end %> + +<% if @spending_proposal.internal_comments.present? %> +

    <%= t("valuation.spending_proposals.show.internal_comments") %>

    + <%= simple_format(safe_html_with_links(@spending_proposal.internal_comments.html_safe), {}, sanitize: false) %> +<% end %> \ No newline at end of file diff --git a/config/locales/valuation.en.yml b/config/locales/valuation.en.yml index 8d5c0f3ed..a9f7fb393 100644 --- a/config/locales/valuation.en.yml +++ b/config/locales/valuation.en.yml @@ -18,4 +18,24 @@ en: valuators_assigned: one: Assigned valuator other: "%{count} valuators assigned" - no_valuators_assigned: No valuators assigned \ No newline at end of file + no_valuators_assigned: No valuators assigned + show: + back: Back + heading: Investment project + info: Author info + association_name: Asociación + by: Sent by + sent: Sent at + geozone: Scope + dossier: Dossier + price: Price + currency: "€" + feasibility: Feasibility + feasible: Feasible + not_feasible: Not feasible + undefined: Undefined + valuation_finished: Valuation finished + internal_comments: Internal comments + responsibles: Responsibles + assigned_admin: Assigned admin + assigned_valuators: Assigned valuators diff --git a/config/locales/valuation.es.yml b/config/locales/valuation.es.yml index ca65fd82a..a30abc252 100644 --- a/config/locales/valuation.es.yml +++ b/config/locales/valuation.es.yml @@ -18,4 +18,24 @@ es: valuators_assigned: one: Evaluador asignado other: "%{count} evaluadores asignados" - no_valuators_assigned: Sin evaluador \ No newline at end of file + no_valuators_assigned: Sin evaluador + show: + back: Volver + heading: Propuesta de inversión + info: Datos de envío + association_name: Asociación + by: Enviada por + sent: Fecha de creación + geozone: Ámbito + dossier: Informe + price: Coste + currency: "€" + feasibility: Viabilidad + feasible: Viable + not_feasible: No viable + undefined: Sin definir + valuation_finished: Informe finalizado + internal_comments: Commentarios internos + responsibles: Responsables + assigned_admin: Administrador asignado + assigned_valuators: Evaluadores asignados diff --git a/spec/features/valuation/spending_proposals_spec.rb b/spec/features/valuation/spending_proposals_spec.rb index ae0c7df7a..78ce2e08d 100644 --- a/spec/features/valuation/spending_proposals_spec.rb +++ b/spec/features/valuation/spending_proposals_spec.rb @@ -140,4 +140,35 @@ feature 'Valuation spending proposals' do expect(page).to have_content("Old idea") end + scenario 'Show' do + administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org')) + valuator = create(:valuator, user: create(:user, username: 'Rachel', email: 'rachel@valuators.org')) + spending_proposal = create(:spending_proposal, + geozone: create(:geozone), + association_name: 'People of the neighbourhood', + price: 1234.56, + feasible: false, + feasible_explanation: 'It is impossible', + administrator: administrator) + spending_proposal.valuators << valuator + + visit valuation_spending_proposals_path + + click_link spending_proposal.title + + expect(page).to have_content(spending_proposal.title) + expect(page).to have_content(spending_proposal.description) + expect(page).to have_content(spending_proposal.author.name) + expect(page).to have_content(spending_proposal.association_name) + expect(page).to have_content(spending_proposal.geozone.name) + expect(page).to have_content('1234.56') + expect(page).to have_content('Not feasible') + expect(page).to have_content('It is impossible') + expect(page).to have_content('Ana (ana@admins.org)') + + within('#assigned_valuators') do + expect(page).to have_content('Rachel (rachel@valuators.org)') + end + end + end From 6929b7863de39cbda375c9d31349a898583543fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Sat, 5 Mar 2016 12:46:16 +0100 Subject: [PATCH 07/17] adds price_first_year to spending proposals --- app/views/admin/spending_proposals/show.html.erb | 4 ++++ app/views/valuation/spending_proposals/show.html.erb | 3 +++ config/locales/admin.en.yml | 1 + config/locales/admin.es.yml | 1 + config/locales/valuation.en.yml | 1 + config/locales/valuation.es.yml | 1 + .../20160305113707_add_price_fields_to_spending_proposals.rb | 5 +++++ db/schema.rb | 3 ++- spec/features/admin/spending_proposals_spec.rb | 2 ++ 9 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20160305113707_add_price_fields_to_spending_proposals.rb diff --git a/app/views/admin/spending_proposals/show.html.erb b/app/views/admin/spending_proposals/show.html.erb index cbdfbb2ad..6be63d9ff 100644 --- a/app/views/admin/spending_proposals/show.html.erb +++ b/app/views/admin/spending_proposals/show.html.erb @@ -62,6 +62,10 @@

    <%= t("admin.spending_proposals.show.price") %> (<%= t("admin.spending_proposals.show.currency") %>): <%= @spending_proposal.price.present? ? @spending_proposal.price : t("admin.spending_proposals.show.undefined") %>

    +

    <%= t("admin.spending_proposals.show.price_first_year") %> (<%= t("admin.spending_proposals.show.currency") %>): + <%= @spending_proposal.price_first_year.present? ? @spending_proposal.price_first_year : t("admin.spending_proposals.show.undefined") %> +

    + <%= simple_format(safe_html_with_links(@spending_proposal.price_explanation.html_safe), {}, sanitize: false) if @spending_proposal.price_explanation.present? %>

    <%= t("admin.spending_proposals.show.feasibility") %>: diff --git a/app/views/valuation/spending_proposals/show.html.erb b/app/views/valuation/spending_proposals/show.html.erb index cc0c8bca6..636249d31 100644 --- a/app/views/valuation/spending_proposals/show.html.erb +++ b/app/views/valuation/spending_proposals/show.html.erb @@ -57,6 +57,9 @@

    <%= t("valuation.spending_proposals.show.price") %> (<%= t("valuation.spending_proposals.show.currency") %>): <%= @spending_proposal.price.present? ? @spending_proposal.price : t("valuation.spending_proposals.show.undefined") %>

    +

    <%= t("valuation.spending_proposals.show.price_first_year") %> (<%= t("valuation.spending_proposals.show.currency") %>): + <%= @spending_proposal.price_first_year.present? ? @spending_proposal.price_first_year : t("valuation.spending_proposals.show.undefined") %> +

    <%= simple_format(safe_html_with_links(@spending_proposal.price_explanation.html_safe), {}, sanitize: false) if @spending_proposal.price_explanation.present? %>

    <%= t("valuation.spending_proposals.show.feasibility") %>: diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml index bd31ad1ad..07f236456 100755 --- a/config/locales/admin.en.yml +++ b/config/locales/admin.en.yml @@ -173,6 +173,7 @@ en: geozone: Scope dossier: Dossier price: Price + price_first_year: Cost during the first year currency: "€" feasibility: Feasibility feasible: Feasible diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml index 53f615c1a..442294de0 100644 --- a/config/locales/admin.es.yml +++ b/config/locales/admin.es.yml @@ -173,6 +173,7 @@ es: geozone: Ámbito dossier: Informe price: Coste + price_first_year: Coste en el primer año currency: "€" feasibility: Viabilidad feasible: Viable diff --git a/config/locales/valuation.en.yml b/config/locales/valuation.en.yml index a9f7fb393..c48153516 100644 --- a/config/locales/valuation.en.yml +++ b/config/locales/valuation.en.yml @@ -29,6 +29,7 @@ en: geozone: Scope dossier: Dossier price: Price + price_first_year: Cost during the first year currency: "€" feasibility: Feasibility feasible: Feasible diff --git a/config/locales/valuation.es.yml b/config/locales/valuation.es.yml index a30abc252..81c082c87 100644 --- a/config/locales/valuation.es.yml +++ b/config/locales/valuation.es.yml @@ -29,6 +29,7 @@ es: geozone: Ámbito dossier: Informe price: Coste + price_first_year: Coste en el primer año currency: "€" feasibility: Viabilidad feasible: Viable diff --git a/db/migrate/20160305113707_add_price_fields_to_spending_proposals.rb b/db/migrate/20160305113707_add_price_fields_to_spending_proposals.rb new file mode 100644 index 000000000..dad22583d --- /dev/null +++ b/db/migrate/20160305113707_add_price_fields_to_spending_proposals.rb @@ -0,0 +1,5 @@ +class AddPriceFieldsToSpendingProposals < ActiveRecord::Migration + def change + add_column :spending_proposals, :price_first_year, :float + end +end diff --git a/db/schema.rb b/db/schema.rb index bd85c43a6..ffe2a9a8b 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: 20160225171916) do +ActiveRecord::Schema.define(version: 20160305113707) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -309,6 +309,7 @@ ActiveRecord::Schema.define(version: 20160225171916) do t.text "explanations_log" t.integer "administrator_id" t.integer "valuation_assignments_count", default: 0 + t.float "price_first_year" end add_index "spending_proposals", ["author_id"], name: "index_spending_proposals_on_author_id", using: :btree diff --git a/spec/features/admin/spending_proposals_spec.rb b/spec/features/admin/spending_proposals_spec.rb index f4bd4582c..3fe32dfbb 100644 --- a/spec/features/admin/spending_proposals_spec.rb +++ b/spec/features/admin/spending_proposals_spec.rb @@ -169,6 +169,7 @@ feature 'Admin spending proposals' do geozone: create(:geozone), association_name: 'People of the neighbourhood', price: 1234.56, + price_first_year: 1000, feasible: false, feasible_explanation: 'It is impossible', administrator: administrator) @@ -184,6 +185,7 @@ feature 'Admin spending proposals' do expect(page).to have_content(spending_proposal.association_name) expect(page).to have_content(spending_proposal.geozone.name) expect(page).to have_content('1234.56') + expect(page).to have_content('1000') expect(page).to have_content('Not feasible') expect(page).to have_content('It is impossible') expect(page).to have_select('spending_proposal[administrator_id]', selected: 'Ana (ana@admins.org)') From 0e0ebc71d08c1acb18671dcfe749f0e788787091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Mon, 7 Mar 2016 16:09:03 +0100 Subject: [PATCH 08/17] adds time scope to spending proposals --- .../20160307150804_add_time_scope_to_spending_proposals.rb | 5 +++++ db/schema.rb | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20160307150804_add_time_scope_to_spending_proposals.rb diff --git a/db/migrate/20160307150804_add_time_scope_to_spending_proposals.rb b/db/migrate/20160307150804_add_time_scope_to_spending_proposals.rb new file mode 100644 index 000000000..550c57061 --- /dev/null +++ b/db/migrate/20160307150804_add_time_scope_to_spending_proposals.rb @@ -0,0 +1,5 @@ +class AddTimeScopeToSpendingProposals < ActiveRecord::Migration + def change + add_column :spending_proposals, :time_scope, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index ffe2a9a8b..a95afc8da 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: 20160305113707) do +ActiveRecord::Schema.define(version: 20160307150804) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -310,6 +310,7 @@ ActiveRecord::Schema.define(version: 20160305113707) do t.integer "administrator_id" t.integer "valuation_assignments_count", default: 0 t.float "price_first_year" + t.string "time_scope" end add_index "spending_proposals", ["author_id"], name: "index_spending_proposals_on_author_id", using: :btree From 7b4b3386f7be20da878439aaf271fa3332b2fe57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Tue, 8 Mar 2016 10:21:37 +0100 Subject: [PATCH 09/17] changes styles for radio buttons and fieldsets --- app/assets/stylesheets/admin.scss | 2 +- app/assets/stylesheets/layout.scss | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index bc9d05e48..4f6d1f7a4 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -168,7 +168,7 @@ body.admin { clear: both; .checkbox { - font-size: rem-calc(12); + font-size: $small-font-size; } } diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index 26931ef86..98cb62258 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -641,6 +641,10 @@ form { line-height: $line-height; } + fieldset legend { + font-weight: bold; + } + input, textarea { height: 48px\9; line-height: 48px\9; @@ -648,13 +652,28 @@ form { width: 100%\9; } - input[type="checkbox"] { + input[type="checkbox"], + input[type="radio"] { height: auto\9; line-height: inherit\9; width: auto\9; } - input[type]:not([type=submit]):not([type=file]):not([type=checkbox]) { + input[type="radio"] { + height: $line-height !important; + vertical-align: top; + width: 18px\9; + + + label { + font-weight: normal; + } + + &:checked + label { + font-weight: bold; + } + } + + input[type]:not([type=submit]):not([type=file]):not([type=checkbox]):not([type=radio]) { background: $input-bg; height: $line-height*2; margin-bottom: rem-calc(16); From fcd6d0ce8b8d54e879eeb8ba14428d872f3c132f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baza=CC=81n?= Date: Tue, 8 Mar 2016 11:19:23 +0100 Subject: [PATCH 10/17] adds dossier edition to valuators --- .../spending_proposals_controller.rb | 12 ++ .../spending_proposals/edit.html.erb | 138 ++++++++++++++++++ .../spending_proposals/index.html.erb | 6 +- .../spending_proposals/show.html.erb | 17 ++- config/locales/valuation.en.yml | 23 ++- config/locales/valuation.es.yml | 23 ++- config/routes.rb | 2 +- .../valuation/spending_proposals_spec.rb | 83 +++++++++-- 8 files changed, 278 insertions(+), 26 deletions(-) create mode 100644 app/views/valuation/spending_proposals/edit.html.erb diff --git a/app/controllers/valuation/spending_proposals_controller.rb b/app/controllers/valuation/spending_proposals_controller.rb index 21389d4a2..309a12a37 100644 --- a/app/controllers/valuation/spending_proposals_controller.rb +++ b/app/controllers/valuation/spending_proposals_controller.rb @@ -9,4 +9,16 @@ class Valuation::SpendingProposalsController < Valuation::BaseController def index @spending_proposals = SpendingProposal.search(params, @current_filter).order(created_at: :desc).page(params[:page]) end + + def valuate + @spending_proposal.update_attributes(valuation_params) + redirect_to valuation_spending_proposal_path(@spending_proposal), notice: t('valuation.spending_proposals.notice.valuate') + end + + private + + def valuation_params + params.require(:spending_proposal).permit(:price, :price_first_year, :price_explanation, :feasible, :feasible_explanation, :time_scope, :valuation_finished, :internal_comments) + end + end diff --git a/app/views/valuation/spending_proposals/edit.html.erb b/app/views/valuation/spending_proposals/edit.html.erb new file mode 100644 index 000000000..eb8c275d4 --- /dev/null +++ b/app/views/valuation/spending_proposals/edit.html.erb @@ -0,0 +1,138 @@ +<%= link_to "#{t('valuation.spending_proposals.show.heading')} #{@spending_proposal.id}", valuation_spending_proposal_path(@spending_proposal), class: 'back' %> +

    <%= t("valuation.spending_proposals.edit.dossier") %>

    + +<%= form_for(@spending_proposal, url: valuate_valuation_spending_proposal_path(@spending_proposal)) do |f| %> + <%= render 'shared/errors', resource: @spending_proposal %> +
    +
    + <%= f.label :price, "#{t('valuation.spending_proposals.edit.price')} (#{t('valuation.spending_proposals.edit.currency')})" %> + <%= f.text_field :price, label: false %> +
    + +
    + <%= f.label :price_first_year, "#{t('valuation.spending_proposals.edit.price_first_year')} ( #{t('valuation.spending_proposals.edit.currency')})" %> + <%= f.text_field :price_first_year, label: false %> +
    +
    + +
    +
    + <%= f.label :price_explanation, t("valuation.spending_proposals.edit.price_explanation") %> + <%= f.text_area :price_explanation, label: false, rows: 3 %> +
    +
    + +
    +
    +
    + <%= t('valuation.spending_proposals.edit.feasibility') %> +
    + + <%= f.radio_button :feasible, true, value: true, label: false %> + <%= f.label :feasible_true, t('valuation.spending_proposals.edit.feasible') %> + +
    + +
    + + <%= f.radio_button :feasible, false, value: false, label: false %> + <%= f.label :feasible_false, t('valuation.spending_proposals.edit.not_feasible') %> + +
    +
    +
    +
    + +
    +
    + <%= f.label :feasible_explanation, t("valuation.spending_proposals.edit.feasible_explanation") %> + <%= f.text_area :feasible_explanation, label: false, rows: 3 %> +
    +
    + +
    +
    + <%= f.label :time_scope, t("valuation.spending_proposals.edit.time_scope") %> + <%= f.text_field :time_scope, label: false %> +
    +
    + +
    +
    + <%= f.label :valuation_finished do %> + <%= f.check_box :valuation_finished, label: false %> + <%= t("valuation.spending_proposals.edit.valuation_finished") %> + <% end %> +
    +
    + +
    +
    + <%= f.label :internal_comments, t("valuation.spending_proposals.edit.internal_comments") %> + <%= f.text_area :internal_comments, label: false, rows: 3 %> +
    +
    + +
    +
    + <%= f.submit(class: "button expanded large", value: t("valuation.spending_proposals.edit.save")) %> +
    +
    +<% end %> + +

    <%= @spending_proposal.title %>

    + +<%= safe_html_with_links @spending_proposal.description %> + +<% if @spending_proposal.external_url.present? %> +

    <%= text_with_links @spending_proposal.external_url %>

    +<% end %> + +

    <%= t("valuation.spending_proposals.show.info") %>

    + +

    <%= t("valuation.spending_proposals.show.by") %>: + <%= link_to @spending_proposal.author.name, user_path(@spending_proposal.author) %> +

    + +<% if @spending_proposal.association_name.present? %> +

    <%= t("valuation.spending_proposals.show.association_name") %>: + <%= @spending_proposal.association_name %> +

    +<% end %> + +

    <%= t("valuation.spending_proposals.show.geozone") %>: + <%= geozone_name(@spending_proposal) %> +

    + +

    <%= t("valuation.spending_proposals.show.sent") %>: + <%= l @spending_proposal.created_at, format: :datetime %> +

    + +

    <%= t("valuation.spending_proposals.show.responsibles") %>

    + +

    <%= t("valuation.spending_proposals.show.assigned_admin") %>: + <% if @spending_proposal.administrator.present? %> + <%= @spending_proposal.administrator.name %> (<%= @spending_proposal.administrator.email %>) + <% else %> + <%= t("valuation.spending_proposals.show.undefined") %> + <% end %> +

    + +

    <%= t("valuation.spending_proposals.show.assigned_valuators") %>:

    +
    +
      + <% @spending_proposal.valuators.each do |valuator| %> +
    • <%= valuator.name %> (<%= valuator.email %>)
    • + <% end %> + + <% if @spending_proposal.valuators.empty? %> +
    • <%= t("valuation.spending_proposals.show.undefined") %>
    • + <% end %> +
    +
    + + + + + + diff --git a/app/views/valuation/spending_proposals/index.html.erb b/app/views/valuation/spending_proposals/index.html.erb index 5aa486677..ddc4003e8 100644 --- a/app/views/valuation/spending_proposals/index.html.erb +++ b/app/views/valuation/spending_proposals/index.html.erb @@ -33,11 +33,7 @@ <%= link_to spending_proposal.title, valuation_spending_proposal_path(spending_proposal) %> - <% if spending_proposal.administrator.present? %> - <%= spending_proposal.administrator.name %> - <% else %> - <%= t("valuation.spending_proposals.index.no_admin_assigned") %> - <% end %> + <%= link_to t("valuation.spending_proposals.index.edit"), edit_valuation_spending_proposal_path(spending_proposal) %> <% case spending_proposal.valuators.size %> diff --git a/app/views/valuation/spending_proposals/show.html.erb b/app/views/valuation/spending_proposals/show.html.erb index 636249d31..9ebaa0c24 100644 --- a/app/views/valuation/spending_proposals/show.html.erb +++ b/app/views/valuation/spending_proposals/show.html.erb @@ -1,5 +1,5 @@ <%= link_to t("valuation.spending_proposals.show.back"), :back, class: 'back' %> -

    <%= t("valuation.spending_proposals.show.heading") %> <%= @spending_proposal.id %>

    +

    <%= t("valuation.spending_proposals.show.heading") %> <%= @spending_proposal.id %>

    <%= @spending_proposal.title %>

    <%= safe_html_with_links @spending_proposal.description %> @@ -51,18 +51,23 @@ -

    <%= t("valuation.spending_proposals.show.dossier") %>

    -

    <%= t("valuation.spending_proposals.show.price") %> (<%= t("valuation.spending_proposals.show.currency") %>): +

    <%= link_to t("valuation.spending_proposals.show.edit_dossier"), edit_valuation_spending_proposal_path(@spending_proposal) %>

    + +

    <%= t("valuation.spending_proposals.show.price") %> (<%= t("valuation.spending_proposals.show.currency") %>): <%= @spending_proposal.price.present? ? @spending_proposal.price : t("valuation.spending_proposals.show.undefined") %>

    -

    <%= t("valuation.spending_proposals.show.price_first_year") %> (<%= t("valuation.spending_proposals.show.currency") %>): +

    <%= t("valuation.spending_proposals.show.price_first_year") %> (<%= t("valuation.spending_proposals.show.currency") %>): <%= @spending_proposal.price_first_year.present? ? @spending_proposal.price_first_year : t("valuation.spending_proposals.show.undefined") %>

    <%= simple_format(safe_html_with_links(@spending_proposal.price_explanation.html_safe), {}, sanitize: false) if @spending_proposal.price_explanation.present? %> -

    <%= t("valuation.spending_proposals.show.feasibility") %>: +

    <%= t("valuation.spending_proposals.show.time_scope") %>: + <%= @spending_proposal.time_scope.present? ? @spending_proposal.time_scope : t("valuation.spending_proposals.show.undefined") %> +

    + +

    <%= t("valuation.spending_proposals.show.feasibility") %>: <%= t("valuation.spending_proposals.show.#{@spending_proposal.feasibility}") %>

    <%= simple_format(safe_html_with_links(@spending_proposal.feasible_explanation.html_safe), {}, sanitize: false) if @spending_proposal.feasible_explanation.present? %> @@ -74,4 +79,4 @@ <% if @spending_proposal.internal_comments.present? %>

    <%= t("valuation.spending_proposals.show.internal_comments") %>

    <%= simple_format(safe_html_with_links(@spending_proposal.internal_comments.html_safe), {}, sanitize: false) %> -<% end %> \ No newline at end of file +<% end %> diff --git a/config/locales/valuation.en.yml b/config/locales/valuation.en.yml index c48153516..826f70db7 100644 --- a/config/locales/valuation.en.yml +++ b/config/locales/valuation.en.yml @@ -13,8 +13,7 @@ en: valuating: Under valuation valuation_finished: Valuation finished title: Investment projects for participatory budgeting - admin_assigned: Assigned administrator - no_admin_assigned: No admin assigned + edit: Edit valuators_assigned: one: Assigned valuator other: "%{count} valuators assigned" @@ -28,6 +27,7 @@ en: sent: Sent at geozone: Scope dossier: Dossier + edit_dossier: Edit dossier price: Price price_first_year: Cost during the first year currency: "€" @@ -36,7 +36,26 @@ en: not_feasible: Not feasible undefined: Undefined valuation_finished: Valuation finished + time_scope: Time scope internal_comments: Internal comments responsibles: Responsibles assigned_admin: Assigned admin assigned_valuators: Assigned valuators + edit: + dossier: Dossier + price: Price + price_first_year: Cost during the first year + currency: "€" + price_explanation: Price explanation + feasibility: Feasibility + feasible: Feasible + not_feasible: Not feasible + feasible_explanation: Feasibility explanation + valuation_finished: Valuation finished + time_scope: Time scope + internal_comments: Internal comments + save: Save changes + notice: + valuate: "Dossier updated" + + diff --git a/config/locales/valuation.es.yml b/config/locales/valuation.es.yml index 81c082c87..8f3804ccb 100644 --- a/config/locales/valuation.es.yml +++ b/config/locales/valuation.es.yml @@ -13,8 +13,7 @@ es: valuating: En evaluación valuation_finished: Evaluación finalizada title: Propuestas de inversión para presupuestos participativos - admin_assigned: Administrador asignado - no_admin_assigned: Sin admin asignado + edit: Editar valuators_assigned: one: Evaluador asignado other: "%{count} evaluadores asignados" @@ -28,6 +27,7 @@ es: sent: Fecha de creación geozone: Ámbito dossier: Informe + edit_dossier: Editar informe price: Coste price_first_year: Coste en el primer año currency: "€" @@ -36,7 +36,24 @@ es: not_feasible: No viable undefined: Sin definir valuation_finished: Informe finalizado - internal_comments: Commentarios internos + time_scope: Plazo de ejecución + internal_comments: Comentarios internos responsibles: Responsables assigned_admin: Administrador asignado assigned_valuators: Evaluadores asignados + edit: + dossier: Informe + price: Coste + price_first_year: Coste en el primer año + currency: "€" + price_explanation: Justificación del precio + feasibility: Viabilidad + feasible: Viable + not_feasible: No viable + feasible_explanation: Justificación de la viabilidad + valuation_finished: Informe finalizado + time_scope: Plazo de ejecución + internal_comments: Comentarios internos + save: Guardar cambios + notice: + valuate: "Informe actualizado" diff --git a/config/routes.rb b/config/routes.rb index 2e1cbce68..77491bb5e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -211,7 +211,7 @@ Rails.application.routes.draw do namespace :valuation do root to: "spending_proposals#index" - resources :spending_proposals, only: [:index, :show] do + resources :spending_proposals, only: [:index, :show, :edit] do member do patch :valuate end diff --git a/spec/features/valuation/spending_proposals_spec.rb b/spec/features/valuation/spending_proposals_spec.rb index 78ce2e08d..e500c8f8d 100644 --- a/spec/features/valuation/spending_proposals_spec.rb +++ b/spec/features/valuation/spending_proposals_spec.rb @@ -3,8 +3,8 @@ require 'rails_helper' feature 'Valuation spending proposals' do background do - valuator = create(:valuator) - login_as(valuator.user) + @valuator = create(:valuator, user: create(:user, username: 'Rachel', email: 'rachel@valuators.org')) + login_as(@valuator.user) end scenario 'Disabled with a feature flag' do @@ -35,17 +35,14 @@ feature 'Valuation spending proposals' do visit valuation_spending_proposals_path within("#spending_proposal_#{spending_proposal1.id}") do - expect(page).to have_content("No admin assigned") expect(page).to have_content("Olga") end within("#spending_proposal_#{spending_proposal2.id}") do - expect(page).to have_content("No admin assigned") expect(page).to have_content("2 valuators assigned") end within("#spending_proposal_#{spending_proposal3.id}") do - expect(page).to have_content("Gema") expect(page).to have_content("No valuators assigned") end end @@ -76,10 +73,10 @@ feature 'Valuation spending proposals' do scenario "Index filtering by valuator", :js do user = create(:user, username: 'Karnak') - valuator = create(:valuator, user: user) + valuator1 = create(:valuator, user: user) spending = create(:spending_proposal, title: "Realocate visitors") - spending.valuators << valuator + spending.valuators << valuator1 create(:spending_proposal, title: "Destroy the city") visit valuation_spending_proposals_path @@ -142,7 +139,7 @@ feature 'Valuation spending proposals' do scenario 'Show' do administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org')) - valuator = create(:valuator, user: create(:user, username: 'Rachel', email: 'rachel@valuators.org')) + valuator2 = create(:valuator, user: create(:user, username: 'Rick', email: 'rick@valuators.org')) spending_proposal = create(:spending_proposal, geozone: create(:geozone), association_name: 'People of the neighbourhood', @@ -150,7 +147,7 @@ feature 'Valuation spending proposals' do feasible: false, feasible_explanation: 'It is impossible', administrator: administrator) - spending_proposal.valuators << valuator + spending_proposal.valuators << [@valuator, valuator2] visit valuation_spending_proposals_path @@ -168,6 +165,74 @@ feature 'Valuation spending proposals' do within('#assigned_valuators') do expect(page).to have_content('Rachel (rachel@valuators.org)') + expect(page).to have_content('Rick (rick@valuators.org)') + end + end + + feature 'Valuate' do + background do + @spending_proposal = create(:spending_proposal, + geozone: create(:geozone), + administrator: create(:administrator)) + @spending_proposal.valuators << @valuator + end + + scenario 'Dossier empty by default' do + visit valuation_spending_proposals_path + click_link @spending_proposal.title + + within('#price') { expect(page).to have_content('Undefined') } + within('#price_first_year') { expect(page).to have_content('Undefined') } + within('#time_scope') { expect(page).to have_content('Undefined') } + within('#feasibility') { expect(page).to have_content('Undefined') } + expect(page).to_not have_content('Valuation finished') + expect(page).to_not have_content('Internal comments') + end + + scenario 'Edit dossier' do + visit valuation_spending_proposals_path + within("#spending_proposal_#{@spending_proposal.id}") do + click_link "Edit" + end + + fill_in 'spending_proposal_price', with: '12345.67' + fill_in 'spending_proposal_price_first_year', with: '8910.11' + fill_in 'spending_proposal_price_explanation', with: 'Very cheap idea' + choose 'spending_proposal_feasible_true' + fill_in 'spending_proposal_feasible_explanation', with: 'Everything is legal and easy to do' + fill_in 'spending_proposal_time_scope', with: '19 months' + fill_in 'spending_proposal_internal_comments', with: 'Should be double checked by the urbanism area' + click_button 'Save changes' + + expect(page).to have_content "Dossier updated" + + visit valuation_spending_proposals_path + click_link @spending_proposal.title + + within('#price') { expect(page).to have_content('12345.67') } + within('#price_first_year') { expect(page).to have_content('8910.11') } + expect(page).to have_content('Very cheap idea') + within('#time_scope') { expect(page).to have_content('19 months') } + within('#feasibility') { expect(page).to have_content('Feasible') } + expect(page).to_not have_content('Valuation finished') + expect(page).to have_content('Internal comments') + expect(page).to have_content('Should be double checked by the urbanism area') + end + + scenario 'Finish valuation' do + visit valuation_spending_proposal_path(@spending_proposal) + click_link 'Edit dossier' + + check 'spending_proposal_valuation_finished' + click_button 'Save changes' + + visit valuation_spending_proposals_path + expect(page).to_not have_content @spending_proposal.title + click_link 'Valuation finished' + + expect(page).to have_content @spending_proposal.title + click_link @spending_proposal.title + expect(page).to have_content('Valuation finished') end end From 6e28ae790cc474b95525709bbc78fb5a05717742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Tue, 8 Mar 2016 11:46:16 +0100 Subject: [PATCH 11/17] changes price columns type: float to integer --- ...3548_change_price_fields_in_spending_proposals.rb | 11 +++++++++++ db/schema.rb | 6 +++--- spec/features/valuation/spending_proposals_spec.rb | 12 ++++++------ 3 files changed, 20 insertions(+), 9 deletions(-) create mode 100644 db/migrate/20160308103548_change_price_fields_in_spending_proposals.rb diff --git a/db/migrate/20160308103548_change_price_fields_in_spending_proposals.rb b/db/migrate/20160308103548_change_price_fields_in_spending_proposals.rb new file mode 100644 index 000000000..532d2662b --- /dev/null +++ b/db/migrate/20160308103548_change_price_fields_in_spending_proposals.rb @@ -0,0 +1,11 @@ +class ChangePriceFieldsInSpendingProposals < ActiveRecord::Migration + def up + change_column :spending_proposals, :price, :integer + change_column :spending_proposals, :price_first_year, :integer + end + + def down + change_column :spending_proposals, :price, :float + change_column :spending_proposals, :price_first_year, :float + end +end diff --git a/db/schema.rb b/db/schema.rb index a95afc8da..04f41722d 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: 20160307150804) do +ActiveRecord::Schema.define(version: 20160308103548) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -299,7 +299,7 @@ ActiveRecord::Schema.define(version: 20160307150804) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "geozone_id" - t.float "price" + t.integer "price" t.boolean "feasible" t.string "association_name" t.text "price_explanation" @@ -309,7 +309,7 @@ ActiveRecord::Schema.define(version: 20160307150804) do t.text "explanations_log" t.integer "administrator_id" t.integer "valuation_assignments_count", default: 0 - t.float "price_first_year" + t.integer "price_first_year" t.string "time_scope" end diff --git a/spec/features/valuation/spending_proposals_spec.rb b/spec/features/valuation/spending_proposals_spec.rb index e500c8f8d..c627ce420 100644 --- a/spec/features/valuation/spending_proposals_spec.rb +++ b/spec/features/valuation/spending_proposals_spec.rb @@ -143,7 +143,7 @@ feature 'Valuation spending proposals' do spending_proposal = create(:spending_proposal, geozone: create(:geozone), association_name: 'People of the neighbourhood', - price: 1234.56, + price: 1234, feasible: false, feasible_explanation: 'It is impossible', administrator: administrator) @@ -158,7 +158,7 @@ feature 'Valuation spending proposals' do expect(page).to have_content(spending_proposal.author.name) expect(page).to have_content(spending_proposal.association_name) expect(page).to have_content(spending_proposal.geozone.name) - expect(page).to have_content('1234.56') + expect(page).to have_content('1234') expect(page).to have_content('Not feasible') expect(page).to have_content('It is impossible') expect(page).to have_content('Ana (ana@admins.org)') @@ -195,8 +195,8 @@ feature 'Valuation spending proposals' do click_link "Edit" end - fill_in 'spending_proposal_price', with: '12345.67' - fill_in 'spending_proposal_price_first_year', with: '8910.11' + fill_in 'spending_proposal_price', with: '12345' + fill_in 'spending_proposal_price_first_year', with: '9876' fill_in 'spending_proposal_price_explanation', with: 'Very cheap idea' choose 'spending_proposal_feasible_true' fill_in 'spending_proposal_feasible_explanation', with: 'Everything is legal and easy to do' @@ -209,8 +209,8 @@ feature 'Valuation spending proposals' do visit valuation_spending_proposals_path click_link @spending_proposal.title - within('#price') { expect(page).to have_content('12345.67') } - within('#price_first_year') { expect(page).to have_content('8910.11') } + within('#price') { expect(page).to have_content('12345') } + within('#price_first_year') { expect(page).to have_content('9876') } expect(page).to have_content('Very cheap idea') within('#time_scope') { expect(page).to have_content('19 months') } within('#feasibility') { expect(page).to have_content('Feasible') } From d39eb9ba9b3b634f766c6101a1a0547621c521b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Tue, 8 Mar 2016 11:58:24 +0100 Subject: [PATCH 12/17] uses number fields for price inputs --- app/views/valuation/spending_proposals/edit.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/valuation/spending_proposals/edit.html.erb b/app/views/valuation/spending_proposals/edit.html.erb index eb8c275d4..215998b3b 100644 --- a/app/views/valuation/spending_proposals/edit.html.erb +++ b/app/views/valuation/spending_proposals/edit.html.erb @@ -6,12 +6,12 @@
    <%= f.label :price, "#{t('valuation.spending_proposals.edit.price')} (#{t('valuation.spending_proposals.edit.currency')})" %> - <%= f.text_field :price, label: false %> + <%= f.number_field :price, label: false %>
    <%= f.label :price_first_year, "#{t('valuation.spending_proposals.edit.price_first_year')} ( #{t('valuation.spending_proposals.edit.currency')})" %> - <%= f.text_field :price_first_year, label: false %> + <%= f.number_field :price_first_year, label: false %>
    From 09bb3a13869fae910dd7e330bae3f7b3d8715925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baza=CC=81n?= Date: Tue, 8 Mar 2016 12:58:09 +0100 Subject: [PATCH 13/17] changes valuation interface to show only assigned Valuators can only see their assigned spending proposals Admins can see/edit all but index only shows their assigned items Removed filter by_valuator --- .../spending_proposals_controller.rb | 18 +- .../spending_proposals/index.html.erb | 7 - config/locales/valuation.en.yml | 1 - config/locales/valuation.es.yml | 1 - .../valuation/spending_proposals_spec.rb | 182 +++++++++++------- 5 files changed, 132 insertions(+), 77 deletions(-) diff --git a/app/controllers/valuation/spending_proposals_controller.rb b/app/controllers/valuation/spending_proposals_controller.rb index 309a12a37..f5074ab1e 100644 --- a/app/controllers/valuation/spending_proposals_controller.rb +++ b/app/controllers/valuation/spending_proposals_controller.rb @@ -2,12 +2,18 @@ class Valuation::SpendingProposalsController < Valuation::BaseController include FeatureFlags feature_flag :spending_proposals - has_filters %w{valuation_open valuating valuation_finished}, only: :index + before_action :restrict_access_to_assigned_items, only: [:show, :edit, :valuate] + + has_filters %w{valuating valuation_finished}, only: :index load_and_authorize_resource def index - @spending_proposals = SpendingProposal.search(params, @current_filter).order(created_at: :desc).page(params[:page]) + if current_user.valuator? + @spending_proposals = SpendingProposal.search(params_for_current_valuator, @current_filter).order(created_at: :desc).page(params[:page]) + else + @spending_proposals = SpendingProposal.none.page(params[:page]) + end end def valuate @@ -21,4 +27,12 @@ class Valuation::SpendingProposalsController < Valuation::BaseController params.require(:spending_proposal).permit(:price, :price_first_year, :price_explanation, :feasible, :feasible_explanation, :time_scope, :valuation_finished, :internal_comments) end + def params_for_current_valuator + params.merge({valuator_id: current_user.valuator.id}) + end + + def restrict_access_to_assigned_items + raise ActionController::RoutingError.new('Not Found') unless current_user.administrator? || ValuationAssignment.exists?(spending_proposal_id: params[:id], valuator_id: current_user.valuator.id) + end + end diff --git a/app/views/valuation/spending_proposals/index.html.erb b/app/views/valuation/spending_proposals/index.html.erb index ddc4003e8..b47348e09 100644 --- a/app/views/valuation/spending_proposals/index.html.erb +++ b/app/views/valuation/spending_proposals/index.html.erb @@ -9,13 +9,6 @@ label: false, class: "js-submit-on-change" } %> -
    - <%= select_tag :valuator_id, - options_for_select(valuator_select_options(current_user.valuator), params[:valuator_id]), - { prompt: t("valuation.spending_proposals.index.valuator_filter_all"), - label: false, - class: "js-submit-on-change" } %> -
    <% end %> diff --git a/config/locales/valuation.en.yml b/config/locales/valuation.en.yml index 826f70db7..2aba2e89c 100644 --- a/config/locales/valuation.en.yml +++ b/config/locales/valuation.en.yml @@ -7,7 +7,6 @@ en: spending_proposals: index: geozone_filter_all: All zones - valuator_filter_all: All valuators filters: valuation_open: Open valuating: Under valuation diff --git a/config/locales/valuation.es.yml b/config/locales/valuation.es.yml index 8f3804ccb..94e9d1ec0 100644 --- a/config/locales/valuation.es.yml +++ b/config/locales/valuation.es.yml @@ -7,7 +7,6 @@ es: spending_proposals: index: geozone_filter_all: Todos los ámbitos de actuación - valuator_filter_all: Todos los evaluadores filters: valuation_open: Abiertas valuating: En evaluación diff --git a/spec/features/valuation/spending_proposals_spec.rb b/spec/features/valuation/spending_proposals_spec.rb index c627ce420..e5bde98d4 100644 --- a/spec/features/valuation/spending_proposals_spec.rb +++ b/spec/features/valuation/spending_proposals_spec.rb @@ -12,11 +12,29 @@ feature 'Valuation spending proposals' do expect{ visit valuation_spending_proposals_path }.to raise_exception(FeatureFlags::FeatureDisabled) end - scenario 'Index shows spending proposals' do - spending_proposal = create(:spending_proposal) + scenario 'Index shows spending proposals assigned to current valuator' do + spending_proposal1 = create(:spending_proposal) + spending_proposal2 = create(:spending_proposal) + + spending_proposal1.valuators << @valuator + visit valuation_spending_proposals_path - expect(page).to have_content(spending_proposal.title) + expect(page).to have_content(spending_proposal1.title) + expect(page).to_not have_content(spending_proposal2.title) + end + + scenario 'Index shows no spending proposals to admins no valuators' do + spending_proposal1 = create(:spending_proposal) + spending_proposal2 = create(:spending_proposal) + spending_proposal1.valuators << @valuator + + logout + login_as create(:administrator).user + visit valuation_spending_proposals_path + + expect(page).to_not have_content(spending_proposal1.title) + expect(page).to_not have_content(spending_proposal2.title) end scenario 'Index shows assignments info' do @@ -24,33 +42,35 @@ feature 'Valuation spending proposals' do spending_proposal2 = create(:spending_proposal) spending_proposal3 = create(:spending_proposal) - valuator1 = create(:valuator, user: create(:user, username: 'Olga')) - valuator2 = create(:valuator, user: create(:user, username: 'Miriam')) - admin = create(:administrator, user: create(:user, username: 'Gema')) + valuator1 = create(:valuator, user: create(:user)) + valuator2 = create(:valuator, user: create(:user)) + valuator3 = create(:valuator, user: create(:user)) - spending_proposal1.valuators << valuator1 - spending_proposal2.valuator_ids = [valuator1.id, valuator2.id] - spending_proposal3.update({administrator_id: admin.id}) + spending_proposal1.valuator_ids = [@valuator.id] + spending_proposal2.valuator_ids = [@valuator.id, valuator1.id, valuator2.id] + spending_proposal3.valuator_ids = [@valuator.id, valuator3.id] visit valuation_spending_proposals_path within("#spending_proposal_#{spending_proposal1.id}") do - expect(page).to have_content("Olga") + expect(page).to have_content("Rachel") end within("#spending_proposal_#{spending_proposal2.id}") do - expect(page).to have_content("2 valuators assigned") + expect(page).to have_content("3 valuators assigned") end within("#spending_proposal_#{spending_proposal3.id}") do - expect(page).to have_content("No valuators assigned") + expect(page).to have_content("2 valuators assigned") end end scenario "Index filtering by geozone", :js do geozone = create(:geozone, name: "District 9") - create(:spending_proposal, title: "Realocate visitors", geozone: geozone) - create(:spending_proposal, title: "Destroy the city") + spending_proposal1 = create(:spending_proposal, title: "Realocate visitors", geozone: geozone) + spending_proposal2 = create(:spending_proposal, title: "Destroy the city") + spending_proposal1.valuators << @valuator + spending_proposal2.valuators << @valuator visit valuation_spending_proposals_path expect(page).to have_link("Realocate visitors") @@ -71,32 +91,8 @@ feature 'Valuation spending proposals' do expect(page).to have_link("Destroy the city") end - scenario "Index filtering by valuator", :js do - user = create(:user, username: 'Karnak') - valuator1 = create(:valuator, user: user) - - spending = create(:spending_proposal, title: "Realocate visitors") - spending.valuators << valuator1 - create(:spending_proposal, title: "Destroy the city") - - visit valuation_spending_proposals_path - expect(page).to have_link("Realocate visitors") - expect(page).to have_link("Destroy the city") - - select "Karnak", from: "valuator_id" - - expect(page).to have_link("Realocate visitors") - expect(page).to_not have_link("Destroy the city") - - select "All valuators", from: "valuator_id" - - expect(page).to 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', - 'valuating' => 'Under valuation', + filters_links = {'valuating' => 'Under valuation', 'valuation_finished' => 'Valuation finished'} visit valuation_spending_proposals_path @@ -118,8 +114,8 @@ feature 'Valuation spending proposals' do scenario "Index filtering by valuation status" do valuating = create(:spending_proposal, title: "Ongoing valuation") valuated = create(:spending_proposal, title: "Old idea", valuation_finished: true) - valuating.valuators << create(:valuator) - valuated.valuators << create(:valuator) + valuating.valuators << @valuator + valuated.valuators << @valuator visit valuation_spending_proposals_path(filter: 'valuation_open') @@ -137,36 +133,90 @@ feature 'Valuation spending proposals' do expect(page).to have_content("Old idea") end - scenario 'Show' do - administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org')) - valuator2 = create(:valuator, user: create(:user, username: 'Rick', email: 'rick@valuators.org')) - spending_proposal = create(:spending_proposal, - geozone: create(:geozone), - association_name: 'People of the neighbourhood', - price: 1234, - feasible: false, - feasible_explanation: 'It is impossible', - administrator: administrator) - spending_proposal.valuators << [@valuator, valuator2] + feature 'Show' do + scenario 'visible for assigned valuators' do + administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org')) + valuator2 = create(:valuator, user: create(:user, username: 'Rick', email: 'rick@valuators.org')) + spending_proposal = create(:spending_proposal, + geozone: create(:geozone), + association_name: 'People of the neighbourhood', + price: 1234, + feasible: false, + feasible_explanation: 'It is impossible', + administrator: administrator) + spending_proposal.valuators << [@valuator, valuator2] - visit valuation_spending_proposals_path + visit valuation_spending_proposals_path - click_link spending_proposal.title + click_link spending_proposal.title - expect(page).to have_content(spending_proposal.title) - expect(page).to have_content(spending_proposal.description) - expect(page).to have_content(spending_proposal.author.name) - expect(page).to have_content(spending_proposal.association_name) - expect(page).to have_content(spending_proposal.geozone.name) - expect(page).to have_content('1234') - expect(page).to have_content('Not feasible') - expect(page).to have_content('It is impossible') - expect(page).to have_content('Ana (ana@admins.org)') + expect(page).to have_content(spending_proposal.title) + expect(page).to have_content(spending_proposal.description) + expect(page).to have_content(spending_proposal.author.name) + expect(page).to have_content(spending_proposal.association_name) + expect(page).to have_content(spending_proposal.geozone.name) + expect(page).to have_content('1234') + expect(page).to have_content('Not feasible') + expect(page).to have_content('It is impossible') + expect(page).to have_content('Ana (ana@admins.org)') - within('#assigned_valuators') do - expect(page).to have_content('Rachel (rachel@valuators.org)') - expect(page).to have_content('Rick (rick@valuators.org)') + within('#assigned_valuators') do + expect(page).to have_content('Rachel (rachel@valuators.org)') + expect(page).to have_content('Rick (rick@valuators.org)') + end end + + scenario 'visible for admins' do + logout + login_as create(:administrator).user + + administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org')) + valuator2 = create(:valuator, user: create(:user, username: 'Rick', email: 'rick@valuators.org')) + spending_proposal = create(:spending_proposal, + geozone: create(:geozone), + association_name: 'People of the neighbourhood', + price: 1234, + feasible: false, + feasible_explanation: 'It is impossible', + administrator: administrator) + spending_proposal.valuators << [@valuator, valuator2] + + visit valuation_spending_proposal_path(spending_proposal) + + expect(page).to have_content(spending_proposal.title) + expect(page).to have_content(spending_proposal.description) + expect(page).to have_content(spending_proposal.author.name) + expect(page).to have_content(spending_proposal.association_name) + expect(page).to have_content(spending_proposal.geozone.name) + expect(page).to have_content('1234') + expect(page).to have_content('Not feasible') + expect(page).to have_content('It is impossible') + expect(page).to have_content('Ana (ana@admins.org)') + + within('#assigned_valuators') do + expect(page).to have_content('Rachel (rachel@valuators.org)') + expect(page).to have_content('Rick (rick@valuators.org)') + end + end + + scenario 'not visible for not assigned valuators' do + logout + login_as create(:valuator).user + + administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org')) + valuator2 = create(:valuator, user: create(:user, username: 'Rick', email: 'rick@valuators.org')) + spending_proposal = create(:spending_proposal, + geozone: create(:geozone), + association_name: 'People of the neighbourhood', + price: 1234, + feasible: false, + feasible_explanation: 'It is impossible', + administrator: administrator) + spending_proposal.valuators << [@valuator, valuator2] + + expect { visit valuation_spending_proposal_path(spending_proposal) }.to raise_error "Not Found" + end + end feature 'Valuate' do From 1cbd1f9324489c7cf2016ec7a6a37ca7dbf943dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Tue, 8 Mar 2016 13:33:03 +0100 Subject: [PATCH 14/17] moves assigned valuators info to helper --- app/helpers/valuation_helper.rb | 15 +++++++++++++++ .../valuation/spending_proposals/index.html.erb | 13 +------------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/app/helpers/valuation_helper.rb b/app/helpers/valuation_helper.rb index becd29abb..cd70a6732 100644 --- a/app/helpers/valuation_helper.rb +++ b/app/helpers/valuation_helper.rb @@ -8,4 +8,19 @@ module ValuationHelper end end + def assigned_valuators_info(valuators) + case valuators.size + when 0 + t("valuation.spending_proposals.index.no_valuators_assigned") + when 1 + "".html_safe + + valuators.first.name + + "".html_safe + else + "".html_safe + + t('valuation.spending_proposals.index.valuators_assigned', count: valuators.size) + + "".html_safe + end + end + end \ No newline at end of file diff --git a/app/views/valuation/spending_proposals/index.html.erb b/app/views/valuation/spending_proposals/index.html.erb index b47348e09..e6c05d6c7 100644 --- a/app/views/valuation/spending_proposals/index.html.erb +++ b/app/views/valuation/spending_proposals/index.html.erb @@ -29,18 +29,7 @@ <%= link_to t("valuation.spending_proposals.index.edit"), edit_valuation_spending_proposal_path(spending_proposal) %> - <% case spending_proposal.valuators.size %> - <% when 0 %> - <%= t("valuation.spending_proposals.index.no_valuators_assigned") %> - <% when 1 %> - - <%= spending_proposal.valuators.first.name %> - - <% else %> - - <%= t('valuation.spending_proposals.index.valuators_assigned', count: spending_proposal.valuators.size) %> - - <% end %> + <%= assigned_valuators_info(spending_proposal.valuators) %> <%= geozone_name(spending_proposal) %> From 7231f72e0101d2f2f3c0b99fabdd2d1f73ca6001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Tue, 8 Mar 2016 13:40:35 +0100 Subject: [PATCH 15/17] cleans up show view --- app/helpers/text_with_links_helper.rb | 4 +++ .../spending_proposals/show.html.erb | 33 ++++++++++++------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/app/helpers/text_with_links_helper.rb b/app/helpers/text_with_links_helper.rb index fe726c51e..ac965dafa 100644 --- a/app/helpers/text_with_links_helper.rb +++ b/app/helpers/text_with_links_helper.rb @@ -11,4 +11,8 @@ module TextWithLinksHelper Rinku.auto_link(html, :all, 'target="_blank" rel="nofollow"').html_safe end + def simple_format_no_tags_no_sanitize(html) + simple_format(html, {}, sanitize: false) + end + end diff --git a/app/views/valuation/spending_proposals/show.html.erb b/app/views/valuation/spending_proposals/show.html.erb index 9ebaa0c24..e98968fee 100644 --- a/app/views/valuation/spending_proposals/show.html.erb +++ b/app/views/valuation/spending_proposals/show.html.erb @@ -53,30 +53,39 @@

    <%= t("valuation.spending_proposals.show.dossier") %>

    -

    <%= link_to t("valuation.spending_proposals.show.edit_dossier"), edit_valuation_spending_proposal_path(@spending_proposal) %>

    - -

    <%= t("valuation.spending_proposals.show.price") %> (<%= t("valuation.spending_proposals.show.currency") %>): - <%= @spending_proposal.price.present? ? @spending_proposal.price : t("valuation.spending_proposals.show.undefined") %> +

    + <%= link_to t("valuation.spending_proposals.show.edit_dossier"), edit_valuation_spending_proposal_path(@spending_proposal) %>

    -

    <%= t("valuation.spending_proposals.show.price_first_year") %> (<%= t("valuation.spending_proposals.show.currency") %>): - <%= @spending_proposal.price_first_year.present? ? @spending_proposal.price_first_year : t("valuation.spending_proposals.show.undefined") %> + +

    + <%= t("valuation.spending_proposals.show.price") %> (<%= t("valuation.spending_proposals.show.currency") %>): + <%= @spending_proposal.price.presence or t("valuation.spending_proposals.show.undefined") %> +

    +

    + <%= t("valuation.spending_proposals.show.price_first_year") %> (<%= t("valuation.spending_proposals.show.currency") %>): + <%= @spending_proposal.price_first_year.presence or t("valuation.spending_proposals.show.undefined") %>

    <%= simple_format(safe_html_with_links(@spending_proposal.price_explanation.html_safe), {}, sanitize: false) if @spending_proposal.price_explanation.present? %> -

    <%= t("valuation.spending_proposals.show.time_scope") %>: - <%= @spending_proposal.time_scope.present? ? @spending_proposal.time_scope : t("valuation.spending_proposals.show.undefined") %> +

    + <%= t("valuation.spending_proposals.show.time_scope") %>: + <%= @spending_proposal.time_scope.presence or t("valuation.spending_proposals.show.undefined") %>

    -

    <%= t("valuation.spending_proposals.show.feasibility") %>: +

    + <%= t("valuation.spending_proposals.show.feasibility") %>: <%= t("valuation.spending_proposals.show.#{@spending_proposal.feasibility}") %>

    -<%= simple_format(safe_html_with_links(@spending_proposal.feasible_explanation.html_safe), {}, sanitize: false) if @spending_proposal.feasible_explanation.present? %> + +<%= simple_format_no_tags_no_sanitize(safe_html_with_links(@spending_proposal.feasible_explanation.html_safe)) if @spending_proposal.feasible_explanation.present? %> <% if @spending_proposal.valuation_finished %> -

    <%= t("valuation.spending_proposals.show.valuation_finished") %> +

    + <%= t("valuation.spending_proposals.show.valuation_finished") %> +

    <% end %> <% if @spending_proposal.internal_comments.present? %>

    <%= t("valuation.spending_proposals.show.internal_comments") %>

    - <%= simple_format(safe_html_with_links(@spending_proposal.internal_comments.html_safe), {}, sanitize: false) %> + <%= simple_format_no_tags_no_sanitize(safe_html_with_links(@spending_proposal.internal_comments.html_safe)) %> <% end %> From 4d1b65c7140403ee389896db87976314abef20ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baza=CC=81n?= Date: Tue, 8 Mar 2016 13:40:42 +0100 Subject: [PATCH 16/17] fixes admin spec --- app/views/valuation/spending_proposals/edit.html.erb | 8 +------- spec/features/admin/spending_proposals_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/app/views/valuation/spending_proposals/edit.html.erb b/app/views/valuation/spending_proposals/edit.html.erb index 215998b3b..a3dba0b4b 100644 --- a/app/views/valuation/spending_proposals/edit.html.erb +++ b/app/views/valuation/spending_proposals/edit.html.erb @@ -129,10 +129,4 @@
  • <%= t("valuation.spending_proposals.show.undefined") %>
  • <% end %> - - - - - - - + \ No newline at end of file diff --git a/spec/features/admin/spending_proposals_spec.rb b/spec/features/admin/spending_proposals_spec.rb index 3fe32dfbb..da17c3f35 100644 --- a/spec/features/admin/spending_proposals_spec.rb +++ b/spec/features/admin/spending_proposals_spec.rb @@ -168,7 +168,7 @@ feature 'Admin spending proposals' do spending_proposal = create(:spending_proposal, geozone: create(:geozone), association_name: 'People of the neighbourhood', - price: 1234.56, + price: 1234, price_first_year: 1000, feasible: false, feasible_explanation: 'It is impossible', @@ -184,7 +184,7 @@ feature 'Admin spending proposals' do expect(page).to have_content(spending_proposal.author.name) expect(page).to have_content(spending_proposal.association_name) expect(page).to have_content(spending_proposal.geozone.name) - expect(page).to have_content('1234.56') + expect(page).to have_content('1234') expect(page).to have_content('1000') expect(page).to have_content('Not feasible') expect(page).to have_content('It is impossible') From 2f4621ab09aa41dc2918fb5e977496745ac9b4f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juanjo=20Baz=C3=A1n?= Date: Tue, 8 Mar 2016 14:01:16 +0100 Subject: [PATCH 17/17] adds helper for explanation fields --- app/helpers/valuation_helper.rb | 4 ++++ app/views/valuation/spending_proposals/show.html.erb | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/helpers/valuation_helper.rb b/app/helpers/valuation_helper.rb index cd70a6732..9e3a054c1 100644 --- a/app/helpers/valuation_helper.rb +++ b/app/helpers/valuation_helper.rb @@ -23,4 +23,8 @@ module ValuationHelper end end + def explanation_field(field) + simple_format_no_tags_no_sanitize(safe_html_with_links(field.html_safe)) if field.present? + end + end \ No newline at end of file diff --git a/app/views/valuation/spending_proposals/show.html.erb b/app/views/valuation/spending_proposals/show.html.erb index e98968fee..16f83dbe4 100644 --- a/app/views/valuation/spending_proposals/show.html.erb +++ b/app/views/valuation/spending_proposals/show.html.erb @@ -65,7 +65,8 @@ <%= t("valuation.spending_proposals.show.price_first_year") %> (<%= t("valuation.spending_proposals.show.currency") %>): <%= @spending_proposal.price_first_year.presence or t("valuation.spending_proposals.show.undefined") %>

    -<%= simple_format(safe_html_with_links(@spending_proposal.price_explanation.html_safe), {}, sanitize: false) if @spending_proposal.price_explanation.present? %> + +<%= explanation_field @spending_proposal.price_explanation %>

    <%= t("valuation.spending_proposals.show.time_scope") %>: @@ -77,7 +78,7 @@ <%= t("valuation.spending_proposals.show.#{@spending_proposal.feasibility}") %>

    -<%= simple_format_no_tags_no_sanitize(safe_html_with_links(@spending_proposal.feasible_explanation.html_safe)) if @spending_proposal.feasible_explanation.present? %> +<%= explanation_field @spending_proposal.feasible_explanation %> <% if @spending_proposal.valuation_finished %>