decidim-initiatives 0.21.0 → 0.22.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +22 -0
- data/app/assets/images/decidim/gamification/badges/initiatives.svg +1 -87
- data/app/assets/images/decidim/initiatives/icon.svg +1 -3
- data/app/assets/stylesheet/decidim/initiatives/initiatives-votes.css.scss +0 -1
- data/app/assets/stylesheet/decidim/initiatives/initiatives.scss +0 -8
- data/app/assets/stylesheet/decidim/initiatives/popularity_item.css.scss +0 -1
- data/app/assets/stylesheet/decidim/initiatives/print-initiative.css.scss +0 -3
- data/app/cells/decidim/initiatives/content_blocks/highlighted_initiatives/show.erb +4 -3
- data/app/cells/decidim/initiatives/initiative_m_cell.rb +11 -0
- data/app/commands/decidim/initiatives/admin/create_initiative_type.rb +3 -0
- data/app/commands/decidim/initiatives/admin/send_initiative_to_technical_validation.rb +17 -0
- data/app/commands/decidim/initiatives/admin/update_initiative.rb +29 -10
- data/app/commands/decidim/initiatives/admin/update_initiative_type.rb +3 -0
- data/app/commands/decidim/initiatives/attachment_methods.rb +33 -0
- data/app/commands/decidim/initiatives/create_initiative.rb +23 -1
- data/app/commands/decidim/initiatives/vote_initiative.rb +16 -0
- data/app/controllers/concerns/decidim/initiatives/admin/filterable.rb +18 -4
- data/app/controllers/concerns/decidim/initiatives/orderable.rb +3 -1
- data/app/controllers/concerns/decidim/initiatives/single_initiative_type.rb +26 -0
- data/app/controllers/decidim/initiatives/admin/initiatives_controller.rb +20 -1
- data/app/controllers/decidim/initiatives/create_initiative_controller.rb +35 -5
- data/app/controllers/decidim/initiatives/initiatives_controller.rb +17 -3
- data/app/controllers/decidim/initiatives/versions_controller.rb +20 -0
- data/app/events/decidim/initiatives/admin/initiative_sent_to_technical_validation_event.rb +21 -0
- data/app/events/decidim/initiatives/admin/support_threshold_reached_event.rb +13 -0
- data/app/forms/decidim/initiatives/admin/initiative_form.rb +31 -0
- data/app/forms/decidim/initiatives/admin/initiative_type_form.rb +5 -1
- data/app/forms/decidim/initiatives/initiative_form.rb +34 -0
- data/app/forms/decidim/initiatives/vote_form.rb +3 -1
- data/app/helpers/decidim/initiatives/application_helper.rb +104 -0
- data/app/helpers/decidim/initiatives/initiative_helper.rb +13 -0
- data/app/helpers/decidim/initiatives/initiatives_helper.rb +10 -0
- data/app/jobs/decidim/initiatives/export_initiatives_job.rb +25 -0
- data/app/mailers/decidim/initiatives/initiatives_mailer.rb +0 -21
- data/app/models/concerns/decidim/initiatives/has_area.rb +30 -0
- data/app/models/decidim/initiative.rb +62 -10
- data/app/permissions/decidim/initiatives/admin/permissions.rb +7 -0
- data/app/permissions/decidim/initiatives/permissions.rb +35 -10
- data/app/serializers/decidim/initiatives/initiative_serializer.rb +32 -0
- data/app/services/decidim/initiatives/diff_renderer.rb +18 -0
- data/app/services/decidim/initiatives/initiative_search.rb +59 -15
- data/app/services/decidim/initiatives/status_change_notifier.rb +4 -5
- data/app/views/decidim/initiatives/admin/exports/_dropdown.html.erb +8 -0
- data/app/views/decidim/initiatives/admin/initiatives/_form.html.erb +24 -1
- data/app/views/decidim/initiatives/admin/initiatives/_initiative_attachments.erb +43 -0
- data/app/views/decidim/initiatives/admin/initiatives/index.html.erb +8 -3
- data/app/views/decidim/initiatives/admin/initiatives_types/_form.html.erb +12 -0
- data/app/views/decidim/initiatives/create_initiative/fill_data.html.erb +44 -10
- data/app/views/decidim/initiatives/create_initiative/finish.html.erb +17 -10
- data/app/views/decidim/initiatives/create_initiative/previous_form.html.erb +2 -1
- data/app/views/decidim/initiatives/create_initiative/promotal_committee.html.erb +1 -1
- data/app/views/decidim/initiatives/create_initiative/select_initiative_type.html.erb +1 -2
- data/app/views/decidim/initiatives/create_initiative/show_similar_initiatives.html.erb +1 -1
- data/app/views/decidim/initiatives/initiative_signatures/fill_personal_data.html.erb +1 -0
- data/app/views/decidim/initiatives/initiatives/_author.html.erb +1 -1
- data/app/views/decidim/initiatives/initiatives/_filters.html.erb +16 -28
- data/app/views/decidim/initiatives/initiatives/_index_header.html.erb +3 -3
- data/app/views/decidim/initiatives/initiatives/_initiatives.html.erb +1 -1
- data/app/views/decidim/initiatives/initiatives/_interactions.html.erb +2 -3
- data/app/views/decidim/initiatives/initiatives/_tags.html.erb +3 -0
- data/app/views/decidim/initiatives/initiatives/index.html.erb +1 -1
- data/app/views/decidim/initiatives/initiatives/show.html.erb +1 -0
- data/app/views/decidim/initiatives/versions/index.html.erb +8 -0
- data/app/views/decidim/initiatives/versions/show.html.erb +10 -0
- data/app/views/layouts/decidim/_initiative_creation_header.html.erb +2 -1
- data/app/views/layouts/decidim/_initiative_header.html.erb +2 -1
- data/app/views/layouts/decidim/_initiative_signature_creation_header.html.erb +1 -1
- data/app/views/layouts/decidim/initiative_creation.html.erb +1 -2
- data/app/views/layouts/decidim/initiative_signature_creation.html.erb +2 -2
- data/config/locales/ar.yml +12 -19
- data/config/locales/bg-BG.yml +13 -0
- data/config/locales/ca.yml +79 -17
- data/config/locales/cs.yml +88 -26
- data/config/locales/da-DK.yml +1 -0
- data/config/locales/de.yml +67 -16
- data/config/locales/el.yml +528 -0
- data/config/locales/en.yml +82 -20
- data/config/locales/es-MX.yml +79 -17
- data/config/locales/es-PY.yml +79 -17
- data/config/locales/es.yml +81 -19
- data/config/locales/et-EE.yml +1 -0
- data/config/locales/eu.yml +4 -7
- data/config/locales/fi-plain.yml +79 -17
- data/config/locales/fi.yml +97 -35
- data/config/locales/fr-CA.yml +529 -0
- data/config/locales/fr.yml +66 -16
- data/config/locales/ga-IE.yml +1 -0
- data/config/locales/gl.yml +4 -7
- data/config/locales/hr-HR.yml +1 -0
- data/config/locales/hu.yml +21 -18
- data/config/locales/id-ID.yml +4 -7
- data/config/locales/is-IS.yml +4 -7
- data/config/locales/it.yml +105 -57
- data/config/locales/ja-JP.yml +535 -0
- data/config/locales/lt-LT.yml +1 -0
- data/config/locales/lv-LV.yml +529 -0
- data/config/locales/mt-MT.yml +1 -0
- data/config/locales/nl.yml +66 -16
- data/config/locales/no.yml +14 -29
- data/config/locales/pl.yml +241 -176
- data/config/locales/pt-BR.yml +5 -8
- data/config/locales/pt.yml +227 -176
- data/config/locales/ro-RO.yml +532 -0
- data/config/locales/ru.yml +4 -7
- data/config/locales/sk-SK.yml +468 -0
- data/config/locales/sk.yml +462 -0
- data/config/locales/sl.yml +18 -0
- data/config/locales/sr-CS.yml +8 -0
- data/config/locales/sv.yml +77 -26
- data/config/locales/tr-TR.yml +4 -7
- data/config/locales/uk.yml +4 -7
- data/db/migrate/20200320105920_index_foreign_keys_in_decidim_initiatives.rb +8 -0
- data/db/migrate/20200320105921_index_foreign_keys_in_decidim_initiatives_votes.rb +8 -0
- data/db/migrate/20200417120551_add_custom_signature_end_time_option.rb +7 -0
- data/db/migrate/20200424110930_add_attachments_enabled_option.rb +7 -0
- data/db/migrate/20200514085422_add_area_to_initiatives.rb +7 -0
- data/db/migrate/20200514102631_add_area_enabled_option_to_initiatives.rb +7 -0
- data/db/seeds/city2.jpeg +0 -0
- data/lib/decidim/initiatives/admin_engine.rb +4 -0
- data/lib/decidim/initiatives/engine.rb +1 -0
- data/lib/decidim/initiatives/participatory_space.rb +9 -1
- data/lib/decidim/initiatives/test/factories.rb +30 -1
- data/lib/decidim/initiatives/version.rb +1 -1
- metadata +55 -15
- data/app/views/decidim/initiatives/initiatives_mailer/notify_validating_request.html.erb +0 -3
@@ -12,15 +12,24 @@ module Decidim
|
|
12
12
|
attribute :description, String
|
13
13
|
attribute :type_id, Integer
|
14
14
|
attribute :scope_id, Integer
|
15
|
+
attribute :area_id, Integer
|
15
16
|
attribute :decidim_user_group_id, Integer
|
16
17
|
attribute :signature_type, String
|
18
|
+
attribute :signature_end_date, Date
|
17
19
|
attribute :state, String
|
20
|
+
attribute :attachment, AttachmentForm
|
18
21
|
|
19
22
|
validates :title, :description, presence: true
|
20
23
|
validates :title, length: { maximum: 150 }
|
21
24
|
validates :signature_type, presence: true
|
22
25
|
validates :type_id, presence: true
|
26
|
+
validates :area, presence: true, if: ->(form) { form.area_id.present? }
|
23
27
|
validate :scope_exists
|
28
|
+
validate :notify_missing_attachment_if_errored
|
29
|
+
validate :trigger_attachment_errors
|
30
|
+
validates :signature_end_date, date: { after: Date.current }, if: lambda { |form|
|
31
|
+
form.context.initiative_type.custom_signature_end_date_enabled? && form.signature_end_date.present?
|
32
|
+
}
|
24
33
|
|
25
34
|
def map_model(model)
|
26
35
|
self.type_id = model.type.id
|
@@ -35,6 +44,10 @@ module Decidim
|
|
35
44
|
super.presence
|
36
45
|
end
|
37
46
|
|
47
|
+
def area
|
48
|
+
@area ||= current_organization.areas.find_by(id: area_id)
|
49
|
+
end
|
50
|
+
|
38
51
|
private
|
39
52
|
|
40
53
|
def scope_exists
|
@@ -42,6 +55,27 @@ module Decidim
|
|
42
55
|
|
43
56
|
errors.add(:scope_id, :invalid) unless InitiativesTypeScope.where(decidim_initiatives_types_id: type_id, decidim_scopes_id: scope_id).exists?
|
44
57
|
end
|
58
|
+
|
59
|
+
# This method will add an error to the `attachment` field only if there's
|
60
|
+
# any error in any other field. This is needed because when the form has
|
61
|
+
# an error, the attachment is lost, so we need a way to inform the user of
|
62
|
+
# this problem.
|
63
|
+
def notify_missing_attachment_if_errored
|
64
|
+
return if attachment.blank?
|
65
|
+
|
66
|
+
errors.add(:attachment, :needs_to_be_reattached) if errors.any?
|
67
|
+
end
|
68
|
+
|
69
|
+
def trigger_attachment_errors
|
70
|
+
return if attachment.blank?
|
71
|
+
return if attachment.valid?
|
72
|
+
|
73
|
+
attachment.errors.each { |error| errors.add(:attachment, error) }
|
74
|
+
|
75
|
+
attachment = Attachment.new(file: attachment.try(:file))
|
76
|
+
|
77
|
+
errors.add(:attachment, :file) if !attachment.save && attachment.errors.has_key?(:file)
|
78
|
+
end
|
45
79
|
end
|
46
80
|
end
|
47
81
|
end
|
@@ -96,7 +96,9 @@ module Decidim
|
|
96
96
|
|
97
97
|
errors.add(:base, :invalid) unless authorized? &&
|
98
98
|
authorization_handler &&
|
99
|
-
authorization_handler_metadata_variations.any?
|
99
|
+
authorization_handler_metadata_variations.any? do |variation|
|
100
|
+
authorization.metadata.symbolize_keys.except(:extras) == variation.symbolize_keys.except(:extras)
|
101
|
+
end
|
100
102
|
end
|
101
103
|
|
102
104
|
def author
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Initiatives
|
5
|
+
# Custom helpers, scoped to the initiatives engine.
|
6
|
+
#
|
7
|
+
module ApplicationHelper
|
8
|
+
include Decidim::CheckBoxesTreeHelper
|
9
|
+
|
10
|
+
def filter_states_values
|
11
|
+
TreeNode.new(
|
12
|
+
TreePoint.new("", t("decidim.initiatives.application_helper.filter_state_values.all")),
|
13
|
+
[
|
14
|
+
TreePoint.new("open", t("decidim.initiatives.application_helper.filter_state_values.open")),
|
15
|
+
TreeNode.new(
|
16
|
+
TreePoint.new("closed", t("decidim.initiatives.application_helper.filter_state_values.closed")),
|
17
|
+
[
|
18
|
+
TreePoint.new("accepted", t("decidim.initiatives.application_helper.filter_state_values.accepted")),
|
19
|
+
TreePoint.new("rejected", t("decidim.initiatives.application_helper.filter_state_values.rejected"))
|
20
|
+
]
|
21
|
+
),
|
22
|
+
TreePoint.new("answered", t("decidim.initiatives.application_helper.filter_state_values.answered"))
|
23
|
+
]
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def filter_scopes_values
|
28
|
+
main_scopes = current_organization.scopes.top_level
|
29
|
+
|
30
|
+
scopes_values = main_scopes.includes(:scope_type, :children).flat_map do |scope|
|
31
|
+
TreeNode.new(
|
32
|
+
TreePoint.new(scope.id.to_s, translated_attribute(scope.name, current_organization)),
|
33
|
+
scope_children_to_tree(scope)
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
scopes_values.prepend(TreePoint.new("global", t("decidim.scopes.global")))
|
38
|
+
|
39
|
+
TreeNode.new(
|
40
|
+
TreePoint.new("", t("decidim.initiatives.application_helper.filter_scope_values.all")),
|
41
|
+
scopes_values
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
def scope_children_to_tree(scope)
|
46
|
+
return unless scope.children.any?
|
47
|
+
|
48
|
+
scope.children.includes(:scope_type, :children).flat_map do |child|
|
49
|
+
TreeNode.new(
|
50
|
+
TreePoint.new(child.id.to_s, translated_attribute(child.name, current_organization)),
|
51
|
+
scope_children_to_tree(child)
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def filter_types_values
|
57
|
+
types_values = Decidim::InitiativesType.where(organization: current_organization).map do |type|
|
58
|
+
TreeNode.new(
|
59
|
+
TreePoint.new(type.id.to_s, type.title[I18n.locale.to_s])
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
TreeNode.new(
|
64
|
+
TreePoint.new("", t("decidim.initiatives.application_helper.filter_type_values.all")),
|
65
|
+
types_values
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
def filter_areas_values
|
70
|
+
areas_or_types = areas_for_select(current_organization)
|
71
|
+
|
72
|
+
areas_values = if areas_or_types.first.is_a?(Decidim::Area)
|
73
|
+
filter_areas(areas_or_types)
|
74
|
+
else
|
75
|
+
filter_areas_and_types(areas_or_types)
|
76
|
+
end
|
77
|
+
|
78
|
+
TreeNode.new(
|
79
|
+
TreePoint.new("", t("decidim.initiatives.application_helper.filter_area_values.all")),
|
80
|
+
areas_values
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
def filter_areas(areas)
|
85
|
+
areas.map do |area|
|
86
|
+
TreeNode.new(
|
87
|
+
TreePoint.new(area.id.to_s, area.name[I18n.locale.to_s])
|
88
|
+
)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def filter_areas_and_types(area_types)
|
93
|
+
area_types.map do |area_type|
|
94
|
+
TreeNode.new(
|
95
|
+
TreePoint.new(area_type.area_ids.join("_"), area_type.name[I18n.locale.to_s]),
|
96
|
+
area_type.areas.map do |area|
|
97
|
+
TreePoint.new(area.id.to_s, area.name[I18n.locale.to_s])
|
98
|
+
end
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -5,6 +5,7 @@ module Decidim
|
|
5
5
|
# Helper method related to initiative object and its internal state.
|
6
6
|
module InitiativeHelper
|
7
7
|
include Decidim::SanitizeHelper
|
8
|
+
include Decidim::ResourceVersionsHelper
|
8
9
|
|
9
10
|
# Public: The css class applied based on the initiative state to
|
10
11
|
# the initiative badge.
|
@@ -99,6 +100,18 @@ module Decidim
|
|
99
100
|
|
100
101
|
send("#{tag}_to", "", html_options, &block)
|
101
102
|
end
|
103
|
+
|
104
|
+
def can_edit_custom_signature_end_date?(initiative)
|
105
|
+
return false unless initiative.custom_signature_end_date_enabled?
|
106
|
+
|
107
|
+
initiative.created? || initiative.validating?
|
108
|
+
end
|
109
|
+
|
110
|
+
def can_edit_area?(initiative)
|
111
|
+
return false unless initiative.area_enabled?
|
112
|
+
|
113
|
+
initiative.created? || initiative.validating?
|
114
|
+
end
|
102
115
|
end
|
103
116
|
end
|
104
117
|
end
|
@@ -7,6 +7,7 @@ module Decidim
|
|
7
7
|
def initiatives_filter_form_for(filter)
|
8
8
|
content_tag :div, class: "filters" do
|
9
9
|
form_for filter,
|
10
|
+
namespace: filter_form_namespace,
|
10
11
|
builder: Decidim::Initiatives::InitiativesFilterFormBuilder,
|
11
12
|
url: url_for,
|
12
13
|
as: :filter,
|
@@ -17,6 +18,15 @@ module Decidim
|
|
17
18
|
end
|
18
19
|
end
|
19
20
|
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Creates a unique namespace for a filter form to prevent dupliacte IDs in
|
25
|
+
# the DOM when multiple filter forms are rendered with the same fields (e.g.
|
26
|
+
# for desktop and mobile).
|
27
|
+
def filter_form_namespace
|
28
|
+
"filters_#{SecureRandom.uuid}"
|
29
|
+
end
|
20
30
|
end
|
21
31
|
end
|
22
32
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Initiatives
|
5
|
+
class ExportInitiativesJob < ApplicationJob
|
6
|
+
queue_as :default
|
7
|
+
|
8
|
+
def perform(user, format)
|
9
|
+
export_data = Decidim::Exporters.find_exporter(format).new(collection, serializer).export
|
10
|
+
|
11
|
+
ExportMailer.export(user, "initiatives", export_data).deliver_now
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def collection
|
17
|
+
Decidim::Initiative.all
|
18
|
+
end
|
19
|
+
|
20
|
+
def serializer
|
21
|
+
Decidim::Initiatives::InitiativeSerializer
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -51,27 +51,6 @@ module Decidim
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
# Notify an initiative requesting technical validation
|
55
|
-
def notify_validating_request(initiative, user)
|
56
|
-
return if user.email.blank?
|
57
|
-
|
58
|
-
@organization = initiative.organization
|
59
|
-
@link = decidim_admin_initiatives.edit_initiative_url(initiative, host: @organization.host)
|
60
|
-
|
61
|
-
with_user(user) do
|
62
|
-
@subject = I18n.t(
|
63
|
-
"decidim.initiatives.initiatives_mailer.technical_validation_for",
|
64
|
-
title: translated_attribute(initiative.title)
|
65
|
-
)
|
66
|
-
@body = I18n.t(
|
67
|
-
"decidim.initiatives.initiatives_mailer.technical_validation_body_for",
|
68
|
-
title: translated_attribute(initiative.title)
|
69
|
-
)
|
70
|
-
|
71
|
-
mail(to: "#{user.name} <#{user.email}>", subject: @subject)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
54
|
# Notify progress to all initiative subscribers.
|
76
55
|
def notify_progress(initiative, user)
|
77
56
|
return if user.email.blank?
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
module Decidim
|
6
|
+
module Initiatives
|
7
|
+
module HasArea
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
belongs_to :area,
|
12
|
+
foreign_key: "decidim_area_id",
|
13
|
+
class_name: "Decidim::Area",
|
14
|
+
optional: true
|
15
|
+
|
16
|
+
delegate :areas, to: :organization
|
17
|
+
|
18
|
+
validate :area_belongs_to_organization
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def area_belongs_to_organization
|
24
|
+
return unless area && organization
|
25
|
+
|
26
|
+
errors.add(:area, :invalid) unless areas.where(id: area.id).exists?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -19,6 +19,7 @@ module Decidim
|
|
19
19
|
include Decidim::HasReference
|
20
20
|
include Decidim::Randomable
|
21
21
|
include Decidim::Searchable
|
22
|
+
include Decidim::Initiatives::HasArea
|
22
23
|
|
23
24
|
belongs_to :organization,
|
24
25
|
foreign_key: "decidim_organization_id",
|
@@ -30,7 +31,8 @@ module Decidim
|
|
30
31
|
inverse_of: :initiatives
|
31
32
|
|
32
33
|
delegate :type, :scope, :scope_name, to: :scoped_type, allow_nil: true
|
33
|
-
delegate :promoting_committee_enabled?, to: :type
|
34
|
+
delegate :attachments_enabled?, :promoting_committee_enabled?, :custom_signature_end_date_enabled?, :area_enabled?, to: :type
|
35
|
+
delegate :name, to: :area, prefix: true, allow_nil: true
|
34
36
|
|
35
37
|
has_many :votes,
|
36
38
|
foreign_key: "decidim_initiative_id",
|
@@ -67,24 +69,32 @@ module Decidim
|
|
67
69
|
case_sensitive: false
|
68
70
|
|
69
71
|
scope :open, lambda {
|
70
|
-
|
71
|
-
|
72
|
-
.where("signature_start_date <= ?", Date.current)
|
73
|
-
.where("signature_end_date >= ?", Date.current)
|
72
|
+
where.not(state: [:discarded, :rejected, :accepted, :created])
|
73
|
+
.currently_signable
|
74
74
|
}
|
75
75
|
scope :closed, lambda {
|
76
|
-
|
77
|
-
.
|
78
|
-
.or(where("signature_start_date > ?", Date.current))
|
79
|
-
.or(where("signature_end_date < ?", Date.current))
|
76
|
+
where(state: [:discarded, :rejected, :accepted])
|
77
|
+
.or(currently_unsignable)
|
80
78
|
}
|
81
79
|
scope :published, -> { where.not(published_at: nil) }
|
82
80
|
scope :with_state, ->(state) { where(state: state) if state.present? }
|
83
81
|
|
82
|
+
scope :currently_signable, lambda {
|
83
|
+
where("signature_start_date <= ?", Date.current)
|
84
|
+
.where("signature_end_date >= ?", Date.current)
|
85
|
+
}
|
86
|
+
scope :currently_unsignable, lambda {
|
87
|
+
where("signature_start_date > ?", Date.current)
|
88
|
+
.or(where("signature_end_date < ?", Date.current))
|
89
|
+
}
|
90
|
+
|
91
|
+
scope :answered, -> { where.not(answered_at: nil) }
|
92
|
+
|
84
93
|
scope :public_spaces, -> { published }
|
85
94
|
scope :signature_type_updatable, -> { created }
|
86
95
|
|
87
96
|
scope :order_by_most_recent, -> { order(created_at: :desc) }
|
97
|
+
scope :order_by_most_recently_published, -> { order(published_at: :desc) }
|
88
98
|
scope :order_by_supports, -> { order(Arel.sql("initiative_votes_count + coalesce(offline_votes, 0) desc")) }
|
89
99
|
scope :order_by_most_commented, lambda {
|
90
100
|
select("decidim_initiatives.*")
|
@@ -227,7 +237,7 @@ module Decidim
|
|
227
237
|
published_at: Time.current,
|
228
238
|
state: "published",
|
229
239
|
signature_start_date: Date.current,
|
230
|
-
signature_end_date: Date.current + Decidim::Initiatives.default_signature_time_period_length
|
240
|
+
signature_end_date: signature_end_date || Date.current + Decidim::Initiatives.default_signature_time_period_length
|
231
241
|
)
|
232
242
|
end
|
233
243
|
|
@@ -301,6 +311,10 @@ module Decidim
|
|
301
311
|
committee_members.approved.where(decidim_users_id: user.id).any?
|
302
312
|
end
|
303
313
|
|
314
|
+
def author_users
|
315
|
+
[author].concat(committee_members.excluding_author.map(&:user))
|
316
|
+
end
|
317
|
+
|
304
318
|
def accepts_offline_votes?
|
305
319
|
published? && (offline_signature_type? || any_signature_type?)
|
306
320
|
end
|
@@ -368,5 +382,43 @@ module Decidim
|
|
368
382
|
|
369
383
|
# Allow ransacker to search on an Enum Field
|
370
384
|
ransacker :state, formatter: proc { |int| states[int] }
|
385
|
+
|
386
|
+
ransacker :type_id do
|
387
|
+
Arel.sql("decidim_initiatives_type_scopes.decidim_initiatives_types_id")
|
388
|
+
end
|
389
|
+
|
390
|
+
# method for sort_link by number of supports
|
391
|
+
ransacker :supports_count do
|
392
|
+
query = <<~SQL
|
393
|
+
(
|
394
|
+
SELECT
|
395
|
+
CASE
|
396
|
+
WHEN signature_type = 0 THEN 0
|
397
|
+
ELSE COALESCE(offline_votes, 0)
|
398
|
+
END
|
399
|
+
+
|
400
|
+
CASE
|
401
|
+
WHEN signature_type = 1 THEN 0
|
402
|
+
ELSE initiative_votes_count + initiative_supports_count
|
403
|
+
END
|
404
|
+
FROM decidim_initiatives as initiatives
|
405
|
+
WHERE initiatives.id = decidim_initiatives.id
|
406
|
+
GROUP BY initiatives.id
|
407
|
+
)
|
408
|
+
SQL
|
409
|
+
Arel.sql(query)
|
410
|
+
end
|
411
|
+
|
412
|
+
ransacker :id_string do
|
413
|
+
Arel.sql(%{cast("decidim_initiatives"."id" as text)})
|
414
|
+
end
|
415
|
+
|
416
|
+
ransacker :author_name do
|
417
|
+
Arel.sql("decidim_users.name")
|
418
|
+
end
|
419
|
+
|
420
|
+
ransacker :author_nickname do
|
421
|
+
Arel.sql("decidim_users.nickname")
|
422
|
+
end
|
371
423
|
end
|
372
424
|
end
|
@@ -35,6 +35,7 @@ module Decidim
|
|
35
35
|
initiative_type_scope_action?
|
36
36
|
initiative_committee_action?
|
37
37
|
initiative_admin_user_action?
|
38
|
+
initiative_export_action?
|
38
39
|
moderator_action?
|
39
40
|
allow! if permission_action.subject == :attachment
|
40
41
|
|
@@ -69,6 +70,8 @@ module Decidim
|
|
69
70
|
def attachment_action?
|
70
71
|
return unless permission_action.subject == :attachment
|
71
72
|
|
73
|
+
disallow! && return unless initiative.attachments_enabled?
|
74
|
+
|
72
75
|
attachment = context.fetch(:attachment, nil)
|
73
76
|
attached = attachment&.attached_to
|
74
77
|
|
@@ -158,6 +161,10 @@ module Decidim
|
|
158
161
|
end
|
159
162
|
end
|
160
163
|
|
164
|
+
def initiative_export_action?
|
165
|
+
allow! if permission_action.subject == :initiatives && permission_action.action == :export
|
166
|
+
end
|
167
|
+
|
161
168
|
def moderator_action?
|
162
169
|
return unless permission_action.subject == :moderation
|
163
170
|
|