diff --git a/CHANGELOG.md b/CHANGELOG.md index 8701852ce..c6fe7ef09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - Added Drafting phase to Budgets https://github.com/consul/consul/pull/2285 +- Added 'Publish investments price' phase to Budgets https://github.com/consul/consul/pull/2296 - Allow admins to destroy budgets without investments https://github.com/consul/consul/pull/2283 - Added rubocop-rspec gem, enabled cops one by one fixing offenses. - Added CSV download link to budget_investments https://github.com/consul/consul/pull/2147 - Added Capistrano task to automate maintenance mode https://github.com/consul/consul/pull/1932 +- Added actions to edit and delete a budget's headings https://github.com/consul/consul/pull/1917 ### Changed - Updated multiple minor & patch gem versions thanks to [Depfu](https://depfu.com) @@ -21,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Redirect admin to budget lists after edit https://github.com/consul/consul/pull/2284 - Improve budget investment form https://github.com/consul/consul/pull/2280 - Prevent edition of investments if budget is in the final phase https://github.com/consul/consul/pull/2223 +- Split 'routes.rb' file into multiple small files https://github.com/consul/consul/pull/1908 ### Deprecated diff --git a/app/controllers/admin/budget_headings_controller.rb b/app/controllers/admin/budget_headings_controller.rb index eea93716f..902f256b5 100644 --- a/app/controllers/admin/budget_headings_controller.rb +++ b/app/controllers/admin/budget_headings_controller.rb @@ -3,12 +3,33 @@ class Admin::BudgetHeadingsController < Admin::BaseController feature_flag :budgets def create - @budget = Budget.find params[:budget_id] - @budget_group = @budget.groups.find params[:budget_group_id] + @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 + def edit + @budget = Budget.find(params[:budget_id]) + @budget_group = @budget.groups.find(params[:budget_group_id]) + @heading = Budget::Heading.find(params[:id]) + end + + def update + @budget = Budget.find(params[:budget_id]) + @budget_group = @budget.groups.find(params[:budget_group_id]) + @heading = Budget::Heading.find(params[:id]) + @heading.assign_attributes(budget_heading_params) + render :edit unless @heading.save + end + + def destroy + @heading = Budget::Heading.find(params[:id]) + @heading.destroy + @budget = Budget.find(params[:budget_id]) + redirect_to admin_budget_path(@budget) + end + private def budget_heading_params diff --git a/app/controllers/admin/budget_investments_controller.rb b/app/controllers/admin/budget_investments_controller.rb index 0208fccd8..dbaa91f99 100644 --- a/app/controllers/admin/budget_investments_controller.rb +++ b/app/controllers/admin/budget_investments_controller.rb @@ -16,7 +16,7 @@ class Admin::BudgetInvestmentsController < Admin::BaseController respond_to do |format| format.html format.csv do - send_data Budget::Investment.to_csv(@investments, {headers: true}), + send_data Budget::Investment.to_csv(@investments, headers: true), filename: 'budget_investments.csv' end end diff --git a/app/helpers/budgets_helper.rb b/app/helpers/budgets_helper.rb index a14b86538..d2d6e1f5d 100644 --- a/app/helpers/budgets_helper.rb +++ b/app/helpers/budgets_helper.rb @@ -6,26 +6,6 @@ module BudgetsHelper csv_params end - def investment_selected_link(investment) - options = investment_selected_link_options(investment) - path = toggle_selection_admin_budget_budget_investment_path(@budget, - investment, filter: params[:filter], page: params[:page]) - link_options = {method: :patch, remote: true, class: options[:link_class]} - link_to options[:text], path, link_options - end - - def investment_selected_link_options(investment) - if investment.selected? - {link_class: "button small expanded", - text: t("admin.budget_investments.index.selected") } - elsif investment.feasible? && investment.valuation_finished? - {link_class: "button small hollow expanded", - text: t("admin.budget_investments.index.select")} - else - {} - end - end - def budget_phases_select_options Budget::PHASES.map { |ph| [ t("budgets.phase.#{ph}"), ph ] } end diff --git a/app/models/budget.rb b/app/models/budget.rb index ce8bc4dfa..6111df301 100644 --- a/app/models/budget.rb +++ b/app/models/budget.rb @@ -3,8 +3,11 @@ class Budget < ActiveRecord::Base include Measurable include Sluggable - PHASES = %w(drafting accepting reviewing selecting valuating balloting - reviewing_ballots finished).freeze + PHASES = %w(drafting accepting reviewing selecting valuating publishing_prices + balloting reviewing_ballots finished).freeze + ON_HOLD_PHASES = %w(reviewing valuating publishing_prices reviewing_ballots).freeze + PUBLISHED_PRICES_PHASES = %w(publishing_prices balloting reviewing_ballots finished).freeze + CURRENCY_SYMBOLS = %w(€ $ £ ¥).freeze validates :name, presence: true, uniqueness: true @@ -19,17 +22,18 @@ class Budget < ActiveRecord::Base before_validation :sanitize_descriptions - scope :on_hold, -> { where(phase: %w(reviewing valuating reviewing_ballots")) } - scope :drafting, -> { where(phase: "drafting") } + scope :on_hold, -> { where(phase: ON_HOLD_PHASES) } + scope :drafting, -> { where(phase: "drafting") } scope :accepting, -> { where(phase: "accepting") } scope :reviewing, -> { where(phase: "reviewing") } scope :selecting, -> { where(phase: "selecting") } scope :valuating, -> { where(phase: "valuating") } + scope :publishing_prices, -> { where(phase: "publishing_prices") } scope :balloting, -> { where(phase: "balloting") } scope :reviewing_ballots, -> { where(phase: "reviewing_ballots") } - scope :finished, -> { where(phase: "finished") } + scope :finished, -> { where(phase: "finished") } - scope :current, -> { where.not(phase: "finished") } + scope :current, -> { where.not(phase: "finished") } def description send("description_#{phase}").try(:html_safe) @@ -63,6 +67,10 @@ class Budget < ActiveRecord::Base phase == "valuating" end + def publishing_prices? + phase == "publishing_prices" + end + def balloting? phase == "balloting" end @@ -75,6 +83,10 @@ class Budget < ActiveRecord::Base phase == "finished" end + def published_prices? + PUBLISHED_PRICES_PHASES.include?(phase) + end + def balloting_process? balloting? || reviewing_ballots? end @@ -84,7 +96,7 @@ class Budget < ActiveRecord::Base end def on_hold? - reviewing? || valuating? || reviewing_ballots? + ON_HOLD_PHASES.include?(phase) end def current? @@ -118,7 +130,7 @@ class Budget < ActiveRecord::Base case phase when 'accepting', 'reviewing' %w{random} - when 'balloting', 'reviewing_ballots' + when 'publishing_prices', 'balloting', 'reviewing_ballots' %w{random price} else %w{random confidence_score} diff --git a/app/models/budget/heading.rb b/app/models/budget/heading.rb index d740db502..c9719a709 100644 --- a/app/models/budget/heading.rb +++ b/app/models/budget/heading.rb @@ -21,7 +21,11 @@ class Budget end def name_exists_in_budget_headings - group.budget.headings.where(name: name).any? + group.budget.headings.where(name: name).where.not(id: id).any? + end + + def can_be_deleted? + investments.empty? end end diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 4e2e5d0b0..579a39525 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -240,15 +240,11 @@ class Budget end def should_show_price? - feasible? && - selected? && - (budget.reviewing_ballots? || budget.finished?) + selected? && price.present? && budget.published_prices? end - def should_show_price_info? - feasible? && - price_explanation.present? && - (budget.balloting? || budget.reviewing_ballots? || budget.finished?) + def should_show_price_explanation? + should_show_price? && price_explanation.present? end def formatted_price diff --git a/app/views/admin/budget_headings/_errors.html.erb b/app/views/admin/budget_headings/_errors.html.erb new file mode 100644 index 000000000..bb3e5482e --- /dev/null +++ b/app/views/admin/budget_headings/_errors.html.erb @@ -0,0 +1,7 @@ +
+ +
diff --git a/app/views/admin/budget_headings/edit.js.erb b/app/views/admin/budget_headings/edit.js.erb new file mode 100644 index 000000000..5f9ac48f8 --- /dev/null +++ b/app/views/admin/budget_headings/edit.js.erb @@ -0,0 +1 @@ +$("#heading-<%=@heading.id%>").html("<%= j render("admin/budgets/heading_form", group: @budget_group, budget: @budget, heading: @heading) %>"); diff --git a/app/views/admin/budget_headings/update.js.erb b/app/views/admin/budget_headings/update.js.erb new file mode 100644 index 000000000..6466959cd --- /dev/null +++ b/app/views/admin/budget_headings/update.js.erb @@ -0,0 +1 @@ +$("#<%= dom_id(@budget_group) %>").html('<%= j render("admin/budgets/group", group: @budget_group, headings: @budget_group.headings) %>'); diff --git a/app/views/admin/budget_investments/_investments.html.erb b/app/views/admin/budget_investments/_investments.html.erb index 16d8a83a6..fa4753ddf 100644 --- a/app/views/admin/budget_investments/_investments.html.erb +++ b/app/views/admin/budget_investments/_investments.html.erb @@ -3,7 +3,8 @@ class: "float-right small" %> <% if @investments.any? %> -

