decidim-plans 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE-AGPLv3.txt +661 -0
- data/README.md +157 -0
- data/Rakefile +48 -0
- data/app/assets/config/admin/decidim_plans_manifest.js +3 -0
- data/app/assets/config/decidim_plans_manifest.css +4 -0
- data/app/assets/config/decidim_plans_manifest.js +2 -0
- data/app/assets/images/decidim/plans/icon.svg +3 -0
- data/app/assets/javascripts/decidim/plans/admin/plans.js.es6 +3 -0
- data/app/assets/javascripts/decidim/plans/admin/sections.js.es6 +78 -0
- data/app/assets/javascripts/decidim/plans/multifield/component.js.es6 +101 -0
- data/app/assets/javascripts/decidim/plans/multifield.js.es6 +5 -0
- data/app/assets/javascripts/decidim/plans/plans_form.js.es6 +9 -0
- data/app/assets/javascripts/decidim/plans/proposal_picker.js.es6 +41 -0
- data/app/assets/javascripts/decidim/plans/remaining_characters.es6 +42 -0
- data/app/assets/javascripts/decidim/plans/social_share.js +2 -0
- data/app/assets/javascripts/decidim/plans/tab_focus.es6 +20 -0
- data/app/assets/stylesheets/decidim/plans/plans_form.scss +26 -0
- data/app/assets/stylesheets/decidim/plans/proposal_picker.scss +3 -0
- data/app/assets/stylesheets/decidim/plans/social_share.css.scss +22 -0
- data/app/cells/decidim/plans/author/flag.erb +5 -0
- data/app/cells/decidim/plans/author/withdraw.erb +6 -0
- data/app/cells/decidim/plans/author_cell.rb +9 -0
- data/app/cells/decidim/plans/coauthorships_cell.rb +23 -0
- data/app/cells/decidim/plans/collapsible_authors/show.erb +17 -0
- data/app/cells/decidim/plans/collapsible_authors_cell.rb +9 -0
- data/app/cells/decidim/plans/plan_activity_cell.rb +19 -0
- data/app/cells/decidim/plans/plan_cell.rb +59 -0
- data/app/cells/decidim/plans/plan_m/footer.erb +8 -0
- data/app/cells/decidim/plans/plan_m_cell.rb +62 -0
- data/app/commands/decidim/plans/accept_access_to_plan.rb +53 -0
- data/app/commands/decidim/plans/admin/answer_plan.rb +82 -0
- data/app/commands/decidim/plans/admin/create_plan.rb +102 -0
- data/app/commands/decidim/plans/admin/update_plan.rb +98 -0
- data/app/commands/decidim/plans/admin/update_sections.rb +54 -0
- data/app/commands/decidim/plans/attachment_methods.rb +78 -0
- data/app/commands/decidim/plans/create_plan.rb +90 -0
- data/app/commands/decidim/plans/destroy_plan.rb +33 -0
- data/app/commands/decidim/plans/nested_updater.rb +26 -0
- data/app/commands/decidim/plans/publish_plan.rb +79 -0
- data/app/commands/decidim/plans/reject_access_to_plan.rb +46 -0
- data/app/commands/decidim/plans/request_access_to_plan.rb +50 -0
- data/app/commands/decidim/plans/respond_to_access_request.rb +76 -0
- data/app/commands/decidim/plans/update_plan.rb +90 -0
- data/app/commands/decidim/plans/withdraw_plan.rb +50 -0
- data/app/controllers/concerns/decidim/plans/orderable.rb +53 -0
- data/app/controllers/decidim/plans/admin/application_controller.rb +16 -0
- data/app/controllers/decidim/plans/admin/plan_answers_controller.rb +40 -0
- data/app/controllers/decidim/plans/admin/plans_controller.rb +80 -0
- data/app/controllers/decidim/plans/admin/sections_controller.rb +75 -0
- data/app/controllers/decidim/plans/application_controller.rb +30 -0
- data/app/controllers/decidim/plans/plan_collaborator_requests_controller.rb +53 -0
- data/app/controllers/decidim/plans/plan_widgets_controller.rb +19 -0
- data/app/controllers/decidim/plans/plans_controller.rb +192 -0
- data/app/controllers/decidim/plans/versions_controller.rb +51 -0
- data/app/events/decidim/plans/accepted_plan_event.rb +9 -0
- data/app/events/decidim/plans/evaluating_plan_event.rb +8 -0
- data/app/events/decidim/plans/plan_access_accepted_event.rb +8 -0
- data/app/events/decidim/plans/plan_access_rejected_event.rb +8 -0
- data/app/events/decidim/plans/plan_access_request_event.rb +27 -0
- data/app/events/decidim/plans/plan_access_requested_event.rb +8 -0
- data/app/events/decidim/plans/plan_access_requester_accepted_event.rb +8 -0
- data/app/events/decidim/plans/plan_access_requester_rejected_event.rb +8 -0
- data/app/events/decidim/plans/publish_plan_event.rb +25 -0
- data/app/events/decidim/plans/rejected_plan_event.rb +9 -0
- data/app/forms/decidim/plans/accept_access_to_plan_form.rb +10 -0
- data/app/forms/decidim/plans/access_to_plan_form.rb +35 -0
- data/app/forms/decidim/plans/admin/plan_answer_form.rb +19 -0
- data/app/forms/decidim/plans/admin/plan_form.rb +88 -0
- data/app/forms/decidim/plans/admin/plan_sections_form.rb +20 -0
- data/app/forms/decidim/plans/admin/section_form.rb +34 -0
- data/app/forms/decidim/plans/attachment_form.rb +20 -0
- data/app/forms/decidim/plans/content_form.rb +58 -0
- data/app/forms/decidim/plans/plan_form.rb +85 -0
- data/app/forms/decidim/plans/reject_access_to_plan_form.rb +9 -0
- data/app/forms/decidim/plans/request_access_to_plan_form.rb +20 -0
- data/app/helpers/decidim/plans/admin/application_helper.rb +19 -0
- data/app/helpers/decidim/plans/application_helper.rb +78 -0
- data/app/helpers/decidim/plans/attached_proposals_helper.rb +44 -0
- data/app/helpers/decidim/plans/attachments_helper.rb +59 -0
- data/app/helpers/decidim/plans/cells_helper.rb +26 -0
- data/app/helpers/decidim/plans/plan_cells_helper.rb +67 -0
- data/app/helpers/decidim/plans/remaining_characters_helper.rb +32 -0
- data/app/helpers/decidim/plans/traceability_helper.rb +79 -0
- data/app/helpers/decidim/plans/user_group_helper.rb +23 -0
- data/app/models/concerns/decidim/plans/traceable.rb +48 -0
- data/app/models/decidim/plans/application_record.rb +10 -0
- data/app/models/decidim/plans/attached_proposal.rb +12 -0
- data/app/models/decidim/plans/content.rb +21 -0
- data/app/models/decidim/plans/paper_trail/version.rb +26 -0
- data/app/models/decidim/plans/paper_trail/version_association.rb +14 -0
- data/app/models/decidim/plans/plan.rb +206 -0
- data/app/models/decidim/plans/plan_collaborator_request.rb +13 -0
- data/app/models/decidim/plans/section.rb +16 -0
- data/app/permissions/decidim/plans/admin/permissions.rb +44 -0
- data/app/permissions/decidim/plans/permissions.rb +67 -0
- data/app/presenters/decidim/plans/admin_log/plan_presenter.rb +49 -0
- data/app/presenters/decidim/plans/admin_log/value_types/plan_state_presenter.rb +16 -0
- data/app/presenters/decidim/plans/content_presenter.rb +25 -0
- data/app/presenters/decidim/plans/log/resource_presenter.rb +18 -0
- data/app/presenters/decidim/plans/official_author_presenter.rb +38 -0
- data/app/presenters/decidim/plans/plan_presenter.rb +48 -0
- data/app/queries/decidim/plans/filtered_plans.rb +37 -0
- data/app/services/decidim/plans/diff_renderer/base.rb +108 -0
- data/app/services/decidim/plans/diff_renderer/categorization.rb +23 -0
- data/app/services/decidim/plans/diff_renderer/content.rb +33 -0
- data/app/services/decidim/plans/diff_renderer/plan.rb +25 -0
- data/app/services/decidim/plans/loggability.rb +19 -0
- data/app/services/decidim/plans/plan_builder.rb +68 -0
- data/app/services/decidim/plans/plan_search.rb +95 -0
- data/app/services/decidim/plans/tracer.rb +29 -0
- data/app/views/decidim/plans/admin/plan_answers/edit.html.erb +22 -0
- data/app/views/decidim/plans/admin/plans/_bulk-actions.html.erb +9 -0
- data/app/views/decidim/plans/admin/plans/_form.html.erb +62 -0
- data/app/views/decidim/plans/admin/plans/_js-callout.html.erb +6 -0
- data/app/views/decidim/plans/admin/plans/_plan-tr.html.erb +53 -0
- data/app/views/decidim/plans/admin/plans/edit.html.erb +7 -0
- data/app/views/decidim/plans/admin/plans/index.html.erb +64 -0
- data/app/views/decidim/plans/admin/plans/new.html.erb +7 -0
- data/app/views/decidim/plans/admin/sections/_bulk-actions.html.erb +7 -0
- data/app/views/decidim/plans/admin/sections/_form.html.erb +27 -0
- data/app/views/decidim/plans/admin/sections/_section.html.erb +66 -0
- data/app/views/decidim/plans/admin/sections/index.html.erb +7 -0
- data/app/views/decidim/plans/admin/shared/_info_plan.html.erb +17 -0
- data/app/views/decidim/plans/attached_proposals/_proposals.html.erb +12 -0
- data/app/views/decidim/plans/plan_widgets/show.html.erb +3 -0
- data/app/views/decidim/plans/plans/_accept_request_access_form.html.erb +8 -0
- data/app/views/decidim/plans/plans/_attached_proposals.html.erb +10 -0
- data/app/views/decidim/plans/plans/_collaborator_requests.html.erb +20 -0
- data/app/views/decidim/plans/plans/_content.html.erb +6 -0
- data/app/views/decidim/plans/plans/_contents.html.erb +8 -0
- data/app/views/decidim/plans/plans/_count.html.erb +1 -0
- data/app/views/decidim/plans/plans/_filters.html.erb +32 -0
- data/app/views/decidim/plans/plans/_filters_small_view.html.erb +18 -0
- data/app/views/decidim/plans/plans/_form.html.erb +57 -0
- data/app/views/decidim/plans/plans/_new_plan_button.html.erb +11 -0
- data/app/views/decidim/plans/plans/_plan.html.erb +1 -0
- data/app/views/decidim/plans/plans/_plan_preview.html.erb +1 -0
- data/app/views/decidim/plans/plans/_plans.html.erb +14 -0
- data/app/views/decidim/plans/plans/_reject_request_access_form.html.erb +10 -0
- data/app/views/decidim/plans/plans/_request_access_form.html.erb +7 -0
- data/app/views/decidim/plans/plans/edit.html.erb +21 -0
- data/app/views/decidim/plans/plans/index.html.erb +28 -0
- data/app/views/decidim/plans/plans/index.js.erb +10 -0
- data/app/views/decidim/plans/plans/new.html.erb +15 -0
- data/app/views/decidim/plans/plans/preview.html.erb +15 -0
- data/app/views/decidim/plans/plans/show.html.erb +133 -0
- data/app/views/decidim/plans/shared/_attachment_fields.html.erb +45 -0
- data/app/views/decidim/plans/shared/_attachments.html.erb +23 -0
- data/app/views/decidim/plans/shared/_remaining_characters_container.html.erb +12 -0
- data/app/views/decidim/plans/shared/_section_content_field.html.erb +39 -0
- data/app/views/decidim/plans/versions/_version.html.erb +20 -0
- data/app/views/decidim/plans/versions/index.html.erb +34 -0
- data/app/views/decidim/plans/versions/show.html.erb +41 -0
- data/config/locales/en.yml +341 -0
- data/config/locales/fi.yml +341 -0
- data/config/locales/sv.yml +341 -0
- data/db/migrate/20181230110225_enable_pg_trgm_extension_for_plans.rb +18 -0
- data/db/migrate/20181230110848_create_decidim_plans.rb +20 -0
- data/db/migrate/20181230111731_create_decidim_plans_sections.rb +13 -0
- data/db/migrate/20181230111931_create_decidim_plans_plan_contents.rb +14 -0
- data/db/migrate/20181230122035_create_decidim_plans_plan_collaborator_requests.rb +12 -0
- data/db/migrate/20190110125855_create_decidim_plans_attached_proposals.rb +12 -0
- data/db/migrate/20190129140441_add_help_to_decidim_plans_sections.rb +7 -0
- data/db/migrate/20190129143607_add_mandatory_to_decidim_plans_sections.rb +7 -0
- data/db/migrate/20190129172040_add_section_type_to_decidim_plans_sections.rb +12 -0
- data/db/migrate/20190129231439_add_answer_length_to_decidim_plans_sections.rb +11 -0
- data/db/migrate/20190202123044_create_version_associations.rb +25 -0
- data/db/migrate/20190202123045_add_transaction_id_column_to_versions.rb +15 -0
- data/db/migrate/20190202200716_add_update_token_to_decidim_plans.rb +7 -0
- data/lib/decidim/plans/admin.rb +10 -0
- data/lib/decidim/plans/admin_engine.rb +29 -0
- data/lib/decidim/plans/component.rb +163 -0
- data/lib/decidim/plans/engine.rb +43 -0
- data/lib/decidim/plans/locale_aware.rb +32 -0
- data/lib/decidim/plans/optionally_translatable_attributes.rb +85 -0
- data/lib/decidim/plans/paper_trail/record_trail.rb +24 -0
- data/lib/decidim/plans/paper_trail.rb +10 -0
- data/lib/decidim/plans/test/factories.rb +130 -0
- data/lib/decidim/plans/version.rb +8 -0
- data/lib/decidim/plans.rb +24 -0
- metadata +323 -0
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
module Admin
|
6
|
+
# This controller allows admins to manage plans in a participatory process.
|
7
|
+
class SectionsController < Admin::ApplicationController
|
8
|
+
include Decidim::ApplicationHelper
|
9
|
+
|
10
|
+
helper Plans::ApplicationHelper
|
11
|
+
|
12
|
+
helper_method :blank_section, :section_types
|
13
|
+
|
14
|
+
def index
|
15
|
+
enforce_permission_to :create, :sections
|
16
|
+
@form = form(Admin::PlanSectionsForm).from_model(sections)
|
17
|
+
end
|
18
|
+
|
19
|
+
def new
|
20
|
+
enforce_permission_to :create, :sections
|
21
|
+
# TODO
|
22
|
+
end
|
23
|
+
|
24
|
+
def create
|
25
|
+
enforce_permission_to :create, :section
|
26
|
+
@form = form(Admin::PlanSectionsForm).from_params(params)
|
27
|
+
|
28
|
+
Admin::UpdateSections.call(@form, sections) do
|
29
|
+
on(:ok) do
|
30
|
+
flash[:notice] = I18n.t("update.success", scope: i18n_flashes_scope)
|
31
|
+
redirect_to sections_url
|
32
|
+
end
|
33
|
+
|
34
|
+
on(:invalid) do
|
35
|
+
flash.now[:alert] = I18n.t("update.invalid", scope: i18n_flashes_scope)
|
36
|
+
render template: "index"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def edit
|
42
|
+
enforce_permission_to :edit, :section, section: section
|
43
|
+
end
|
44
|
+
|
45
|
+
def update
|
46
|
+
enforce_permission_to :edit, :section, section: section
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def i18n_flashes_scope
|
52
|
+
"decidim.plans.admin.sections"
|
53
|
+
end
|
54
|
+
|
55
|
+
def sections
|
56
|
+
@sections ||= Section.where(component: current_component).order(:position)
|
57
|
+
end
|
58
|
+
|
59
|
+
def section
|
60
|
+
@section ||= Section.where(component: current_component).find(params[:id])
|
61
|
+
end
|
62
|
+
|
63
|
+
def blank_section
|
64
|
+
@blank_section ||= Admin::SectionForm.new
|
65
|
+
end
|
66
|
+
|
67
|
+
def section_types
|
68
|
+
@section_types ||= Section::TYPES.map do |section_type|
|
69
|
+
[I18n.t("decidim.plans.section_types.#{section_type}"), section_type]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
# This controller is the abstract class from which all other controllers of
|
6
|
+
# this engine inherit.
|
7
|
+
#
|
8
|
+
# Note that it inherits from `Decidim::Components::BaseController`, which
|
9
|
+
# override its layout and provide all kinds of useful methods.
|
10
|
+
class ApplicationController < Decidim::Components::BaseController
|
11
|
+
helper Decidim::Messaging::ConversationHelper
|
12
|
+
helper_method :plan_limit_reached?
|
13
|
+
|
14
|
+
def plan_limit
|
15
|
+
return nil if component_settings.plan_limit.zero?
|
16
|
+
component_settings.plan_limit
|
17
|
+
end
|
18
|
+
|
19
|
+
def plan_limit_reached?
|
20
|
+
return false unless plan_limit
|
21
|
+
|
22
|
+
plans.where(author: current_user).count >= plan_limit
|
23
|
+
end
|
24
|
+
|
25
|
+
def plans
|
26
|
+
Plan.where(component: current_component)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
# Exposes Plan Request actions for collaboration between
|
6
|
+
# participants on a resource.
|
7
|
+
class PlanCollaboratorRequestsController < Decidim::Plans::PlansController
|
8
|
+
before_action :retrieve_plan, only: [:request_access, :request_accept, :request_reject]
|
9
|
+
|
10
|
+
def request_access
|
11
|
+
@request_access_form = form(RequestAccessToPlanForm).from_params(params)
|
12
|
+
RequestAccessToPlan.call(@request_access_form, current_user) do
|
13
|
+
on(:ok) do |_plan|
|
14
|
+
flash[:notice] = t("access_requested.success", scope: "decidim.plans.requests")
|
15
|
+
end
|
16
|
+
|
17
|
+
on(:invalid) do
|
18
|
+
flash[:alert] = t("access_requested.error", scope: "decidim.plans.requests")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(@plan).path
|
22
|
+
end
|
23
|
+
|
24
|
+
def request_accept
|
25
|
+
@accept_request_form = form(AcceptAccessToPlanForm).from_params(params)
|
26
|
+
AcceptAccessToPlan.call(@accept_request_form, current_user) do
|
27
|
+
on(:ok) do |requester_user|
|
28
|
+
flash[:notice] = t("accepted_request.success", scope: "decidim.plans.requests", user: requester_user.nickname)
|
29
|
+
end
|
30
|
+
|
31
|
+
on(:invalid) do
|
32
|
+
flash[:alert] = t("accepted_request.error", scope: "decidim.plans.requests")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(@plan).path
|
36
|
+
end
|
37
|
+
|
38
|
+
def request_reject
|
39
|
+
@reject_request_form = form(RejectAccessToPlanForm).from_params(params)
|
40
|
+
RejectAccessToPlan.call(@reject_request_form, current_user) do
|
41
|
+
on(:ok) do |requester_user|
|
42
|
+
flash[:notice] = t("rejected_request.success", scope: "decidim.plans.requests", user: requester_user.nickname)
|
43
|
+
end
|
44
|
+
|
45
|
+
on(:invalid) do
|
46
|
+
flash.now[:alert] = t("rejected_request.error", scope: "decidim.plans.requests")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(@plan).path
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
class PlanWidgetsController < Decidim::WidgetsController
|
6
|
+
helper Plans::ApplicationHelper
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def model
|
11
|
+
@model ||= Plan.where(component: params[:component_id]).find(params[:plan_id])
|
12
|
+
end
|
13
|
+
|
14
|
+
def iframe_url
|
15
|
+
@iframe_url ||= plan_plan_widget_url(model)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
# Exposes the plan resource so users can view and create them.
|
6
|
+
class PlansController < Decidim::Plans::ApplicationController
|
7
|
+
helper Decidim::WidgetUrlsHelper
|
8
|
+
helper UserGroupHelper
|
9
|
+
helper TooltipHelper
|
10
|
+
helper Plans::AttachmentsHelper
|
11
|
+
helper Plans::RemainingCharactersHelper
|
12
|
+
include AttachedProposalsHelper
|
13
|
+
include FormFactory
|
14
|
+
include FilterResource
|
15
|
+
include Orderable
|
16
|
+
include Paginable
|
17
|
+
|
18
|
+
helper_method :attached_proposals_picker_field
|
19
|
+
|
20
|
+
before_action :authenticate_user!, only: [:new, :create, :edit, :update, :withdraw, :preview, :publish, :destroy]
|
21
|
+
before_action :check_draft, only: [:new]
|
22
|
+
before_action :retrieve_plan, only: [:show, :edit, :update, :withdraw, :preview, :publish, :destroy]
|
23
|
+
before_action :ensure_published!, only: [:show, :withdraw]
|
24
|
+
|
25
|
+
def index
|
26
|
+
@plans = search
|
27
|
+
.results
|
28
|
+
.published
|
29
|
+
.not_hidden
|
30
|
+
.includes(:category)
|
31
|
+
.includes(:scope)
|
32
|
+
|
33
|
+
@plans = paginate(@plans)
|
34
|
+
@plans = reorder(@plans)
|
35
|
+
end
|
36
|
+
|
37
|
+
def show
|
38
|
+
@report_form = form(Decidim::ReportForm).from_params(reason: "spam")
|
39
|
+
@request_access_form = form(RequestAccessToPlanForm).from_params({})
|
40
|
+
@accept_request_form = form(AcceptAccessToPlanForm).from_params({})
|
41
|
+
@reject_request_form = form(RejectAccessToPlanForm).from_params({})
|
42
|
+
end
|
43
|
+
|
44
|
+
def new
|
45
|
+
enforce_permission_to :create, :plan
|
46
|
+
|
47
|
+
@form = form(PlanForm).from_model(Plan.new(component: current_component))
|
48
|
+
end
|
49
|
+
|
50
|
+
def create
|
51
|
+
enforce_permission_to :create, :plan
|
52
|
+
|
53
|
+
@form = form(PlanForm).from_params(params, component: current_component)
|
54
|
+
|
55
|
+
CreatePlan.call(@form, current_user) do
|
56
|
+
on(:ok) do |plan|
|
57
|
+
flash[:notice] = I18n.t("plans.plans.create.success", scope: "decidim")
|
58
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(plan).path + "/preview"
|
59
|
+
end
|
60
|
+
|
61
|
+
on(:invalid) do
|
62
|
+
flash.now[:alert] = I18n.t("plans.plans.create.error", scope: "decidim")
|
63
|
+
render :new
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def edit
|
69
|
+
enforce_permission_to :edit, :plan, plan: @plan
|
70
|
+
|
71
|
+
@form = form(PlanForm).from_model(@plan)
|
72
|
+
end
|
73
|
+
|
74
|
+
def update
|
75
|
+
enforce_permission_to :edit, :plan, plan: @plan
|
76
|
+
|
77
|
+
@form = form(PlanForm).from_params(params, compontent: current_component)
|
78
|
+
UpdatePlan.call(@form, current_user, @plan) do
|
79
|
+
on(:ok) do |plan|
|
80
|
+
flash[:notice] = I18n.t("plans.plans.update.success", scope: "decidim")
|
81
|
+
|
82
|
+
return redirect_to Decidim::ResourceLocatorPresenter.new(plan).path if plan.published?
|
83
|
+
|
84
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(plan).path + "/preview"
|
85
|
+
end
|
86
|
+
|
87
|
+
on(:invalid) do
|
88
|
+
flash.now[:alert] = I18n.t("plans.plans.update.error", scope: "decidim")
|
89
|
+
render :edit
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def destroy
|
95
|
+
enforce_permission_to :edit, :plan, plan: @plan
|
96
|
+
|
97
|
+
# Form needed in case destroing fails
|
98
|
+
@form = form(PlanForm).from_model(@plan)
|
99
|
+
|
100
|
+
DestroyPlan.call(@plan, current_user) do
|
101
|
+
on(:ok) do
|
102
|
+
flash[:notice] = I18n.t("plans.plans.destroy.success", scope: "decidim")
|
103
|
+
redirect_to new_plan_path
|
104
|
+
end
|
105
|
+
|
106
|
+
on(:invalid) do
|
107
|
+
flash.now[:alert] = I18n.t("plans.plans.destroy.error", scope: "decidim")
|
108
|
+
render :edit
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def withdraw
|
114
|
+
raise ActionController::RoutingError, "Not Found" if @plan.withdrawn?
|
115
|
+
enforce_permission_to :withdraw, :plan, plan: @plan
|
116
|
+
|
117
|
+
WithdrawPlan.call(@plan, current_user) do
|
118
|
+
on(:ok) do
|
119
|
+
flash[:notice] = t("withdraw.success", scope: "decidim.plans.plans")
|
120
|
+
end
|
121
|
+
|
122
|
+
on(:invalid) do
|
123
|
+
flash.now[:alert] = t("withdraw.error", scope: "decidim.plans.plans")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(@plan).path
|
127
|
+
end
|
128
|
+
|
129
|
+
def preview; end
|
130
|
+
|
131
|
+
def publish
|
132
|
+
PublishPlan.call(@plan, current_user) do
|
133
|
+
on(:ok) do |plan|
|
134
|
+
flash[:notice] = I18n.t("publish.success", scope: "decidim.plans.plans.plan")
|
135
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(plan).path
|
136
|
+
end
|
137
|
+
|
138
|
+
on(:invalid) do
|
139
|
+
flash.now[:alert] = t("publish.error", scope: "decidim.plans.plans.plan")
|
140
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(@plan).path
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
def check_draft
|
148
|
+
redirect_to edit_plan_path(plan_draft) if plan_draft.present?
|
149
|
+
end
|
150
|
+
|
151
|
+
def plan_draft
|
152
|
+
Plan.drafts.from_all_author_identities(current_user).not_hidden.where(component: current_component)
|
153
|
+
end
|
154
|
+
|
155
|
+
def retrieve_plan
|
156
|
+
@plan = Plan.where(component: current_component).find(params[:id])
|
157
|
+
end
|
158
|
+
|
159
|
+
def ensure_published!
|
160
|
+
return unless @plan
|
161
|
+
return if @plan.published?
|
162
|
+
|
163
|
+
raise ActionController::RoutingError, "Not Found" unless @plan.editable_by?(current_user)
|
164
|
+
|
165
|
+
redirect_to preview_plan_path(@plan)
|
166
|
+
end
|
167
|
+
|
168
|
+
def search_klass
|
169
|
+
PlanSearch
|
170
|
+
end
|
171
|
+
|
172
|
+
def default_filter_params
|
173
|
+
{
|
174
|
+
search_text: "",
|
175
|
+
origin: "all",
|
176
|
+
activity: "",
|
177
|
+
category_id: "",
|
178
|
+
state: "except_rejected",
|
179
|
+
scope_id: nil,
|
180
|
+
related_to: ""
|
181
|
+
}
|
182
|
+
end
|
183
|
+
|
184
|
+
def context_params
|
185
|
+
{
|
186
|
+
component: current_component,
|
187
|
+
organization: current_organization
|
188
|
+
}
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
# Exposes Plan versions so users can see how a Plan
|
6
|
+
# has been updated through time.
|
7
|
+
class VersionsController < Decidim::Plans::ApplicationController
|
8
|
+
helper Decidim::Plans::TraceabilityHelper
|
9
|
+
helper_method :current_version, :item_versions, :associated_versions,
|
10
|
+
:content_versions, :item
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def item
|
15
|
+
@item ||= Plan.where(component: current_component).find(params[:plan_id])
|
16
|
+
end
|
17
|
+
|
18
|
+
def current_version
|
19
|
+
return nil if params[:id].to_i < 1
|
20
|
+
@current_version ||= item.versions[params[:id].to_i - 1]
|
21
|
+
end
|
22
|
+
|
23
|
+
def item_versions
|
24
|
+
# There may be multiple updates on the item during the same transaction
|
25
|
+
Decidim::Plans::PaperTrail::Version.where(
|
26
|
+
transaction_id: current_version.transaction_id,
|
27
|
+
item_type: "Decidim::Plans::Plan"
|
28
|
+
).order(:created_at)
|
29
|
+
end
|
30
|
+
|
31
|
+
def associated_versions
|
32
|
+
@associated_versions ||= Decidim::Plans::PaperTrail::Version.where(
|
33
|
+
transaction_id: current_version.transaction_id
|
34
|
+
).where.not(
|
35
|
+
item_type: ["Decidim::Plans::Plan", "Decidim::Plans::Content"]
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def content_versions
|
40
|
+
@content_versions ||= item.sections.map do |section|
|
41
|
+
content = item.contents.find_by(section: section)
|
42
|
+
next unless content
|
43
|
+
|
44
|
+
content.versions.find_by(
|
45
|
+
transaction_id: current_version.transaction_id
|
46
|
+
)
|
47
|
+
end.compact
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen-string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
class PlanAccessRequestEvent < Decidim::Events::SimpleEvent
|
6
|
+
i18n_attributes :requester_name, :requester_path, :requester_nickname
|
7
|
+
|
8
|
+
delegate :name, to: :requester, prefix: true
|
9
|
+
|
10
|
+
delegate :nickname, to: :requester, prefix: true
|
11
|
+
|
12
|
+
def requester_path
|
13
|
+
requester.profile_path
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def requester
|
19
|
+
@requester ||= Decidim::UserPresenter.new(rejected_requester_user)
|
20
|
+
end
|
21
|
+
|
22
|
+
def rejected_requester_user
|
23
|
+
@rejected_requester_user ||= Decidim::User.find_by(id: extra[:requester_id])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen-string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
class PublishPlanEvent < Decidim::Events::SimpleEvent
|
6
|
+
include Decidim::Events::CoauthorEvent
|
7
|
+
|
8
|
+
def resource_text
|
9
|
+
# TODO
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def i18n_scope
|
15
|
+
return super unless participatory_space_event?
|
16
|
+
|
17
|
+
"decidim.events.plans.plan_published_for_space"
|
18
|
+
end
|
19
|
+
|
20
|
+
def participatory_space_event?
|
21
|
+
extra.dig(:participatory_space)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
# A form object common to accept and reject actions requesters of Plans.
|
6
|
+
class AccessToPlanForm < Decidim::Form
|
7
|
+
mimic :plan
|
8
|
+
|
9
|
+
attribute :id, String
|
10
|
+
attribute :requester_user_id, String
|
11
|
+
attribute :state, String
|
12
|
+
|
13
|
+
validates :id, :requester_user_id, presence: true
|
14
|
+
validates :state, presence: true, inclusion: { in: %w(open) }
|
15
|
+
|
16
|
+
validate :existence_of_requester_in_requesters
|
17
|
+
|
18
|
+
def plan
|
19
|
+
@plan ||= Decidim::Plans::Plan.find id if id
|
20
|
+
end
|
21
|
+
|
22
|
+
def requester_user
|
23
|
+
@requester_user ||= Decidim::User.find_by(id: requester_user_id, organization: current_organization) if requester_user_id
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def existence_of_requester_in_requesters
|
29
|
+
if plan
|
30
|
+
errors.add(:requester_user_id, :invalid) unless plan.requesters.exists? requester_user_id
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
module Admin
|
6
|
+
# A form object to be used when admin users want to answer a plan.
|
7
|
+
class PlanAnswerForm < Decidim::Form
|
8
|
+
include TranslatableAttributes
|
9
|
+
mimic :plan_answer
|
10
|
+
|
11
|
+
translatable_attribute :answer, String
|
12
|
+
attribute :state, String
|
13
|
+
|
14
|
+
validates :state, presence: true, inclusion: { in: %w(accepted rejected evaluating) }
|
15
|
+
validates :answer, translatable_presence: true, if: ->(form) { form.state == "rejected" }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|