Skip to content

Commit

Permalink
Refactor intiative wizard (decidim#10727)
Browse files Browse the repository at this point in the history
* Refactor intiative wizard

* Fix the initiative creation

* Fixing failing specs

* Apply review recommendations

* Update decidim-initiatives/app/models/decidim/initiative.rb

Co-authored-by: Andrés Pereira de Lucena <[email protected]>

* Apply review recommendations

* Fix the user group creation

* Small refactor on initiatives

* Add spec for custom signature end date in update command

* Update decidim-initiatives/app/controllers/decidim/initiatives/create_initiative_controller.rb

Co-authored-by: Andrés Pereira de Lucena <[email protected]>

* Update decidim-initiatives/lib/decidim/initiatives/engine.rb

Co-authored-by: Andrés Pereira de Lucena <[email protected]>

* Apply latest review recommendations

* Add area spec

* Apply suggestions from code review

Co-authored-by: Antti Hukkanen <[email protected]>

---------

Co-authored-by: Andrés Pereira de Lucena <[email protected]>
Co-authored-by: Antti Hukkanen <[email protected]>
  • Loading branch information
3 people authored and fblupi committed Feb 27, 2024
1 parent 5d7a06b commit 3b077db
Show file tree
Hide file tree
Showing 22 changed files with 257 additions and 301 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ module Initiatives
# A command with all the business logic that creates a new initiative.
class CreateInitiative < Decidim::Command
include CurrentLocale
include ::Decidim::MultipleAttachmentsMethods

# Public: Initializes the command.
#
Expand All @@ -19,17 +18,12 @@ def initialize(form, current_user)
# Executes the command. Broadcasts these events:
#
# - :ok when everything is valid.
# - :invalid if the form wasn't valid and we couldn't proceed.
# - :invalid if the form was not valid and we could not proceed.
#
# Returns nothing.
def call
return broadcast(:invalid) if form.invalid?

if process_attachments?
build_attachments
return broadcast(:invalid) if attachments_invalid?
end

initiative = create_initiative

if initiative.persisted?
Expand All @@ -50,8 +44,6 @@ def create_initiative

initiative.transaction do
initiative.save!
@attached_to = initiative
create_attachments if process_attachments?

create_components_for(initiative)
send_notification(initiative)
Expand All @@ -68,21 +60,14 @@ def build_initiative
title: { current_locale => form.title },
description: { current_locale => form.description },
author: current_user,
decidim_user_group_id: form.decidim_user_group_id,
scoped_type: scoped_type,
area: area,
signature_type: form.signature_type,
signature_end_date: signature_end_date,
state: "created",
hashtag: form.hashtag
signature_type: form.type.signature_type,
state: "created"
)
end

def scoped_type
InitiativesTypeScope.find_by(
type: form.initiative_type,
scope: form.scope
)
InitiativesTypeScope.order(:id).find_by(type: form.type)
end

def signature_end_date
Expand Down Expand Up @@ -112,7 +97,7 @@ def create_components_for(initiative)

def initialize_pages(component)
Decidim::Pages::CreatePage.call(component) do
on(:invalid) { raise "Can't create page" }
on(:invalid) { raise "Cannot create page" }
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ def attributes
attrs = {
title: { current_locale => form.title },
description: { current_locale => form.description },
hashtag: form.hashtag
hashtag: form.hashtag,
decidim_user_group_id: form.decidim_user_group_id
}

if form.signature_type_updatable?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ module Initiatives
class CreateInitiativeController < Decidim::Initiatives::ApplicationController
layout "layouts/decidim/initiative_creation"

include Wicked::Wizard
include Decidim::FormFactory
include InitiativeHelper
include TypeSelectorOptions
Expand All @@ -26,163 +25,127 @@ class CreateInitiativeController < Decidim::Initiatives::ApplicationController
helper_method :promotal_committee_required?

before_action :authenticate_user!
before_action :ensure_type_exists,
only: [:store_initiative_type, :previous_form, :store_initial_data, :fill_data, :store_data, :show_similar_initiatives, :promotal_committee, :finish]
before_action :ensure_user_can_create_initiative,
only: [:previous_form, :store_initial_data, :fill_data, :store_data, :show_similar_initiatives, :promotal_committee, :finish]
before_action :ensure_initiative_exists, only: [:fill_data, :store_data, :show_similar_initiatives, :promotal_committee, :finish]

steps :select_initiative_type,
:previous_form,
:show_similar_initiatives,
:fill_data,
:promotal_committee,
:finish
def select_initiative_type
@form = form(Decidim::Initiatives::SelectInitiativeTypeForm).from_params(params)

before_action :ensure_type_exists, only: :show

def show
send("#{step}_step", initiative: session_initiative)
end

def update
enforce_permission_to :create, :initiative, { initiative_type: initiative_type_from_params }
send("#{step}_step", params)
end

private

def ensure_type_exists
destination_step = single_initiative_type? ? :previous_form : :select_initiative_type

return if step == destination_step
return if initiative_type_id.present? && initiative_type.present?

redirect_to wizard_path(destination_step)
redirect_to previous_form_create_initiative_index_path if single_initiative_type?
end

def select_initiative_type_step(_parameters)
@form = form(Decidim::Initiatives::SelectInitiativeTypeForm).instance
session[:initiative] = {}
def store_initiative_type
@form = form(Decidim::Initiatives::SelectInitiativeTypeForm).from_params(params)

if single_initiative_type?
redirect_to next_wizard_path
return
if @form.valid?
session[:type_id] = @form.type_id
redirect_to previous_form_create_initiative_index_path
else
render :select_initiative_type
end

