Merge pull request #4369 from consul/draft_budgets
Refactor participatory budgets in draft mode
This commit is contained in:
@@ -657,6 +657,7 @@ code {
|
||||
.admin-content > header {
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
a {
|
||||
@include regular-button;
|
||||
|
||||
37
app/assets/stylesheets/admin/budgets/drafting.scss
Normal file
37
app/assets/stylesheets/admin/budgets/drafting.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
16
app/components/admin/budgets/drafting_component.html.erb
Normal file
16
app/components/admin/budgets/drafting_component.html.erb
Normal 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>
|
||||
8
app/components/admin/budgets/drafting_component.rb
Normal file
8
app/components/admin/budgets/drafting_component.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
class Admin::Budgets::DraftingComponent < ApplicationComponent
|
||||
delegate :can?, to: :controller
|
||||
attr_reader :budget
|
||||
|
||||
def initialize(budget)
|
||||
@budget = budget
|
||||
end
|
||||
end
|
||||
@@ -12,4 +12,8 @@
|
||||
<% else %>
|
||||
<%= link_to_create_budget_poll %>
|
||||
<% end %>
|
||||
<%= link_to t("admin.budgets.actions.preview"),
|
||||
budget_path(budget),
|
||||
target: "_blank",
|
||||
class: "preview-link" %>
|
||||
<% end %>
|
||||
|
||||
@@ -7,6 +7,7 @@ class Admin::BudgetsController < Admin::BaseController
|
||||
has_filters %w[open finished], only: :index
|
||||
|
||||
before_action :load_budget, except: [:index, :new, :create]
|
||||
before_action :load_staff, only: [:new, :create, :edit, :update, :show]
|
||||
load_and_authorize_resource
|
||||
|
||||
def index
|
||||
@@ -14,14 +15,18 @@ class Admin::BudgetsController < Admin::BaseController
|
||||
end
|
||||
|
||||
def show
|
||||
render :edit
|
||||
end
|
||||
|
||||
def new
|
||||
load_staff
|
||||
end
|
||||
|
||||
def edit
|
||||
load_staff
|
||||
end
|
||||
|
||||
def publish
|
||||
@budget.publish!
|
||||
redirect_to edit_admin_budget_path(@budget), notice: t("admin.budgets.publish.notice")
|
||||
end
|
||||
|
||||
def calculate_winners
|
||||
@@ -38,17 +43,15 @@ class Admin::BudgetsController < Admin::BaseController
|
||||
if @budget.update(budget_params)
|
||||
redirect_to admin_budgets_path, notice: t("admin.budgets.update.notice")
|
||||
else
|
||||
load_staff
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@budget = Budget.new(budget_params)
|
||||
@budget = Budget.new(budget_params.merge(published: false))
|
||||
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
|
||||
load_staff
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
@@ -64,7 +64,7 @@ module BudgetsHelper
|
||||
end
|
||||
|
||||
def budget_published?(budget)
|
||||
!budget.drafting? || current_user&.administrator?
|
||||
budget.published? || current_user&.administrator?
|
||||
end
|
||||
|
||||
def current_budget_map_locations
|
||||
|
||||
@@ -62,6 +62,7 @@ module Abilities
|
||||
can :manage, Dashboard::Action
|
||||
|
||||
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::Heading
|
||||
can [:hide, :admin_update, :toggle_selection], Budget::Investment
|
||||
|
||||
@@ -43,7 +43,8 @@ class Budget < ApplicationRecord
|
||||
|
||||
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 :accepting, -> { where(phase: "accepting") }
|
||||
scope :reviewing, -> { where(phase: "reviewing") }
|
||||
@@ -59,7 +60,7 @@ class Budget < ApplicationRecord
|
||||
scope :open, -> { where.not(phase: "finished") }
|
||||
|
||||
def self.current
|
||||
where.not(phase: "drafting").order(:created_at).last
|
||||
published.order(:created_at).last
|
||||
end
|
||||
|
||||
def current_phase
|
||||
@@ -86,8 +87,12 @@ class Budget < ApplicationRecord
|
||||
80
|
||||
end
|
||||
|
||||
def publish!
|
||||
update!(published: true)
|
||||
end
|
||||
|
||||
def drafting?
|
||||
phase == "drafting"
|
||||
!published?
|
||||
end
|
||||
|
||||
def informing?
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Budget
|
||||
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
|
||||
PUBLISHED_PRICES_PHASES = %w[publishing_prices balloting reviewing_ballots finished].freeze
|
||||
SUMMARY_MAX_LENGTH = 1000
|
||||
@@ -18,7 +18,7 @@ class Budget
|
||||
validates_translation :summary, length: { maximum: SUMMARY_MAX_LENGTH }
|
||||
validates_translation :description, length: { maximum: DESCRIPTION_MAX_LENGTH }
|
||||
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 :prev_phase_dates_valid?
|
||||
validate :next_phase_dates_valid?
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<%= back_link_to admin_budgets_path %>
|
||||
|
||||
<header>
|
||||
<h2><%= t("admin.budgets.edit.title") %></h2>
|
||||
<%= render Admin::Budgets::DraftingComponent.new(@budget) %>
|
||||
</header>
|
||||
|
||||
<%= render "/admin/budgets/form" %>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<%= back_link_to admin_budgets_path %>
|
||||
|
||||
<h2><%= @budget.name %></h2>
|
||||
|
||||
<%= render "form" %>
|
||||
@@ -63,6 +63,8 @@ en:
|
||||
type: Type
|
||||
no_activity: There are no moderators activity.
|
||||
budgets:
|
||||
actions:
|
||||
preview: "Preview budget"
|
||||
index:
|
||||
title: Participatory budgets
|
||||
new_link: Create new budget
|
||||
@@ -82,8 +84,12 @@ en:
|
||||
notice: New participatory budget created successfully!
|
||||
update:
|
||||
notice: Participatory budget updated successfully
|
||||
publish:
|
||||
notice: "Participatory budget published successfully"
|
||||
edit:
|
||||
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
|
||||
phase: Phase
|
||||
dates: Dates
|
||||
|
||||
@@ -63,6 +63,8 @@ es:
|
||||
type: Tipo
|
||||
no_activity: No hay actividad de moderadores.
|
||||
budgets:
|
||||
actions:
|
||||
preview: "Previsualizar presupuesto"
|
||||
index:
|
||||
title: Presupuestos participativos
|
||||
new_link: Crear nuevo presupuesto
|
||||
@@ -82,8 +84,12 @@ es:
|
||||
notice: '¡Presupuestos participativos creados con éxito!'
|
||||
update:
|
||||
notice: Presupuestos participativos actualizados
|
||||
publish:
|
||||
notice: "Presupuestos participativos actualizados"
|
||||
edit:
|
||||
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
|
||||
phase: Fase
|
||||
dates: Fechas
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace :admin do
|
||||
|
||||
resources :budgets do
|
||||
member do
|
||||
patch :publish
|
||||
put :calculate_winners
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddPublishedStatusToBudgets < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :budgets, :published, :boolean
|
||||
end
|
||||
end
|
||||
@@ -360,6 +360,7 @@ ActiveRecord::Schema.define(version: 2021_01_23_100638) do
|
||||
t.text "description_publishing_prices"
|
||||
t.text "description_informing"
|
||||
t.string "voting_style", default: "knapsack"
|
||||
t.boolean "published"
|
||||
end
|
||||
|
||||
create_table "campaigns", id: :serial, force: :cascade do |t|
|
||||
|
||||
@@ -10,4 +10,23 @@ namespace :budgets do
|
||||
Budget.last.email_unselected
|
||||
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
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace :consul do
|
||||
desc "Runs tasks needed to upgrade from 1.2.0 to 1.3.0"
|
||||
task "execute_release_1.3.0_tasks": [
|
||||
"db:load_sdg",
|
||||
"db:calculate_tsv"
|
||||
"db:calculate_tsv",
|
||||
"budgets:set_published"
|
||||
]
|
||||
end
|
||||
|
||||
@@ -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
|
||||
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 "Edit headings groups", href: /groups/
|
||||
expect(page).to have_link "Edit budget", href: /edit/
|
||||
expect(page).to have_link "Admin ballots"
|
||||
expect(page).to have_link "Preview budget", href: /budgets/
|
||||
end
|
||||
|
||||
it "renders link to create new poll for budgets without polls" do
|
||||
|
||||
@@ -2,6 +2,7 @@ FactoryBot.define do
|
||||
factory :budget do
|
||||
sequence(:name) { |n| "#{Faker::Lorem.word} #{n}" }
|
||||
currency_symbol { "€" }
|
||||
published { true }
|
||||
phase { "accepting" }
|
||||
description_drafting { "This budget is drafting" }
|
||||
description_informing { "This budget is informing" }
|
||||
@@ -15,7 +16,7 @@ FactoryBot.define do
|
||||
description_finished { "This budget is finished" }
|
||||
|
||||
trait :drafting do
|
||||
phase { "drafting" }
|
||||
published { false }
|
||||
end
|
||||
|
||||
trait :informing do
|
||||
|
||||
70
spec/lib/tasks/budgets_spec.rb
Normal file
70
spec/lib/tasks/budgets_spec.rb
Normal 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
|
||||
@@ -2,11 +2,10 @@ require "rails_helper"
|
||||
|
||||
describe Budget::Phase do
|
||||
let(:budget) { create(:budget) }
|
||||
let(:first_phase) { budget.phases.drafting }
|
||||
let(:second_phase) { budget.phases.informing }
|
||||
let(:third_phase) { budget.phases.accepting }
|
||||
let(:fourth_phase) { budget.phases.reviewing }
|
||||
let(:final_phase) { budget.phases.finished }
|
||||
let(:informing_phase) { budget.phases.informing }
|
||||
let(:accepting_phase) { budget.phases.accepting }
|
||||
let(:reviewing_phase) { budget.phases.reviewing }
|
||||
let(:finished_phase) { budget.phases.finished }
|
||||
|
||||
it_behaves_like "globalizable", :budget_phase
|
||||
|
||||
@@ -31,54 +30,53 @@ describe Budget::Phase do
|
||||
|
||||
describe "#dates_range_valid?" 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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
describe "#prev_phase_dates_valid?" do
|
||||
let(:error) do
|
||||
"Start date must be later than the start date of the previous enabled phase"\
|
||||
" (Draft (Not visible to the public))"
|
||||
"Start date must be later than the start date of the previous enabled phase (Information)"
|
||||
end
|
||||
|
||||
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(second_phase.errors.messages[:starts_at]).to include(error)
|
||||
expect(accepting_phase).not_to be_valid
|
||||
expect(accepting_phase.errors.messages[:starts_at]).to include(error)
|
||||
end
|
||||
|
||||
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(second_phase.errors.messages[:starts_at]).to include(error)
|
||||
expect(accepting_phase).not_to be_valid
|
||||
expect(accepting_phase.errors.messages[:starts_at]).to include(error)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
@@ -88,29 +86,29 @@ describe Budget::Phase do
|
||||
end
|
||||
|
||||
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(second_phase.errors.messages[:ends_at]).to include(error)
|
||||
expect(informing_phase).not_to be_valid
|
||||
expect(informing_phase.errors.messages[:ends_at]).to include(error)
|
||||
end
|
||||
|
||||
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(second_phase.errors.messages[:ends_at]).to include(error)
|
||||
expect(informing_phase).not_to be_valid
|
||||
expect(informing_phase.errors.messages[:ends_at]).to include(error)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
@@ -128,50 +126,50 @@ describe Budget::Phase do
|
||||
end
|
||||
|
||||
describe "#adjust_date_ranges" do
|
||||
let(:prev_enabled_phase) { second_phase.prev_enabled_phase }
|
||||
let(:next_enabled_phase) { second_phase.next_enabled_phase }
|
||||
let(:prev_enabled_phase) { accepting_phase.prev_enabled_phase }
|
||||
let(:next_enabled_phase) { accepting_phase.next_enabled_phase }
|
||||
|
||||
describe "when enabled" 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
|
||||
|
||||
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
|
||||
|
||||
describe "when being enabled" do
|
||||
before do
|
||||
second_phase.update!(enabled: false,
|
||||
accepting_phase.update!(enabled: false,
|
||||
starts_at: Date.current,
|
||||
ends_at: Date.current + 2.days)
|
||||
end
|
||||
|
||||
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)
|
||||
end
|
||||
|
||||
it "adjusts next enabled phase start date to its own end date" 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
|
||||
end
|
||||
|
||||
describe "when disabled" do
|
||||
before do
|
||||
second_phase.update!(enabled: false)
|
||||
accepting_phase.update!(enabled: false)
|
||||
end
|
||||
|
||||
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 }
|
||||
end
|
||||
|
||||
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 }
|
||||
end
|
||||
end
|
||||
@@ -179,7 +177,7 @@ describe Budget::Phase do
|
||||
describe "when being disabled" do
|
||||
it "doesn't adjust previous enabled phase end date to its own start date" do
|
||||
expect do
|
||||
second_phase.update(enabled: false,
|
||||
accepting_phase.update(enabled: false,
|
||||
starts_at: Date.current,
|
||||
ends_at: Date.current + 2.days)
|
||||
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
|
||||
expect do
|
||||
second_phase.update(enabled: false,
|
||||
accepting_phase.update(enabled: false,
|
||||
starts_at: Date.current,
|
||||
ends_at: Date.current + 2.days)
|
||||
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
|
||||
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
|
||||
|
||||
describe "#next_enabled_phase" do
|
||||
it "returns the right next enabled phase" do
|
||||
expect(first_phase.reload.next_enabled_phase).to eq(third_phase)
|
||||
expect(third_phase.reload.next_enabled_phase).to eq(fourth_phase)
|
||||
expect(final_phase.reload.next_enabled_phase).to eq(nil)
|
||||
expect(informing_phase.reload.next_enabled_phase).to eq(reviewing_phase)
|
||||
expect(reviewing_phase.reload.next_enabled_phase).to eq(finished_phase)
|
||||
expect(finished_phase.reload.next_enabled_phase).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#prev_enabled_phase" do
|
||||
it "returns the right previous enabled phase" do
|
||||
expect(first_phase.reload.prev_enabled_phase).to eq(nil)
|
||||
expect(third_phase.reload.prev_enabled_phase).to eq(first_phase)
|
||||
expect(fourth_phase.reload.prev_enabled_phase).to eq(third_phase)
|
||||
expect(informing_phase.reload.prev_enabled_phase).to eq(nil)
|
||||
expect(reviewing_phase.reload.prev_enabled_phase).to eq(informing_phase)
|
||||
expect(finished_phase.reload.prev_enabled_phase).to eq(reviewing_phase)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -32,6 +32,36 @@ describe Budget do
|
||||
expect(Budget.valuating_or_later).to be_empty
|
||||
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
|
||||
|
||||
describe "name" do
|
||||
@@ -96,9 +126,6 @@ describe Budget do
|
||||
end
|
||||
|
||||
it "produces auxiliary methods" do
|
||||
budget.phase = "drafting"
|
||||
expect(budget).to be_drafting
|
||||
|
||||
budget.phase = "accepting"
|
||||
expect(budget).to be_accepting
|
||||
|
||||
@@ -248,7 +275,6 @@ describe Budget do
|
||||
end
|
||||
|
||||
describe "#generate_phases" do
|
||||
let(:drafting_phase) { budget.phases.drafting }
|
||||
let(:informing_phase) { budget.phases.informing }
|
||||
let(:accepting_phase) { budget.phases.accepting }
|
||||
let(:reviewing_phase) { budget.phases.reviewing }
|
||||
@@ -262,7 +288,6 @@ describe Budget do
|
||||
it "generates all phases linked in correct order" do
|
||||
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(accepting_phase.next_phase).to eq(reviewing_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(finished_phase.next_phase).to eq(nil)
|
||||
|
||||
expect(drafting_phase.prev_phase).to eq(nil)
|
||||
expect(informing_phase.prev_phase).to eq(drafting_phase)
|
||||
expect(informing_phase.prev_phase).to eq(nil)
|
||||
expect(accepting_phase.prev_phase).to eq(informing_phase)
|
||||
expect(reviewing_phase.prev_phase).to eq(accepting_phase)
|
||||
expect(selecting_phase.prev_phase).to eq(reviewing_phase)
|
||||
|
||||
@@ -15,19 +15,20 @@ describe "Admin budgets", :admin do
|
||||
let!(:budget) { create(:budget, slug: "budget_slug") }
|
||||
|
||||
scenario "finds budget by slug" do
|
||||
visit admin_budget_path("budget_slug")
|
||||
expect(page).to have_content(budget.name)
|
||||
visit edit_admin_budget_path("budget_slug")
|
||||
|
||||
expect(page).to have_content("Edit Participatory budget")
|
||||
end
|
||||
|
||||
scenario "raises an error if budget slug is not found" do
|
||||
expect do
|
||||
visit admin_budget_path("wrong_budget")
|
||||
visit edit_admin_budget_path("wrong_budget")
|
||||
end.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
|
||||
scenario "raises an error if budget id is not found" do
|
||||
expect do
|
||||
visit admin_budget_path(0)
|
||||
visit edit_admin_budget_path(0)
|
||||
end.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
@@ -107,11 +108,13 @@ describe "Admin budgets", :admin do
|
||||
click_button "Create Budget"
|
||||
|
||||
expect(page).to have_content "New participatory budget created successfully!"
|
||||
expect(page).to have_content "M30 - Summer campaign"
|
||||
expect(Budget.last.voting_style).to eq "knapsack"
|
||||
expect(page).to have_field "Name", with: "M30 - Summer campaign"
|
||||
expect(page).to have_select "Final voting style", selected: "Knapsack"
|
||||
end
|
||||
|
||||
scenario "Create budget - Approval voting", :js do
|
||||
admin = Administrator.first
|
||||
|
||||
visit admin_budgets_path
|
||||
click_link "Create new budget"
|
||||
|
||||
@@ -121,8 +124,12 @@ describe "Admin budgets", :admin do
|
||||
click_button "Create Budget"
|
||||
|
||||
expect(page).to have_content "New participatory budget created successfully!"
|
||||
expect(page).to have_content "M30 - Summer campaign"
|
||||
expect(Budget.last.voting_style).to eq "approval"
|
||||
expect(page).to have_field "Name", with: "M30 - Summer campaign"
|
||||
expect(page).to have_select "Final voting style", selected: "Approval"
|
||||
|
||||
click_link "Select administrators"
|
||||
|
||||
expect(page).to have_field admin.name
|
||||
end
|
||||
|
||||
scenario "Name is mandatory" do
|
||||
@@ -155,6 +162,49 @@ describe "Admin budgets", :admin do
|
||||
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
|
||||
let!(:budget) { create(:budget) }
|
||||
let(:heading) { create(:budget_heading, budget: budget) }
|
||||
@@ -236,7 +286,7 @@ describe "Admin budgets", :admin do
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
visit edit_admin_budget_path(budget)
|
||||
|
||||
@@ -168,7 +168,7 @@ describe "Budgets" do
|
||||
scenario "Not show investment links earlier of balloting " do
|
||||
budget = create(:budget)
|
||||
create(:budget_heading, budget: budget)
|
||||
phases_without_links = ["drafting", "informing"]
|
||||
phases_without_links = ["informing"]
|
||||
not_allowed_phase_list = Budget::Phase::PHASE_KINDS -
|
||||
phases_without_links -
|
||||
allowed_phase_list
|
||||
@@ -205,9 +205,10 @@ describe "Budgets" do
|
||||
scenario "Index shows only published phases" do
|
||||
budget.update!(phase: :finished)
|
||||
phases = budget.phases
|
||||
phases.drafting.update!(starts_at: "30-12-2017", ends_at: "31-12-2017", enabled: true,
|
||||
description: "Description of drafting phase",
|
||||
summary: "<p>This is the summary for drafting phase</p>")
|
||||
|
||||
phases.informing.update!(starts_at: "30-12-2017", ends_at: "31-12-2017", enabled: true,
|
||||
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,
|
||||
description: "Description of accepting phase",
|
||||
@@ -243,8 +244,6 @@ describe "Budgets" do
|
||||
|
||||
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 "January 11, 2018 - January 20, 2018"
|
||||
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 "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 "January 01, 2018 - January 20, 2018"
|
||||
expect(page).to have_content "This is the summary for selecting phase"
|
||||
@@ -478,7 +479,7 @@ describe "Budgets" do
|
||||
|
||||
before do
|
||||
logout
|
||||
budget.update!(phase: "drafting")
|
||||
budget.update!(published: false)
|
||||
create(:budget)
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user