Merge pull request #4369 from consul/draft_budgets

Refactor participatory budgets in draft mode
This commit is contained in:
Javi Martín
2021-02-23 18:34:17 +01:00
committed by GitHub
26 changed files with 357 additions and 97 deletions

View File

@@ -657,6 +657,7 @@ code {
.admin-content > header { .admin-content > header {
align-items: flex-start; align-items: flex-start;
display: flex; display: flex;
flex-wrap: wrap;
a { a {
@include regular-button; @include regular-button;

View File

@@ -0,0 +1,37 @@
.admin .drafting {
margin-bottom: 2 * $line-height / 3;
margin-left: auto;
@include breakpoint(large) {
align-items: flex-start;
display: flex;
.callout {
flex: 1;
margin-bottom: 0;
}
}
@include breakpoint(small medium only) {
text-align: right;
.callout {
text-align: left;
}
}
.preview-link {
@include has-fa-icon(eye, regular);
@include hollow-button;
}
.publish-link {
@include regular-button;
margin-bottom: 0;
}
.preview-link,
.publish-link {
margin-left: $line-height / 2;
}
}

View File

@@ -0,0 +1,16 @@
<div class="drafting">
<% if can? :publish, budget %>
<div class="callout warning">
<strong><%= t("admin.budgets.edit.drafting") %></strong>
</div>
<% end %>
<%= link_to t("admin.budgets.actions.preview"), budget_path(budget), class: "preview-link", target: "_blank" %>
<% if can? :publish, budget %>
<%= link_to t("admin.budgets.edit.publish"),
publish_admin_budget_path(budget),
method: :patch, class: "publish-link",
data: { confirm: t("admin.actions.confirm") } %>
<% end %>
</div>

View File

@@ -0,0 +1,8 @@
class Admin::Budgets::DraftingComponent < ApplicationComponent
delegate :can?, to: :controller
attr_reader :budget
def initialize(budget)
@budget = budget
end
end

View File

@@ -12,4 +12,8 @@
<% else %> <% else %>
<%= link_to_create_budget_poll %> <%= link_to_create_budget_poll %>
<% end %> <% end %>
<%= link_to t("admin.budgets.actions.preview"),
budget_path(budget),
target: "_blank",
class: "preview-link" %>
<% end %> <% end %>

View File

@@ -7,6 +7,7 @@ class Admin::BudgetsController < Admin::BaseController
has_filters %w[open finished], only: :index has_filters %w[open finished], only: :index
before_action :load_budget, except: [:index, :new, :create] before_action :load_budget, except: [:index, :new, :create]
before_action :load_staff, only: [:new, :create, :edit, :update, :show]
load_and_authorize_resource load_and_authorize_resource
def index def index
@@ -14,14 +15,18 @@ class Admin::BudgetsController < Admin::BaseController
end end
def show def show
render :edit
end end
def new def new
load_staff
end end
def edit def edit
load_staff end
def publish
@budget.publish!
redirect_to edit_admin_budget_path(@budget), notice: t("admin.budgets.publish.notice")
end end
def calculate_winners def calculate_winners
@@ -38,17 +43,15 @@ class Admin::BudgetsController < Admin::BaseController
if @budget.update(budget_params) if @budget.update(budget_params)
redirect_to admin_budgets_path, notice: t("admin.budgets.update.notice") redirect_to admin_budgets_path, notice: t("admin.budgets.update.notice")
else else
load_staff
render :edit render :edit
end end
end end
def create def create
@budget = Budget.new(budget_params) @budget = Budget.new(budget_params.merge(published: false))
if @budget.save if @budget.save
redirect_to admin_budget_path(@budget), notice: t("admin.budgets.create.notice") redirect_to edit_admin_budget_path(@budget), notice: t("admin.budgets.create.notice")
else else
load_staff
render :new render :new
end end
end end

View File

@@ -64,7 +64,7 @@ module BudgetsHelper
end end
def budget_published?(budget) def budget_published?(budget)
!budget.drafting? || current_user&.administrator? budget.published? || current_user&.administrator?
end end
def current_budget_map_locations def current_budget_map_locations

View File

@@ -62,6 +62,7 @@ module Abilities
can :manage, Dashboard::Action can :manage, Dashboard::Action
can [:index, :read, :new, :create, :update, :destroy, :calculate_winners], Budget can [:index, :read, :new, :create, :update, :destroy, :calculate_winners], Budget
can :publish, Budget, id: Budget.drafting.ids
can [:read, :create, :update, :destroy], Budget::Group can [:read, :create, :update, :destroy], Budget::Group
can [:read, :create, :update, :destroy], Budget::Heading can [:read, :create, :update, :destroy], Budget::Heading
can [:hide, :admin_update, :toggle_selection], Budget::Investment can [:hide, :admin_update, :toggle_selection], Budget::Investment

View File

@@ -43,7 +43,8 @@ class Budget < ApplicationRecord
after_create :generate_phases after_create :generate_phases
scope :drafting, -> { where(phase: "drafting") } scope :published, -> { where(published: true) }
scope :drafting, -> { where.not(id: published) }
scope :informing, -> { where(phase: "informing") } scope :informing, -> { where(phase: "informing") }
scope :accepting, -> { where(phase: "accepting") } scope :accepting, -> { where(phase: "accepting") }
scope :reviewing, -> { where(phase: "reviewing") } scope :reviewing, -> { where(phase: "reviewing") }
@@ -59,7 +60,7 @@ class Budget < ApplicationRecord
scope :open, -> { where.not(phase: "finished") } scope :open, -> { where.not(phase: "finished") }
def self.current def self.current
where.not(phase: "drafting").order(:created_at).last published.order(:created_at).last
end end
def current_phase def current_phase
@@ -86,8 +87,12 @@ class Budget < ApplicationRecord
80 80
end end
def publish!
update!(published: true)
end
def drafting? def drafting?
phase == "drafting" !published?
end end
def informing? def informing?

View File

@@ -1,6 +1,6 @@
class Budget class Budget
class Phase < ApplicationRecord class Phase < ApplicationRecord
PHASE_KINDS = %w[drafting informing accepting reviewing selecting valuating publishing_prices balloting PHASE_KINDS = %w[informing accepting reviewing selecting valuating publishing_prices balloting
reviewing_ballots finished].freeze reviewing_ballots finished].freeze
PUBLISHED_PRICES_PHASES = %w[publishing_prices balloting reviewing_ballots finished].freeze PUBLISHED_PRICES_PHASES = %w[publishing_prices balloting reviewing_ballots finished].freeze
SUMMARY_MAX_LENGTH = 1000 SUMMARY_MAX_LENGTH = 1000
@@ -18,7 +18,7 @@ class Budget
validates_translation :summary, length: { maximum: SUMMARY_MAX_LENGTH } validates_translation :summary, length: { maximum: SUMMARY_MAX_LENGTH }
validates_translation :description, length: { maximum: DESCRIPTION_MAX_LENGTH } validates_translation :description, length: { maximum: DESCRIPTION_MAX_LENGTH }
validates :budget, presence: true validates :budget, presence: true
validates :kind, presence: true, uniqueness: { scope: :budget }, inclusion: { in: PHASE_KINDS } validates :kind, presence: true, uniqueness: { scope: :budget }, inclusion: { in: ->(*) { PHASE_KINDS }}
validate :invalid_dates_range? validate :invalid_dates_range?
validate :prev_phase_dates_valid? validate :prev_phase_dates_valid?
validate :next_phase_dates_valid? validate :next_phase_dates_valid?

View File

@@ -1,5 +1,8 @@
<%= back_link_to admin_budgets_path %> <%= back_link_to admin_budgets_path %>
<h2><%= t("admin.budgets.edit.title") %></h2> <header>
<h2><%= t("admin.budgets.edit.title") %></h2>
<%= render Admin::Budgets::DraftingComponent.new(@budget) %>
</header>
<%= render "/admin/budgets/form" %> <%= render "/admin/budgets/form" %>

View File

@@ -1,5 +0,0 @@
<%= back_link_to admin_budgets_path %>
<h2><%= @budget.name %></h2>
<%= render "form" %>

View File

@@ -63,6 +63,8 @@ en:
type: Type type: Type
no_activity: There are no moderators activity. no_activity: There are no moderators activity.
budgets: budgets:
actions:
preview: "Preview budget"
index: index:
title: Participatory budgets title: Participatory budgets
new_link: Create new budget new_link: Create new budget
@@ -82,8 +84,12 @@ en:
notice: New participatory budget created successfully! notice: New participatory budget created successfully!
update: update:
notice: Participatory budget updated successfully notice: Participatory budget updated successfully
publish:
notice: "Participatory budget published successfully"
edit: edit:
title: Edit Participatory budget title: Edit Participatory budget
drafting: "This participatory budget is in draft mode, only administrators can see it in the public site. Once it's published it cannot be changed to draft mode again."
publish: "Publish budget"
delete: Delete budget delete: Delete budget
phase: Phase phase: Phase
dates: Dates dates: Dates

View File

@@ -63,6 +63,8 @@ es:
type: Tipo type: Tipo
no_activity: No hay actividad de moderadores. no_activity: No hay actividad de moderadores.
budgets: budgets:
actions:
preview: "Previsualizar presupuesto"
index: index:
title: Presupuestos participativos title: Presupuestos participativos
new_link: Crear nuevo presupuesto new_link: Crear nuevo presupuesto
@@ -82,8 +84,12 @@ es:
notice: '¡Presupuestos participativos creados con éxito!' notice: '¡Presupuestos participativos creados con éxito!'
update: update:
notice: Presupuestos participativos actualizados notice: Presupuestos participativos actualizados
publish:
notice: "Presupuestos participativos actualizados"
edit: edit:
title: Editar presupuestos participativos title: Editar presupuestos participativos
drafting: "Este presupuesto participativo está en modo borrador, solo los administradores pueden verlo desde la parte pública de la página. Una vez se haya publicado, no se podrá volver a poner en modo borrador otra vez."
publish: "Publicar presupuesto"
delete: Eliminar presupuesto delete: Eliminar presupuesto
phase: Fase phase: Fase
dates: Fechas dates: Fechas

View File

@@ -53,6 +53,7 @@ namespace :admin do
resources :budgets do resources :budgets do
member do member do
patch :publish
put :calculate_winners put :calculate_winners
end end

View File

@@ -0,0 +1,5 @@
class AddPublishedStatusToBudgets < ActiveRecord::Migration[5.2]
def change
add_column :budgets, :published, :boolean
end
end

View File

@@ -360,6 +360,7 @@ ActiveRecord::Schema.define(version: 2021_01_23_100638) do
t.text "description_publishing_prices" t.text "description_publishing_prices"
t.text "description_informing" t.text "description_informing"
t.string "voting_style", default: "knapsack" t.string "voting_style", default: "knapsack"
t.boolean "published"
end end
create_table "campaigns", id: :serial, force: :cascade do |t| create_table "campaigns", id: :serial, force: :cascade do |t|

View File

@@ -10,4 +10,23 @@ namespace :budgets do
Budget.last.email_unselected Budget.last.email_unselected
end end
end end
desc "Set published attribute"
task set_published: :environment do
Budget.where(published: nil).each do |budget|
if budget.phase == "drafting"
if budget.phases.enabled.first.present?
next_enabled_phase = budget.phases.enabled.where.not(kind: "drafting").first.kind
else
next_enabled_phase = "informing"
budget.phases.informing.update!(enabled: true)
end
budget.update!(phase: next_enabled_phase)
budget.update!(published: false)
else
budget.update!(published: true)
end
end
end
end end

View File

@@ -7,6 +7,7 @@ namespace :consul do
desc "Runs tasks needed to upgrade from 1.2.0 to 1.3.0" desc "Runs tasks needed to upgrade from 1.2.0 to 1.3.0"
task "execute_release_1.3.0_tasks": [ task "execute_release_1.3.0_tasks": [
"db:load_sdg", "db:load_sdg",
"db:calculate_tsv" "db:calculate_tsv",
"budgets:set_published"
] ]
end end

View File

@@ -11,11 +11,12 @@ describe Admin::Budgets::TableActionsComponent, type: :component do
it "renders links to edit budget, manage investments and edit groups and manage ballots" do it "renders links to edit budget, manage investments and edit groups and manage ballots" do
render_inline component render_inline component
expect(page).to have_css "a", count: 4 expect(page).to have_css "a", count: 5
expect(page).to have_link "Manage projects", href: /investments/ expect(page).to have_link "Manage projects", href: /investments/
expect(page).to have_link "Edit headings groups", href: /groups/ expect(page).to have_link "Edit headings groups", href: /groups/
expect(page).to have_link "Edit budget", href: /edit/ expect(page).to have_link "Edit budget", href: /edit/
expect(page).to have_link "Admin ballots" expect(page).to have_link "Admin ballots"
expect(page).to have_link "Preview budget", href: /budgets/
end end
it "renders link to create new poll for budgets without polls" do it "renders link to create new poll for budgets without polls" do

View File

@@ -2,6 +2,7 @@ FactoryBot.define do
factory :budget do factory :budget do
sequence(:name) { |n| "#{Faker::Lorem.word} #{n}" } sequence(:name) { |n| "#{Faker::Lorem.word} #{n}" }
currency_symbol { "" } currency_symbol { "" }
published { true }
phase { "accepting" } phase { "accepting" }
description_drafting { "This budget is drafting" } description_drafting { "This budget is drafting" }
description_informing { "This budget is informing" } description_informing { "This budget is informing" }
@@ -15,7 +16,7 @@ FactoryBot.define do
description_finished { "This budget is finished" } description_finished { "This budget is finished" }
trait :drafting do trait :drafting do
phase { "drafting" } published { false }
end end
trait :informing do trait :informing do

View File

@@ -0,0 +1,70 @@
require "rails_helper"
describe Budget do
let(:run_rake_task) do
Rake::Task["budgets:set_published"].reenable
Rake.application.invoke_task("budgets:set_published")
end
it "does not change anything if the published attribute is set" do
budget = create(:budget, published: false, phase: "accepting")
run_rake_task
budget.reload
expect(budget.phase).to eq "accepting"
expect(budget.published).to be false
end
it "publishes budgets which are not in draft mode" do
budget = create(:budget, published: nil, phase: "accepting")
run_rake_task
budget.reload
expect(budget.phase).to eq "accepting"
expect(budget.published).to be true
end
it "changes the published attribute to false on drafting budgets" do
stub_const("Budget::Phase::PHASE_KINDS", ["drafting"] + Budget::Phase::PHASE_KINDS)
budget = create(:budget, published: nil)
budget.update_column(:phase, "drafting")
stub_const("Budget::Phase::PHASE_KINDS", Budget::Phase::PHASE_KINDS - ["drafting"])
run_rake_task
budget.reload
expect(budget.published).to be false
expect(budget.phase).to eq "informing"
end
it "changes the phase to the first enabled phase" do
budget = create(:budget, published: nil)
budget.update_column(:phase, "drafting")
budget.phases.informing.update!(enabled: false)
expect(budget.phase).to eq "drafting"
run_rake_task
budget.reload
expect(budget.phase).to eq "accepting"
expect(budget.published).to be false
end
it "enables and select the informing phase if there are not any enabled phases" do
budget = create(:budget, published: nil)
budget.update_column(:phase, "drafting")
budget.phases.each { |phase| phase.update!(enabled: false) }
expect(budget.phase).to eq "drafting"
run_rake_task
budget.reload
expect(budget.phase).to eq "informing"
expect(budget.phases.informing.enabled).to be true
expect(budget.published).to be false
end
end

View File

@@ -1,12 +1,11 @@
require "rails_helper" require "rails_helper"
describe Budget::Phase do describe Budget::Phase do
let(:budget) { create(:budget) } let(:budget) { create(:budget) }
let(:first_phase) { budget.phases.drafting } let(:informing_phase) { budget.phases.informing }
let(:second_phase) { budget.phases.informing } let(:accepting_phase) { budget.phases.accepting }
let(:third_phase) { budget.phases.accepting } let(:reviewing_phase) { budget.phases.reviewing }
let(:fourth_phase) { budget.phases.reviewing } let(:finished_phase) { budget.phases.finished }
let(:final_phase) { budget.phases.finished }
it_behaves_like "globalizable", :budget_phase it_behaves_like "globalizable", :budget_phase
@@ -31,54 +30,53 @@ describe Budget::Phase do
describe "#dates_range_valid?" do describe "#dates_range_valid?" do
it "is valid when start & end dates are different & consecutive" do it "is valid when start & end dates are different & consecutive" do
first_phase.assign_attributes(starts_at: Date.current, ends_at: Date.tomorrow) informing_phase.assign_attributes(starts_at: Date.current, ends_at: Date.tomorrow)
expect(first_phase).to be_valid expect(informing_phase).to be_valid
end end
it "is not valid when dates are equal" do it "is not valid when dates are equal" do
first_phase.assign_attributes(starts_at: Date.current, ends_at: Date.current) informing_phase.assign_attributes(starts_at: Date.current, ends_at: Date.current)
expect(first_phase).not_to be_valid expect(informing_phase).not_to be_valid
end end
it "is not valid when start date is later than end date" do it "is not valid when start date is later than end date" do
first_phase.assign_attributes(starts_at: Date.tomorrow, ends_at: Date.current) informing_phase.assign_attributes(starts_at: Date.tomorrow, ends_at: Date.current)
expect(first_phase).not_to be_valid expect(informing_phase).not_to be_valid
end end
end end
describe "#prev_phase_dates_valid?" do describe "#prev_phase_dates_valid?" do
let(:error) do let(:error) do
"Start date must be later than the start date of the previous enabled phase"\ "Start date must be later than the start date of the previous enabled phase (Information)"
" (Draft (Not visible to the public))"
end end
it "is invalid when start date is same as previous enabled phase start date" do it "is invalid when start date is same as previous enabled phase start date" do
second_phase.assign_attributes(starts_at: second_phase.prev_enabled_phase.starts_at) accepting_phase.assign_attributes(starts_at: accepting_phase.prev_enabled_phase.starts_at)
expect(second_phase).not_to be_valid expect(accepting_phase).not_to be_valid
expect(second_phase.errors.messages[:starts_at]).to include(error) expect(accepting_phase.errors.messages[:starts_at]).to include(error)
end end
it "is invalid when start date is earlier than previous enabled phase start date" do it "is invalid when start date is earlier than previous enabled phase start date" do
second_phase.assign_attributes(starts_at: second_phase.prev_enabled_phase.starts_at - 1.day) accepting_phase.assign_attributes(starts_at: accepting_phase.prev_enabled_phase.starts_at - 1.day)
expect(second_phase).not_to be_valid expect(accepting_phase).not_to be_valid
expect(second_phase.errors.messages[:starts_at]).to include(error) expect(accepting_phase.errors.messages[:starts_at]).to include(error)
end end
it "is valid when start date is in between previous enabled phase start & end dates" do it "is valid when start date is in between previous enabled phase start & end dates" do
second_phase.assign_attributes(starts_at: second_phase.prev_enabled_phase.starts_at + 1.day) accepting_phase.assign_attributes(starts_at: accepting_phase.prev_enabled_phase.starts_at + 1.day)
expect(second_phase).to be_valid expect(accepting_phase).to be_valid
end end
it "is valid when start date is later than previous enabled phase end date" do it "is valid when start date is later than previous enabled phase end date" do
second_phase.assign_attributes(starts_at: second_phase.prev_enabled_phase.ends_at + 1.day) accepting_phase.assign_attributes(starts_at: accepting_phase.prev_enabled_phase.ends_at + 1.day)
expect(second_phase).to be_valid expect(accepting_phase).to be_valid
end end
end end
@@ -88,29 +86,29 @@ describe Budget::Phase do
end end
it "is invalid when end date is same as next enabled phase end date" do it "is invalid when end date is same as next enabled phase end date" do
second_phase.assign_attributes(ends_at: second_phase.next_enabled_phase.ends_at) informing_phase.assign_attributes(ends_at: informing_phase.next_enabled_phase.ends_at)
expect(second_phase).not_to be_valid expect(informing_phase).not_to be_valid
expect(second_phase.errors.messages[:ends_at]).to include(error) expect(informing_phase.errors.messages[:ends_at]).to include(error)
end end
it "is invalid when end date is later than next enabled phase end date" do it "is invalid when end date is later than next enabled phase end date" do
second_phase.assign_attributes(ends_at: second_phase.next_enabled_phase.ends_at + 1.day) informing_phase.assign_attributes(ends_at: informing_phase.next_enabled_phase.ends_at + 1.day)
expect(second_phase).not_to be_valid expect(informing_phase).not_to be_valid
expect(second_phase.errors.messages[:ends_at]).to include(error) expect(informing_phase.errors.messages[:ends_at]).to include(error)
end end
it "is valid when end date is in between next enabled phase start & end dates" do it "is valid when end date is in between next enabled phase start & end dates" do
second_phase.assign_attributes(ends_at: second_phase.next_enabled_phase.ends_at - 1.day) informing_phase.assign_attributes(ends_at: informing_phase.next_enabled_phase.ends_at - 1.day)
expect(second_phase).to be_valid expect(informing_phase).to be_valid
end end
it "is valid when end date is earlier than next enabled phase start date" do it "is valid when end date is earlier than next enabled phase start date" do
second_phase.assign_attributes(ends_at: second_phase.next_enabled_phase.starts_at - 1.day) informing_phase.assign_attributes(ends_at: informing_phase.next_enabled_phase.starts_at - 1.day)
expect(second_phase).to be_valid expect(informing_phase).to be_valid
end end
end end
end end
@@ -128,50 +126,50 @@ describe Budget::Phase do
end end
describe "#adjust_date_ranges" do describe "#adjust_date_ranges" do
let(:prev_enabled_phase) { second_phase.prev_enabled_phase } let(:prev_enabled_phase) { accepting_phase.prev_enabled_phase }
let(:next_enabled_phase) { second_phase.next_enabled_phase } let(:next_enabled_phase) { accepting_phase.next_enabled_phase }
describe "when enabled" do describe "when enabled" do
it "adjusts previous enabled phase end date to its own start date" do it "adjusts previous enabled phase end date to its own start date" do
expect(prev_enabled_phase.ends_at).to eq(second_phase.starts_at) expect(prev_enabled_phase.ends_at).to eq(accepting_phase.starts_at)
end end
it "adjusts next enabled phase start date to its own end date" do it "adjusts next enabled phase start date to its own end date" do
expect(next_enabled_phase.starts_at).to eq(second_phase.ends_at) expect(next_enabled_phase.starts_at).to eq(accepting_phase.ends_at)
end end
end end
describe "when being enabled" do describe "when being enabled" do
before do before do
second_phase.update!(enabled: false, accepting_phase.update!(enabled: false,
starts_at: Date.current, starts_at: Date.current,
ends_at: Date.current + 2.days) ends_at: Date.current + 2.days)
end end
it "adjusts previous enabled phase end date to its own start date" do it "adjusts previous enabled phase end date to its own start date" do
expect { second_phase.update(enabled: true) } expect { accepting_phase.update(enabled: true) }
.to change { prev_enabled_phase.ends_at.to_date }.to(Date.current) .to change { prev_enabled_phase.ends_at.to_date }.to(Date.current)
end end
it "adjusts next enabled phase start date to its own end date" do it "adjusts next enabled phase start date to its own end date" do
expect do expect do
second_phase.update(enabled: true) accepting_phase.update(enabled: true)
end.to change { next_enabled_phase.starts_at.to_date }.to(Date.current + 2.days) end.to change { next_enabled_phase.starts_at.to_date }.to(Date.current + 2.days)
end end
end end
describe "when disabled" do describe "when disabled" do
before do before do
second_phase.update!(enabled: false) accepting_phase.update!(enabled: false)
end end
it "doesn't change previous enabled phase end date" do it "doesn't change previous enabled phase end date" do
expect { second_phase.update(starts_at: Date.current, ends_at: Date.current + 2.days) } expect { accepting_phase.update(starts_at: Date.current, ends_at: Date.current + 2.days) }
.not_to change { prev_enabled_phase.ends_at } .not_to change { prev_enabled_phase.ends_at }
end end
it "doesn't change next enabled phase start date" do it "doesn't change next enabled phase start date" do
expect { second_phase.update(starts_at: Date.current, ends_at: Date.current + 2.days) } expect { accepting_phase.update(starts_at: Date.current, ends_at: Date.current + 2.days) }
.not_to change { next_enabled_phase.starts_at } .not_to change { next_enabled_phase.starts_at }
end end
end end
@@ -179,7 +177,7 @@ describe Budget::Phase do
describe "when being disabled" do describe "when being disabled" do
it "doesn't adjust previous enabled phase end date to its own start date" do it "doesn't adjust previous enabled phase end date to its own start date" do
expect do expect do
second_phase.update(enabled: false, accepting_phase.update(enabled: false,
starts_at: Date.current, starts_at: Date.current,
ends_at: Date.current + 2.days) ends_at: Date.current + 2.days)
end.not_to change { prev_enabled_phase.ends_at } end.not_to change { prev_enabled_phase.ends_at }
@@ -187,7 +185,7 @@ describe Budget::Phase do
it "adjusts next enabled phase start date to its own start date" do it "adjusts next enabled phase start date to its own start date" do
expect do expect do
second_phase.update(enabled: false, accepting_phase.update(enabled: false,
starts_at: Date.current, starts_at: Date.current,
ends_at: Date.current + 2.days) ends_at: Date.current + 2.days)
end.to change { next_enabled_phase.starts_at.to_date }.to(Date.current) end.to change { next_enabled_phase.starts_at.to_date }.to(Date.current)
@@ -197,22 +195,25 @@ describe Budget::Phase do
describe "next & prev enabled phases" do describe "next & prev enabled phases" do
before do before do
second_phase.update(enabled: false) accepting_phase.update!(enabled: false)
%w[selecting reviewing_ballots balloting publishing_prices valuating].each do |phase|
budget.phases.send(phase).update(enabled: false)
end
end end
describe "#next_enabled_phase" do describe "#next_enabled_phase" do
it "returns the right next enabled phase" do it "returns the right next enabled phase" do
expect(first_phase.reload.next_enabled_phase).to eq(third_phase) expect(informing_phase.reload.next_enabled_phase).to eq(reviewing_phase)
expect(third_phase.reload.next_enabled_phase).to eq(fourth_phase) expect(reviewing_phase.reload.next_enabled_phase).to eq(finished_phase)
expect(final_phase.reload.next_enabled_phase).to eq(nil) expect(finished_phase.reload.next_enabled_phase).to eq(nil)
end end
end end
describe "#prev_enabled_phase" do describe "#prev_enabled_phase" do
it "returns the right previous enabled phase" do it "returns the right previous enabled phase" do
expect(first_phase.reload.prev_enabled_phase).to eq(nil) expect(informing_phase.reload.prev_enabled_phase).to eq(nil)
expect(third_phase.reload.prev_enabled_phase).to eq(first_phase) expect(reviewing_phase.reload.prev_enabled_phase).to eq(informing_phase)
expect(fourth_phase.reload.prev_enabled_phase).to eq(third_phase) expect(finished_phase.reload.prev_enabled_phase).to eq(reviewing_phase)
end end
end end
end end

View File

@@ -32,6 +32,36 @@ describe Budget do
expect(Budget.valuating_or_later).to be_empty expect(Budget.valuating_or_later).to be_empty
end end
end end
describe ".drafting" do
it "returns unpublished budgets" do
undefined = create(:budget, published: nil)
drafting = create(:budget, published: false)
expect(Budget.drafting).to match_array([undefined, drafting])
end
it "does not return published budgets" do
create(:budget, published: true)
expect(Budget.drafting).to be_empty
end
end
describe ".published" do
it "does not return unpublished budgets" do
create(:budget, published: nil)
create(:budget, published: false)
expect(Budget.published).to be_empty
end
it "returns published budgets" do
published = create(:budget, published: true)
expect(Budget.published).to eq [published]
end
end
end end
describe "name" do describe "name" do
@@ -96,9 +126,6 @@ describe Budget do
end end
it "produces auxiliary methods" do it "produces auxiliary methods" do
budget.phase = "drafting"
expect(budget).to be_drafting
budget.phase = "accepting" budget.phase = "accepting"
expect(budget).to be_accepting expect(budget).to be_accepting
@@ -248,7 +275,6 @@ describe Budget do
end end
describe "#generate_phases" do describe "#generate_phases" do
let(:drafting_phase) { budget.phases.drafting }
let(:informing_phase) { budget.phases.informing } let(:informing_phase) { budget.phases.informing }
let(:accepting_phase) { budget.phases.accepting } let(:accepting_phase) { budget.phases.accepting }
let(:reviewing_phase) { budget.phases.reviewing } let(:reviewing_phase) { budget.phases.reviewing }
@@ -262,7 +288,6 @@ describe Budget do
it "generates all phases linked in correct order" do it "generates all phases linked in correct order" do
expect(budget.phases.count).to eq(Budget::Phase::PHASE_KINDS.count) expect(budget.phases.count).to eq(Budget::Phase::PHASE_KINDS.count)
expect(drafting_phase.next_phase).to eq(informing_phase)
expect(informing_phase.next_phase).to eq(accepting_phase) expect(informing_phase.next_phase).to eq(accepting_phase)
expect(accepting_phase.next_phase).to eq(reviewing_phase) expect(accepting_phase.next_phase).to eq(reviewing_phase)
expect(reviewing_phase.next_phase).to eq(selecting_phase) expect(reviewing_phase.next_phase).to eq(selecting_phase)
@@ -273,8 +298,7 @@ describe Budget do
expect(reviewing_ballots_phase.next_phase).to eq(finished_phase) expect(reviewing_ballots_phase.next_phase).to eq(finished_phase)
expect(finished_phase.next_phase).to eq(nil) expect(finished_phase.next_phase).to eq(nil)
expect(drafting_phase.prev_phase).to eq(nil) expect(informing_phase.prev_phase).to eq(nil)
expect(informing_phase.prev_phase).to eq(drafting_phase)
expect(accepting_phase.prev_phase).to eq(informing_phase) expect(accepting_phase.prev_phase).to eq(informing_phase)
expect(reviewing_phase.prev_phase).to eq(accepting_phase) expect(reviewing_phase.prev_phase).to eq(accepting_phase)
expect(selecting_phase.prev_phase).to eq(reviewing_phase) expect(selecting_phase.prev_phase).to eq(reviewing_phase)

View File

@@ -15,19 +15,20 @@ describe "Admin budgets", :admin do
let!(:budget) { create(:budget, slug: "budget_slug") } let!(:budget) { create(:budget, slug: "budget_slug") }
scenario "finds budget by slug" do scenario "finds budget by slug" do
visit admin_budget_path("budget_slug") visit edit_admin_budget_path("budget_slug")
expect(page).to have_content(budget.name)
expect(page).to have_content("Edit Participatory budget")
end end
scenario "raises an error if budget slug is not found" do scenario "raises an error if budget slug is not found" do
expect do expect do
visit admin_budget_path("wrong_budget") visit edit_admin_budget_path("wrong_budget")
end.to raise_error ActiveRecord::RecordNotFound end.to raise_error ActiveRecord::RecordNotFound
end end
scenario "raises an error if budget id is not found" do scenario "raises an error if budget id is not found" do
expect do expect do
visit admin_budget_path(0) visit edit_admin_budget_path(0)
end.to raise_error ActiveRecord::RecordNotFound end.to raise_error ActiveRecord::RecordNotFound
end end
end end
@@ -107,11 +108,13 @@ describe "Admin budgets", :admin do
click_button "Create Budget" click_button "Create Budget"
expect(page).to have_content "New participatory budget created successfully!" expect(page).to have_content "New participatory budget created successfully!"
expect(page).to have_content "M30 - Summer campaign" expect(page).to have_field "Name", with: "M30 - Summer campaign"
expect(Budget.last.voting_style).to eq "knapsack" expect(page).to have_select "Final voting style", selected: "Knapsack"
end end
scenario "Create budget - Approval voting", :js do scenario "Create budget - Approval voting", :js do
admin = Administrator.first
visit admin_budgets_path visit admin_budgets_path
click_link "Create new budget" click_link "Create new budget"
@@ -121,8 +124,12 @@ describe "Admin budgets", :admin do
click_button "Create Budget" click_button "Create Budget"
expect(page).to have_content "New participatory budget created successfully!" expect(page).to have_content "New participatory budget created successfully!"
expect(page).to have_content "M30 - Summer campaign" expect(page).to have_field "Name", with: "M30 - Summer campaign"
expect(Budget.last.voting_style).to eq "approval" expect(page).to have_select "Final voting style", selected: "Approval"
click_link "Select administrators"
expect(page).to have_field admin.name
end end
scenario "Name is mandatory" do scenario "Name is mandatory" do
@@ -155,6 +162,49 @@ describe "Admin budgets", :admin do
end end
end end
context "Create", :js do
scenario "A new budget is always created in draft mode" do
visit admin_budgets_path
click_link "Create new budget"
fill_in "Name", with: "M30 - Summer campaign"
select "Accepting projects", from: "budget[phase]"
click_button "Create Budget"
expect(page).to have_content "New participatory budget created successfully!"
expect(page).to have_content "This participatory budget is in draft mode"
expect(page).to have_link "Preview budget"
expect(page).to have_link "Publish budget"
end
end
context "Publish", :js do
let(:budget) { create(:budget, :drafting) }
scenario "Can preview budget before it is published" do
visit edit_admin_budget_path(budget)
within_window(window_opened_by { click_link "Preview budget" }) do
expect(page).to have_current_path budget_path(budget)
end
end
scenario "Can preview a budget after it is published" do
visit edit_admin_budget_path(budget)
accept_confirm { click_link "Publish budget" }
expect(page).to have_content "Participatory budget published successfully"
expect(page).not_to have_content "This participatory budget is in draft mode"
expect(page).not_to have_link "Publish budget"
within_window(window_opened_by { click_link "Preview budget" }) do
expect(page).to have_current_path budget_path(budget)
end
end
end
context "Destroy" do context "Destroy" do
let!(:budget) { create(:budget) } let!(:budget) { create(:budget) }
let(:heading) { create(:budget_heading, budget: budget) } let(:heading) { create(:budget_heading, budget: budget) }
@@ -236,7 +286,7 @@ describe "Admin budgets", :admin do
end end
scenario "Changing name for current locale will update the slug if budget is in draft phase", :js do scenario "Changing name for current locale will update the slug if budget is in draft phase", :js do
budget.update!(phase: "drafting") budget.update!(published: false)
old_slug = budget.slug old_slug = budget.slug
visit edit_admin_budget_path(budget) visit edit_admin_budget_path(budget)

View File

@@ -168,7 +168,7 @@ describe "Budgets" do
scenario "Not show investment links earlier of balloting " do scenario "Not show investment links earlier of balloting " do
budget = create(:budget) budget = create(:budget)
create(:budget_heading, budget: budget) create(:budget_heading, budget: budget)
phases_without_links = ["drafting", "informing"] phases_without_links = ["informing"]
not_allowed_phase_list = Budget::Phase::PHASE_KINDS - not_allowed_phase_list = Budget::Phase::PHASE_KINDS -
phases_without_links - phases_without_links -
allowed_phase_list allowed_phase_list
@@ -205,9 +205,10 @@ describe "Budgets" do
scenario "Index shows only published phases" do scenario "Index shows only published phases" do
budget.update!(phase: :finished) budget.update!(phase: :finished)
phases = budget.phases phases = budget.phases
phases.drafting.update!(starts_at: "30-12-2017", ends_at: "31-12-2017", enabled: true,
description: "Description of drafting phase", phases.informing.update!(starts_at: "30-12-2017", ends_at: "31-12-2017", enabled: true,
summary: "<p>This is the summary for drafting phase</p>") description: "Description of informing phase",
summary: "<p>This is the summary for informing phase</p>")
phases.accepting.update!(starts_at: "01-01-2018", ends_at: "10-01-2018", enabled: true, phases.accepting.update!(starts_at: "01-01-2018", ends_at: "10-01-2018", enabled: true,
description: "Description of accepting phase", description: "Description of accepting phase",
@@ -243,8 +244,6 @@ describe "Budgets" do
visit budgets_path visit budgets_path
expect(page).not_to have_content "This is the summary for drafting phase"
expect(page).not_to have_content "December 30, 2017 - December 31, 2017"
expect(page).not_to have_content "This is the summary for reviewing phase" expect(page).not_to have_content "This is the summary for reviewing phase"
expect(page).not_to have_content "January 11, 2018 - January 20, 2018" expect(page).not_to have_content "January 11, 2018 - January 20, 2018"
expect(page).not_to have_content "This is the summary for valuating phase" expect(page).not_to have_content "This is the summary for valuating phase"
@@ -254,6 +253,8 @@ describe "Budgets" do
expect(page).not_to have_content "This is the summary for reviewing_ballots phase" expect(page).not_to have_content "This is the summary for reviewing_ballots phase"
expect(page).not_to have_content "March 11, 2018 - March 20, 2018" expect(page).not_to have_content "March 11, 2018 - March 20, 2018"
expect(page).to have_content "This is the summary for informing phase"
expect(page).to have_content "December 30, 2017 - December 31, 2017"
expect(page).to have_content "This is the summary for accepting phase" expect(page).to have_content "This is the summary for accepting phase"
expect(page).to have_content "January 01, 2018 - January 20, 2018" expect(page).to have_content "January 01, 2018 - January 20, 2018"
expect(page).to have_content "This is the summary for selecting phase" expect(page).to have_content "This is the summary for selecting phase"
@@ -478,7 +479,7 @@ describe "Budgets" do
before do before do
logout logout
budget.update!(phase: "drafting") budget.update!(published: false)
create(:budget) create(:budget)
end end