<%= page_entries_info @investments %>

+

<%= page_entries_info @investments %>

+ @@ -28,14 +29,20 @@ <%= investment.id %> <% if params[:filter] == 'selected' %>
- <%= link_to investment.title, admin_budget_budget_investment_path(budget_id: @budget.id, id: investment.id, params: 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)), + target: "_blank" %> <%= investment.total_votes %> <% if investment.administrator.present? %> - <%= investment.administrator.name %> + + <%= investment.administrator.name %> + <% else %> <%= t("admin.budget_investments.index.no_admin_assigned") %> <% end %> @@ -59,7 +66,27 @@ <%= investment.valuation_finished? ? t('shared.yes'): t('shared.no') %> - <%= investment_selected_link(investment) %> + <% if investment.selected? %> + <%= link_to_unless investment.budget.finished?, + t("admin.budget_investments.index.selected"), + toggle_selection_admin_budget_budget_investment_path(@budget, + investment, + filter: params[:filter], + page: params[:page]), + method: :patch, + remote: true, + class: "button small expanded" %> + <% elsif investment.feasible? && investment.valuation_finished? %> + <%= link_to_unless investment.budget.finished?, + t("admin.budget_investments.index.select"), + toggle_selection_admin_budget_budget_investment_path(@budget, + investment, + filter: params[:filter], + page: params[:page]), + method: :patch, + remote: true, + class: "button small hollow expanded" %> + <% end %> diff --git a/app/views/admin/budgets/_group.html.erb b/app/views/admin/budgets/_group.html.erb index fab722083..d6a648f10 100644 --- a/app/views/admin/budgets/_group.html.erb +++ b/app/views/admin/budgets/_group.html.erb @@ -1,7 +1,7 @@ - @@ -11,7 +11,7 @@ - + @@ -29,62 +30,14 @@ - <% headings.each do |heading| %> - - - - - + <%= render "admin/budgets/heading", group: group, budget: @budget, heading: heading %> <% end %> diff --git a/app/views/admin/budgets/_heading.html.erb b/app/views/admin/budgets/_heading.html.erb new file mode 100644 index 000000000..bc9d59c5f --- /dev/null +++ b/app/views/admin/budgets/_heading.html.erb @@ -0,0 +1,27 @@ + + + + + + diff --git a/app/views/admin/budgets/_heading_form.html.erb b/app/views/admin/budgets/_heading_form.html.erb new file mode 100644 index 000000000..56590bf1b --- /dev/null +++ b/app/views/admin/budgets/_heading_form.html.erb @@ -0,0 +1,35 @@ +<%= form_for [:admin, budget, group, heading], remote: true do |f| %> + <%= render 'shared/errors', resource: heading %> + + <%= f.text_field :name, + label: false, + maxlength: 50, + placeholder: t("admin.budgets.form.heading") %> + +
+
+ + <%= f.text_field :price, + label: false, + maxlength: 8, + placeholder: t("admin.budgets.form.amount") %> +
+
+
+
+ + <%= f.text_field :population, + label: false, + maxlength: 8, + placeholder: t("admin.budgets.form.population"), + data: {toggle_focus: "population-info"} %> +
+
+ +
+
+ + <%= f.submit t("admin.budgets.form.save_heading"), class: "button success" %> +<% end %> diff --git a/app/views/budgets/investments/_investment_show.html.erb b/app/views/budgets/investments/_investment_show.html.erb index f81dd43b8..9e0fa1cdb 100644 --- a/app/views/budgets/investments/_investment_show.html.erb +++ b/app/views/budgets/investments/_investment_show.html.erb @@ -64,7 +64,7 @@

<%= investment.unfeasibility_explanation %>

<% end %> - <% if investment.should_show_price_info? %> + <% if investment.should_show_price_explanation? %>

<%= t('budgets.investments.show.price_explanation') %>

<%= investment.price_explanation %>