@form = form(Decidim::Initiatives::SelectInitiativeTypeForm).instance
render_wizard unless performed?
end

def previous_form_step(parameters)
@form = build_form(Decidim::Initiatives::PreviousForm, parameters)

enforce_permission_to :create, :initiative, { initiative_type: initiative_type }

render_wizard
def previous_form
@form = form(Decidim::Initiatives::PreviousForm).from_params({ type_id: initiative_type_id })
end

def show_similar_initiatives_step(parameters)
@form = build_form(Decidim::Initiatives::PreviousForm, parameters)
unless @form.valid?
redirect_to previous_wizard_path(validate_form: true)
return
end
def store_initial_data
@form = form(Decidim::Initiatives::PreviousForm).from_params(params, { initiative_type: initiative_type })

if similar_initiatives.empty?
@form = build_form(Decidim::Initiatives::InitiativeForm, parameters)
redirect_to wizard_path(:fill_data)
end
CreateInitiative.call(@form, current_user) do
on(:ok) do |initiative|
session[:initiative_id] = initiative.id
redirect_to show_similar_initiatives_create_initiative_index_path
end

render_wizard unless performed?
on(:invalid) do
render :previous_form
end
end
end

def fill_data_step(parameters)
@form = build_form(Decidim::Initiatives::InitiativeForm, parameters)
@form.attachment = form(AttachmentForm).from_params({})
def show_similar_initiatives
@form = form(Decidim::Initiatives::PreviousForm).from_model(current_initiative)

render_wizard
redirect_to fill_data_create_initiative_index_path if similar_initiatives.empty?
end

def promotal_committee_step(parameters)
@form = build_form(Decidim::Initiatives::InitiativeForm, parameters)
unless @form.valid?
redirect_to previous_wizard_path(validate_form: true)
return
end
def fill_data
@form = form(Decidim::Initiatives::InitiativeForm).from_model(current_initiative, { initiative_type: initiative_type })
end

skip_step unless promotal_committee_required?
def store_data
@form = form(Decidim::Initiatives::InitiativeForm).from_params(params, { initiative_type: initiative_type })

if session_initiative.has_key?(:id)
render_wizard
return
end
UpdateInitiative.call(current_initiative, @form, current_user) do
on(:ok) do
path = promotal_committee_required? ? "promotal_committee" : "finish"

CreateInitiative.call(@form, current_user) do
on(:ok) do |initiative|
session[:initiative][:id] = initiative.id
if current_initiative.created_by_individual?
render_wizard
else
redirect_to wizard_path(:finish)
end
redirect_to send("#{path}_create_initiative_index_path".to_sym)
end

on(:invalid) do |initiative|
logger.fatal "Failed creating initiative: #{initiative.errors.full_messages.join(", ")}" if initiative
redirect_to previous_wizard_path(validate_form: true)
on(:invalid) do
render :fill_data
end
end
end

def finish_step(_parameters)
render_wizard
def promotal_committee
redirect_to finish_create_initiative_index_path unless promotal_committee_required?
end

def similar_initiatives
@similar_initiatives ||= Decidim::Initiatives::SimilarInitiatives
.for(current_organization, @form)
.all
end
def finish; end

def build_form(klass, parameters)
@form = if single_initiative_type?
form(klass).from_params(parameters.except(:id).merge(type_id: current_organization_initiatives_type.first.id), extra_context)
else
form(klass).from_params(parameters.except(:id), extra_context)
end
private

attributes = @form.attributes_with_values
session[:initiative] = session_initiative.merge(attributes)
@form.valid? if params[:validate_form]
def ensure_user_can_create_initiative
enforce_permission_to :create, :initiative, { initiative_type: initiative_type }
end

@form
def initiative_type_id
@initiative_type_id ||= fetch_initiative_type_id
end

def extra_context
return {} unless initiative_type_id
def fetch_initiative_type_id
return current_organization_initiatives_type.first.id if single_initiative_type?
return params.dig(:initiative, :type_id) if params.dig(:initiative, :type_id).present?
return current_initiative&.type&.id if session[:initiative_id].present?

{ initiative_type: initiative_type }
session[:type_id]
end

def scopes
@scopes ||= @form.available_scopes
def ensure_initiative_exists
redirect_to previous_form_create_initiative_index_path if session[:initiative_id].blank?
end

def current_initiative
Initiative.where(organization: current_organization).find_by(id: session_initiative[:id]) if session_initiative.has_key?(:id)
def ensure_type_exists
destination_step = single_initiative_type? ? "previous_form" : "select_initiative_type"

return if action_name == destination_step
return if initiative_type_id.present? && initiative_type.present?

redirect_to send("#{destination_step}_create_initiative_index_path".to_sym)
end

def initiative_type
@initiative_type ||= InitiativesType.where(organization: current_organization).find_by(id: initiative_type_id)
def similar_initiatives
@similar_initiatives ||= Decidim::Initiatives::SimilarInitiatives
.for(current_organization, @form)
.all
end

def initiative_type_from_params
Decidim::InitiativesType.find_by(id: params["initiative"]["type_id"])
def scopes
@scopes ||= @form.available_scopes
end

def initiative_type_id
session_initiative[:type_id] || @form&.type_id
def current_initiative
Initiative.find(session[:initiative_id] || nil)
end

def session_initiative
session[:initiative] ||= {}
session[:initiative].with_indifferent_access
def initiative_type
@initiative_type ||= InitiativesType.find(initiative_type_id)
end

def promotal_committee_required?
Expand Down
Loading

0 comments on commit 3b077db

Please sign in to comment.