decidim-initiatives 0.20.0 → 0.23.1.rc1
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/javascripts/decidim/initiatives/admin/initiatives_types.js.es6 +18 -0
- data/app/assets/stylesheet/decidim/initiatives/initiatives-votes.css.scss +0 -1
- data/app/assets/stylesheet/decidim/initiatives/initiatives.scss +6 -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 +25 -0
- data/app/cells/decidim/initiatives_votes/vote/show.erb +12 -9
- data/app/cells/decidim/initiatives_votes/vote_cell.rb +7 -0
- data/app/commands/decidim/initiatives/admin/create_initiative_type.rb +6 -1
- 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 +6 -1
- data/app/commands/decidim/initiatives/attachment_methods.rb +37 -0
- data/app/commands/decidim/initiatives/create_initiative.rb +25 -3
- data/app/commands/decidim/initiatives/unvote_initiative.rb +4 -10
- data/app/commands/decidim/initiatives/vote_initiative.rb +47 -31
- data/app/controllers/concerns/decidim/initiatives/admin/filterable.rb +51 -0
- 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/answers_controller.rb +2 -3
- data/app/controllers/decidim/initiatives/admin/initiatives_controller.rb +28 -15
- data/app/controllers/decidim/initiatives/create_initiative_controller.rb +36 -6
- data/app/controllers/decidim/initiatives/initiative_signatures_controller.rb +19 -23
- data/app/controllers/decidim/initiatives/initiative_votes_controller.rb +11 -5
- data/app/controllers/decidim/initiatives/initiatives_controller.rb +28 -13
- data/app/controllers/decidim/initiatives/initiatives_type_scopes_controller.rb +9 -1
- data/app/controllers/decidim/initiatives/versions_controller.rb +20 -0
- data/app/controllers/decidim/initiatives/{initiative_widgets_controller.rb → widgets_controller.rb} +2 -2
- 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 +49 -7
- data/app/forms/decidim/initiatives/admin/initiative_type_form.rb +8 -1
- data/app/forms/decidim/initiatives/initiative_form.rb +56 -1
- data/app/forms/decidim/initiatives/vote_form.rb +133 -76
- 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 +184 -44
- data/app/models/decidim/initiatives_type.rb +5 -2
- data/app/models/decidim/initiatives_type_scope.rb +5 -1
- data/app/models/decidim/initiatives_vote.rb +19 -23
- data/app/permissions/decidim/initiatives/admin/permissions.rb +19 -8
- data/app/permissions/decidim/initiatives/permissions.rb +37 -14
- data/app/presenters/decidim/initiatives/initiative_stats_presenter.rb +1 -5
- data/app/queries/decidim/initiatives/admin/manageable_initiatives.rb +7 -39
- 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/types/decidim/initiatives/initiative_api_type.rb +26 -0
- data/app/types/decidim/initiatives/initiative_committee_member_type.rb +18 -0
- data/app/types/decidim/initiatives/initiative_type.rb +42 -0
- data/app/views/decidim/initiatives/admin/answers/_info_initiative.html.erb +1 -1
- data/app/views/decidim/initiatives/admin/exports/_dropdown.html.erb +8 -0
- data/app/views/decidim/initiatives/admin/initiatives/_form.html.erb +59 -14
- data/app/views/decidim/initiatives/admin/initiatives/_initiative_attachments.erb +43 -0
- data/app/views/decidim/initiatives/admin/initiatives/export_pdf_signatures.pdf.erb +12 -9
- data/app/views/decidim/initiatives/admin/initiatives/index.html.erb +10 -45
- data/app/views/decidim/initiatives/admin/initiatives_types/_form.html.erb +47 -10
- data/app/views/decidim/initiatives/admin/initiatives_types/_initiative_type_scopes.html.erb +28 -25
- data/app/views/decidim/initiatives/create_initiative/fill_data.html.erb +46 -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 -1
- data/app/views/decidim/initiatives/initiative_signatures/update_buttons_and_counters.js.erb +1 -1
- data/app/views/decidim/initiatives/initiative_votes/update_buttons_and_counters.js.erb +1 -1
- 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 +39 -5
- data/app/views/decidim/initiatives/initiatives/_initiatives.html.erb +11 -1
- data/app/views/decidim/initiatives/initiatives/_interactions.html.erb +2 -3
- data/app/views/decidim/initiatives/initiatives/_progress_bar.html.erb +24 -9
- data/app/views/decidim/initiatives/initiatives/_tags.html.erb +3 -0
- data/app/views/decidim/initiatives/initiatives/_vote_cabin.html.erb +1 -13
- data/app/views/decidim/initiatives/initiatives/index.html.erb +1 -1
- data/app/views/decidim/initiatives/initiatives/show.html.erb +2 -3
- 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.html.erb +1 -0
- 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/am-ET.yml +1 -0
- data/config/locales/ar.yml +17 -21
- data/config/locales/bg-BG.yml +13 -0
- data/config/locales/bg.yml +13 -0
- data/config/locales/ca.yml +100 -22
- data/config/locales/cs.yml +110 -32
- data/config/locales/da-DK.yml +1 -0
- data/config/locales/da.yml +1 -0
- data/config/locales/de.yml +75 -21
- data/config/locales/el-GR.yml +1 -0
- data/config/locales/el.yml +525 -0
- data/config/locales/en.yml +102 -24
- data/config/locales/eo.yml +1 -0
- data/config/locales/es-MX.yml +100 -21
- data/config/locales/es-PY.yml +100 -21
- data/config/locales/es.yml +104 -25
- data/config/locales/et-EE.yml +1 -0
- data/config/locales/et.yml +1 -0
- data/config/locales/eu.yml +4 -21
- data/config/locales/fi-plain.yml +99 -21
- data/config/locales/fi.yml +117 -39
- data/config/locales/fr-CA.yml +557 -0
- data/config/locales/fr.yml +101 -23
- data/config/locales/ga-IE.yml +1 -0
- data/config/locales/gl.yml +4 -21
- data/config/locales/hr-HR.yml +1 -0
- data/config/locales/hr.yml +1 -0
- data/config/locales/hu.yml +30 -24
- data/config/locales/id-ID.yml +4 -21
- data/config/locales/is-IS.yml +251 -0
- data/config/locales/is.yml +251 -0
- data/config/locales/it.yml +116 -61
- data/config/locales/ja-JP.yml +529 -0
- data/config/locales/ja.yml +549 -0
- data/config/locales/ko-KR.yml +1 -0
- data/config/locales/ko.yml +1 -0
- data/config/locales/lt-LT.yml +1 -0
- data/config/locales/lt.yml +1 -0
- data/config/locales/lv.yml +525 -0
- data/config/locales/mt-MT.yml +1 -0
- data/config/locales/mt.yml +1 -0
- data/config/locales/nl.yml +76 -21
- data/config/locales/no.yml +368 -9
- data/config/locales/om-ET.yml +1 -0
- data/config/locales/pl.yml +260 -189
- data/config/locales/pt-BR.yml +5 -22
- data/config/locales/pt.yml +231 -179
- data/config/locales/ro-RO.yml +533 -0
- data/config/locales/ru.yml +4 -21
- data/config/locales/sk-SK.yml +468 -0
- data/config/locales/sk.yml +458 -0
- data/config/locales/sl.yml +24 -0
- data/config/locales/so-SO.yml +1 -0
- data/config/locales/sr-CS.yml +8 -0
- data/config/locales/sv.yml +102 -31
- data/config/locales/ti-ER.yml +1 -0
- data/config/locales/tr-TR.yml +4 -21
- data/config/locales/uk.yml +4 -21
- data/config/locales/vi-VN.yml +1 -0
- data/config/locales/vi.yml +1 -0
- data/config/locales/zh-CN.yml +549 -0
- data/config/locales/zh-TW.yml +1 -0
- data/db/migrate/20191106144259_add_settings_to_initiatives_types.rb +8 -0
- data/db/migrate/20191107134847_add_scopes_to_initiatives_votes.rb +28 -0
- data/db/migrate/20191116170841_allow_multiple_initiative_votes_counter_caches.rb +32 -0
- data/db/migrate/20191118105634_allow_multiple_offline_votes.rb +34 -0
- 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/migrate/20200528151456_remove_user_groups_from_initiative_votes.rb +7 -0
- data/db/migrate/20200827154214_add_commentable_counter_cache_to_initiatives.rb +9 -0
- data/db/seeds/city.jpeg +0 -0
- data/db/seeds/city2.jpeg +0 -0
- data/lib/decidim/api/initiative_type_interface.rb +13 -0
- data/lib/decidim/initiatives/admin_engine.rb +5 -0
- data/lib/decidim/initiatives/api.rb +7 -0
- data/lib/decidim/initiatives/engine.rb +11 -2
- data/lib/decidim/initiatives/participatory_space.rb +18 -1
- data/lib/decidim/initiatives/query_extensions.rb +40 -0
- data/lib/decidim/initiatives/test/factories.rb +57 -10
- data/lib/decidim/initiatives/version.rb +1 -1
- data/lib/tasks/decidim_initiatives.rake +1 -3
- metadata +95 -22
- data/app/views/decidim/initiatives/initiative_widgets/show.html.erb +0 -4
- data/app/views/decidim/initiatives/initiatives/_supports.html.erb +0 -22
- data/app/views/decidim/initiatives/initiatives/signature_identities.html.erb +0 -42
- data/app/views/decidim/initiatives/initiatives_mailer/notify_validating_request.html.erb +0 -3
@@ -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
|
@@ -7,7 +7,7 @@ module Decidim
|
|
7
7
|
include Decidim::Authorable
|
8
8
|
include Decidim::Participable
|
9
9
|
include Decidim::Publicable
|
10
|
-
include Decidim::
|
10
|
+
include Decidim::ScopableParticipatorySpace
|
11
11
|
include Decidim::Comments::Commentable
|
12
12
|
include Decidim::Followable
|
13
13
|
include Decidim::HasAttachments
|
@@ -19,6 +19,10 @@ module Decidim
|
|
19
19
|
include Decidim::HasReference
|
20
20
|
include Decidim::Randomable
|
21
21
|
include Decidim::Searchable
|
22
|
+
include Decidim::Initiatives::HasArea
|
23
|
+
include Decidim::TranslatableResource
|
24
|
+
|
25
|
+
translatable_fields :title, :description, :answer
|
22
26
|
|
23
27
|
belongs_to :organization,
|
24
28
|
foreign_key: "decidim_organization_id",
|
@@ -29,8 +33,9 @@ module Decidim
|
|
29
33
|
class_name: "Decidim::InitiativesTypeScope",
|
30
34
|
inverse_of: :initiatives
|
31
35
|
|
32
|
-
delegate :type, :scope, :scope_name, to: :scoped_type, allow_nil: true
|
33
|
-
delegate :promoting_committee_enabled?, to: :type
|
36
|
+
delegate :type, :scope, :scope_name, :supports_required, to: :scoped_type, allow_nil: true
|
37
|
+
delegate :attachments_enabled?, :promoting_committee_enabled?, :custom_signature_end_date_enabled?, :area_enabled?, to: :type
|
38
|
+
delegate :name, to: :area, prefix: true, allow_nil: true
|
34
39
|
|
35
40
|
has_many :votes,
|
36
41
|
foreign_key: "decidim_initiative_id",
|
@@ -59,41 +64,51 @@ module Decidim
|
|
59
64
|
|
60
65
|
validates :title, :description, :state, presence: true
|
61
66
|
validates :signature_type, presence: true
|
62
|
-
validate :signature_type_allowed
|
63
|
-
|
64
67
|
validates :hashtag,
|
65
68
|
uniqueness: true,
|
66
69
|
allow_blank: true,
|
67
70
|
case_sensitive: false
|
71
|
+
validate :signature_type_allowed
|
68
72
|
|
69
73
|
scope :open, lambda {
|
70
|
-
|
71
|
-
|
72
|
-
.where("signature_start_date <= ?", Date.current)
|
73
|
-
.where("signature_end_date >= ?", Date.current)
|
74
|
+
where.not(state: [:discarded, :rejected, :accepted, :created])
|
75
|
+
.currently_signable
|
74
76
|
}
|
75
77
|
scope :closed, lambda {
|
76
|
-
|
77
|
-
.
|
78
|
-
.or(where("signature_start_date > ?", Date.current))
|
79
|
-
.or(where("signature_end_date < ?", Date.current))
|
78
|
+
where(state: [:discarded, :rejected, :accepted])
|
79
|
+
.or(currently_unsignable)
|
80
80
|
}
|
81
81
|
scope :published, -> { where.not(published_at: nil) }
|
82
82
|
scope :with_state, ->(state) { where(state: state) if state.present? }
|
83
83
|
|
84
|
+
scope :currently_signable, lambda {
|
85
|
+
where("signature_start_date <= ?", Date.current)
|
86
|
+
.where("signature_end_date >= ?", Date.current)
|
87
|
+
}
|
88
|
+
scope :currently_unsignable, lambda {
|
89
|
+
where("signature_start_date > ?", Date.current)
|
90
|
+
.or(where("signature_end_date < ?", Date.current))
|
91
|
+
}
|
92
|
+
|
93
|
+
scope :answered, -> { where.not(answered_at: nil) }
|
94
|
+
|
84
95
|
scope :public_spaces, -> { published }
|
85
96
|
scope :signature_type_updatable, -> { created }
|
86
97
|
|
87
98
|
scope :order_by_most_recent, -> { order(created_at: :desc) }
|
88
|
-
scope :order_by_supports, -> { order(Arel.sql("
|
99
|
+
scope :order_by_supports, -> { order(Arel.sql("(coalesce((online_votes->>'total')::int,0) + coalesce((offline_votes->>'total')::int,0)) DESC")) }
|
100
|
+
scope :order_by_most_recently_published, -> { order(published_at: :desc) }
|
89
101
|
scope :order_by_most_commented, lambda {
|
90
102
|
select("decidim_initiatives.*")
|
91
103
|
.left_joins(:comments)
|
92
104
|
.group("decidim_initiatives.id")
|
93
105
|
.order(Arel.sql("count(decidim_comments_comments.id) desc"))
|
94
106
|
}
|
107
|
+
scope :future_spaces, -> { none }
|
108
|
+
scope :past_spaces, -> { closed }
|
95
109
|
|
96
|
-
|
110
|
+
before_update :set_offline_votes_total
|
111
|
+
after_commit :notify_state_change
|
97
112
|
after_create :notify_creation
|
98
113
|
|
99
114
|
searchable_fields({
|
@@ -106,18 +121,20 @@ module Decidim
|
|
106
121
|
# is Resourceable instead of ParticipatorySpaceResourceable so we can't use `visible?`
|
107
122
|
index_on_update: ->(initiative) { initiative.published? })
|
108
123
|
|
109
|
-
def self.future_spaces
|
110
|
-
none
|
111
|
-
end
|
112
|
-
|
113
|
-
def self.past_spaces
|
114
|
-
closed
|
115
|
-
end
|
116
|
-
|
117
124
|
def self.log_presenter_class_for(_log)
|
118
125
|
Decidim::Initiatives::AdminLog::InitiativePresenter
|
119
126
|
end
|
120
127
|
|
128
|
+
# PUBLIC banner image
|
129
|
+
#
|
130
|
+
# Overrides participatory space's banner image with the banner image defined
|
131
|
+
# for the initiative type.
|
132
|
+
#
|
133
|
+
# RETURNS string
|
134
|
+
delegate :banner_image, to: :type
|
135
|
+
delegate :document_number_authorization_handler, :promoting_committee_enabled?, to: :type
|
136
|
+
delegate :type, :scope, :scope_name, to: :scoped_type, allow_nil: true
|
137
|
+
|
121
138
|
# PUBLIC
|
122
139
|
#
|
123
140
|
# Returns true when an initiative has been created by an individual person.
|
@@ -172,17 +189,6 @@ module Decidim
|
|
172
189
|
ActionController::Base.helpers.asset_path("decidim/default-avatar.svg")
|
173
190
|
end
|
174
191
|
|
175
|
-
# PUBLIC banner image
|
176
|
-
#
|
177
|
-
# Overrides participatory space's banner image with the banner image defined
|
178
|
-
# for the initiative type.
|
179
|
-
#
|
180
|
-
# RETURNS string
|
181
|
-
delegate :banner_image, to: :type
|
182
|
-
|
183
|
-
delegate :document_number_authorization_handler, to: :type
|
184
|
-
delegate :supports_required, to: :scoped_type
|
185
|
-
|
186
192
|
def votes_enabled?
|
187
193
|
published? &&
|
188
194
|
signature_start_date <= Date.current &&
|
@@ -227,11 +233,10 @@ module Decidim
|
|
227
233
|
published_at: Time.current,
|
228
234
|
state: "published",
|
229
235
|
signature_start_date: Date.current,
|
230
|
-
signature_end_date: Date.current + Decidim::Initiatives.default_signature_time_period_length
|
236
|
+
signature_end_date: signature_end_date || Date.current + Decidim::Initiatives.default_signature_time_period_length
|
231
237
|
)
|
232
238
|
end
|
233
239
|
|
234
|
-
#
|
235
240
|
# Public: Unpublishes this initiative
|
236
241
|
#
|
237
242
|
# Returns true if the record was properly saved, false otherwise.
|
@@ -251,10 +256,25 @@ module Decidim
|
|
251
256
|
attributes["hashtag"].to_s.delete("#")
|
252
257
|
end
|
253
258
|
|
259
|
+
# Public: Calculates the number of total current supports.
|
260
|
+
#
|
261
|
+
# Returns an Integer.
|
254
262
|
def supports_count
|
255
|
-
|
256
|
-
|
257
|
-
|
263
|
+
online_votes_count + offline_votes_count
|
264
|
+
end
|
265
|
+
|
266
|
+
# Public: Calculates the number of current supports for a scope.
|
267
|
+
#
|
268
|
+
# Returns an Integer.
|
269
|
+
def supports_count_for(scope)
|
270
|
+
online_votes_count_for(scope) + offline_votes_count_for(scope)
|
271
|
+
end
|
272
|
+
|
273
|
+
# Public: Calculates the number of supports required to accept the initiative for a scope.
|
274
|
+
#
|
275
|
+
# Returns an Integer.
|
276
|
+
def supports_required_for(scope)
|
277
|
+
initiative_type_scopes.find_by(decidim_scopes_id: scope&.id).supports_required
|
258
278
|
end
|
259
279
|
|
260
280
|
# Public: Returns the percentage of required supports reached
|
@@ -266,7 +286,75 @@ module Decidim
|
|
266
286
|
|
267
287
|
# Public: Whether the supports required objective has been reached
|
268
288
|
def supports_goal_reached?
|
269
|
-
|
289
|
+
initiative_type_scopes.map(&:scope).all? { |scope| supports_goal_reached_for?(scope) }
|
290
|
+
end
|
291
|
+
|
292
|
+
# Public: Whether the supports required objective has been reached for a scope
|
293
|
+
def supports_goal_reached_for?(scope)
|
294
|
+
supports_count_for(scope) >= supports_required_for(scope)
|
295
|
+
end
|
296
|
+
|
297
|
+
# Public: Calculates all the votes across all the scopes.
|
298
|
+
#
|
299
|
+
# Returns an Integer.
|
300
|
+
def online_votes_count
|
301
|
+
return 0 if offline_signature_type?
|
302
|
+
|
303
|
+
online_votes["total"].to_i
|
304
|
+
end
|
305
|
+
|
306
|
+
def offline_votes_count
|
307
|
+
return 0 if online_signature_type?
|
308
|
+
|
309
|
+
offline_votes["total"].to_i
|
310
|
+
end
|
311
|
+
|
312
|
+
def online_votes_count_for(scope)
|
313
|
+
return 0 if offline_signature_type?
|
314
|
+
|
315
|
+
scope_key = (scope&.id || "global").to_s
|
316
|
+
|
317
|
+
(online_votes || {}).fetch(scope_key, 0).to_i
|
318
|
+
end
|
319
|
+
|
320
|
+
def offline_votes_count_for(scope)
|
321
|
+
return 0 if online_signature_type?
|
322
|
+
|
323
|
+
scope_key = (scope&.id || "global").to_s
|
324
|
+
|
325
|
+
(offline_votes || {}).fetch(scope_key, 0).to_i
|
326
|
+
end
|
327
|
+
|
328
|
+
def update_online_votes_counters
|
329
|
+
online_votes = votes.group(:scope).count.each_with_object({}) do |(scope, count), counters|
|
330
|
+
counters[scope&.id || "global"] = count
|
331
|
+
counters["total"] ||= 0
|
332
|
+
counters["total"] += count
|
333
|
+
end
|
334
|
+
|
335
|
+
# rubocop:disable Rails/SkipsModelValidations
|
336
|
+
update_column("online_votes", online_votes)
|
337
|
+
# rubocop:enable Rails/SkipsModelValidations
|
338
|
+
end
|
339
|
+
|
340
|
+
def set_offline_votes_total
|
341
|
+
return if offline_votes.blank? || scope.nil?
|
342
|
+
|
343
|
+
offline_votes["total"] = offline_votes[scope.id.to_s]
|
344
|
+
end
|
345
|
+
|
346
|
+
# Public: Finds all the InitiativeTypeScopes that are eligible to be voted by a user.
|
347
|
+
# Usually this is only the `scoped_type` but voting on children of the scoped type is
|
348
|
+
# enabled we have to filter all the available scopes in the initiative type to select
|
349
|
+
# the ones that are a descendant of the initiative type.
|
350
|
+
#
|
351
|
+
# Returns an Array of Decidim::InitiativesScopeType.
|
352
|
+
def votable_initiative_type_scopes
|
353
|
+
return Array(scoped_type) unless type.child_scope_threshold_enabled?
|
354
|
+
|
355
|
+
initiative_type_scopes.select do |initiative_type_scope|
|
356
|
+
initiative_type_scope.scope.present? && (scoped_type.global_scope? || scoped_type.scope.ancestor_of?(initiative_type_scope.scope))
|
357
|
+
end.prepend(scoped_type).uniq
|
270
358
|
end
|
271
359
|
|
272
360
|
# Public: Overrides slug attribute from participatory processes.
|
@@ -289,18 +377,20 @@ module Decidim
|
|
289
377
|
true
|
290
378
|
end
|
291
379
|
|
292
|
-
#
|
293
|
-
#
|
294
|
-
# Checks if user is the author or is part of the promotal committee
|
380
|
+
# Public: Checks if user is the author or is part of the promotal committee
|
295
381
|
# of the initiative.
|
296
382
|
#
|
297
|
-
#
|
383
|
+
# Returns a Boolean.
|
298
384
|
def has_authorship?(user)
|
299
385
|
return true if author.id == user.id
|
300
386
|
|
301
387
|
committee_members.approved.where(decidim_users_id: user.id).any?
|
302
388
|
end
|
303
389
|
|
390
|
+
def author_users
|
391
|
+
[author].concat(committee_members.excluding_author.map(&:user))
|
392
|
+
end
|
393
|
+
|
304
394
|
def accepts_offline_votes?
|
305
395
|
published? && (offline_signature_type? || any_signature_type?)
|
306
396
|
end
|
@@ -332,8 +422,27 @@ module Decidim
|
|
332
422
|
organization.available_authorizations.include?("sms") && type.validate_sms_code_on_votes?
|
333
423
|
end
|
334
424
|
|
425
|
+
# Public: Returns an empty object. This method should be implemented by
|
426
|
+
# `ParticipatorySpaceResourceable`, but for some reason this model does not
|
427
|
+
# implement this interface.
|
428
|
+
def user_role_config_for(_user, _role_name)
|
429
|
+
Decidim::ParticipatorySpaceRoleConfig::Base.new(:empty_role_name)
|
430
|
+
end
|
431
|
+
|
335
432
|
private
|
336
433
|
|
434
|
+
# Private: This is just an alias because the naming on InitiativeTypeScope
|
435
|
+
# is very confusing. The `scopes` method doesn't return Decidim::Scope but
|
436
|
+
# Decidim::InitiativeTypeScopes.
|
437
|
+
#
|
438
|
+
# ¯\_(ツ)_/¯
|
439
|
+
#
|
440
|
+
# Returns an Array of Decidim::InitiativesScopeType.
|
441
|
+
def initiative_type_scopes
|
442
|
+
type.scopes
|
443
|
+
end
|
444
|
+
|
445
|
+
# Private: A validator that verifies the signaature type is allowed by the InitiativeType.
|
337
446
|
def signature_type_allowed
|
338
447
|
return if published?
|
339
448
|
|
@@ -351,5 +460,36 @@ module Decidim
|
|
351
460
|
notifier = Decidim::Initiatives::StatusChangeNotifier.new(initiative: self)
|
352
461
|
notifier.notify
|
353
462
|
end
|
463
|
+
|
464
|
+
# Allow ransacker to search for a key in a hstore column (`title`.`en`)
|
465
|
+
[:title, :description].each do |column|
|
466
|
+
ransacker column do |parent|
|
467
|
+
Arel::Nodes::InfixOperation.new("->>", parent.table[column], Arel::Nodes.build_quoted(I18n.locale.to_s))
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
# Allow ransacker to search on an Enum Field
|
472
|
+
ransacker :state, formatter: proc { |int| states[int] }
|
473
|
+
|
474
|
+
ransacker :type_id do
|
475
|
+
Arel.sql("decidim_initiatives_type_scopes.decidim_initiatives_types_id")
|
476
|
+
end
|
477
|
+
|
478
|
+
# method for sort_link by number of supports
|
479
|
+
ransacker :supports_count do
|
480
|
+
Arel.sql("(coalesce((online_votes->>'total')::int,0) + coalesce((offline_votes->>'total')::int,0))")
|
481
|
+
end
|
482
|
+
|
483
|
+
ransacker :id_string do
|
484
|
+
Arel.sql(%{cast("decidim_initiatives"."id" as text)})
|
485
|
+
end
|
486
|
+
|
487
|
+
ransacker :author_name do
|
488
|
+
Arel.sql("decidim_users.name")
|
489
|
+
end
|
490
|
+
|
491
|
+
ransacker :author_nickname do
|
492
|
+
Arel.sql("decidim_users.nickname")
|
493
|
+
end
|
354
494
|
end
|
355
495
|
end
|