<% end %> diff --git a/config/initializers/routing.rb b/config/initializers/routing.rb new file mode 100644 index 000000000..32783d4a8 --- /dev/null +++ b/config/initializers/routing.rb @@ -0,0 +1,5 @@ +class ActionDispatch::Routing::Mapper + def draw(route_file) + instance_eval(File.read(Rails.root.join("config/routes/#{route_file}.rb"))) + end +end diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index df5a59c90..39d0e022a 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -125,6 +125,10 @@ en: title: "Title" description: "Description" publication_date: "Publication date" + budget/heading: + name: "Heading name" + price: "Price" + population: "Population" comment: body: "Comment" user: "User" diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 02811db20..67dd4a88a 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -141,6 +141,7 @@ en: undecided: "Undecided" selected: "Selected" select: "Select" + download_current_selection: "Download current selection" table_id: "ID" table_title: "Title" table_supports: "Supports" diff --git a/config/locales/en/budgets.yml b/config/locales/en/budgets.yml index 51a4571f2..a0fd28cac 100644 --- a/config/locales/en/budgets.yml +++ b/config/locales/en/budgets.yml @@ -34,6 +34,7 @@ en: reviewing: Reviewing projects selecting: Selecting projects valuating: Valuating projects + publishing_prices: Publishing projects prices balloting: Balloting projects reviewing_ballots: Reviewing Ballots finished: Finished budget diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 9feb6496a..9aa5447c2 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -177,6 +177,7 @@ en: proposal_notification: "Notification" spending_proposal: Spending proposal budget/investment: Investment + budget/heading: Budget Heading poll/shift: Shift poll/question/answer: Answer user: Account diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 60492dc32..18296b7bf 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -116,6 +116,10 @@ es: organization_name: "Si estás proponiendo en nombre de una organización o colectivo, escribe su nombre" image: "Imagen descriptiva de la propuesta de inversión" image_title: "Título de la imagen" + budget/heading: + name: "Nombre de la partida" + price: "Cantidad" + population: "Población" budget/investment/milestone: title: "Título" description: "Descripción" diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 6c95e6a15..a6fe235cc 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -141,6 +141,7 @@ es: undecided: "Sin decidir" selected: "Seleccionada" select: "Seleccionar" + download_current_selection: "Descargar selección actual" table_id: "ID" table_title: "Título" table_supports: "Apoyos" diff --git a/config/locales/es/budgets.yml b/config/locales/es/budgets.yml index bfd55f9cc..258f394d6 100644 --- a/config/locales/es/budgets.yml +++ b/config/locales/es/budgets.yml @@ -34,6 +34,7 @@ es: reviewing: Revisión interna de proyectos selecting: Fase de apoyos valuating: Evaluación de proyectos + publishing_prices: Publicación de precios balloting: Votación final reviewing_ballots: Votación finalizada finished: Resultados diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index 740751bc2..cf497ae9d 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -177,6 +177,7 @@ es: proposal_notification: "la notificación" spending_proposal: la propuesta de gasto budget/investment: la propuesta de inversión + budget/heading: la partida presupuestaria poll/shift: el turno poll/question/answer: la respuesta user: la cuenta diff --git a/config/routes.rb b/config/routes.rb index fb1535b6c..c85deab68 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -5,484 +5,47 @@ Rails.application.routes.draw do get '/sandbox/*template' => 'sandbox#show' end - devise_for :users, controllers: { - registrations: 'users/registrations', - sessions: 'users/sessions', - confirmations: 'users/confirmations', - omniauth_callbacks: 'users/omniauth_callbacks' - } - devise_for :organizations, class_name: 'User', - controllers: { - registrations: 'organizations/registrations', - sessions: 'devise/sessions' - }, - skip: [:omniauth_callbacks] + mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development? - devise_scope :organization do - get 'organizations/sign_up/success', to: 'organizations/registrations#success' - end - - devise_scope :user do - patch '/user/confirmation', to: 'users/confirmations#update', as: :update_user_confirmation - get '/user/registrations/check_username', to: 'users/registrations#check_username' - get 'users/sign_up/success', to: 'users/registrations#success' - get 'users/registrations/delete_form', to: 'users/registrations#delete_form' - delete 'users/registrations', to: 'users/registrations#delete' - get :finish_signup, to: 'users/registrations#finish_signup' - patch :do_finish_signup, to: 'users/registrations#do_finish_signup' - end + draw :account + draw :admin + draw :annotation + draw :budget + draw :comment + draw :community + draw :debate + draw :devise + draw :direct_upload + draw :document + draw :graphql + draw :legislation + draw :management + draw :moderation + draw :notification + draw :officing + draw :poll + draw :proposal + draw :related_content + draw :tag + draw :user + draw :valuation + draw :verification root 'welcome#index' get '/welcome', to: 'welcome#welcome' - get '/cuentasegura', to: 'welcome#verification', as: :cuentasegura - get '/consul.json', to: "installation#details" - resources :debates do - member do - post :vote - put :flag - put :unflag - put :mark_featured - put :unmark_featured - end - collection do - get :map - get :suggest - end - end - - resources :proposals do - member do - post :vote - post :vote_featured - put :flag - put :unflag - get :retire_form - get :share - patch :retire - end - collection do - get :map - get :suggest - get :summary - end - end - - resources :comments, only: [:create, :show], shallow: true do - member do - post :vote - put :flag - put :unflag - end - end - - resources :budgets, only: [:show, :index] do - resources :groups, controller: "budgets/groups", only: [:show] - resources :investments, controller: "budgets/investments", only: [:index, :new, :create, :show, :destroy] do - member do - post :vote - end - collection { get :suggest } - end - resource :ballot, only: :show, controller: "budgets/ballots" do - resources :lines, controller: "budgets/ballot/lines", only: [:create, :destroy] - end - resource :results, only: :show, controller: "budgets/results" - end - - scope '/participatory_budget' do - resources :spending_proposals, only: [:index, :new, :create, :show, :destroy], path: 'investment_projects' do - post :vote, on: :member - end - end - + resources :stats, only: [:index] + resources :images, only: [:destroy] + resources :documents, only: [:destroy] resources :follows, only: [:create, :destroy] - resources :documents, only: [:destroy] - - resources :images, only: [:destroy] - - resources :direct_uploads, only: [:create] - delete "direct_uploads/destroy", to: "direct_uploads#destroy", as: :direct_upload_destroy - - resources :stats, only: [:index] - - resources :legacy_legislations, only: [:show], path: 'legislations' - - resources :annotations do - get :search, on: :collection - end - - resources :polls, only: [:show, :index] do - member do - get :stats - get :results - end - resources :questions, controller: 'polls/questions', shallow: true do - post :answer, on: :member - end - end - - namespace :legislation do - resources :processes, only: [:index, :show] do - member do - get :debate - get :draft_publication - get :allegations - get :result_publication - get :proposals - end - resources :questions, only: [:show] do - resources :answers, only: [:create] - end - resources :proposals do - member do - post :vote - put :flag - put :unflag - end - collection do - get :map - get :suggest - end - end - resources :draft_versions, only: [:show] do - get :go_to_version, on: :collection - get :changes - resources :annotations do - get :search, on: :collection - get :comments - post :new_comment - end - end - end - end - - resources :users, only: [:show] do - resources :direct_messages, only: [:new, :create, :show] - end - - resource :account, controller: "account", only: [:show, :update, :delete] do - get :erase, on: :collection - end - - resources :notifications, only: [:index, :show] do - put :mark_all_as_read, on: :collection - end - - resources :proposal_notifications, only: [:new, :create, :show] - - resource :verification, controller: "verification", only: [:show] - - resources :communities, only: [:show] do - resources :topics - end - - scope module: :verification do - resource :residence, controller: "residence", only: [:new, :create] - resource :sms, controller: "sms", only: [:new, :create, :edit, :update] - resource :verified_user, controller: "verified_user", only: [:show] - resource :email, controller: "email", only: [:new, :show, :create] - resource :letter, controller: "letter", only: [:new, :create, :show, :edit, :update] - end - - resources :tags do - collection do - get :suggest - end - end - - namespace :admin do - root to: "dashboard#index" - resources :organizations, only: :index do - get :search, on: :collection - member do - put :verify - put :reject - end - end - - resources :hidden_users, only: [:index, :show] do - member do - put :restore - put :confirm_hide - end - end - - resources :debates, only: :index do - member do - put :restore - put :confirm_hide - end - end - - resources :proposals, only: :index do - member do - put :restore - put :confirm_hide - end - end - - resources :spending_proposals, only: [:index, :show, :edit, :update] do - member do - patch :assign_admin - patch :assign_valuators - end - - get :summary, on: :collection - end - - resources :budgets do - member do - put :calculate_winners - end - - resources :budget_groups do - resources :budget_headings do - end - end - - resources :budget_investments, only: [:index, :show, :edit, :update] do - resources :budget_investment_milestones - member { patch :toggle_selection } - end - end - - resources :signature_sheets, only: [:index, :new, :create, :show] - - resources :banners, only: [:index, :new, :create, :edit, :update, :destroy] do - collection { get :search} - end - - resources :comments, only: :index do - member do - put :restore - put :confirm_hide - end - end - - resources :tags, only: [:index, :create, :update, :destroy] - resources :officials, only: [:index, :edit, :update, :destroy] do - get :search, on: :collection - end - - resources :settings, only: [:index, :update] - put :update_map, to: "settings#update_map" - - resources :moderators, only: [:index, :create, :destroy] do - get :search, on: :collection - end - - resources :valuators, only: [:index, :create, :destroy] do - get :search, on: :collection - get :summary, on: :collection - end - - resources :managers, only: [:index, :create, :destroy] do - get :search, on: :collection - end - - resources :administrators, only: [:index, :create, :destroy] do - get :search, on: :collection - end - - resources :users, only: [:index, :show] - - scope module: :poll do - resources :polls do - get :booth_assignments, on: :collection - patch :add_question, on: :member - - resources :booth_assignments, only: [:index, :show, :create, :destroy] do - get :search_booths, on: :collection - get :manage, on: :collection - end - - resources :officer_assignments, only: [:index, :create, :destroy] do - get :search_officers, on: :collection - get :by_officer, on: :collection - end - - resources :recounts, only: :index - resources :results, only: :index - end - - resources :officers do - get :search, on: :collection - end - - resources :booths do - get :available, on: :collection - - resources :shifts do - get :search_officers, on: :collection - end - end - - resources :questions, shallow: true do - resources :answers, except: [:index, :destroy], controller: 'questions/answers', shallow: true do - resources :images, controller: 'questions/answers/images' - resources :videos, controller: 'questions/answers/videos' - get :documents, to: 'questions/answers#documents' - end - post '/answers/order_answers', to: 'questions/answers#order_answers' - end - end - - resources :verifications, controller: :verifications, only: :index do - get :search, on: :collection - end - - resource :activity, controller: :activity, only: :show - resources :newsletters, only: :index do - get :users, on: :collection - end - resource :stats, only: :show do - get :proposal_notifications, on: :collection - get :direct_messages, on: :collection - get :polls, on: :collection - end - - namespace :legislation do - resources :processes do - resources :questions - resources :proposals - resources :draft_versions - end - end - - namespace :api do - resource :stats, only: :show - end - - resources :geozones, only: [:index, :new, :create, :edit, :update, :destroy] - - namespace :site_customization do - resources :pages, except: [:show] - resources :images, only: [:index, :update, :destroy] - resources :content_blocks, except: [:show] - end - end - - namespace :moderation do - root to: "dashboard#index" - - resources :users, only: :index do - member do - put :hide - put :hide_in_moderation_screen - end - end - - resources :debates, only: :index do - put :hide, on: :member - put :moderate, on: :collection - end - - resources :proposals, only: :index do - put :hide, on: :member - put :moderate, on: :collection - end - - resources :comments, only: :index do - put :hide, on: :member - put :moderate, on: :collection - end - end - - namespace :valuation do - root to: "budgets#index" - - resources :spending_proposals, only: [:index, :show, :edit] do - patch :valuate, on: :member - end - - resources :budgets, only: :index do - resources :budget_investments, only: [:index, :show, :edit] do - patch :valuate, on: :member - end - end - end - - namespace :management do - root to: "dashboard#index" - - resources :document_verifications, only: [:index, :new, :create] do - post :check, on: :collection - end - - resources :email_verifications, only: [:new, :create] - - resources :user_invites, only: [:new, :create] - - resources :users, only: [:new, :create] do - collection do - delete :logout - delete :erase - end - end - - resource :account, controller: "account", only: [:show] - - get 'sign_in', to: 'sessions#create', as: :sign_in - - resource :session, only: [:create, :destroy] - resources :proposals, only: [:index, :new, :create, :show] do - post :vote, on: :member - get :print, on: :collection - end - - resources :spending_proposals, only: [:index, :new, :create, :show] do - post :vote, on: :member - get :print, on: :collection - end - - resources :budgets, only: :index do - collection do - get :create_investments - get :support_investments - get :print_investments - end - resources :investments, only: [:index, :new, :create, :show, :destroy], controller: 'budgets/investments' do - post :vote, on: :member - get :print, on: :collection - end - end - end - - namespace :officing do - resources :polls, only: [:index] do - get :final, on: :collection - - resources :results, only: [:new, :create, :index] - end - resource :residence, controller: "residence", only: [:new, :create] - resources :voters, only: [:new, :create] - root to: "dashboard#index" - end - - resources :related_contents, only: [:create] do - member do - put :score_positive - put :score_negative - end - end - - # GraphQL - get '/graphql', to: 'graphql#query' - post '/graphql', to: 'graphql#query' - - mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development? - - mount GraphiQL::Rails::Engine, at: '/graphiql', graphql_path: '/graphql' - - # more info pages + # More info pages get 'more-information', to: 'pages#show', id: 'more_info/index', as: 'more_info' get 'more-information/how-to-use', to: 'pages#show', id: 'more_info/how_to_use/index', as: 'how_to_use' get 'more-information/faq', to: 'pages#show', id: 'more_info/faq/index', as: 'faq' - # static pages + # Static pages get '/blog' => redirect("http://blog.consul/") resources :pages, path: '/', only: [:show] end diff --git a/config/routes/account.rb b/config/routes/account.rb new file mode 100644 index 000000000..2b377bc36 --- /dev/null +++ b/config/routes/account.rb @@ -0,0 +1,3 @@ +resource :account, controller: "account", only: [:show, :update, :delete] do + get :erase, on: :collection +end diff --git a/config/routes/admin.rb b/config/routes/admin.rb new file mode 100644 index 000000000..93a1a0cc8 --- /dev/null +++ b/config/routes/admin.rb @@ -0,0 +1,172 @@ +namespace :admin do + root to: "dashboard#index" + resources :organizations, only: :index do + get :search, on: :collection + member do + put :verify + put :reject + end + end + + resources :hidden_users, only: [:index, :show] do + member do + put :restore + put :confirm_hide + end + end + + resources :debates, only: :index do + member do + put :restore + put :confirm_hide + end + end + + resources :proposals, only: :index do + member do + put :restore + put :confirm_hide + end + end + + resources :spending_proposals, only: [:index, :show, :edit, :update] do + member do + patch :assign_admin + patch :assign_valuators + end + + get :summary, on: :collection + end + + resources :budgets do + member do + put :calculate_winners + end + + resources :budget_groups do + resources :budget_headings + end + + resources :budget_investments, only: [:index, :show, :edit, :update] do + resources :budget_investment_milestones + member { patch :toggle_selection } + end + end + + resources :signature_sheets, only: [:index, :new, :create, :show] + + resources :banners, only: [:index, :new, :create, :edit, :update, :destroy] do + collection { get :search } + end + + resources :comments, only: :index do + member do + put :restore + put :confirm_hide + end + end + + resources :tags, only: [:index, :create, :update, :destroy] + resources :officials, only: [:index, :edit, :update, :destroy] do + get :search, on: :collection + end + + resources :settings, only: [:index, :update] + put :update_map, to: "settings#update_map" + + resources :moderators, only: [:index, :create, :destroy] do + get :search, on: :collection + end + + resources :valuators, only: [:index, :create, :destroy] do + get :search, on: :collection + get :summary, on: :collection + end + + resources :managers, only: [:index, :create, :destroy] do + get :search, on: :collection + end + + resources :administrators, only: [:index, :create, :destroy] do + get :search, on: :collection + end + + resources :users, only: [:index, :show] + + scope module: :poll do + resources :polls do + get :booth_assignments, on: :collection + patch :add_question, on: :member + + resources :booth_assignments, only: [:index, :show, :create, :destroy] do + get :search_booths, on: :collection + get :manage, on: :collection + end + + resources :officer_assignments, only: [:index, :create, :destroy] do + get :search_officers, on: :collection + get :by_officer, on: :collection + end + + resources :recounts, only: :index + resources :results, only: :index + end + + resources :officers do + get :search, on: :collection + end + + resources :booths do + get :available, on: :collection + + resources :shifts do + get :search_officers, on: :collection + end + end + + resources :questions, shallow: true do + resources :answers, except: [:index, :destroy], controller: 'questions/answers' do + resources :images, controller: 'questions/answers/images' + resources :videos, controller: 'questions/answers/videos' + get :documents, to: 'questions/answers#documents' + end + post '/answers/order_answers', to: 'questions/answers#order_answers' + end + end + + resources :verifications, controller: :verifications, only: :index do + get :search, on: :collection + end + + resource :activity, controller: :activity, only: :show + + resources :newsletters, only: :index do + get :users, on: :collection + end + + resource :stats, only: :show do + get :proposal_notifications, on: :collection + get :direct_messages, on: :collection + get :polls, on: :collection + end + + namespace :legislation do + resources :processes do + resources :questions + resources :proposals + resources :draft_versions + end + end + + namespace :api do + resource :stats, only: :show + end + + resources :geozones, only: [:index, :new, :create, :edit, :update, :destroy] + + namespace :site_customization do + resources :pages, except: [:show] + resources :images, only: [:index, :update, :destroy] + resources :content_blocks, except: [:show] + end +end diff --git a/config/routes/annotation.rb b/config/routes/annotation.rb new file mode 100644 index 000000000..7566f73d6 --- /dev/null +++ b/config/routes/annotation.rb @@ -0,0 +1,3 @@ +resources :annotations do + get :search, on: :collection +end diff --git a/config/routes/budget.rb b/config/routes/budget.rb new file mode 100644 index 000000000..3a06f3c7c --- /dev/null +++ b/config/routes/budget.rb @@ -0,0 +1,19 @@ +resources :budgets, only: [:show, :index] do + resources :groups, controller: "budgets/groups", only: [:show] + resources :investments, controller: "budgets/investments", only: [:index, :new, :create, :show, :destroy] do + member { post :vote } + collection { get :suggest } + end + + resource :ballot, only: :show, controller: "budgets/ballots" do + resources :lines, controller: "budgets/ballot/lines", only: [:create, :destroy] + end + + resource :results, only: :show, controller: "budgets/results" +end + +scope '/participatory_budget' do + resources :spending_proposals, only: [:index, :new, :create, :show, :destroy], path: 'investment_projects' do + post :vote, on: :member + end +end diff --git a/config/routes/comment.rb b/config/routes/comment.rb new file mode 100644 index 000000000..f3e525396 --- /dev/null +++ b/config/routes/comment.rb @@ -0,0 +1,7 @@ +resources :comments, only: [:create, :show], shallow: true do + member do + post :vote + put :flag + put :unflag + end +end diff --git a/config/routes/community.rb b/config/routes/community.rb new file mode 100644 index 000000000..9e010ffb7 --- /dev/null +++ b/config/routes/community.rb @@ -0,0 +1,3 @@ +resources :communities, only: [:show] do + resources :topics +end diff --git a/config/routes/debate.rb b/config/routes/debate.rb new file mode 100644 index 000000000..2345d150f --- /dev/null +++ b/config/routes/debate.rb @@ -0,0 +1,14 @@ +resources :debates do + member do + post :vote + put :flag + put :unflag + put :mark_featured + put :unmark_featured + end + + collection do + get :map + get :suggest + end +end diff --git a/config/routes/devise.rb b/config/routes/devise.rb new file mode 100644 index 000000000..e789aec52 --- /dev/null +++ b/config/routes/devise.rb @@ -0,0 +1,27 @@ +devise_for :users, controllers: { + registrations: 'users/registrations', + sessions: 'users/sessions', + confirmations: 'users/confirmations', + omniauth_callbacks: 'users/omniauth_callbacks' + } + +devise_scope :user do + patch '/user/confirmation', to: 'users/confirmations#update', as: :update_user_confirmation + get '/user/registrations/check_username', to: 'users/registrations#check_username' + get 'users/sign_up/success', to: 'users/registrations#success' + get 'users/registrations/delete_form', to: 'users/registrations#delete_form' + delete 'users/registrations', to: 'users/registrations#delete' + get :finish_signup, to: 'users/registrations#finish_signup' + patch :do_finish_signup, to: 'users/registrations#do_finish_signup' +end + +devise_for :organizations, class_name: 'User', + controllers: { + registrations: 'organizations/registrations', + sessions: 'devise/sessions', + }, + skip: [:omniauth_callbacks] + +devise_scope :organization do + get 'organizations/sign_up/success', to: 'organizations/registrations#success' +end diff --git a/config/routes/direct_upload.rb b/config/routes/direct_upload.rb new file mode 100644 index 000000000..dbcf9a9d0 --- /dev/null +++ b/config/routes/direct_upload.rb @@ -0,0 +1,2 @@ +resources :direct_uploads, only: [:create] +delete "direct_uploads/destroy", to: "direct_uploads#destroy", as: :direct_upload_destroy diff --git a/config/routes/document.rb b/config/routes/document.rb new file mode 100644 index 000000000..164153b50 --- /dev/null +++ b/config/routes/document.rb @@ -0,0 +1,7 @@ +resources :documents, only: [:new, :create, :destroy] do + collection do + get :new_nested + delete :destroy_upload + post :upload + end +end diff --git a/config/routes/graphql.rb b/config/routes/graphql.rb new file mode 100644 index 000000000..d41efc54a --- /dev/null +++ b/config/routes/graphql.rb @@ -0,0 +1,3 @@ +get '/graphql', to: 'graphql#query' +post '/graphql', to: 'graphql#query' +mount GraphiQL::Rails::Engine, at: '/graphiql', graphql_path: '/graphql' diff --git a/config/routes/legislation.rb b/config/routes/legislation.rb new file mode 100644 index 000000000..a38dfcac5 --- /dev/null +++ b/config/routes/legislation.rb @@ -0,0 +1,37 @@ +namespace :legislation do + resources :processes, only: [:index, :show] do + member do + get :debate + get :draft_publication + get :allegations + get :result_publication + get :proposals + end + + resources :questions, only: [:show] do + resources :answers, only: [:create] + end + + resources :proposals do + member do + post :vote + put :flag + put :unflag + end + collection do + get :map + get :suggest + end + end + + resources :draft_versions, only: [:show] do + get :go_to_version, on: :collection + get :changes + resources :annotations do + get :search, on: :collection + get :comments + post :new_comment + end + end + end +end diff --git a/config/routes/management.rb b/config/routes/management.rb new file mode 100644 index 000000000..e7a746540 --- /dev/null +++ b/config/routes/management.rb @@ -0,0 +1,44 @@ +namespace :management do + root to: "dashboard#index" + + resources :document_verifications, only: [:index, :new, :create] do + post :check, on: :collection + end + + resources :email_verifications, only: [:new, :create] + resources :user_invites, only: [:new, :create] + + resources :users, only: [:new, :create] do + collection do + delete :logout + delete :erase + end + end + + resource :account, controller: "account", only: [:show] + resource :session, only: [:create, :destroy] + get 'sign_in', to: 'sessions#create', as: :sign_in + + resources :proposals, only: [:index, :new, :create, :show] do + post :vote, on: :member + get :print, on: :collection + end + + resources :spending_proposals, only: [:index, :new, :create, :show] do + post :vote, on: :member + get :print, on: :collection + end + + resources :budgets, only: :index do + collection do + get :create_investments + get :support_investments + get :print_investments + end + + resources :investments, only: [:index, :new, :create, :show, :destroy], controller: 'budgets/investments' do + post :vote, on: :member + get :print, on: :collection + end + end +end diff --git a/config/routes/moderation.rb b/config/routes/moderation.rb new file mode 100644 index 000000000..77eb0a216 --- /dev/null +++ b/config/routes/moderation.rb @@ -0,0 +1,25 @@ +namespace :moderation do + root to: "dashboard#index" + + resources :users, only: :index do + member do + put :hide + put :hide_in_moderation_screen + end + end + + resources :debates, only: :index do + put :hide, on: :member + put :moderate, on: :collection + end + + resources :proposals, only: :index do + put :hide, on: :member + put :moderate, on: :collection + end + + resources :comments, only: :index do + put :hide, on: :member + put :moderate, on: :collection + end +end diff --git a/config/routes/notification.rb b/config/routes/notification.rb new file mode 100644 index 000000000..18936ff59 --- /dev/null +++ b/config/routes/notification.rb @@ -0,0 +1,5 @@ +resources :notifications, only: [:index, :show] do + put :mark_all_as_read, on: :collection +end + +resources :proposal_notifications, only: [:new, :create, :show] diff --git a/config/routes/officing.rb b/config/routes/officing.rb new file mode 100644 index 000000000..7adfbbf60 --- /dev/null +++ b/config/routes/officing.rb @@ -0,0 +1,10 @@ +namespace :officing do + resources :polls, only: [:index] do + get :final, on: :collection + resources :results, only: [:new, :create, :index] + end + + resource :residence, controller: "residence", only: [:new, :create] + resources :voters, only: [:new, :create] + root to: "dashboard#index" +end diff --git a/config/routes/poll.rb b/config/routes/poll.rb new file mode 100644 index 000000000..2e9502745 --- /dev/null +++ b/config/routes/poll.rb @@ -0,0 +1,10 @@ +resources :polls, only: [:show, :index] do + member do + get :stats + get :results + end + + resources :questions, controller: 'polls/questions', shallow: true do + post :answer, on: :member + end +end diff --git a/config/routes/proposal.rb b/config/routes/proposal.rb new file mode 100644 index 000000000..d3408ed29 --- /dev/null +++ b/config/routes/proposal.rb @@ -0,0 +1,17 @@ +resources :proposals do + member do + post :vote + post :vote_featured + put :flag + put :unflag + get :retire_form + get :share + patch :retire + end + + collection do + get :map + get :suggest + get :summary + end +end diff --git a/config/routes/related_content.rb b/config/routes/related_content.rb new file mode 100644 index 000000000..e8730c344 --- /dev/null +++ b/config/routes/related_content.rb @@ -0,0 +1,6 @@ +resources :related_contents, only: [:create] do + member do + put :score_positive + put :score_negative + end +end diff --git a/config/routes/tag.rb b/config/routes/tag.rb new file mode 100644 index 000000000..f9c5ab66f --- /dev/null +++ b/config/routes/tag.rb @@ -0,0 +1,5 @@ +resources :tags do + collection do + get :suggest + end +end diff --git a/config/routes/user.rb b/config/routes/user.rb new file mode 100644 index 000000000..56647fd2e --- /dev/null +++ b/config/routes/user.rb @@ -0,0 +1,3 @@ +resources :users, only: [:show] do + resources :direct_messages, only: [:new, :create, :show] +end diff --git a/config/routes/valuation.rb b/config/routes/valuation.rb new file mode 100644 index 000000000..743bc1c72 --- /dev/null +++ b/config/routes/valuation.rb @@ -0,0 +1,13 @@ +namespace :valuation do + root to: "budgets#index" + + resources :spending_proposals, only: [:index, :show, :edit] do + patch :valuate, on: :member + end + + resources :budgets, only: :index do + resources :budget_investments, only: [:index, :show, :edit] do + patch :valuate, on: :member + end + end +end diff --git a/config/routes/verification.rb b/config/routes/verification.rb new file mode 100644 index 000000000..6af42e005 --- /dev/null +++ b/config/routes/verification.rb @@ -0,0 +1,9 @@ +scope module: :verification do + resource :residence, controller: "residence", only: [:new, :create] + resource :sms, controller: "sms", only: [:new, :create, :edit, :update] + resource :verified_user, controller: "verified_user", only: [:show] + resource :email, controller: "email", only: [:new, :show, :create] + resource :letter, controller: "letter", only: [:new, :create, :show, :edit, :update] +end + +resource :verification, controller: "verification", only: [:show] diff --git a/db/dev_seeds.rb b/db/dev_seeds.rb index d2c32cb02..8ed80d5cb 100644 --- a/db/dev_seeds.rb +++ b/db/dev_seeds.rb @@ -535,41 +535,29 @@ end section "Creating polls" do Poll.create(name: "Current Poll", - # TODO: Uncomment when Poll get slugs - # slug: "current-poll", starts_at: 7.days.ago, ends_at: 7.days.from_now, geozone_restricted: false) Poll.create(name: "Current Poll Geozone Restricted", - # TODO: Uncomment when Poll get slugs - # slug: "current-poll-geozone-restricted", starts_at: 5.days.ago, ends_at: 5.days.from_now, geozone_restricted: true, geozones: Geozone.reorder("RANDOM()").limit(3)) Poll.create(name: "Incoming Poll", - # TODO: Uncomment when Poll get slugs - # slug: "incoming-poll", starts_at: 1.month.from_now, ends_at: 2.months.from_now) Poll.create(name: "Recounting Poll", - # TODO: Uncomment when Poll get slugs - # slug: "recounting-poll", starts_at: 15.days.ago, ends_at: 2.days.ago) Poll.create(name: "Expired Poll without Stats & Results", - # TODO: Uncomment when Poll get slugs - # slug: "expired-poll-without-stats-and-results", starts_at: 2.months.ago, ends_at: 1.month.ago) Poll.create(name: "Expired Poll with Stats & Results", - # TODO: Uncomment when Poll get slugs - # slug: "expired-poll-with-stats-and-results", starts_at: 2.months.ago, ends_at: 1.month.ago, results_enabled: true, diff --git a/db/migrate/20180109175851_add_publishing_prices_phase_to_budget.rb b/db/migrate/20180109175851_add_publishing_prices_phase_to_budget.rb new file mode 100644 index 000000000..e6181f6e1 --- /dev/null +++ b/db/migrate/20180109175851_add_publishing_prices_phase_to_budget.rb @@ -0,0 +1,5 @@ +class AddPublishingPricesPhaseToBudget < ActiveRecord::Migration + def change + add_column :budgets, :description_publishing_prices, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index d599658c1..d2c5d3450 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: 20180108182839) do +ActiveRecord::Schema.define(version: 20180109175851) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -202,6 +202,7 @@ ActiveRecord::Schema.define(version: 20180108182839) do t.text "description_finished" t.string "slug" t.text "description_drafting" + t.text "description_publishing_prices" end create_table "campaigns", force: :cascade do |t| diff --git a/spec/factories.rb b/spec/factories.rb index 252e40f5c..7372b5ba9 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -228,6 +228,7 @@ FactoryBot.define do description_reviewing "This budget is reviewing" description_selecting "This budget is selecting" description_valuating "This budget is valuating" + description_publishing_prices "This budget is publishing prices" description_balloting "This budget is balloting" description_reviewing_ballots "This budget is reviewing ballots" description_finished "This budget is finished" @@ -252,6 +253,10 @@ FactoryBot.define do phase 'valuating' end + trait :publishing_prices do + phase 'publishing_prices' + end + trait :balloting do phase 'balloting' end @@ -313,7 +318,6 @@ FactoryBot.define do selected true feasibility "feasible" valuation_finished true - end trait :winner do @@ -326,6 +330,12 @@ FactoryBot.define do incompatible true end + trait :selected_with_price do + selected + price 1000 + price_explanation 'Because of reasons' + end + trait :unselected do selected false feasibility "feasible" diff --git a/spec/features/admin/budget_investments_spec.rb b/spec/features/admin/budget_investments_spec.rb index c3fc69473..ae3cfed70 100644 --- a/spec/features/admin/budget_investments_spec.rb +++ b/spec/features/admin/budget_investments_spec.rb @@ -47,7 +47,7 @@ feature 'Admin budget investments' do expect(page).to have_content(budget_investment.heading.name) expect(page).to have_content(budget_investment.id) expect(page).to have_content(budget_investment.total_votes) - expect(page).to_not have_link("Selected") + expect(page).not_to have_link("Selected") end end @@ -339,9 +339,9 @@ feature 'Admin budget investments' do click_link budget_investment.title - expect(page).to_not have_link "Edit" - expect(page).to_not have_link "Edit classification" - expect(page).to_not have_link "Edit dossier" + expect(page).not_to have_link "Edit" + expect(page).not_to have_link "Edit classification" + expect(page).not_to have_link "Edit dossier" expect(page).to have_link "Create new milestone" end end @@ -639,7 +639,10 @@ feature 'Admin budget investments' do admin = create(:administrator, user: create(:user, username: 'Gema')) investment.update(administrator_id: admin.id) - visit admin_budget_budget_investments_path(@budget, format: :csv) + visit admin_budget_budget_investments_path(@budget) + within('#filter-subnav') { click_link 'All' } + + click_link "Download current selection" header = page.response_headers['Content-Disposition'] expect(header).to match(/^attachment/) @@ -666,15 +669,18 @@ feature 'Admin budget investments' do title: 'compatible') investment2 = create(:budget_investment, :finished, budget: @budget, title: 'finished') - visit admin_budget_budget_investments_path(@budget, format: :csv, - filter: :valuation_finished) + + visit admin_budget_budget_investments_path(@budget) + within('#filter-subnav') { click_link 'Valuation finished' } + + click_link "Download current selection" header = page.response_headers['Content-Disposition'] header.should match(/^attachment/) header.should match(/filename="budget_investments.csv"$/) expect(page).to have_content investment2.title - expect(page).to_not have_content investment1.title + expect(page).not_to have_content investment1.title end end diff --git a/spec/features/admin/budgets_spec.rb b/spec/features/admin/budgets_spec.rb index 0507b45f2..239865317 100644 --- a/spec/features/admin/budgets_spec.rb +++ b/spec/features/admin/budgets_spec.rb @@ -244,5 +244,43 @@ feature 'Admin budgets' do end end + scenario 'Update heading', :js do + budget = create(:budget, name: 'Yearly participatory budget') + group = create(:budget_group, budget: budget, name: 'Districts improvments') + heading = create(:budget_heading, group: group, name: "District 1") + heading = create(:budget_heading, group: group, name: "District 3") + + visit admin_budget_path(budget) + + within("#heading-#{heading.id}") do + click_link 'Edit' + + fill_in 'budget_heading_name', with: 'District 2' + fill_in 'budget_heading_price', with: '10000' + fill_in 'budget_heading_population', with: '6000' + click_button 'Save heading' + end + + expect(page).to have_content 'District 2' + expect(page).to have_content '10000' + expect(page).to have_content '6000' + end + + scenario 'Delete heading', :js do + budget = create(:budget, name: 'Yearly participatory budget') + group = create(:budget_group, budget: budget, name: 'Districts improvments') + heading = create(:budget_heading, group: group, name: "District 1") + + visit admin_budget_path(budget) + + expect(page).to have_content 'District 1' + + within("#heading-#{heading.id}") do + click_link 'Delete' + end + + expect(page).to_not have_content 'District 1' + end + end end diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index d4c9a0176..69ab52df1 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -418,6 +418,64 @@ feature 'Budget Investments' do end end + context "Show Investment's price & cost explanation" do + + let(:investment) { create(:budget_investment, :selected_with_price, heading: heading) } + + context "When investment with price is selected" do + + scenario "Price & explanation is shown when Budget is on published prices phase" do + Budget::PUBLISHED_PRICES_PHASES.each do |phase| + budget.update(phase: phase) + visit budget_investment_path(budget_id: budget.id, id: investment.id) + + expect(page).to have_content(investment.formatted_price) + expect(page).to have_content(investment.price_explanation) + + visit budget_investments_path(budget) + + expect(page).to have_content(investment.formatted_price) + end + end + + scenario "Price & explanation isn't shown when Budget is not on published prices phase" do + (Budget::PHASES - Budget::PUBLISHED_PRICES_PHASES).each do |phase| + budget.update(phase: phase) + visit budget_investment_path(budget_id: budget.id, id: investment.id) + + expect(page).not_to have_content(investment.formatted_price) + expect(page).not_to have_content(investment.price_explanation) + + visit budget_investments_path(budget) + + expect(page).not_to have_content(investment.formatted_price) + end + end + end + + context "When investment with price is unselected" do + + background do + investment.update(selected: false) + end + + scenario "Price & explanation isn't shown for any Budget's phase" do + Budget::PHASES.each do |phase| + budget.update(phase: phase) + visit budget_investment_path(budget_id: budget.id, id: investment.id) + + expect(page).not_to have_content(investment.formatted_price) + expect(page).not_to have_content(investment.price_explanation) + + visit budget_investments_path(budget) + + expect(page).not_to have_content(investment.formatted_price) + end + end + end + + end + scenario 'Can access the community' do Setting['feature.community'] = true @@ -477,13 +535,6 @@ feature 'Budget Investments' do expect(page).not_to have_content(investment.price_explanation) end - scenario "Budget in balloting phase" do - budget.update(phase: "balloting") - 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 end scenario "Show (unfeasible budget investment)" do diff --git a/spec/models/budget/heading_spec.rb b/spec/models/budget/heading_spec.rb index 70787550f..655a77b4f 100644 --- a/spec/models/budget/heading_spec.rb +++ b/spec/models/budget/heading_spec.rb @@ -44,4 +44,16 @@ describe Budget::Heading do end end + describe "heading" do + it "can be deleted if no budget's investments associated" do + heading1 = create(:budget_heading, group: group, name: 'name') + heading2 = create(:budget_heading, group: group, name: 'name 2') + + create(:budget_investment, heading: heading1) + + expect(heading1.can_be_deleted?).to eq false + expect(heading2.can_be_deleted?).to eq true + end + end + end diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb index a04134ce4..63065cfbe 100644 --- a/spec/models/budget/investment_spec.rb +++ b/spec/models/budget/investment_spec.rb @@ -193,37 +193,73 @@ describe Budget::Investment do end end - describe "#should_show_price_info?" do - it "returns true for feasibles if phase is balloting or later and price_explanation is present" do - ["balloting", "reviewing_ballots", "finished"].each do |phase| - budget = create(:budget, phase: phase) - investment = create(:budget_investment, :feasible, budget: budget, price_explanation: "price explanation") + describe "#should_show_price?" do + let(:budget) { create(:budget, :publishing_prices) } + let(:investment) do + create(:budget_investment, :selected, budget: budget) + end - expect(investment.should_show_price_info?).to eq(true) + it "returns true for selected investments which budget's phase is publishing_prices or later" do + Budget::PUBLISHED_PRICES_PHASES.each do |phase| + budget.update(phase: phase) + + expect(investment.should_show_price?).to eq(true) end end it "returns false in any other phase" do - (Budget::PHASES - ["balloting", "reviewing_ballots", "finished"]).each do |phase| - budget = create(:budget, phase: phase) - investment = create(:budget_investment, :feasible, budget: budget, price_explanation: "price explanation") + (Budget::PHASES - Budget::PUBLISHED_PRICES_PHASES).each do |phase| + budget.update(phase: phase) - expect(investment.should_show_price_info?).to eq(false) + expect(investment.should_show_price?).to eq(false) end end - it "returns false if investment is unfeasible" do - budget = create(:budget, phase: "balloting") - investment = create(:budget_investment, :unfeasible, budget: budget, price_explanation: "price explanation") + it "returns false if investment is not selected" do + investment.selected = false - expect(investment.should_show_price_info?).to eq(false) + expect(investment.should_show_price?).to eq(false) end - it "returns false if price_explanation is blank" do - budget = create(:budget, phase: "balloting") - investment = create(:budget_investment, :unfeasible, budget: budget, price_explanation: "") + it "returns false if price is not present" do + investment.price = nil - expect(investment.should_show_price_info?).to eq(false) + expect(investment.should_show_price?).to eq(false) + end + end + + describe "#should_show_price_explanation?" do + let(:budget) { create(:budget, :publishing_prices) } + let(:investment) do + create(:budget_investment, :selected, budget: budget, price_explanation: "because of reasons") + end + + it "returns true for selected with price_explanation & budget in publishing_prices or later" do + Budget::PUBLISHED_PRICES_PHASES.each do |phase| + budget.update(phase: phase) + + expect(investment.should_show_price_explanation?).to eq(true) + end + end + + it "returns false in any other phase" do + (Budget::PHASES - Budget::PUBLISHED_PRICES_PHASES).each do |phase| + budget.update(phase: phase) + + expect(investment.should_show_price_explanation?).to eq(false) + end + end + + it "returns false if investment is not selected" do + investment.selected = false + + expect(investment.should_show_price_explanation?).to eq(false) + end + + it "returns false if price_explanation is not present" do + investment.price_explanation = "" + + expect(investment.should_show_price_explanation?).to eq(false) end end diff --git a/spec/models/budget_spec.rb b/spec/models/budget_spec.rb index b86db7e6e..af42b4bc0 100644 --- a/spec/models/budget_spec.rb +++ b/spec/models/budget_spec.rb @@ -55,6 +55,9 @@ describe Budget do budget.phase = "valuating" expect(budget).to be_valuating + budget.phase = "publishing_prices" + expect(budget).to be_publishing_prices + budget.phase = "balloting" expect(budget).to be_balloting @@ -81,6 +84,9 @@ describe Budget do budget.phase = "valuating" expect(budget).to be_on_hold + budget.phase = "publishing_prices" + expect(budget).to be_on_hold + budget.phase = "balloting" expect(budget).not_to be_on_hold @@ -107,6 +113,9 @@ describe Budget do budget.phase = "valuating" expect(budget).not_to be_balloting_or_later + budget.phase = "publishing_prices" + expect(budget).not_to be_balloting_or_later + budget.phase = "balloting" expect(budget).to be_balloting_or_later @@ -142,6 +151,8 @@ describe Budget do expect(budget.investments_orders).to eq(['random']) end it "is random and price when ballotting and reviewing ballots" do + budget.phase = 'publishing_prices' + expect(budget.investments_orders).to eq(['random', 'price']) budget.phase = 'balloting' expect(budget.investments_orders).to eq(['random', 'price']) budget.phase = 'reviewing_ballots'
+ <%= 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") %>
@@ -22,6 +22,7 @@
<%= t("admin.budgets.form.table_heading") %> <%= t("admin.budgets.form.table_amount") %> <%= t("admin.budgets.form.table_population") %><%= t("admin.actions.actions") %>
- <%= heading.name %> - - <%= heading.price %> - - <%= heading.population %> -
+ <%= heading.name %> + + <%= heading.price %> + + <%= heading.population %> + + <%= link_to t("admin.actions.edit"), + edit_admin_budget_budget_group_budget_heading_path(budget_id: group.budget.id, budget_group_id: group.id, id: heading.id), + class: "button hollow", + remote: true %> + <%= link_to t("admin.budget_investments.index.title"), + admin_budget_budget_investments_path(budget_id: group.budget.id, heading_id: heading.id), + class: "button hollow" %> + <% if heading.can_be_deleted? %> + <%= link_to t('admin.administrators.administrator.delete'), + #admin_budget_budget_group_budget_headings_path(group.budget.id, group.id), + [:admin, group.budget, group, heading], + method: :delete, + class: "button hollow alert" %> + <% end %> +