decidim-consultations 0.11.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +51 -0
- data/Rakefile +3 -0
- data/app/assets/config/decidim_consultations_manifest.js +5 -0
- data/app/assets/config/decidim_consultations_manifest.scss +3 -0
- data/app/assets/images/decidim/consultations/icon.svg +70 -0
- data/app/assets/images/decidim/consultations/icon2.svg +88 -0
- data/app/assets/javascripts/decidim/consultations/show_more.js.es6 +12 -0
- data/app/assets/javascripts/decidim/consultations/social_share.js +2 -0
- data/app/assets/javascripts/decidim/consultations/utils.js.es6 +19 -0
- data/app/assets/javascripts/decidim/consultations/vote_dialog.js +36 -0
- data/app/assets/stylesheets/decidim/consultations/_question.scss +46 -0
- data/app/assets/stylesheets/decidim/consultations/_stats.scss +22 -0
- data/app/assets/stylesheets/decidim/consultations/_video_wrapper.scss +14 -0
- data/app/assets/stylesheets/decidim/consultations/banners/_block-banner.scss +39 -0
- data/app/assets/stylesheets/decidim/consultations/consultations.scss +6 -0
- data/app/assets/stylesheets/decidim/consultations/consultations/_consultations-banner.scss +13 -0
- data/app/assets/stylesheets/decidim/consultations/consultations/_consultations-card.scss +17 -0
- data/app/assets/stylesheets/decidim/consultations/consultations/_consultations-header.scss +115 -0
- data/app/assets/stylesheets/decidim/consultations/consultations/_consultations-home-banner.scss +15 -0
- data/app/assets/stylesheets/decidim/consultations/consultations/_consultations-home-intro.scss +30 -0
- data/app/assets/stylesheets/decidim/consultations/consultations/_consultations-intro.scss +11 -0
- data/app/assets/stylesheets/decidim/consultations/consultations/_consultations-title.scss +26 -0
- data/app/assets/stylesheets/decidim/consultations/consultations/_consultations_nav.scss +7 -0
- data/app/assets/stylesheets/decidim/consultations/consultations/introductory_image.scss +3 -0
- data/app/assets/stylesheets/decidim/consultations/highlighted-content-banner.css.scss +42 -0
- data/app/assets/stylesheets/decidim/consultations/social_share.css.scss +18 -0
- data/app/commands/decidim/consultations/admin/create_consultation.rb +61 -0
- data/app/commands/decidim/consultations/admin/create_question.rb +68 -0
- data/app/commands/decidim/consultations/admin/create_response.rb +39 -0
- data/app/commands/decidim/consultations/admin/publish_consultation.rb +34 -0
- data/app/commands/decidim/consultations/admin/publish_consultation_results.rb +34 -0
- data/app/commands/decidim/consultations/admin/publish_question.rb +34 -0
- data/app/commands/decidim/consultations/admin/unpublish_consultation.rb +34 -0
- data/app/commands/decidim/consultations/admin/unpublish_consultation_results.rb +34 -0
- data/app/commands/decidim/consultations/admin/unpublish_question.rb +34 -0
- data/app/commands/decidim/consultations/admin/update_consultation.rb +64 -0
- data/app/commands/decidim/consultations/admin/update_question.rb +72 -0
- data/app/commands/decidim/consultations/admin/update_response.rb +46 -0
- data/app/commands/decidim/consultations/unvote_question.rb +37 -0
- data/app/commands/decidim/consultations/vote_question.rb +42 -0
- data/app/constraints/decidim/consultations/current_component.rb +28 -0
- data/app/constraints/decidim/consultations/current_question.rb +36 -0
- data/app/controllers/concerns/decidim/consultations/action_authorization.rb +38 -0
- data/app/controllers/concerns/decidim/consultations/admin/consultation_admin.rb +24 -0
- data/app/controllers/concerns/decidim/consultations/admin/question_admin.rb +28 -0
- data/app/controllers/concerns/decidim/consultations/needs_consultation.rb +54 -0
- data/app/controllers/concerns/decidim/consultations/needs_question.rb +79 -0
- data/app/controllers/concerns/decidim/consultations/orderable.rb +52 -0
- data/app/controllers/decidim/consultations/admin/application_controller.rb +14 -0
- data/app/controllers/decidim/consultations/admin/categories_controller.rb +13 -0
- data/app/controllers/decidim/consultations/admin/component_permissions_controller.rb +13 -0
- data/app/controllers/decidim/consultations/admin/components_controller.rb +13 -0
- data/app/controllers/decidim/consultations/admin/consultation_publications_controller.rb +44 -0
- data/app/controllers/decidim/consultations/admin/consultation_results_publications_controller.rb +44 -0
- data/app/controllers/decidim/consultations/admin/consultations_controller.rb +100 -0
- data/app/controllers/decidim/consultations/admin/question_attachments_controller.rb +25 -0
- data/app/controllers/decidim/consultations/admin/question_publications_controller.rb +44 -0
- data/app/controllers/decidim/consultations/admin/questions_controller.rb +88 -0
- data/app/controllers/decidim/consultations/admin/responses_controller.rb +85 -0
- data/app/controllers/decidim/consultations/consultation_widgets_controller.rb +25 -0
- data/app/controllers/decidim/consultations/consultations_controller.rb +75 -0
- data/app/controllers/decidim/consultations/question_votes_controller.rb +40 -0
- data/app/controllers/decidim/consultations/question_widgets_controller.rb +26 -0
- data/app/controllers/decidim/consultations/questions_controller.rb +23 -0
- data/app/forms/decidim/consultations/admin/consultation_form.rb +56 -0
- data/app/forms/decidim/consultations/admin/question_form.rb +74 -0
- data/app/forms/decidim/consultations/admin/response_form.rb +18 -0
- data/app/forms/decidim/consultations/vote_form.rb +28 -0
- data/app/helpers/decidim/consultations/admin/consultations_helper.rb +14 -0
- data/app/helpers/decidim/consultations/admin/questions_helper.rb +14 -0
- data/app/helpers/decidim/consultations/consultations_helper.rb +17 -0
- data/app/models/concerns/decidim/consultations/override_categorization.rb +21 -0
- data/app/models/concerns/decidim/consultations/publicable_results.rb +51 -0
- data/app/models/decidim/consultation.rb +79 -0
- data/app/models/decidim/consultations/abilities/admin/consultation_admin_ability.rb +34 -0
- data/app/models/decidim/consultations/abilities/admin/question_admin_ability.rb +30 -0
- data/app/models/decidim/consultations/abilities/admin/response_admin_ability.rb +26 -0
- data/app/models/decidim/consultations/abilities/current_user_ability.rb +45 -0
- data/app/models/decidim/consultations/abilities/everyone_ability.rb +23 -0
- data/app/models/decidim/consultations/application_record.rb +9 -0
- data/app/models/decidim/consultations/question.rb +127 -0
- data/app/models/decidim/consultations/response.rb +19 -0
- data/app/models/decidim/consultations/vote.rb +26 -0
- data/app/presenters/decidim/consultations/question_stats_presenter.rb +52 -0
- data/app/queries/decidim/consultations/admin/admin_users.rb +40 -0
- data/app/queries/decidim/consultations/organization_active_consultations.rb +20 -0
- data/app/queries/decidim/consultations/organization_consultations.rb +20 -0
- data/app/queries/decidim/consultations/organization_questions.rb +20 -0
- data/app/services/decidim/consultations/consultation_search.rb +51 -0
- data/app/views/decidim/consultations/_consultation.html.erb +32 -0
- data/app/views/decidim/consultations/admin/consultations/_form.html.erb +58 -0
- data/app/views/decidim/consultations/admin/consultations/edit.html.erb +42 -0
- data/app/views/decidim/consultations/admin/consultations/index.html.erb +74 -0
- data/app/views/decidim/consultations/admin/consultations/new.html.erb +11 -0
- data/app/views/decidim/consultations/admin/questions/_form.html.erb +84 -0
- data/app/views/decidim/consultations/admin/questions/edit.html.erb +32 -0
- data/app/views/decidim/consultations/admin/questions/index.html.erb +74 -0
- data/app/views/decidim/consultations/admin/questions/new.html.erb +13 -0
- data/app/views/decidim/consultations/admin/responses/_form.html.erb +11 -0
- data/app/views/decidim/consultations/admin/responses/edit.html.erb +18 -0
- data/app/views/decidim/consultations/admin/responses/index.html.erb +48 -0
- data/app/views/decidim/consultations/admin/responses/new.html.erb +13 -0
- data/app/views/decidim/consultations/consultation_widgets/show.html.erb +5 -0
- data/app/views/decidim/consultations/consultations/_consultation_card.html.erb +24 -0
- data/app/views/decidim/consultations/consultations/_consultation_details.html.erb +17 -0
- data/app/views/decidim/consultations/consultations/_consultations.html.erb +16 -0
- data/app/views/decidim/consultations/consultations/_count.html.erb +1 -0
- data/app/views/decidim/consultations/consultations/_filters.html.erb +25 -0
- data/app/views/decidim/consultations/consultations/_filters_small_view.html.erb +23 -0
- data/app/views/decidim/consultations/consultations/_highlighted_questions.html.erb +13 -0
- data/app/views/decidim/consultations/consultations/_question.html.erb +40 -0
- data/app/views/decidim/consultations/consultations/_regular_questions.html.erb +14 -0
- data/app/views/decidim/consultations/consultations/finished.html.erb +15 -0
- data/app/views/decidim/consultations/consultations/index.html.erb +27 -0
- data/app/views/decidim/consultations/consultations/index.js.erb +10 -0
- data/app/views/decidim/consultations/consultations/show.html.erb +11 -0
- data/app/views/decidim/consultations/question_votes/update_vote_button.js.erb +9 -0
- data/app/views/decidim/consultations/question_widgets/show.html.erb +2 -0
- data/app/views/decidim/consultations/questions/_results.html.erb +15 -0
- data/app/views/decidim/consultations/questions/_right_column.html.erb +20 -0
- data/app/views/decidim/consultations/questions/_statistics.html.erb +31 -0
- data/app/views/decidim/consultations/questions/_technical_data.html.erb +38 -0
- data/app/views/decidim/consultations/questions/_vote_button.html.erb +76 -0
- data/app/views/decidim/consultations/questions/_vote_modal.html.erb +27 -0
- data/app/views/decidim/consultations/questions/_vote_modal_confirm.html.erb +33 -0
- data/app/views/decidim/consultations/questions/show.html.erb +58 -0
- data/app/views/layouts/decidim/_consultation_header.html.erb +16 -0
- data/app/views/layouts/decidim/_consultation_voting_data.html.erb +10 -0
- data/app/views/layouts/decidim/_question_components.html.erb +38 -0
- data/app/views/layouts/decidim/_question_header.html.erb +46 -0
- data/app/views/layouts/decidim/admin/consultation.html.erb +28 -0
- data/app/views/layouts/decidim/admin/consultations.html.erb +16 -0
- data/app/views/layouts/decidim/admin/question.html.erb +72 -0
- data/app/views/layouts/decidim/consultation.html.erb +17 -0
- data/app/views/layouts/decidim/consultation_choose.html.erb +7 -0
- data/app/views/layouts/decidim/question.html.erb +19 -0
- data/config/locales/ca.yml +248 -0
- data/config/locales/en.yml +249 -0
- data/config/locales/es.yml +248 -0
- data/config/locales/eu.yml +248 -0
- data/config/locales/fi.yml +248 -0
- data/config/locales/fr.yml +248 -0
- data/config/locales/gl.yml +248 -0
- data/config/locales/it.yml +248 -0
- data/config/locales/nl.yml +248 -0
- data/config/locales/pl.yml +258 -0
- data/config/locales/pt-BR.yml +248 -0
- data/config/locales/pt.yml +248 -0
- data/config/locales/ru.yml +6 -0
- data/config/locales/sv.yml +248 -0
- data/config/locales/uk.yml +6 -0
- data/db/migrate/20180109092205_create_decidim_consultations.rb +37 -0
- data/db/migrate/20180112053247_create_decidim_consultations_questions.rb +35 -0
- data/db/migrate/20180115132000_add_end_voting_date_to_decidim_consultations.rb +18 -0
- data/db/migrate/20180115170933_add_slug_to_decidim_consultations_questions.rb +32 -0
- data/db/migrate/20180119084217_create_decidim_consultations_votes.rb +17 -0
- data/db/migrate/20180119084331_add_votes_count_to_decidim_consultations_question.rb +7 -0
- data/db/migrate/20180122113155_add_origin_scope_to_decidim_consultations_questions.rb +8 -0
- data/db/migrate/20180122113400_add_origin_title_to_decidim_consultations_questions.rb +8 -0
- data/db/migrate/20180122113447_add_origin_string_to_decidim_consultations_questions.rb +7 -0
- data/db/migrate/20180126142459_add_enable_highlighted_banner_to_decidim_consultations.rb +7 -0
- data/db/migrate/20180129063438_add_i_frame_url_to_decidim_consultations_questions.rb +8 -0
- data/db/migrate/20180129063700_create_decidim_consultations_responses.rb +14 -0
- data/db/migrate/20180129122226_rename_decidim_consultations_vote_to_decidim_consultations_endorsement.rb +7 -0
- data/db/migrate/20180129122504_rename_decidim_consultations_questions_votes_count_to_endorsements_count.rb +7 -0
- data/db/migrate/20180130060754_add_responses_count_to_decidim_consultations_questions.rb +22 -0
- data/db/migrate/20180130110449_rename_vote_related_attributes.rb +9 -0
- data/db/migrate/20180130142018_add_decidim_user_group_id_to_decidim_consultations_endorsements.rb +7 -0
- data/db/migrate/20180130142411_rename_vote_indexes_to_endorsement_indexes.rb +36 -0
- data/db/migrate/20180131083844_add_response_to_decidim_consultations_endorsements.rb +10 -0
- data/db/migrate/20180201135823_rename_endorsement_to_vote.rb +23 -0
- data/db/migrate/20180202050920_add_hero_image_to_decidim_consultations_question.rb +8 -0
- data/db/migrate/20180202085309_add_results_published_at_to_decidim_consultations.rb +7 -0
- data/db/migrate/20180202133655_add_votes_count_to_decidim_consultations_response.rb +7 -0
- data/db/migrate/20180212100503_remove_enable_highlighted_banner_flag.rb +7 -0
- data/db/migrate/20180219092120_add_order_to_decidim_consultations_questions.rb +7 -0
- data/db/migrate/20180320100658_add_introductory_image_to_decidim_consultations.rb +7 -0
- data/db/seeds/Exampledocument.pdf +0 -0
- data/db/seeds/city.jpeg +0 -0
- data/db/seeds/city2.jpeg +0 -0
- data/db/seeds/homepage_image.jpg +0 -0
- data/lib/decidim/consultations.rb +18 -0
- data/lib/decidim/consultations/admin.rb +10 -0
- data/lib/decidim/consultations/admin_engine.rb +72 -0
- data/lib/decidim/consultations/engine.rb +83 -0
- data/lib/decidim/consultations/participatory_space.rb +171 -0
- data/lib/decidim/consultations/test/factories.rb +104 -0
- data/lib/decidim/consultations/version.rb +9 -0
- metadata +288 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Consultations
|
5
|
+
class QuestionVotesController < Decidim::ApplicationController
|
6
|
+
include NeedsQuestion
|
7
|
+
include Decidim::FormFactory
|
8
|
+
|
9
|
+
before_action :authenticate_user!
|
10
|
+
|
11
|
+
def create
|
12
|
+
authorize! :vote, current_question
|
13
|
+
|
14
|
+
vote_form = form(VoteForm).from_params(params, current_question: current_question)
|
15
|
+
VoteQuestion.call(vote_form) do
|
16
|
+
on(:ok) do
|
17
|
+
current_question.reload
|
18
|
+
render :update_vote_button
|
19
|
+
end
|
20
|
+
|
21
|
+
on(:invalid) do
|
22
|
+
render json: {
|
23
|
+
error: I18n.t("question_votes.create.error", scope: "decidim.consultations")
|
24
|
+
}, status: 422
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def destroy
|
30
|
+
authorize! :unvote, current_question
|
31
|
+
UnvoteQuestion.call(current_question, current_user) do
|
32
|
+
on(:ok) do
|
33
|
+
current_question.reload
|
34
|
+
render :update_vote_button
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Consultations
|
5
|
+
# This controller provides a widget that allows embedding the question
|
6
|
+
class QuestionWidgetsController < Decidim::WidgetsController
|
7
|
+
include NeedsQuestion
|
8
|
+
|
9
|
+
helper Decidim::SanitizeHelper
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def model
|
14
|
+
@model ||= current_question
|
15
|
+
end
|
16
|
+
|
17
|
+
def current_participatory_space
|
18
|
+
model
|
19
|
+
end
|
20
|
+
|
21
|
+
def iframe_url
|
22
|
+
@iframe_url ||= question_question_widget_url(model)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Consultations
|
5
|
+
# A controller that holds the logic to show questions in a
|
6
|
+
# public layout.
|
7
|
+
class QuestionsController < Decidim::ApplicationController
|
8
|
+
layout "layouts/decidim/question"
|
9
|
+
|
10
|
+
include NeedsQuestion
|
11
|
+
|
12
|
+
helper Decidim::SanitizeHelper
|
13
|
+
helper Decidim::IconHelper
|
14
|
+
helper Decidim::Comments::CommentsHelper
|
15
|
+
helper Decidim::AttachmentsHelper
|
16
|
+
helper Decidim::ResourceReferenceHelper
|
17
|
+
|
18
|
+
def show
|
19
|
+
authorize! :read, current_question
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Consultations
|
5
|
+
module Admin
|
6
|
+
# A form object used to create consultations from the admin dashboard.
|
7
|
+
class ConsultationForm < Form
|
8
|
+
include TranslatableAttributes
|
9
|
+
|
10
|
+
mimic :consultation
|
11
|
+
|
12
|
+
translatable_attribute :title, String
|
13
|
+
translatable_attribute :subtitle, String
|
14
|
+
translatable_attribute :description, String
|
15
|
+
attribute :slug, String
|
16
|
+
attribute :banner_image
|
17
|
+
attribute :remove_banner_image
|
18
|
+
attribute :introductory_video_url, String
|
19
|
+
attribute :introductory_image, String
|
20
|
+
attribute :decidim_highlighted_scope_id, Integer
|
21
|
+
attribute :start_voting_date, Date
|
22
|
+
attribute :end_voting_date, Date
|
23
|
+
|
24
|
+
validates :slug, presence: true, format: { with: Decidim::Consultation.slug_format }
|
25
|
+
validates :title, :subtitle, :description, translatable_presence: true
|
26
|
+
validates :decidim_highlighted_scope_id, presence: true
|
27
|
+
validates :start_voting_date, presence: true, date: { before_or_equal_to: :end_voting_date }
|
28
|
+
validates :end_voting_date, presence: true, date: { after_or_equal_to: :start_voting_date }
|
29
|
+
validate :slug_uniqueness
|
30
|
+
|
31
|
+
validates :banner_image,
|
32
|
+
file_size: { less_than_or_equal_to: ->(_record) { Decidim.maximum_attachment_size } },
|
33
|
+
file_content_type: { allow: ["image/jpeg", "image/png"] }
|
34
|
+
validates :introductory_image,
|
35
|
+
file_size: { less_than_or_equal_to: ->(_record) { Decidim.maximum_attachment_size } },
|
36
|
+
file_content_type: { allow: ["image/jpeg", "image/png"] }
|
37
|
+
|
38
|
+
def highlighted_scope
|
39
|
+
@highlighted_scope ||= current_organization.scopes.find_by(id: decidim_highlighted_scope_id)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def slug_uniqueness
|
45
|
+
return unless OrganizationConsultations
|
46
|
+
.new(current_organization)
|
47
|
+
.query
|
48
|
+
.where(slug: slug)
|
49
|
+
.where.not(id: context[:consultation_id]).any?
|
50
|
+
|
51
|
+
errors.add(:slug, :taken)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Consultations
|
5
|
+
module Admin
|
6
|
+
# A form object used to create questions for a consultation from the admin dashboard.
|
7
|
+
class QuestionForm < Form
|
8
|
+
include TranslatableAttributes
|
9
|
+
|
10
|
+
mimic :question
|
11
|
+
|
12
|
+
translatable_attribute :title, String
|
13
|
+
translatable_attribute :promoter_group, String
|
14
|
+
translatable_attribute :participatory_scope, String
|
15
|
+
translatable_attribute :question_context, String
|
16
|
+
translatable_attribute :subtitle, String
|
17
|
+
translatable_attribute :what_is_decided, String
|
18
|
+
translatable_attribute :origin_scope, String
|
19
|
+
translatable_attribute :origin_title, String
|
20
|
+
attribute :origin_url, String
|
21
|
+
attribute :slug, String
|
22
|
+
attribute :remove_hero_image
|
23
|
+
attribute :hero_image
|
24
|
+
attribute :banner_image
|
25
|
+
attribute :remove_banner_image
|
26
|
+
attribute :hashtag, String
|
27
|
+
attribute :decidim_scope_id, Integer
|
28
|
+
attribute :external_voting, Boolean, default: false
|
29
|
+
attribute :i_frame_url, String
|
30
|
+
attribute :order, Integer
|
31
|
+
|
32
|
+
validates :slug, presence: true, format: { with: Decidim::Consultations::Question.slug_format }
|
33
|
+
validates :title, :promoter_group, :participatory_scope, :subtitle, :what_is_decided, translatable_presence: true
|
34
|
+
validates :decidim_scope_id, presence: true
|
35
|
+
validates :hero_image,
|
36
|
+
file_size: { less_than_or_equal_to: ->(_record) { Decidim.maximum_attachment_size } },
|
37
|
+
file_content_type: { allow: ["image/jpeg", "image/png"] }
|
38
|
+
validates :banner_image,
|
39
|
+
file_size: { less_than_or_equal_to: ->(_record) { Decidim.maximum_attachment_size } },
|
40
|
+
file_content_type: { allow: ["image/jpeg", "image/png"] }
|
41
|
+
validate :slug_uniqueness
|
42
|
+
validates :origin_scope, :origin_title, translatable_presence: true, if: :has_origin_data?
|
43
|
+
validates :i_frame_url, presence: true, if: :external_voting
|
44
|
+
validates :order, numericality: { only_integer: true, allow_nil: true, allow_blank: true }
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def slug_uniqueness
|
49
|
+
return unless OrganizationQuestions
|
50
|
+
.new(current_organization)
|
51
|
+
.query
|
52
|
+
.where(slug: slug)
|
53
|
+
.where.not(id: context[:question_id]).any?
|
54
|
+
|
55
|
+
errors.add(:slug, :taken)
|
56
|
+
end
|
57
|
+
|
58
|
+
def has_origin_data?
|
59
|
+
has_value?(origin_title) || has_value?(origin_scope) || origin_url.present?
|
60
|
+
end
|
61
|
+
|
62
|
+
def has_value?(translatable_attribute)
|
63
|
+
return false if translatable_attribute.nil?
|
64
|
+
|
65
|
+
Decidim.available_locales.each do |locale|
|
66
|
+
return true if translatable_attribute.with_indifferent_access[locale].present?
|
67
|
+
end
|
68
|
+
|
69
|
+
false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Consultations
|
5
|
+
module Admin
|
6
|
+
# A form object used to create responses for a question from the admin dashboard.
|
7
|
+
class ResponseForm < Form
|
8
|
+
include TranslatableAttributes
|
9
|
+
|
10
|
+
mimic :response
|
11
|
+
|
12
|
+
translatable_attribute :title, String
|
13
|
+
|
14
|
+
validates :title, translatable_presence: true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Consultations
|
5
|
+
class VoteForm < Form
|
6
|
+
mimic :vote
|
7
|
+
|
8
|
+
attribute :decidim_consultations_response_id, Integer
|
9
|
+
|
10
|
+
validates :decidim_consultations_response_id, presence: true
|
11
|
+
validate :response_exists
|
12
|
+
|
13
|
+
def response
|
14
|
+
@response ||= Response.find_by(id: decidim_consultations_response_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def response_exists
|
20
|
+
return unless response.nil?
|
21
|
+
errors.add(
|
22
|
+
:decidim_consultations_response_id,
|
23
|
+
I18n.t("decidim_consultations_response_id.not_found", scope: "activemodel.errors.vote")
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Consultations
|
5
|
+
module Admin
|
6
|
+
# Helper for consultation controller
|
7
|
+
module ConsultationsHelper
|
8
|
+
def consultation_example_slug
|
9
|
+
"consultation-#{Time.now.utc.year}-#{Time.now.utc.month}-1"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Consultations
|
5
|
+
module Admin
|
6
|
+
# Helper for questions controller
|
7
|
+
module QuestionsHelper
|
8
|
+
def question_example_slug
|
9
|
+
"question-#{Time.now.utc.year}-#{Time.now.utc.month}-1"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Consultations
|
5
|
+
module ConsultationsHelper
|
6
|
+
# Returns options for state filter selector.
|
7
|
+
def options_for_state_filter
|
8
|
+
[
|
9
|
+
["all", t("consultations.filters.all", scope: "decidim")],
|
10
|
+
["active", t("consultations.filters.active", scope: "decidim")],
|
11
|
+
["upcoming", t("consultations.filters.upcoming", scope: "decidim")],
|
12
|
+
["finished", t("consultations.filters.finished", scope: "decidim")]
|
13
|
+
]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
module Decidim
|
6
|
+
module Consultations
|
7
|
+
module OverrideCategorization
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
# This relationship exists only by compatibility reasons.
|
12
|
+
# Consultations are not intended to have categories.
|
13
|
+
has_many :categories,
|
14
|
+
foreign_key: "decidim_participatory_space_id",
|
15
|
+
foreign_type: "decidim_participatory_space_type",
|
16
|
+
dependent: :destroy,
|
17
|
+
as: :participatory_space
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
module Decidim
|
6
|
+
module Consultations
|
7
|
+
# This concern contains the logic related to results publication and promotion.
|
8
|
+
module PublicableResults
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
# Public: Scope to return only records with its results published.
|
13
|
+
#
|
14
|
+
# Returns an ActiveRecord::Relation.
|
15
|
+
def results_published
|
16
|
+
where.not(results_published_at: nil)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Public: Scope to return only records with its results unpublished.
|
20
|
+
#
|
21
|
+
# Returns an ActiveRecord::Relation.
|
22
|
+
def results_unpublished
|
23
|
+
where(results_published_at: nil)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Public: Checks whether the record has its results published or not.
|
28
|
+
#
|
29
|
+
# Returns true if published, false otherwise.
|
30
|
+
def results_published?
|
31
|
+
results_published_at.present?
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Public: Publishes the results of the given component
|
36
|
+
#
|
37
|
+
# Returns true if the record was properly saved, false otherwise.
|
38
|
+
def publish_results!
|
39
|
+
update!(results_published_at: Time.current)
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Public: Unpublishes the results
|
44
|
+
#
|
45
|
+
# Returns true if the record was properly saved, false otherwise.
|
46
|
+
def unpublish_results!
|
47
|
+
update!(results_published_at: nil)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
# The data store for a Consultation in the Decidim::Consultations component.
|
5
|
+
class Consultation < ApplicationRecord
|
6
|
+
include Decidim::Participable
|
7
|
+
include Decidim::Publicable
|
8
|
+
include Decidim::Consultations::PublicableResults
|
9
|
+
|
10
|
+
belongs_to :organization,
|
11
|
+
foreign_key: "decidim_organization_id",
|
12
|
+
class_name: "Decidim::Organization"
|
13
|
+
|
14
|
+
belongs_to :highlighted_scope,
|
15
|
+
foreign_key: "decidim_highlighted_scope_id",
|
16
|
+
class_name: "Decidim::Scope"
|
17
|
+
|
18
|
+
has_many :questions,
|
19
|
+
foreign_key: "decidim_consultation_id",
|
20
|
+
class_name: "Decidim::Consultations::Question",
|
21
|
+
inverse_of: :consultation,
|
22
|
+
dependent: :destroy
|
23
|
+
|
24
|
+
validates :slug, uniqueness: { scope: :organization }
|
25
|
+
validates :slug, presence: true, format: { with: Decidim::Consultation.slug_format }
|
26
|
+
|
27
|
+
mount_uploader :banner_image, Decidim::BannerImageUploader
|
28
|
+
mount_uploader :introductory_image, Decidim::BannerImageUploader
|
29
|
+
|
30
|
+
scope :upcoming, -> { published.where("start_voting_date > ?", Time.now.utc) }
|
31
|
+
scope :active, lambda {
|
32
|
+
published
|
33
|
+
.where("start_voting_date <= ?", Time.now.utc)
|
34
|
+
.where("end_voting_date >= ?", Time.now.utc)
|
35
|
+
}
|
36
|
+
scope :finished, -> { published.where("end_voting_date < ?", Time.now.utc) }
|
37
|
+
scope :order_by_most_recent, -> { order(created_at: :desc) }
|
38
|
+
|
39
|
+
def to_param
|
40
|
+
slug
|
41
|
+
end
|
42
|
+
|
43
|
+
def upcoming?
|
44
|
+
start_voting_date > Time.now.utc
|
45
|
+
end
|
46
|
+
|
47
|
+
def active?
|
48
|
+
start_voting_date <= Time.now.utc && end_voting_date >= Time.now.utc
|
49
|
+
end
|
50
|
+
|
51
|
+
def finished?
|
52
|
+
end_voting_date < Time.now.utc
|
53
|
+
end
|
54
|
+
|
55
|
+
def highlighted_questions
|
56
|
+
questions.published.where(decidim_scope_id: decidim_highlighted_scope_id)
|
57
|
+
end
|
58
|
+
|
59
|
+
def regular_questions
|
60
|
+
questions.published.where.not(decidim_scope_id: decidim_highlighted_scope_id).group_by(&:scope)
|
61
|
+
end
|
62
|
+
|
63
|
+
# This method exists with the only purpose of getting rid of whats seems to be an issue in
|
64
|
+
# the new scope picker: This engine is a bit special: consultations and questions are a kind of
|
65
|
+
# nested participatory spaces. When a new question is created the consultation is the participatory space.
|
66
|
+
# Since seems that the scope picker is asking to the current participatory space for its scope
|
67
|
+
# this method is necessary to exist an return nil in order to be able to browse the scope hierarchy
|
68
|
+
def scope
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.order_randomly(seed)
|
73
|
+
transaction do
|
74
|
+
connection.execute("SELECT setseed(#{connection.quote(seed)})")
|
75
|
+
select('"decidim_consultations".*, RANDOM()').order("RANDOM()").load
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|