diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss
index 428390f91..c620a3751 100644
--- a/app/assets/stylesheets/admin.scss
+++ b/app/assets/stylesheets/admin.scss
@@ -657,6 +657,7 @@ code {
.admin-content > header {
align-items: flex-start;
display: flex;
+ flex-wrap: wrap;
a {
@include regular-button;
diff --git a/app/assets/stylesheets/admin/budgets/drafting.scss b/app/assets/stylesheets/admin/budgets/drafting.scss
new file mode 100644
index 000000000..aa7cde254
--- /dev/null
+++ b/app/assets/stylesheets/admin/budgets/drafting.scss
@@ -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;
+ }
+}
diff --git a/app/components/admin/budgets/drafting_component.html.erb b/app/components/admin/budgets/drafting_component.html.erb
new file mode 100644
index 000000000..6c84a4972
--- /dev/null
+++ b/app/components/admin/budgets/drafting_component.html.erb
@@ -0,0 +1,16 @@
+
+ <% if can? :publish, budget %>
+
+ <%= t("admin.budgets.edit.drafting") %>
+
+ <% 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 %>
+
diff --git a/app/components/admin/budgets/drafting_component.rb b/app/components/admin/budgets/drafting_component.rb
new file mode 100644
index 000000000..18d37b93f
--- /dev/null
+++ b/app/components/admin/budgets/drafting_component.rb
@@ -0,0 +1,8 @@
+class Admin::Budgets::DraftingComponent < ApplicationComponent
+ delegate :can?, to: :controller
+ attr_reader :budget
+
+ def initialize(budget)
+ @budget = budget
+ end
+end
diff --git a/app/components/admin/budgets/table_actions_component.html.erb b/app/components/admin/budgets/table_actions_component.html.erb
index 8bc788c34..e2d86ae80 100644
--- a/app/components/admin/budgets/table_actions_component.html.erb
+++ b/app/components/admin/budgets/table_actions_component.html.erb
@@ -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 %>
diff --git a/app/controllers/admin/budgets_controller.rb b/app/controllers/admin/budgets_controller.rb
index 1a953af9e..e3b74ca65 100644
--- a/app/controllers/admin/budgets_controller.rb
+++ b/app/controllers/admin/budgets_controller.rb
@@ -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
diff --git a/app/helpers/budgets_helper.rb b/app/helpers/budgets_helper.rb
index b3a01f7d5..d27fec415 100644
--- a/app/helpers/budgets_helper.rb
+++ b/app/helpers/budgets_helper.rb
@@ -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
diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb
index b70c7f4d0..e5eb20015 100644
--- a/app/models/abilities/administrator.rb
+++ b/app/models/abilities/administrator.rb
@@ -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
diff --git a/app/models/budget.rb b/app/models/budget.rb
index 269fd3d61..b36535278 100644
--- a/app/models/budget.rb
+++ b/app/models/budget.rb
@@ -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?
diff --git a/app/models/budget/phase.rb b/app/models/budget/phase.rb
index 8294b7c17..d8b59207f 100644
--- a/app/models/budget/phase.rb
+++ b/app/models/budget/phase.rb
@@ -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?
diff --git a/app/views/admin/budgets/edit.html.erb b/app/views/admin/budgets/edit.html.erb
index 455546803..70cdcfd69 100644
--- a/app/views/admin/budgets/edit.html.erb
+++ b/app/views/admin/budgets/edit.html.erb
@@ -1,5 +1,8 @@
<%= back_link_to admin_budgets_path %>
-<%= t("admin.budgets.edit.title") %>
+
+ <%= t("admin.budgets.edit.title") %>
+ <%= render Admin::Budgets::DraftingComponent.new(@budget) %>
+
<%= render "/admin/budgets/form" %>
diff --git a/app/views/admin/budgets/show.html.erb b/app/views/admin/budgets/show.html.erb
deleted file mode 100644
index 2e46f79c8..000000000
--- a/app/views/admin/budgets/show.html.erb
+++ /dev/null
@@ -1,5 +0,0 @@
-<%= back_link_to admin_budgets_path %>
-
-<%= @budget.name %>
-
-<%= render "form" %>
diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml
index 513ed25cf..ddaafb641 100644
--- a/config/locales/en/admin.yml
+++ b/config/locales/en/admin.yml
@@ -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
diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml
index de520b625..8afb17164 100644
--- a/config/locales/es/admin.yml
+++ b/config/locales/es/admin.yml
@@ -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
diff --git a/config/routes/admin.rb b/config/routes/admin.rb
index 13fdc5935..21712e04a 100644
--- a/config/routes/admin.rb
+++ b/config/routes/admin.rb
@@ -53,6 +53,7 @@ namespace :admin do
resources :budgets do
member do
+ patch :publish
put :calculate_winners
end
diff --git a/db/migrate/20200211123827_add_published_status_to_budgets.rb b/db/migrate/20200211123827_add_published_status_to_budgets.rb
new file mode 100644
index 000000000..8cf696ea4
--- /dev/null
+++ b/db/migrate/20200211123827_add_published_status_to_budgets.rb
@@ -0,0 +1,5 @@
+class AddPublishedStatusToBudgets < ActiveRecord::Migration[5.2]
+ def change
+ add_column :budgets, :published, :boolean
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 25e23d4cb..27cc45b9d 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -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|
diff --git a/lib/tasks/budgets.rake b/lib/tasks/budgets.rake
index 172944420..c5ffa9ef6 100644
--- a/lib/tasks/budgets.rake
+++ b/lib/tasks/budgets.rake
@@ -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
diff --git a/lib/tasks/consul.rake b/lib/tasks/consul.rake
index 4f169c387..b4775c285 100644
--- a/lib/tasks/consul.rake
+++ b/lib/tasks/consul.rake
@@ -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
diff --git a/spec/components/admin/budgets/table_actions_component_spec.rb b/spec/components/admin/budgets/table_actions_component_spec.rb
index 36aeea537..97f20083f 100644
--- a/spec/components/admin/budgets/table_actions_component_spec.rb
+++ b/spec/components/admin/budgets/table_actions_component_spec.rb
@@ -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
diff --git a/spec/factories/budgets.rb b/spec/factories/budgets.rb
index 871309dfe..db9f9c5f0 100644
--- a/spec/factories/budgets.rb
+++ b/spec/factories/budgets.rb
@@ -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
diff --git a/spec/lib/tasks/budgets_spec.rb b/spec/lib/tasks/budgets_spec.rb
new file mode 100644
index 000000000..609e218c7
--- /dev/null
+++ b/spec/lib/tasks/budgets_spec.rb
@@ -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
diff --git a/spec/models/budget/phase_spec.rb b/spec/models/budget/phase_spec.rb
index e44a2e234..c5eccfaa2 100644
--- a/spec/models/budget/phase_spec.rb
+++ b/spec/models/budget/phase_spec.rb
@@ -1,12 +1,11 @@
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(:budget) { create(:budget) }
+ 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
diff --git a/spec/models/budget_spec.rb b/spec/models/budget_spec.rb
index 05b63c586..9f734f452 100644
--- a/spec/models/budget_spec.rb
+++ b/spec/models/budget_spec.rb
@@ -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)
diff --git a/spec/system/admin/budgets_spec.rb b/spec/system/admin/budgets_spec.rb
index ad0bfe854..3303084aa 100644
--- a/spec/system/admin/budgets_spec.rb
+++ b/spec/system/admin/budgets_spec.rb
@@ -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)
diff --git a/spec/system/budgets/budgets_spec.rb b/spec/system/budgets/budgets_spec.rb
index 66f1da827..7e9c31723 100644
--- a/spec/system/budgets/budgets_spec.rb
+++ b/spec/system/budgets/budgets_spec.rb
@@ -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: "This is the summary for drafting phase
")
+
+ phases.informing.update!(starts_at: "30-12-2017", ends_at: "31-12-2017", enabled: true,
+ description: "Description of informing phase",
+ summary: "This is the summary for informing phase
")
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