decidim-plans 0.16.0 → 0.16.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -0
- data/app/assets/javascripts/decidim/plans/proposal_picker.js.es6 +52 -32
- data/app/commands/decidim/plans/close_plan.rb +44 -0
- data/app/commands/decidim/plans/reopen_plan.rb +44 -0
- data/app/controllers/decidim/plans/admin/plans_controller.rb +32 -0
- data/app/controllers/decidim/plans/admin/sections_controller.rb +1 -6
- data/app/controllers/decidim/plans/plan_collaborator_requests_controller.rb +6 -0
- data/app/controllers/decidim/plans/plans_controller.rb +40 -4
- data/app/controllers/decidim/plans/versions_controller.rb +6 -0
- data/app/helpers/decidim/plans/attached_proposals_helper.rb +2 -0
- data/app/helpers/decidim/plans/traceability_helper.rb +8 -12
- data/app/models/decidim/plans/plan.rb +15 -0
- data/app/permissions/decidim/plans/admin/permissions.rb +2 -0
- data/app/permissions/decidim/plans/permissions.rb +7 -1
- data/app/services/decidim/plans/diff_renderer/base.rb +1 -1
- data/app/views/decidim/plans/admin/plans/_bulk-actions.html.erb +2 -0
- data/app/views/decidim/plans/admin/plans/_plan-tr.html.erb +8 -0
- data/app/views/decidim/plans/plans/show.html.erb +7 -0
- data/config/locales/en.yml +23 -0
- data/config/locales/fi.yml +23 -0
- data/config/locales/sv.yml +24 -0
- data/db/migrate/20190214124014_add_closed_at_to_decidim_plans.rb +8 -0
- data/lib/decidim/plans/admin_engine.rb +4 -0
- data/lib/decidim/plans/component.rb +16 -3
- data/lib/decidim/plans/engine.rb +2 -0
- data/lib/decidim/plans/plan_serializer.rb +82 -0
- data/lib/decidim/plans/test/factories.rb +9 -2
- data/lib/decidim/plans/version.rb +1 -1
- data/lib/decidim/plans.rb +4 -2
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0beab872d687c4002db352e84e5de788545493a03a5c9e06d22af045d014a10
|
4
|
+
data.tar.gz: b422c03351c34cb8919b22bef233b85451c808edaf90b638e213d027493f2484
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3a45ded830363d9e5c1bffe7f9f22b52fff04f62ba8f5d2dea1cb44cf22a716466ce945c67b5bf9f8230becc3102add69f7196fc90f36cb4fb3207fb0b3e9ec
|
7
|
+
data.tar.gz: 5fc28c2575d607f354eb8fe677f9d33886239b948614c939b04f40ddfc095a816c61d0cfaa272af340922184d3c32fe418a956c92163626c83f0989dc5fb1ee8
|
data/README.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# Decidim::Plans
|
2
2
|
|
3
|
+
[![Build Status](https://travis-ci.com/mainio/decidim-module-plans.svg?branch=master)](https://travis-ci.com/mainio/decidim-module-plans)
|
4
|
+
[![codecov](https://codecov.io/gh/mainio/decidim-module-plans/branch/master/graph/badge.svg)](https://codecov.io/gh/mainio/decidim-module-plans)
|
5
|
+
|
6
|
+
The gem has been developed by [Mainio Tech](https://www.mainiotech.fi/).
|
7
|
+
|
3
8
|
A [Decidim](https://github.com/decidim/decidim) module that provides a new
|
4
9
|
component that can be added to any participatory space in Decidim. The component
|
5
10
|
allows users to write plans together that link to specific proposals. Further on
|
@@ -26,6 +31,9 @@ following differences:
|
|
26
31
|
converted to sub-headings in the budgeting project's description and the
|
27
32
|
budget needs to be specified by the user doing the conversion.
|
28
33
|
|
34
|
+
Development of this gem has been sponsored by the
|
35
|
+
[City of Helsinki](https://www.hel.fi/).
|
36
|
+
|
29
37
|
## Installation
|
30
38
|
|
31
39
|
Add this line to your application's Gemfile:
|
@@ -4,38 +4,58 @@
|
|
4
4
|
// = require_self
|
5
5
|
|
6
6
|
$(function() {
|
7
|
-
$(document).on(
|
8
|
-
|
7
|
+
$(document).on(
|
8
|
+
"open.zf.reveal", "#data_picker-modal",
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
try {
|
14
|
-
xhr.abort();
|
15
|
-
} catch (exception) { xhr = null; }
|
10
|
+
/* @this HTMLElement */
|
11
|
+
function () {
|
12
|
+
let xhr = null;
|
16
13
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
{
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
14
|
+
$("#data_picker-autocomplete").autoComplete({
|
15
|
+
minChars: 2,
|
16
|
+
source: function(term, response) {
|
17
|
+
try {
|
18
|
+
xhr.abort();
|
19
|
+
} catch (exception) { xhr = null; }
|
20
|
+
|
21
|
+
let url = $("#proposal-picker-choose").attr("href");
|
22
|
+
xhr = $.getJSON(
|
23
|
+
url,
|
24
|
+
{ term: term },
|
25
|
+
function(data) { response(data); }
|
26
|
+
);
|
27
|
+
},
|
28
|
+
renderItem: function (item, search) {
|
29
|
+
let sanitizedSearch = search.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
30
|
+
let re = new RegExp(`(${sanitizedSearch.split(" ").join("|")})`, "gi");
|
31
|
+
let title = item[0];
|
32
|
+
let modelId = item[1];
|
33
|
+
return `<div class="autocomplete-suggestion" data-model-id="${modelId}" data-val ="${title}">${title.replace(re, "<b>$1</b>")}</div>`;
|
34
|
+
},
|
35
|
+
onSelect: function(event, term, item) {
|
36
|
+
let choose = $("#proposal-picker-choose");
|
37
|
+
let modelId = item.data("modelId");
|
38
|
+
let val = item.data("val");
|
39
|
+
choose.data("picker-value", modelId);
|
40
|
+
choose.data("picker-text", val);
|
41
|
+
choose.data("picker-choose", "");
|
42
|
+
}
|
43
|
+
});
|
44
|
+
|
45
|
+
// Remove all the empty values after the selection is made to prevent
|
46
|
+
// these empty values appearing in the list.
|
47
|
+
// This is needed until the following is merged to the core:
|
48
|
+
// https://github.com/decidim/decidim/pull/4842
|
49
|
+
const $choose = $("#proposal-picker-choose", this);
|
50
|
+
$choose.on("click", function() {
|
51
|
+
const $values = $("#plan_proposals .picker-values");
|
52
|
+
$("input[type='checkbox']", $values).each(function(_ev, input) {
|
53
|
+
const $input = $(input);
|
54
|
+
if ($input.val().length < 1) {
|
55
|
+
$input.parent().remove();
|
56
|
+
}
|
57
|
+
});
|
58
|
+
});
|
59
|
+
}
|
60
|
+
);
|
41
61
|
});
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
# A command with all the business logic when a user closes a plan.
|
6
|
+
class ClosePlan < Rectify::Command
|
7
|
+
# Public: Initializes the command.
|
8
|
+
#
|
9
|
+
# plan - The plan to publish.
|
10
|
+
# current_user - The current user.
|
11
|
+
def initialize(plan, current_user)
|
12
|
+
@plan = plan
|
13
|
+
@current_user = current_user
|
14
|
+
end
|
15
|
+
|
16
|
+
# Executes the command. Broadcasts these events:
|
17
|
+
#
|
18
|
+
# - :ok when everything is valid and the plan is published.
|
19
|
+
# - :invalid if the plan's author is not the current user.
|
20
|
+
#
|
21
|
+
# Returns nothing.
|
22
|
+
def call
|
23
|
+
return broadcast(:invalid) if @current_user.nil?
|
24
|
+
|
25
|
+
close_plan
|
26
|
+
|
27
|
+
broadcast(:ok, @plan)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def close_plan
|
33
|
+
Decidim.traceability.perform_action!(
|
34
|
+
"close",
|
35
|
+
@plan,
|
36
|
+
@current_user,
|
37
|
+
visibility: "public-only"
|
38
|
+
) do
|
39
|
+
@plan.update closed_at: Time.current
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
# A command with all the business logic when a user reopens a plan.
|
6
|
+
class ReopenPlan < Rectify::Command
|
7
|
+
# Public: Initializes the command.
|
8
|
+
#
|
9
|
+
# plan - The plan to publish.
|
10
|
+
# current_user - The current user.
|
11
|
+
def initialize(plan, current_user)
|
12
|
+
@plan = plan
|
13
|
+
@current_user = current_user
|
14
|
+
end
|
15
|
+
|
16
|
+
# Executes the command. Broadcasts these events:
|
17
|
+
#
|
18
|
+
# - :ok when everything is valid and the plan is published.
|
19
|
+
# - :invalid if the plan's author is not the current user.
|
20
|
+
#
|
21
|
+
# Returns nothing.
|
22
|
+
def call
|
23
|
+
return broadcast(:invalid) if @current_user.nil?
|
24
|
+
|
25
|
+
close_plan
|
26
|
+
|
27
|
+
broadcast(:ok, @plan)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def close_plan
|
33
|
+
Decidim.traceability.perform_action!(
|
34
|
+
"reopen",
|
35
|
+
@plan,
|
36
|
+
@current_user,
|
37
|
+
visibility: "public-only"
|
38
|
+
) do
|
39
|
+
@plan.update closed_at: nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -57,6 +57,38 @@ module Decidim
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
def close
|
61
|
+
enforce_permission_to :close, :plan, plan: plan
|
62
|
+
|
63
|
+
ClosePlan.call(plan, current_user) do
|
64
|
+
on(:ok) do
|
65
|
+
flash[:notice] = I18n.t("close.success", scope: "decidim.plans.plans.plan")
|
66
|
+
redirect_to plans_path
|
67
|
+
end
|
68
|
+
|
69
|
+
on(:invalid) do
|
70
|
+
flash.now[:alert] = t("close.error", scope: "decidim.plans.plans.plan")
|
71
|
+
redirect_to plans_path
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def reopen
|
77
|
+
enforce_permission_to :close, :plan, plan: plan
|
78
|
+
|
79
|
+
ReopenPlan.call(plan, current_user) do
|
80
|
+
on(:ok) do
|
81
|
+
flash[:notice] = I18n.t("reopen.success", scope: "decidim.plans.plans.plan")
|
82
|
+
redirect_to plans_path
|
83
|
+
end
|
84
|
+
|
85
|
+
on(:invalid) do
|
86
|
+
flash.now[:alert] = t("reopen.error", scope: "decidim.plans.plans.plan")
|
87
|
+
redirect_to plans_path
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
60
92
|
private
|
61
93
|
|
62
94
|
def query
|
@@ -16,11 +16,6 @@ module Decidim
|
|
16
16
|
@form = form(Admin::PlanSectionsForm).from_model(sections)
|
17
17
|
end
|
18
18
|
|
19
|
-
def new
|
20
|
-
enforce_permission_to :create, :sections
|
21
|
-
# TODO
|
22
|
-
end
|
23
|
-
|
24
19
|
def create
|
25
20
|
enforce_permission_to :create, :section
|
26
21
|
@form = form(Admin::PlanSectionsForm).from_params(params)
|
@@ -33,7 +28,7 @@ module Decidim
|
|
33
28
|
|
34
29
|
on(:invalid) do
|
35
30
|
flash.now[:alert] = I18n.t("update.invalid", scope: i18n_flashes_scope)
|
36
|
-
render
|
31
|
+
render action: :index
|
37
32
|
end
|
38
33
|
end
|
39
34
|
end
|
@@ -8,6 +8,8 @@ module Decidim
|
|
8
8
|
before_action :retrieve_plan, only: [:request_access, :request_accept, :request_reject]
|
9
9
|
|
10
10
|
def request_access
|
11
|
+
enforce_permission_to :request_access, :plan, plan: @plan
|
12
|
+
|
11
13
|
@request_access_form = form(RequestAccessToPlanForm).from_params(params)
|
12
14
|
RequestAccessToPlan.call(@request_access_form, current_user) do
|
13
15
|
on(:ok) do |_plan|
|
@@ -22,6 +24,8 @@ module Decidim
|
|
22
24
|
end
|
23
25
|
|
24
26
|
def request_accept
|
27
|
+
enforce_permission_to :edit, :plan, plan: @plan
|
28
|
+
|
25
29
|
@accept_request_form = form(AcceptAccessToPlanForm).from_params(params)
|
26
30
|
AcceptAccessToPlan.call(@accept_request_form, current_user) do
|
27
31
|
on(:ok) do |requester_user|
|
@@ -36,6 +40,8 @@ module Decidim
|
|
36
40
|
end
|
37
41
|
|
38
42
|
def request_reject
|
43
|
+
enforce_permission_to :edit, :plan, plan: @plan
|
44
|
+
|
39
45
|
@reject_request_form = form(RejectAccessToPlanForm).from_params(params)
|
40
46
|
RejectAccessToPlan.call(@reject_request_form, current_user) do
|
41
47
|
on(:ok) do |requester_user|
|
@@ -17,9 +17,9 @@ module Decidim
|
|
17
17
|
|
18
18
|
helper_method :attached_proposals_picker_field
|
19
19
|
|
20
|
-
before_action :authenticate_user!, only: [:new, :create, :edit, :update, :withdraw, :preview, :publish, :destroy]
|
20
|
+
before_action :authenticate_user!, only: [:new, :create, :edit, :update, :withdraw, :preview, :publish, :close, :reopen, :destroy]
|
21
21
|
before_action :check_draft, only: [:new]
|
22
|
-
before_action :retrieve_plan, only: [:show, :edit, :update, :withdraw, :preview, :publish, :destroy]
|
22
|
+
before_action :retrieve_plan, only: [:show, :edit, :update, :withdraw, :preview, :publish, :close, :reopen, :destroy]
|
23
23
|
before_action :ensure_published!, only: [:show, :withdraw]
|
24
24
|
|
25
25
|
def index
|
@@ -129,6 +129,8 @@ module Decidim
|
|
129
129
|
def preview; end
|
130
130
|
|
131
131
|
def publish
|
132
|
+
enforce_permission_to :publish, :plan, plan: @plan
|
133
|
+
|
132
134
|
PublishPlan.call(@plan, current_user) do
|
133
135
|
on(:ok) do |plan|
|
134
136
|
flash[:notice] = I18n.t("publish.success", scope: "decidim.plans.plans.plan")
|
@@ -142,6 +144,38 @@ module Decidim
|
|
142
144
|
end
|
143
145
|
end
|
144
146
|
|
147
|
+
def close
|
148
|
+
enforce_permission_to :close, :plan, plan: @plan
|
149
|
+
|
150
|
+
ClosePlan.call(@plan, current_user) do
|
151
|
+
on(:ok) do |plan|
|
152
|
+
flash[:notice] = I18n.t("close.success", scope: "decidim.plans.plans.plan")
|
153
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(plan).path
|
154
|
+
end
|
155
|
+
|
156
|
+
on(:invalid) do
|
157
|
+
flash.now[:alert] = t("close.error", scope: "decidim.plans.plans.plan")
|
158
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(@plan).path
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def reopen
|
164
|
+
enforce_permission_to :close, :plan, plan: @plan
|
165
|
+
|
166
|
+
ReopenPlan.call(@plan, current_user) do
|
167
|
+
on(:ok) do |plan|
|
168
|
+
flash[:notice] = I18n.t("reopen.success", scope: "decidim.plans.plans.plan")
|
169
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(plan).path
|
170
|
+
end
|
171
|
+
|
172
|
+
on(:invalid) do
|
173
|
+
flash.now[:alert] = t("reopen.error", scope: "decidim.plans.plans.plan")
|
174
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(@plan).path
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
145
179
|
private
|
146
180
|
|
147
181
|
def check_draft
|
@@ -149,12 +183,14 @@ module Decidim
|
|
149
183
|
end
|
150
184
|
|
151
185
|
def plan_draft
|
152
|
-
Plan.drafts.from_all_author_identities(current_user).not_hidden.
|
186
|
+
@plan_draft ||= Plan.drafts.from_all_author_identities(current_user).not_hidden.find_by(component: current_component)
|
153
187
|
end
|
154
188
|
|
189
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
155
190
|
def retrieve_plan
|
156
|
-
@plan
|
191
|
+
@plan ||= Plan.where(component: current_component).find(params[:id])
|
157
192
|
end
|
193
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
158
194
|
|
159
195
|
def ensure_published!
|
160
196
|
return unless @plan
|
@@ -21,6 +21,8 @@ module Decidim
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def item_versions
|
24
|
+
return [] if current_version.transaction_id.nil?
|
25
|
+
|
24
26
|
# There may be multiple updates on the item during the same transaction
|
25
27
|
Decidim::Plans::PaperTrail::Version.where(
|
26
28
|
transaction_id: current_version.transaction_id,
|
@@ -29,6 +31,8 @@ module Decidim
|
|
29
31
|
end
|
30
32
|
|
31
33
|
def associated_versions
|
34
|
+
return [] if current_version.transaction_id.nil?
|
35
|
+
|
32
36
|
@associated_versions ||= Decidim::Plans::PaperTrail::Version.where(
|
33
37
|
transaction_id: current_version.transaction_id
|
34
38
|
).where.not(
|
@@ -37,6 +41,8 @@ module Decidim
|
|
37
41
|
end
|
38
42
|
|
39
43
|
def content_versions
|
44
|
+
return [] if current_version.transaction_id.nil?
|
45
|
+
|
40
46
|
@content_versions ||= item.sections.map do |section|
|
41
47
|
content = item.contents.find_by(section: section)
|
42
48
|
next unless content
|
@@ -35,6 +35,8 @@ module Decidim
|
|
35
35
|
.try(:resource_scope, current_component)
|
36
36
|
&.order(title: :asc)
|
37
37
|
&.where("title ilike ?", "%#{params[:term]}%")
|
38
|
+
&.where&.not(state: "rejected")
|
39
|
+
&.where&.not(published_at: nil)
|
38
40
|
render json: query.all.collect { |p| [present(p).title, p.id] }
|
39
41
|
end
|
40
42
|
end
|
@@ -32,21 +32,17 @@ module Decidim
|
|
32
32
|
private
|
33
33
|
|
34
34
|
def renderer_for(version)
|
35
|
+
return nil if version.item.nil?
|
36
|
+
|
35
37
|
locale = current_locale unless component_settings.multilingual_answers?
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
Decidim::Plans::DiffRenderer::Content
|
43
|
-
when "Decidim::Categorization"
|
44
|
-
Decidim::Plans::DiffRenderer::Categorization
|
45
|
-
when "Decidim::Component"
|
46
|
-
Decidim::Plans::DiffRenderer::Component
|
47
|
-
end
|
39
|
+
item_klass = version.item.class.name
|
40
|
+
lastpart = item_klass.split("::").last
|
41
|
+
renderer_klass = "Decidim::Plans::DiffRenderer::#{lastpart}"
|
42
|
+
|
43
|
+
return nil unless defined?(renderer_klass)
|
48
44
|
|
49
|
-
renderer_klass.new(version, locale)
|
45
|
+
renderer_klass.constantize.new(version, locale)
|
50
46
|
end
|
51
47
|
|
52
48
|
# Renders the given value in a user-friendly way based on the value class.
|
@@ -99,6 +99,13 @@ module Decidim
|
|
99
99
|
published_at.present?
|
100
100
|
end
|
101
101
|
|
102
|
+
# Public: Checks if the plan has been closed or not.
|
103
|
+
#
|
104
|
+
# Returns Boolean.
|
105
|
+
def closed?
|
106
|
+
closed_at.present?
|
107
|
+
end
|
108
|
+
|
102
109
|
# Public: Checks if the organization has given an answer for the plan.
|
103
110
|
#
|
104
111
|
# Returns Boolean.
|
@@ -191,6 +198,14 @@ module Decidim
|
|
191
198
|
Arel.sql(query)
|
192
199
|
end
|
193
200
|
|
201
|
+
def self.export_serializer
|
202
|
+
Decidim::Plans::PlanSerializer
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.data_portability_images(user)
|
206
|
+
user_collection(user).map { |p| p.attachments.collect(&:file) }
|
207
|
+
end
|
208
|
+
|
194
209
|
# Checks whether the plan is inside the time window to be editable or not once published.
|
195
210
|
def within_edit_time_limit?
|
196
211
|
true
|
@@ -35,6 +35,8 @@ module Decidim
|
|
35
35
|
can_withdraw_plan?
|
36
36
|
when :publish
|
37
37
|
can_publish_plan?
|
38
|
+
when :close
|
39
|
+
can_close_plan?
|
38
40
|
when :request_access
|
39
41
|
can_request_access_plan?
|
40
42
|
end
|
@@ -45,7 +47,7 @@ module Decidim
|
|
45
47
|
end
|
46
48
|
|
47
49
|
def can_edit_plan?
|
48
|
-
toggle_allow(plan.open? && plan.editable_by?(user))
|
50
|
+
toggle_allow(plan.open? && !plan.closed? && plan.editable_by?(user))
|
49
51
|
end
|
50
52
|
|
51
53
|
def can_withdraw_plan?
|
@@ -56,6 +58,10 @@ module Decidim
|
|
56
58
|
toggle_allow(plan.open? && plan.editable_by?(user))
|
57
59
|
end
|
58
60
|
|
61
|
+
def can_close_plan?
|
62
|
+
toggle_allow(plan && plan.created_by?(user))
|
63
|
+
end
|
64
|
+
|
59
65
|
def can_request_access_plan?
|
60
66
|
return toggle_allow(false) unless plan.open?
|
61
67
|
return toggle_allow(false) if plan.editable_by?(user)
|
@@ -40,6 +40,14 @@
|
|
40
40
|
<%= icon_link_to "pencil", edit_plan_path(plan), t("actions.edit_plan", scope: "decidim.plans"), class: "action-icon--edit-plan" %>
|
41
41
|
<% end %>
|
42
42
|
|
43
|
+
<% if allowed_to? :close, :plan, plan: plan %>
|
44
|
+
<% if plan.closed? %>
|
45
|
+
<%= icon_link_to "action-undo", reopen_plan_path(plan), t("actions.reopen_plan", scope: "decidim.plans"), method: :post, class: "action-icon--reopen-plan" %>
|
46
|
+
<% else %>
|
47
|
+
<%= icon_link_to "ban", close_plan_path(plan), t("actions.close_plan", scope: "decidim.plans"), method: :post, class: "action-icon--close-plan" %>
|
48
|
+
<% end %>
|
49
|
+
<% end %>
|
50
|
+
|
43
51
|
<% if allowed_to? :create, :plan_answer %>
|
44
52
|
<%= icon_link_to "comment-square", edit_plan_plan_answer_path(plan_id: plan.id, id: plan.id), t("actions.answer", scope: "decidim.plans"), class: " icon--small" %>
|
45
53
|
<% else %>
|
@@ -45,6 +45,13 @@
|
|
45
45
|
<% if allowed_to?(:edit, :plan, plan: @plan) %>
|
46
46
|
<%= link_to t("edit", scope:"decidim.plans.plans.show"), edit_plan_path(@plan), class: "button secondary hollow expanded button--sc mt-s", id: "plan_edit" %>
|
47
47
|
<% end %>
|
48
|
+
<% if allowed_to?(:close, :plan, plan: @plan) %>
|
49
|
+
<% if @plan.closed? %>
|
50
|
+
<%= link_to t("reopen", scope:"decidim.plans.plans.show"), reopen_plan_path(@plan), method: :post, class: "button secondary hollow expanded button--sc mt-s", id: "plan_reopen", data: { confirm: t("reopen_confirm", scope:"decidim.plans.plans.show") } %>
|
51
|
+
<% else %>
|
52
|
+
<%= link_to t("close", scope:"decidim.plans.plans.show"), close_plan_path(@plan), method: :post, class: "button secondary hollow expanded button--sc mt-s", id: "plan_close", data: { confirm: t("close_confirm", scope:"decidim.plans.plans.show") } %>
|
53
|
+
<% end %>
|
54
|
+
<% end %>
|
48
55
|
|
49
56
|
<%= render "request_access_form" %>
|
50
57
|
|
data/config/locales/en.yml
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
---
|
2
2
|
en:
|
3
|
+
activerecord:
|
4
|
+
models:
|
5
|
+
decidim/plans/plan: Plan
|
3
6
|
activemodel:
|
4
7
|
attributes:
|
5
8
|
plan:
|
6
9
|
proposals: Proposals
|
7
10
|
category_id: Category
|
8
11
|
decidim_category_id: Category
|
12
|
+
decidim_component_id: Component
|
9
13
|
decidim_scope_id: Scope
|
10
14
|
state: State
|
11
15
|
title: Title
|
@@ -39,19 +43,27 @@ en:
|
|
39
43
|
comments_blocked: Comments blocked
|
40
44
|
creation_enabled: Creation enabled
|
41
45
|
plan_answering_enabled: Answering enabled
|
46
|
+
pages:
|
47
|
+
home:
|
48
|
+
statistics:
|
49
|
+
plans_count: Plans
|
42
50
|
participatory_processes:
|
43
51
|
statistics:
|
44
52
|
plans_count: Plans
|
45
53
|
plans:
|
46
54
|
actions:
|
47
55
|
answer: Answer
|
56
|
+
close_plan: Mark as done
|
48
57
|
edit_plan: Edit
|
49
58
|
new: Submit new plan
|
59
|
+
reopen_plan: Open for editing
|
50
60
|
sections: Sections
|
51
61
|
title: Actions
|
52
62
|
admin:
|
53
63
|
actions:
|
54
64
|
preview: Preview
|
65
|
+
exports:
|
66
|
+
plans: Plans
|
55
67
|
plan_answers:
|
56
68
|
edit:
|
57
69
|
accepted: Accepted
|
@@ -207,15 +219,24 @@ en:
|
|
207
219
|
random: Random
|
208
220
|
recent: Recent
|
209
221
|
plan:
|
222
|
+
close:
|
223
|
+
error: Error marking the item as done.
|
224
|
+
success: Item marked done successfully.
|
210
225
|
publish:
|
211
226
|
error: Error publishing new content.
|
212
227
|
success: Published successfully.
|
228
|
+
reopen:
|
229
|
+
error: Error opening item for editing.
|
230
|
+
success: Item opened for editing successfully.
|
213
231
|
view_plan: View plan
|
214
232
|
withdraw:
|
215
233
|
error: Error withdrawing.
|
216
234
|
success: Withdrawn successfully.
|
217
235
|
show:
|
218
236
|
back: Back
|
237
|
+
close: Mark as done
|
238
|
+
close_confirm: Are you sure you want to mark this item done? After
|
239
|
+
marking done, the item can no longer be edited.
|
219
240
|
edit: Edit
|
220
241
|
hidden_authors_count:
|
221
242
|
one: and %{count} more person
|
@@ -229,6 +250,8 @@ en:
|
|
229
250
|
publish: Publish
|
230
251
|
publish_info: Publish this version of the draft or
|
231
252
|
published_proposal: published plan
|
253
|
+
reopen: Open for editing
|
254
|
+
reopen_confirm: Are you sure you want to open this item for editing?
|
232
255
|
report: Report
|
233
256
|
request_access: Request editing permissions
|
234
257
|
requested_access: Editing permissions requested
|
data/config/locales/fi.yml
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
---
|
2
2
|
fi:
|
3
|
+
activerecord:
|
4
|
+
models:
|
5
|
+
decidim/plans/plan: Suunnitelma
|
3
6
|
activemodel:
|
4
7
|
attributes:
|
5
8
|
plan:
|
6
9
|
proposals: Ehdotukset
|
7
10
|
category_id: Kategoria
|
8
11
|
decidim_category_id: Kategoria
|
12
|
+
decidim_component_id: Komponentti
|
9
13
|
decidim_scope_id: Teema
|
10
14
|
state: Tila
|
11
15
|
title: Otsikko
|
@@ -39,19 +43,27 @@ fi:
|
|
39
43
|
comments_blocked: Kommentointi estetty
|
40
44
|
creation_enabled: Luonti sallittu
|
41
45
|
plan_answering_enabled: Vastaaminen sallittu
|
46
|
+
pages:
|
47
|
+
home:
|
48
|
+
statistics:
|
49
|
+
plans_count: Suunnitelmia
|
42
50
|
participatory_processes:
|
43
51
|
statistics:
|
44
52
|
plans_count: Suunnitelmaa
|
45
53
|
plans:
|
46
54
|
actions:
|
47
55
|
answer: Vastaa
|
56
|
+
close_plan: Merkitse valmiiksi
|
48
57
|
edit_plan: Muokkaa
|
49
58
|
new: Tee uusi suunnitelma
|
59
|
+
reopen_plan: Avaa muokattavaksi
|
50
60
|
sections: Osiot
|
51
61
|
title: Toiminnot
|
52
62
|
admin:
|
53
63
|
actions:
|
54
64
|
preview: Esikatsele
|
65
|
+
exports:
|
66
|
+
plans: Suunnitelmat
|
55
67
|
plan_answers:
|
56
68
|
edit:
|
57
69
|
accepted: Hyväksytty
|
@@ -207,15 +219,24 @@ fi:
|
|
207
219
|
random: Satunnainen
|
208
220
|
recent: Uusimmat
|
209
221
|
plan:
|
222
|
+
close:
|
223
|
+
error: Valmiiksi merkitseminen epäonnistui.
|
224
|
+
success: Valmiiksi merkitseminen onnistui.
|
210
225
|
publish:
|
211
226
|
error: Uuden sisällön julkaiseminen epäonnistui.
|
212
227
|
success: Julkaisu onnistui.
|
228
|
+
reopen:
|
229
|
+
error: Muokattavaksi avaaminen epäonnistui.
|
230
|
+
success: Muokattavaksi avaaminen onnistui.
|
213
231
|
view_plan: Näytä suunnitelma
|
214
232
|
withdraw:
|
215
233
|
error: Peruuttaminen epäonnistui.
|
216
234
|
success: Peruuttaminen onnistui.
|
217
235
|
show:
|
218
236
|
back: Takaisin
|
237
|
+
close: Merkitse valmiiksi
|
238
|
+
close_confirm: Haluatko varmasti merkitä tämän kohteen valmiiksi? Kun
|
239
|
+
kohde on merkitty valmiiksi, sitä ei voi enää muokata.
|
219
240
|
edit: Muokkaa
|
220
241
|
hidden_authors_count:
|
221
242
|
one: ja %{count} muu henkilö
|
@@ -229,6 +250,8 @@ fi:
|
|
229
250
|
publish: Julkaise
|
230
251
|
publish_info: Julkaise tämä luonnosversio tai
|
231
252
|
published_proposal: julkaistu suunnitelma
|
253
|
+
reopen: Avaa muokattavaksi
|
254
|
+
reopen_confirm: Haluatko varmasti avata tämän kohteen muokattavaksi?
|
232
255
|
report: Ilmoita
|
233
256
|
request_access: Pyydä muokkausoikeudet
|
234
257
|
requested_access: Muokkausoikeudet pyydetty
|
data/config/locales/sv.yml
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
---
|
2
2
|
sv:
|
3
|
+
activerecord:
|
4
|
+
models:
|
5
|
+
decidim/plans/plan: Plan
|
3
6
|
activemodel:
|
4
7
|
attributes:
|
5
8
|
plan:
|
6
9
|
proposals: Proposals
|
7
10
|
category_id: Category
|
8
11
|
decidim_category_id: Category
|
12
|
+
decidim_component_id: Component
|
13
|
+
decidim_proposal_id: Proposal
|
9
14
|
decidim_scope_id: Scope
|
10
15
|
state: State
|
11
16
|
title: Title
|
@@ -39,19 +44,27 @@ sv:
|
|
39
44
|
comments_blocked: Comments blocked
|
40
45
|
creation_enabled: Creation enabled
|
41
46
|
plan_answering_enabled: Answering enabled
|
47
|
+
pages:
|
48
|
+
home:
|
49
|
+
statistics:
|
50
|
+
plans_count: Plans
|
42
51
|
participatory_processes:
|
43
52
|
statistics:
|
44
53
|
plans_count: Plans
|
45
54
|
plans:
|
46
55
|
actions:
|
47
56
|
answer: Answer
|
57
|
+
close_plan: Mark as done
|
48
58
|
edit_plan: Edit
|
49
59
|
new: Submit new plan
|
60
|
+
reopen_plan: Open for editing
|
50
61
|
sections: Sections
|
51
62
|
title: Actions
|
52
63
|
admin:
|
53
64
|
actions:
|
54
65
|
preview: Preview
|
66
|
+
exports:
|
67
|
+
plans: Plans
|
55
68
|
plan_answers:
|
56
69
|
edit:
|
57
70
|
accepted: Accepted
|
@@ -207,15 +220,24 @@ sv:
|
|
207
220
|
random: Random
|
208
221
|
recent: Recent
|
209
222
|
plan:
|
223
|
+
close:
|
224
|
+
error: Error marking the item as done.
|
225
|
+
success: Item marked done successfully.
|
210
226
|
publish:
|
211
227
|
error: Error publishing new content.
|
212
228
|
success: Published successfully.
|
229
|
+
reopen:
|
230
|
+
error: Error opening item for editing.
|
231
|
+
success: Item opened for editing successfully.
|
213
232
|
view_plan: View plan
|
214
233
|
withdraw:
|
215
234
|
error: Error withdrawing.
|
216
235
|
success: Withdrawn successfully.
|
217
236
|
show:
|
218
237
|
back: Back
|
238
|
+
close: Mark as done
|
239
|
+
close_confirm: Are you sure you want to mark this item done? After
|
240
|
+
marking done, the item can no longer be edited.
|
219
241
|
edit: Edit
|
220
242
|
hidden_authors_count:
|
221
243
|
one: and %{count} more person
|
@@ -229,6 +251,8 @@ sv:
|
|
229
251
|
publish: Publish
|
230
252
|
publish_info: Publish this version of the draft or
|
231
253
|
published_proposal: published plan
|
254
|
+
reopen: Open for editing
|
255
|
+
reopen_confirm: Are you sure you want to open this item for editing?
|
232
256
|
report: Report
|
233
257
|
request_access: Request editing permissions
|
234
258
|
requested_access: Editing permissions requested
|
@@ -13,6 +13,10 @@ module Decidim
|
|
13
13
|
resources :plans, only: [:index, :new, :create, :edit, :update] do
|
14
14
|
get :search_proposals
|
15
15
|
resources :plan_answers, only: [:edit, :update]
|
16
|
+
member do
|
17
|
+
post :close
|
18
|
+
post :reopen
|
19
|
+
end
|
16
20
|
end
|
17
21
|
resources :sections, only: [:index, :new, :create, :edit, :update]
|
18
22
|
|
@@ -13,7 +13,7 @@ Decidim.register_component(:plans) do |component|
|
|
13
13
|
|
14
14
|
component.data_portable_entities = ["Decidim::Plans::Plan"]
|
15
15
|
|
16
|
-
component.actions = %w(create withdraw)
|
16
|
+
component.actions = %w(create withdraw close reopen)
|
17
17
|
|
18
18
|
component.permissions_class_name = "Decidim::Plans::Permissions"
|
19
19
|
|
@@ -23,7 +23,7 @@ Decidim.register_component(:plans) do |component|
|
|
23
23
|
settings.attribute :comments_enabled, type: :boolean, default: true
|
24
24
|
settings.attribute :announcement, type: :text, translated: true, editor: true
|
25
25
|
settings.attribute :attachments_allowed, type: :boolean, default: false
|
26
|
-
settings.attribute :multilingual_answers, type: :boolean
|
26
|
+
settings.attribute :multilingual_answers, type: :boolean
|
27
27
|
end
|
28
28
|
|
29
29
|
component.settings(:step) do |settings|
|
@@ -51,6 +51,19 @@ Decidim.register_component(:plans) do |component|
|
|
51
51
|
Decidim::Comments::Comment.where(root_commentable: plans).count
|
52
52
|
end
|
53
53
|
|
54
|
+
component.exports :plans do |exports|
|
55
|
+
exports.collection do |component_instance|
|
56
|
+
Decidim::Plans::Plan
|
57
|
+
.published
|
58
|
+
.where(component: component_instance)
|
59
|
+
.includes(:category, component: { participatory_space: :organization })
|
60
|
+
end
|
61
|
+
|
62
|
+
exports.include_in_open_data = true
|
63
|
+
|
64
|
+
exports.serializer Decidim::Plans::PlanSerializer
|
65
|
+
end
|
66
|
+
|
54
67
|
component.seeds do |participatory_space|
|
55
68
|
admin_user = Decidim::User.find_by(
|
56
69
|
organization: participatory_space.organization,
|
@@ -69,7 +82,7 @@ Decidim.register_component(:plans) do |component|
|
|
69
82
|
published_at: Time.current,
|
70
83
|
participatory_space: participatory_space,
|
71
84
|
settings: {
|
72
|
-
multilingual_answers:
|
85
|
+
multilingual_answers: false
|
73
86
|
},
|
74
87
|
step_settings: step_settings
|
75
88
|
}
|
data/lib/decidim/plans/engine.rb
CHANGED
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Plans
|
5
|
+
# This class serializes a Proposal so can be exported to CSV, JSON or other
|
6
|
+
# formats.
|
7
|
+
class PlanSerializer < Decidim::Exporters::Serializer
|
8
|
+
include Decidim::ApplicationHelper
|
9
|
+
include Decidim::ResourceHelper
|
10
|
+
|
11
|
+
# Public: Initializes the serializer with a plan.
|
12
|
+
def initialize(plan)
|
13
|
+
@plan = plan
|
14
|
+
end
|
15
|
+
|
16
|
+
# Public: Exports a hash with the serialized data for this proposal.
|
17
|
+
def serialize
|
18
|
+
values = {
|
19
|
+
id: plan.id,
|
20
|
+
category: {
|
21
|
+
id: plan.category.try(:id),
|
22
|
+
name: plan.category.try(:name)
|
23
|
+
},
|
24
|
+
scope: {
|
25
|
+
id: plan.scope.try(:id),
|
26
|
+
name: plan.scope.try(:name)
|
27
|
+
},
|
28
|
+
participatory_space: {
|
29
|
+
id: plan.participatory_space.id,
|
30
|
+
url: Decidim::ResourceLocatorPresenter.new(plan.participatory_space).url
|
31
|
+
},
|
32
|
+
component: { id: component.id },
|
33
|
+
state: plan.state.to_s,
|
34
|
+
comments: plan.comments.count,
|
35
|
+
attachments: plan.attachments.count,
|
36
|
+
followers: plan.followers.count,
|
37
|
+
published_at: plan.published_at,
|
38
|
+
closed_at: plan.closed_at,
|
39
|
+
url: url,
|
40
|
+
related_proposals: {
|
41
|
+
ids: related_proposal_ids,
|
42
|
+
urls: related_proposal_urls
|
43
|
+
},
|
44
|
+
title: plan.title
|
45
|
+
}
|
46
|
+
|
47
|
+
# Add section content
|
48
|
+
plan.sections.each do |sect|
|
49
|
+
content = plan.contents.find_by(section: sect)
|
50
|
+
values["section_#{sect.id}".to_sym] = {
|
51
|
+
title: sect.body,
|
52
|
+
value: content.try(:body)
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
values
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
attr_reader :plan
|
62
|
+
|
63
|
+
def component
|
64
|
+
plan.component
|
65
|
+
end
|
66
|
+
|
67
|
+
def related_proposal_ids
|
68
|
+
plan.proposals.map(&:id)
|
69
|
+
end
|
70
|
+
|
71
|
+
def related_proposal_urls
|
72
|
+
plan.proposals.map do |proposal|
|
73
|
+
Decidim::ResourceLocatorPresenter.new(proposal).url
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def url
|
78
|
+
Decidim::ResourceLocatorPresenter.new(plan).url
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -41,10 +41,10 @@ FactoryBot.define do
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
trait :
|
44
|
+
trait :with_multilingual_answers do
|
45
45
|
settings do
|
46
46
|
{
|
47
|
-
multilingual_answers:
|
47
|
+
multilingual_answers: true
|
48
48
|
}
|
49
49
|
end
|
50
50
|
end
|
@@ -89,6 +89,13 @@ FactoryBot.define do
|
|
89
89
|
published_at { nil }
|
90
90
|
end
|
91
91
|
|
92
|
+
trait :official do
|
93
|
+
after :build do |plan|
|
94
|
+
plan.coauthorships.clear
|
95
|
+
plan.coauthorships.build(author: plan.organization)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
92
99
|
trait :evaluating do
|
93
100
|
state { "evaluating" }
|
94
101
|
answered_at { Time.current }
|
data/lib/decidim/plans.rb
CHANGED
@@ -6,11 +6,13 @@ require_relative "plans/engine"
|
|
6
6
|
require_relative "plans/admin_engine"
|
7
7
|
require_relative "plans/paper_trail"
|
8
8
|
require_relative "plans/component"
|
9
|
-
require_relative "plans/locale_aware"
|
10
|
-
require_relative "plans/optionally_translatable_attributes"
|
11
9
|
|
12
10
|
module Decidim
|
13
11
|
module Plans
|
12
|
+
autoload :LocaleAware, "decidim/plans/locale_aware"
|
13
|
+
autoload :OptionallyTranslatableAttributes, "decidim/plans/optionally_translatable_attributes"
|
14
|
+
autoload :PlanSerializer, "decidim/plans/plan_serializer"
|
15
|
+
|
14
16
|
# Public: Stores an instance of Loggability
|
15
17
|
def self.loggability
|
16
18
|
@loggability ||= Loggability.new
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: decidim-plans
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.16.
|
4
|
+
version: 0.16.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Antti Hukkanen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-02-
|
11
|
+
date: 2019-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: decidim-core
|
@@ -151,11 +151,13 @@ files:
|
|
151
151
|
- app/commands/decidim/plans/admin/update_plan.rb
|
152
152
|
- app/commands/decidim/plans/admin/update_sections.rb
|
153
153
|
- app/commands/decidim/plans/attachment_methods.rb
|
154
|
+
- app/commands/decidim/plans/close_plan.rb
|
154
155
|
- app/commands/decidim/plans/create_plan.rb
|
155
156
|
- app/commands/decidim/plans/destroy_plan.rb
|
156
157
|
- app/commands/decidim/plans/nested_updater.rb
|
157
158
|
- app/commands/decidim/plans/publish_plan.rb
|
158
159
|
- app/commands/decidim/plans/reject_access_to_plan.rb
|
160
|
+
- app/commands/decidim/plans/reopen_plan.rb
|
159
161
|
- app/commands/decidim/plans/request_access_to_plan.rb
|
160
162
|
- app/commands/decidim/plans/respond_to_access_request.rb
|
161
163
|
- app/commands/decidim/plans/update_plan.rb
|
@@ -286,6 +288,7 @@ files:
|
|
286
288
|
- db/migrate/20190202123044_create_version_associations.rb
|
287
289
|
- db/migrate/20190202123045_add_transaction_id_column_to_versions.rb
|
288
290
|
- db/migrate/20190202200716_add_update_token_to_decidim_plans.rb
|
291
|
+
- db/migrate/20190214124014_add_closed_at_to_decidim_plans.rb
|
289
292
|
- lib/decidim/plans.rb
|
290
293
|
- lib/decidim/plans/admin.rb
|
291
294
|
- lib/decidim/plans/admin_engine.rb
|
@@ -295,6 +298,7 @@ files:
|
|
295
298
|
- lib/decidim/plans/optionally_translatable_attributes.rb
|
296
299
|
- lib/decidim/plans/paper_trail.rb
|
297
300
|
- lib/decidim/plans/paper_trail/record_trail.rb
|
301
|
+
- lib/decidim/plans/plan_serializer.rb
|
298
302
|
- lib/decidim/plans/test/factories.rb
|
299
303
|
- lib/decidim/plans/version.rb
|
300
304
|
homepage: https://github.com/mainio/decidim-module-plans
|