decidim-challenges 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE-AGPLv3.txt +661 -0
- data/README.md +49 -0
- data/Rakefile +9 -0
- data/app/cells/decidim/challenges/challenge_cell.rb +21 -0
- data/app/cells/decidim/challenges/challenge_g/show.erb +47 -0
- data/app/cells/decidim/challenges/challenge_g_cell.rb +69 -0
- data/app/cells/decidim/problems/problem_cell.rb +21 -0
- data/app/cells/decidim/problems/problem_g/show.erb +35 -0
- data/app/cells/decidim/problems/problem_g_cell.rb +61 -0
- data/app/cells/decidim/solutions/solution_cell.rb +21 -0
- data/app/cells/decidim/solutions/solution_g/show.erb +30 -0
- data/app/cells/decidim/solutions/solution_g_cell.rb +84 -0
- data/app/commands/decidim/challenges/admin/create_challenge.rb +67 -0
- data/app/commands/decidim/challenges/admin/destroy_challenge.rb +49 -0
- data/app/commands/decidim/challenges/admin/export_challenge_surveys.rb +45 -0
- data/app/commands/decidim/challenges/admin/publish_challenge.rb +40 -0
- data/app/commands/decidim/challenges/admin/unpublish_challenge.rb +40 -0
- data/app/commands/decidim/challenges/admin/update_challenge.rb +72 -0
- data/app/commands/decidim/challenges/admin/update_surveys.rb +43 -0
- data/app/commands/decidim/challenges/survey_challenge.rb +67 -0
- data/app/commands/decidim/command_utils.rb +20 -0
- data/app/commands/decidim/problems/admin/create_problem.rb +66 -0
- data/app/commands/decidim/problems/admin/destroy_problem.rb +49 -0
- data/app/commands/decidim/problems/admin/publish_problem.rb +40 -0
- data/app/commands/decidim/problems/admin/unpublish_problem.rb +40 -0
- data/app/commands/decidim/problems/admin/update_problem.rb +69 -0
- data/app/commands/decidim/solutions/admin/create_solution.rb +65 -0
- data/app/commands/decidim/solutions/admin/destroy_solution.rb +43 -0
- data/app/commands/decidim/solutions/admin/publish_solution.rb +40 -0
- data/app/commands/decidim/solutions/admin/unpublish_solution.rb +40 -0
- data/app/commands/decidim/solutions/admin/update_solution.rb +67 -0
- data/app/commands/decidim/solutions/create_solution.rb +67 -0
- data/app/controllers/concerns/decidim/challenges/admin/filterable.rb +27 -0
- data/app/controllers/concerns/decidim/challenges/orderable_challenges.rb +37 -0
- data/app/controllers/concerns/decidim/problems/admin/filterable.rb +27 -0
- data/app/controllers/concerns/decidim/problems/orderable_problems.rb +37 -0
- data/app/controllers/concerns/decidim/solutions/admin/filterable.rb +27 -0
- data/app/controllers/concerns/decidim/solutions/orderable_solutions.rb +37 -0
- data/app/controllers/concerns/decidim/with_default_filters.rb +23 -0
- data/app/controllers/concerns/decidim/with_sdgs.rb +19 -0
- data/app/controllers/decidim/challenges/admin/application_controller.rb +15 -0
- data/app/controllers/decidim/challenges/admin/challenge_publications_controller.rb +53 -0
- data/app/controllers/decidim/challenges/admin/challenges_controller.rb +108 -0
- data/app/controllers/decidim/challenges/admin/survey_form_controller.rb +43 -0
- data/app/controllers/decidim/challenges/admin/surveys_controller.rb +104 -0
- data/app/controllers/decidim/challenges/application_controller.rb +13 -0
- data/app/controllers/decidim/challenges/challenges_controller.rb +70 -0
- data/app/controllers/decidim/challenges/surveys_controller.rb +61 -0
- data/app/controllers/decidim/problems/admin/application_controller.rb +15 -0
- data/app/controllers/decidim/problems/admin/problem_publications_controller.rb +53 -0
- data/app/controllers/decidim/problems/admin/problems_controller.rb +102 -0
- data/app/controllers/decidim/problems/application_controller.rb +13 -0
- data/app/controllers/decidim/problems/problems_controller.rb +62 -0
- data/app/controllers/decidim/sdgs/admin/application_controller.rb +15 -0
- data/app/controllers/decidim/sdgs/admin/sdgs_controller.rb +18 -0
- data/app/controllers/decidim/sdgs/application_controller.rb +13 -0
- data/app/controllers/decidim/sdgs/sdgs_controller.rb +24 -0
- data/app/controllers/decidim/solutions/admin/application_controller.rb +15 -0
- data/app/controllers/decidim/solutions/admin/solution_publications_controller.rb +53 -0
- data/app/controllers/decidim/solutions/admin/solutions_controller.rb +106 -0
- data/app/controllers/decidim/solutions/application_controller.rb +13 -0
- data/app/controllers/decidim/solutions/solutions_controller.rb +115 -0
- data/app/forms/decidim/challenges/admin/challenge_surveys_form.rb +35 -0
- data/app/forms/decidim/challenges/admin/challenges_form.rb +78 -0
- data/app/forms/decidim/problems/admin/problems_form.rb +90 -0
- data/app/forms/decidim/solutions/admin/solutions_form.rb +71 -0
- data/app/forms/decidim/solutions/solutions_form.rb +50 -0
- data/app/helpers/decidim/challenges/application_helper.rb +25 -0
- data/app/helpers/decidim/challenges/challenge_cells_helper.rb +57 -0
- data/app/helpers/decidim/challenges/challenges_helper.rb +39 -0
- data/app/helpers/decidim/problems/application_helper.rb +10 -0
- data/app/helpers/decidim/problems/problem_cells_helper.rb +23 -0
- data/app/helpers/decidim/problems/problems_helper.rb +24 -0
- data/app/helpers/decidim/sdgs/sdgs_helper.rb +28 -0
- data/app/helpers/decidim/show_filters_helper.rb +13 -0
- data/app/helpers/decidim/solutions/application_helper.rb +27 -0
- data/app/helpers/decidim/solutions/solution_cells_helper.rb +56 -0
- data/app/helpers/decidim/solutions/solutions_helper.rb +21 -0
- data/app/models/decidim/application_record.rb +8 -0
- data/app/models/decidim/challenges/challenge.rb +82 -0
- data/app/models/decidim/challenges/survey.rb +19 -0
- data/app/models/decidim/problems/problem.rb +118 -0
- data/app/models/decidim/sdgs/sdg.rb +47 -0
- data/app/models/decidim/solutions/application_record.rb +10 -0
- data/app/models/decidim/solutions/solution.rb +69 -0
- data/app/packs/entrypoints/decidim_challenges.js +4 -0
- data/app/packs/entrypoints/decidim_challenges.scss +1 -0
- data/app/packs/entrypoints/decidim_problems.js +1 -0
- data/app/packs/entrypoints/decidim_problems.scss +1 -0
- data/app/packs/entrypoints/decidim_sdgs.js +6 -0
- data/app/packs/entrypoints/decidim_sdgs.scss +3 -0
- data/app/packs/entrypoints/decidim_shared.js +1 -0
- data/app/packs/entrypoints/decidim_shared.scss +1 -0
- data/app/packs/entrypoints/decidim_solutions.js +4 -0
- data/app/packs/entrypoints/decidim_solutions.scss +1 -0
- data/app/packs/fonts/Oswald-Medium.ttf +0 -0
- data/app/packs/images/decidim/challenges/decidim_challenges_icon.svg +1 -0
- data/app/packs/images/decidim/sdgs/ods-01.svg +11 -0
- data/app/packs/images/decidim/sdgs/ods-02.svg +11 -0
- data/app/packs/images/decidim/sdgs/ods-03.svg +11 -0
- data/app/packs/images/decidim/sdgs/ods-04.svg +12 -0
- data/app/packs/images/decidim/sdgs/ods-05.svg +12 -0
- data/app/packs/images/decidim/sdgs/ods-06.svg +20 -0
- data/app/packs/images/decidim/sdgs/ods-07.svg +18 -0
- data/app/packs/images/decidim/sdgs/ods-08.svg +13 -0
- data/app/packs/images/decidim/sdgs/ods-09.svg +25 -0
- data/app/packs/images/decidim/sdgs/ods-10.svg +13 -0
- data/app/packs/images/decidim/sdgs/ods-11.svg +41 -0
- data/app/packs/images/decidim/sdgs/ods-12.svg +11 -0
- data/app/packs/images/decidim/sdgs/ods-13.svg +57 -0
- data/app/packs/images/decidim/sdgs/ods-14.svg +14 -0
- data/app/packs/images/decidim/sdgs/ods-15.svg +11 -0
- data/app/packs/images/decidim/sdgs/ods-16.svg +14 -0
- data/app/packs/images/decidim/sdgs/ods-17.svg +39 -0
- data/app/packs/images/decidim/sdgs/sdg-wheel.png +0 -0
- data/app/packs/images/decidim/sdgs/un_emblem_square.png +0 -0
- data/app/packs/src/decidim/challenges/add_challenge.js +3 -0
- data/app/packs/src/decidim/challenges/admin/challenges_form.js +3 -0
- data/app/packs/src/decidim/sdgs/filter.js +75 -0
- data/app/packs/stylesheets/decidim/challenges/challenges.scss +3 -0
- data/app/packs/stylesheets/decidim/problems/problems.scss +3 -0
- data/app/packs/stylesheets/decidim/sdgs/ods.scss +185 -0
- data/app/packs/stylesheets/decidim/sdgs/sdgs_filter/button.scss +27 -0
- data/app/packs/stylesheets/decidim/sdgs/sdgs_filter/modal.scss +60 -0
- data/app/packs/stylesheets/decidim/shared/_cards.scss +52 -0
- data/app/packs/stylesheets/decidim/shared/base.scss +9 -0
- data/app/packs/stylesheets/decidim/solutions/solutions.scss +3 -0
- data/app/permissions/decidim/challenges/admin/permissions.rb +88 -0
- data/app/permissions/decidim/challenges/permissions.rb +27 -0
- data/app/permissions/decidim/problems/admin/permissions.rb +52 -0
- data/app/permissions/decidim/problems/permissions.rb +16 -0
- data/app/permissions/decidim/solutions/admin/permissions.rb +58 -0
- data/app/permissions/decidim/solutions/permissions.rb +17 -0
- data/app/presenters/decidim/challenges/challenge_presenter.rb +134 -0
- data/app/presenters/decidim/problems/problem_presenter.rb +108 -0
- data/app/presenters/decidim/solutions/solution_presenter.rb +198 -0
- data/app/serializers/decidim/challenges/data_serializer.rb +46 -0
- data/app/serializers/decidim/challenges/survey_serializer.rb +37 -0
- data/app/types/decidim/challenges/challenge_type.rb +28 -0
- data/app/types/decidim/challenges/challenges_type.rb +32 -0
- data/app/types/decidim/problems/problem_type.rb +29 -0
- data/app/types/decidim/problems/problems_type.rb +32 -0
- data/app/types/decidim/solutions/solution_type.rb +25 -0
- data/app/types/decidim/solutions/solutions_type.rb +32 -0
- data/app/views/decidim/challenges/admin/challenges/_form.html.erb +78 -0
- data/app/views/decidim/challenges/admin/challenges/edit.html.erb +24 -0
- data/app/views/decidim/challenges/admin/challenges/index.html.erb +88 -0
- data/app/views/decidim/challenges/admin/challenges/new.html.erb +18 -0
- data/app/views/decidim/challenges/admin/surveys/_form.html.erb +9 -0
- data/app/views/decidim/challenges/admin/surveys/edit.html.erb +39 -0
- data/app/views/decidim/challenges/admin/surveys/index.html.erb +49 -0
- data/app/views/decidim/challenges/admin/surveys/show.html.erb +43 -0
- data/app/views/decidim/challenges/challenges/_challenge.html.erb +1 -0
- data/app/views/decidim/challenges/challenges/_challenges.html.erb +11 -0
- data/app/views/decidim/challenges/challenges/_related_problems.html.erb +14 -0
- data/app/views/decidim/challenges/challenges/_sidebar_data.html.erb +60 -0
- data/app/views/decidim/challenges/challenges/index.html.erb +29 -0
- data/app/views/decidim/challenges/challenges/index.js.erb +5 -0
- data/app/views/decidim/challenges/challenges/show.html.erb +41 -0
- data/app/views/decidim/problems/admin/problems/_form.html.erb +79 -0
- data/app/views/decidim/problems/admin/problems/edit.html.erb +24 -0
- data/app/views/decidim/problems/admin/problems/index.html.erb +93 -0
- data/app/views/decidim/problems/admin/problems/new.html.erb +18 -0
- data/app/views/decidim/problems/problems/_problem.html.erb +1 -0
- data/app/views/decidim/problems/problems/_problems.html.erb +11 -0
- data/app/views/decidim/problems/problems/_sidebar_data.html.erb +70 -0
- data/app/views/decidim/problems/problems/index.html.erb +28 -0
- data/app/views/decidim/problems/problems/index.js.erb +5 -0
- data/app/views/decidim/problems/problems/show.html.erb +38 -0
- data/app/views/decidim/sdgs/sdgs/_objectives.html.erb +320 -0
- data/app/views/decidim/sdgs/sdgs/_ods.html.erb +132 -0
- data/app/views/decidim/sdgs/sdgs/index.html.erb +64 -0
- data/app/views/decidim/sdgs/sdgs_filter/_filter_selector.html.erb +7 -0
- data/app/views/decidim/sdgs/sdgs_filter/_modal.html.erb +35 -0
- data/app/views/decidim/shared/_related_solutions.html.erb +14 -0
- data/app/views/decidim/solutions/admin/solutions/_documents.html.erb +13 -0
- data/app/views/decidim/solutions/admin/solutions/_form.html.erb +70 -0
- data/app/views/decidim/solutions/admin/solutions/_photos.html.erb +13 -0
- data/app/views/decidim/solutions/admin/solutions/edit.html.erb +24 -0
- data/app/views/decidim/solutions/admin/solutions/index.html.erb +97 -0
- data/app/views/decidim/solutions/admin/solutions/new.html.erb +18 -0
- data/app/views/decidim/solutions/admin/solutions/show.html.erb +114 -0
- data/app/views/decidim/solutions/solutions/_form.html.erb +22 -0
- data/app/views/decidim/solutions/solutions/_sidebar_data.html.erb +114 -0
- data/app/views/decidim/solutions/solutions/_solution.html.erb +1 -0
- data/app/views/decidim/solutions/solutions/_solutions.html.erb +13 -0
- data/app/views/decidim/solutions/solutions/index.html.erb +37 -0
- data/app/views/decidim/solutions/solutions/index.js.erb +5 -0
- data/app/views/decidim/solutions/solutions/new.html.erb +20 -0
- data/app/views/decidim/solutions/solutions/show.html.erb +72 -0
- data/config/assets.rb +27 -0
- data/config/i18n-tasks.yml +10 -0
- data/config/locales/ca.yml +1244 -0
- data/config/locales/cs.yml +668 -0
- data/config/locales/en.yml +1245 -0
- data/config/locales/es.yml +1250 -0
- data/config/locales/oc.yml +1229 -0
- data/db/migrate/20201014125000_create_decidim_challenges_challenges.rb +23 -0
- data/db/migrate/20201103155100_create_decidim_problems_problems.rb +25 -0
- data/db/migrate/20201116111200_create_decidim_solutions_solutions.rb +21 -0
- data/db/migrate/20210413083244_create_decidim_challenges_surveys.rb +14 -0
- data/db/migrate/20210413083507_add_survey_attributes_to_challenges.rb +7 -0
- data/db/migrate/20210413083604_add_questionnaire_to_existing_challenges.rb +15 -0
- data/db/migrate/20210413112229_add_challenge_reference_to_solutions.rb +7 -0
- data/db/migrate/20210427091033_remove_require_null_in_problems_for_solutions.rb +7 -0
- data/db/migrate/20220407110503_add_card_image_to_challenges.rb +7 -0
- data/db/migrate/20240919094714_add_public_fields_to_solutions.rb +10 -0
- data/lib/decidim/challenges/admin.rb +10 -0
- data/lib/decidim/challenges/admin_engine.rb +37 -0
- data/lib/decidim/challenges/component.rb +65 -0
- data/lib/decidim/challenges/engine.rb +39 -0
- data/lib/decidim/challenges/test/factories.rb +59 -0
- data/lib/decidim/challenges/version.rb +14 -0
- data/lib/decidim/challenges.rb +13 -0
- data/lib/decidim/problems/admin.rb +10 -0
- data/lib/decidim/problems/admin_engine.rb +25 -0
- data/lib/decidim/problems/component.rb +51 -0
- data/lib/decidim/problems/engine.rb +31 -0
- data/lib/decidim/problems/test/factories.rb +39 -0
- data/lib/decidim/sdgs/admin.rb +10 -0
- data/lib/decidim/sdgs/admin_engine.rb +28 -0
- data/lib/decidim/sdgs/component.rb +44 -0
- data/lib/decidim/sdgs/engine.rb +23 -0
- data/lib/decidim/sdgs/test/factories.rb +13 -0
- data/lib/decidim/solutions/admin.rb +10 -0
- data/lib/decidim/solutions/admin_engine.rb +25 -0
- data/lib/decidim/solutions/component.rb +52 -0
- data/lib/decidim/solutions/engine.rb +31 -0
- data/lib/decidim/solutions/test/factories.rb +28 -0
- metadata +316 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Challenges
|
5
|
+
#
|
6
|
+
# Decorator for challenge
|
7
|
+
#
|
8
|
+
class ChallengePresenter < SimpleDelegator
|
9
|
+
include Rails.application.routes.mounted_helpers
|
10
|
+
include ActionView::Helpers::UrlHelper
|
11
|
+
include Decidim::SanitizeHelper
|
12
|
+
include Decidim::TranslatableAttributes
|
13
|
+
|
14
|
+
delegate :url, to: :card_image, prefix: true
|
15
|
+
|
16
|
+
def challenge
|
17
|
+
__getobj__
|
18
|
+
end
|
19
|
+
|
20
|
+
def challenge_path
|
21
|
+
Decidim::ResourceLocatorPresenter.new(challenge).path
|
22
|
+
end
|
23
|
+
|
24
|
+
def display_mention
|
25
|
+
link_to title, challenge_path
|
26
|
+
end
|
27
|
+
|
28
|
+
# Render the challenge title
|
29
|
+
#
|
30
|
+
# links - should render hashtags as links?
|
31
|
+
# extras - should include extra hashtags?
|
32
|
+
#
|
33
|
+
# Returns a String.
|
34
|
+
def title(links: false, extras: true, html_escape: false)
|
35
|
+
text = translated_attribute(challenge.title)
|
36
|
+
text = decidim_html_escape(text) if html_escape
|
37
|
+
|
38
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(text)
|
39
|
+
renderer.render(links:, extras:).html_safe
|
40
|
+
end
|
41
|
+
|
42
|
+
def id_and_title(links: false, extras: true, html_escape: false)
|
43
|
+
"##{challenge.id} - #{title(links:, extras:, html_escape:)}"
|
44
|
+
end
|
45
|
+
|
46
|
+
# Render the challenge local_description
|
47
|
+
#
|
48
|
+
# links - should render hashtags as links?
|
49
|
+
# extras - should include extra hashtags?
|
50
|
+
#
|
51
|
+
# Returns a String.
|
52
|
+
def local_description(links: false, extras: true, strip_tags: false)
|
53
|
+
text = translated_attribute(challenge.local_description)
|
54
|
+
|
55
|
+
text = strip_tags(sanitize_text(text)) if strip_tags
|
56
|
+
|
57
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(text)
|
58
|
+
text = renderer.render(links:, extras:).html_safe
|
59
|
+
|
60
|
+
text = Decidim::ContentRenderers::LinkRenderer.new(text).render if links
|
61
|
+
text
|
62
|
+
end
|
63
|
+
|
64
|
+
# Render the challenge global_description
|
65
|
+
#
|
66
|
+
# links - should render hashtags as links?
|
67
|
+
# extras - should include extra hashtags?
|
68
|
+
#
|
69
|
+
# Returns a String.
|
70
|
+
def global_description(links: false, extras: true, strip_tags: false)
|
71
|
+
text = translated_attribute(challenge.global_description)
|
72
|
+
|
73
|
+
text = strip_tags(sanitize_text(text)) if strip_tags
|
74
|
+
|
75
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(text)
|
76
|
+
text = renderer.render(links:, extras:).html_safe
|
77
|
+
|
78
|
+
text = Decidim::ContentRenderers::LinkRenderer.new(text).render if links
|
79
|
+
text
|
80
|
+
end
|
81
|
+
|
82
|
+
def card_image_url
|
83
|
+
return if challenge.card_image.blank?
|
84
|
+
|
85
|
+
challenge.attached_uploader(:card_image).url(host: challenge.organization.host)
|
86
|
+
end
|
87
|
+
|
88
|
+
delegate :count, to: :versions, prefix: true
|
89
|
+
|
90
|
+
def resource_manifest
|
91
|
+
challenge.class.resource_manifest
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def sanitize_unordered_lists(text)
|
97
|
+
text.gsub(%r{(?=.*</ul>)(?!.*?<li>.*?</ol>.*?</ul>)<li>}) { |li| "#{li}• " }
|
98
|
+
end
|
99
|
+
|
100
|
+
def sanitize_ordered_lists(text)
|
101
|
+
i = 0
|
102
|
+
|
103
|
+
text.gsub(%r{(?=.*</ol>)(?!.*?<li>.*?</ul>.*?</ol>)<li>}) do |li|
|
104
|
+
i += 1
|
105
|
+
|
106
|
+
li + "#{i}. "
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def add_line_feeds_to_paragraphs(text)
|
111
|
+
text.gsub("</p>") { |p| "#{p}\n\n" }
|
112
|
+
end
|
113
|
+
|
114
|
+
def add_line_feeds_to_list_items(text)
|
115
|
+
text.gsub("</li>") { |li| "#{li}\n" }
|
116
|
+
end
|
117
|
+
|
118
|
+
# Adds line feeds after the paragraph and list item closing tags.
|
119
|
+
#
|
120
|
+
# Returns a String.
|
121
|
+
def add_line_feeds(text)
|
122
|
+
add_line_feeds_to_paragraphs(add_line_feeds_to_list_items(text))
|
123
|
+
end
|
124
|
+
|
125
|
+
# Maintains the paragraphs and lists separations with their bullet points and
|
126
|
+
# list numberings where appropriate.
|
127
|
+
#
|
128
|
+
# Returns a String.
|
129
|
+
def sanitize_text(text)
|
130
|
+
add_line_feeds(sanitize_ordered_lists(sanitize_unordered_lists(text)))
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Problems
|
5
|
+
#
|
6
|
+
# Decorator for problem
|
7
|
+
#
|
8
|
+
class ProblemPresenter < SimpleDelegator
|
9
|
+
include Rails.application.routes.mounted_helpers
|
10
|
+
include ActionView::Helpers::UrlHelper
|
11
|
+
include Decidim::SanitizeHelper
|
12
|
+
include Decidim::TranslatableAttributes
|
13
|
+
|
14
|
+
def problem
|
15
|
+
__getobj__
|
16
|
+
end
|
17
|
+
|
18
|
+
def problem_path
|
19
|
+
Decidim::ResourceLocatorPresenter.new(problem).path
|
20
|
+
end
|
21
|
+
|
22
|
+
def display_mention
|
23
|
+
link_to title, problem_path
|
24
|
+
end
|
25
|
+
|
26
|
+
# Render the problem title
|
27
|
+
#
|
28
|
+
# links - should render hashtags as links?
|
29
|
+
# extras - should include extra hashtags?
|
30
|
+
#
|
31
|
+
# Returns a String.
|
32
|
+
def title(links: false, extras: true, html_escape: false)
|
33
|
+
text = translated_attribute(problem.title)
|
34
|
+
text = decidim_html_escape(text) if html_escape
|
35
|
+
|
36
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(text)
|
37
|
+
renderer.render(links:, extras:).html_safe
|
38
|
+
end
|
39
|
+
|
40
|
+
def id_and_title(links: false, extras: true, html_escape: false)
|
41
|
+
"##{problem.id} - #{title(links:, extras:, html_escape:)}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Render the problem description
|
45
|
+
#
|
46
|
+
# links - should render hashtags as links?
|
47
|
+
# extras - should include extra hashtags?
|
48
|
+
#
|
49
|
+
# Returns a String.
|
50
|
+
def description(links: false, extras: true, strip_tags: false)
|
51
|
+
text = translated_attribute(problem.description)
|
52
|
+
|
53
|
+
text = strip_tags(sanitize_text(text)) if strip_tags
|
54
|
+
|
55
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(text)
|
56
|
+
text = renderer.render(links:, extras:).html_safe
|
57
|
+
|
58
|
+
text = Decidim::ContentRenderers::LinkRenderer.new(text).render if links
|
59
|
+
text
|
60
|
+
end
|
61
|
+
|
62
|
+
delegate :count, to: :versions, prefix: true
|
63
|
+
|
64
|
+
def resource_manifest
|
65
|
+
problem.class.resource_manifest
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def sanitize_unordered_lists(text)
|
71
|
+
text.gsub(%r{(?=.*</ul>)(?!.*?<li>.*?</ol>.*?</ul>)<li>}) { |li| "#{li}• " }
|
72
|
+
end
|
73
|
+
|
74
|
+
def sanitize_ordered_lists(text)
|
75
|
+
i = 0
|
76
|
+
|
77
|
+
text.gsub(%r{(?=.*</ol>)(?!.*?<li>.*?</ul>.*?</ol>)<li>}) do |li|
|
78
|
+
i += 1
|
79
|
+
|
80
|
+
li + "#{i}. "
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_line_feeds_to_paragraphs(text)
|
85
|
+
text.gsub("</p>") { |p| "#{p}\n\n" }
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_line_feeds_to_list_items(text)
|
89
|
+
text.gsub("</li>") { |li| "#{li}\n" }
|
90
|
+
end
|
91
|
+
|
92
|
+
# Adds line feeds after the paragraph and list item closing tags.
|
93
|
+
#
|
94
|
+
# Returns a String.
|
95
|
+
def add_line_feeds(text)
|
96
|
+
add_line_feeds_to_paragraphs(add_line_feeds_to_list_items(text))
|
97
|
+
end
|
98
|
+
|
99
|
+
# Maintains the paragraphs and lists separations with their bullet points and
|
100
|
+
# list numberings where appropriate.
|
101
|
+
#
|
102
|
+
# Returns a String.
|
103
|
+
def sanitize_text(text)
|
104
|
+
add_line_feeds(sanitize_ordered_lists(sanitize_unordered_lists(text)))
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Solutions
|
5
|
+
#
|
6
|
+
# Decorator for solution
|
7
|
+
#
|
8
|
+
class SolutionPresenter < SimpleDelegator
|
9
|
+
include Rails.application.routes.mounted_helpers
|
10
|
+
include ActionView::Helpers::UrlHelper
|
11
|
+
include Decidim::SanitizeHelper
|
12
|
+
include Decidim::TranslatableAttributes
|
13
|
+
|
14
|
+
def solution
|
15
|
+
__getobj__
|
16
|
+
end
|
17
|
+
|
18
|
+
def solution_path
|
19
|
+
Decidim::ResourceLocatorPresenter.new(solution).path
|
20
|
+
end
|
21
|
+
|
22
|
+
def display_mention
|
23
|
+
link_to title, solution_path
|
24
|
+
end
|
25
|
+
|
26
|
+
# Render the solution title
|
27
|
+
#
|
28
|
+
# links - should render hashtags as links?
|
29
|
+
# extras - should include extra hashtags?
|
30
|
+
#
|
31
|
+
# Returns a String.
|
32
|
+
def title(links: false, extras: true, html_escape: false)
|
33
|
+
text = translated_attribute(solution.title)
|
34
|
+
text = decidim_html_escape(text) if html_escape
|
35
|
+
|
36
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(text)
|
37
|
+
renderer.render(links:, extras:).html_safe
|
38
|
+
end
|
39
|
+
|
40
|
+
def id_and_title(links: false, extras: true, html_escape: false)
|
41
|
+
"##{solution.id} - #{title(links:, extras:, html_escape:)}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Render the solution description
|
45
|
+
#
|
46
|
+
# links - should render hashtags as links?
|
47
|
+
# extras - should include extra hashtags?
|
48
|
+
#
|
49
|
+
# Returns a String.
|
50
|
+
def description(links: false, extras: true, strip_tags: false)
|
51
|
+
text = translated_attribute(solution.description)
|
52
|
+
|
53
|
+
text = strip_tags(sanitize_text(text)) if strip_tags
|
54
|
+
|
55
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(text)
|
56
|
+
text = renderer.render(links:, extras:).html_safe
|
57
|
+
|
58
|
+
text = Decidim::ContentRenderers::LinkRenderer.new(text).render if links
|
59
|
+
text
|
60
|
+
end
|
61
|
+
|
62
|
+
# Render the solution indicators
|
63
|
+
#
|
64
|
+
# links - should render hashtags as links?
|
65
|
+
# extras - should include extra hashtags?
|
66
|
+
#
|
67
|
+
# Returns a String.
|
68
|
+
def indicators(links: false, extras: true, strip_tags: false)
|
69
|
+
text = translated_attribute(solution.indicators)
|
70
|
+
|
71
|
+
text = strip_tags(sanitize_text(text)) if strip_tags
|
72
|
+
|
73
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(text)
|
74
|
+
text = renderer.render(links:, extras:).html_safe
|
75
|
+
|
76
|
+
text = Decidim::ContentRenderers::LinkRenderer.new(text).render if links
|
77
|
+
text
|
78
|
+
end
|
79
|
+
|
80
|
+
# Render the solution beneficiaries
|
81
|
+
#
|
82
|
+
# links - should render hashtags as links?
|
83
|
+
# extras - should include extra hashtags?
|
84
|
+
#
|
85
|
+
# Returns a String.
|
86
|
+
def beneficiaries(links: false, extras: true, strip_tags: false)
|
87
|
+
text = translated_attribute(solution.beneficiaries)
|
88
|
+
|
89
|
+
text = strip_tags(sanitize_text(text)) if strip_tags
|
90
|
+
|
91
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(text)
|
92
|
+
text = renderer.render(links:, extras:).html_safe
|
93
|
+
|
94
|
+
text = Decidim::ContentRenderers::LinkRenderer.new(text).render if links
|
95
|
+
text
|
96
|
+
end
|
97
|
+
|
98
|
+
# Render the solution requirements
|
99
|
+
#
|
100
|
+
# links - should render hashtags as links?
|
101
|
+
# extras - should include extra hashtags?
|
102
|
+
#
|
103
|
+
# Returns a String.
|
104
|
+
def requirements(links: false, extras: true, strip_tags: false)
|
105
|
+
text = translated_attribute(solution.requirements)
|
106
|
+
|
107
|
+
text = strip_tags(sanitize_text(text)) if strip_tags
|
108
|
+
|
109
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(text)
|
110
|
+
text = renderer.render(links:, extras:).html_safe
|
111
|
+
|
112
|
+
text = Decidim::ContentRenderers::LinkRenderer.new(text).render if links
|
113
|
+
text
|
114
|
+
end
|
115
|
+
|
116
|
+
# Render the solution financing_type
|
117
|
+
#
|
118
|
+
# links - should render hashtags as links?
|
119
|
+
# extras - should include extra hashtags?
|
120
|
+
#
|
121
|
+
# Returns a String.
|
122
|
+
def financing_type(links: false, extras: true, strip_tags: false)
|
123
|
+
text = translated_attribute(solution.financing_type)
|
124
|
+
|
125
|
+
text = strip_tags(sanitize_text(text)) if strip_tags
|
126
|
+
|
127
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(text)
|
128
|
+
text = renderer.render(links:, extras:).html_safe
|
129
|
+
|
130
|
+
text = Decidim::ContentRenderers::LinkRenderer.new(text).render if links
|
131
|
+
text
|
132
|
+
end
|
133
|
+
|
134
|
+
# Render the solution objectives
|
135
|
+
#
|
136
|
+
# links - should render hashtags as links?
|
137
|
+
# extras - should include extra hashtags?
|
138
|
+
#
|
139
|
+
# Returns a String.
|
140
|
+
def objectives(links: false, extras: true, strip_tags: false)
|
141
|
+
text = translated_attribute(solution.objectives)
|
142
|
+
|
143
|
+
text = strip_tags(sanitize_text(text)) if strip_tags
|
144
|
+
|
145
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(text)
|
146
|
+
text = renderer.render(links:, extras:).html_safe
|
147
|
+
|
148
|
+
text = Decidim::ContentRenderers::LinkRenderer.new(text).render if links
|
149
|
+
text
|
150
|
+
end
|
151
|
+
|
152
|
+
delegate :count, to: :versions, prefix: true
|
153
|
+
|
154
|
+
def resource_manifest
|
155
|
+
solution.class.resource_manifest
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def sanitize_unordered_lists(text)
|
161
|
+
text.gsub(%r{(?=.*</ul>)(?!.*?<li>.*?</ol>.*?</ul>)<li>}) { |li| "#{li}• " }
|
162
|
+
end
|
163
|
+
|
164
|
+
def sanitize_ordered_lists(text)
|
165
|
+
i = 0
|
166
|
+
|
167
|
+
text.gsub(%r{(?=.*</ol>)(?!.*?<li>.*?</ul>.*?</ol>)<li>}) do |li|
|
168
|
+
i += 1
|
169
|
+
|
170
|
+
li + "#{i}. "
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def add_line_feeds_to_paragraphs(text)
|
175
|
+
text.gsub("</p>") { |p| "#{p}\n\n" }
|
176
|
+
end
|
177
|
+
|
178
|
+
def add_line_feeds_to_list_items(text)
|
179
|
+
text.gsub("</li>") { |li| "#{li}\n" }
|
180
|
+
end
|
181
|
+
|
182
|
+
# Adds line feeds after the paragraph and list item closing tags.
|
183
|
+
#
|
184
|
+
# Returns a String.
|
185
|
+
def add_line_feeds(text)
|
186
|
+
add_line_feeds_to_paragraphs(add_line_feeds_to_list_items(text))
|
187
|
+
end
|
188
|
+
|
189
|
+
# Maintains the paragraphs and lists separations with their bullet points and
|
190
|
+
# list numberings where appropriate.
|
191
|
+
#
|
192
|
+
# Returns a String.
|
193
|
+
def sanitize_text(text)
|
194
|
+
add_line_feeds(sanitize_ordered_lists(sanitize_unordered_lists(text)))
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Challenges
|
5
|
+
# This class serializes the specific data in each Survey.
|
6
|
+
# This is `Questionnaire->questions->answer_options` but not `answers`
|
7
|
+
# and `answer_choices`.
|
8
|
+
class DataSerializer < Decidim::Exporters::Serializer
|
9
|
+
# Returns: Array of Decidim::Forms::Questionnaire as a json hash,
|
10
|
+
# or nil if none exists.
|
11
|
+
def serialize
|
12
|
+
component = resource
|
13
|
+
surveys = Decidim::Challenges::Survey.where(component:)
|
14
|
+
surveys.collect do |survey|
|
15
|
+
next if survey.questionnaire.nil?
|
16
|
+
|
17
|
+
json = serialize_survey(survey)
|
18
|
+
json.with_indifferent_access.merge(survey_id: survey.id)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def serialize_survey(survey)
|
23
|
+
questionnaire = survey.questionnaire
|
24
|
+
questionnaire_json = questionnaire.attributes.as_json
|
25
|
+
questionnaire_json[:questions] = serialize_questions(questionnaire.questions.order(:position))
|
26
|
+
json = survey.attributes.as_json
|
27
|
+
json[:questionnaire] = questionnaire_json
|
28
|
+
json
|
29
|
+
end
|
30
|
+
|
31
|
+
def serialize_questions(questions)
|
32
|
+
questions.collect do |question|
|
33
|
+
json = question.attributes.as_json
|
34
|
+
json[:answer_options] = serialize_answer_options(question.answer_options)
|
35
|
+
json
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def serialize_answer_options(answer_options)
|
40
|
+
answer_options.collect do |option|
|
41
|
+
option.attributes.as_json
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Challenges
|
5
|
+
class SurveySerializer < Decidim::Exporters::Serializer
|
6
|
+
include Decidim::TranslationsHelper
|
7
|
+
# Serializes a registration
|
8
|
+
def serialize
|
9
|
+
{
|
10
|
+
id: resource.id,
|
11
|
+
user: {
|
12
|
+
name: resource.user.name,
|
13
|
+
email: resource.user.email,
|
14
|
+
},
|
15
|
+
survey_form_answers: serialize_answers,
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def serialize_answers
|
22
|
+
questions = resource.challenge.questionnaire.questions
|
23
|
+
answers = resource.challenge.questionnaire.answers.where(user: resource.user)
|
24
|
+
questions.each_with_index.inject({}) do |serialized, (question, idx)|
|
25
|
+
answer = answers.find_by(question:)
|
26
|
+
serialized.update("#{idx + 1}. #{translated_attribute(question.body)}" => normalize_body(answer))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def normalize_body(answer)
|
31
|
+
return "" unless answer
|
32
|
+
|
33
|
+
answer.body || answer.choices.pluck(:body)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Challenges
|
5
|
+
class ChallengeType < Decidim::Api::Types::BaseObject
|
6
|
+
implements Decidim::Core::ScopableInterface
|
7
|
+
implements Decidim::Core::AttachableInterface
|
8
|
+
implements Decidim::Core::TraceableInterface
|
9
|
+
implements Decidim::Core::TimestampsInterface
|
10
|
+
|
11
|
+
graphql_name "Challenge"
|
12
|
+
description "A challenge"
|
13
|
+
|
14
|
+
field :id, GraphQL::Types::ID, null: false
|
15
|
+
field :title, Decidim::Core::TranslatedFieldType, "The title of this challenge (same as the component name).", null: false
|
16
|
+
field :local_description, Decidim::Core::TranslatedFieldType, "The local description of this challenge.", null: true
|
17
|
+
field :global_description, Decidim::Core::TranslatedFieldType, "The global description of this challenge.", null: true
|
18
|
+
field :tags, Decidim::Core::TranslatedFieldType, "The tags of this challenge.", null: true
|
19
|
+
field :sdg_code, GraphQL::Types::String, "The Sustainable Development Goal this challenge is associated with.", null: true
|
20
|
+
field :state, GraphQL::Types::String, "The state for this challenge.", null: true
|
21
|
+
field :start_date, Decidim::Core::DateType, "The start date", null: true
|
22
|
+
field :end_date, Decidim::Core::DateType, "The end date", null: true
|
23
|
+
field :published_at, Decidim::Core::DateTimeType, "The moment at which it was published", null: true
|
24
|
+
field :coordinating_entities, GraphQL::Types::String, "The entities coordinating this challenge.", null: true
|
25
|
+
field :collaborating_entities, GraphQL::Types::String, "The entities collaborating with this challenge.", null: true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Challenges
|
5
|
+
class ChallengesType < Decidim::Api::Types::BaseObject
|
6
|
+
implements Decidim::Core::ComponentInterface
|
7
|
+
|
8
|
+
graphql_name "Challenges"
|
9
|
+
description "A challenges component of a participatory space."
|
10
|
+
|
11
|
+
field :challenges, ChallengeType.connection_type, null: true, connection: true
|
12
|
+
|
13
|
+
def challenges
|
14
|
+
ChallengesTypeHelper.base_scope(object).includes(:component)
|
15
|
+
end
|
16
|
+
|
17
|
+
field(:challenge, ChallengeType, null: true) do
|
18
|
+
argument :id, GraphQL::Types::ID, required: true
|
19
|
+
end
|
20
|
+
|
21
|
+
def challenge(**args)
|
22
|
+
ChallengesTypeHelper.base_scope(object).find_by(id: args[:id])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module ChallengesTypeHelper
|
27
|
+
def self.base_scope(component)
|
28
|
+
Challenge.where(component:).published
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Problems
|
5
|
+
class ProblemType < Decidim::Api::Types::BaseObject
|
6
|
+
implements Decidim::Core::TraceableInterface
|
7
|
+
implements Decidim::Core::TimestampsInterface
|
8
|
+
|
9
|
+
graphql_name "Problem"
|
10
|
+
description "A problem"
|
11
|
+
|
12
|
+
field :id, GraphQL::Types::ID, null: false
|
13
|
+
field :title, Decidim::Core::TranslatedFieldType, "The title of this problem (same as the component name).", null: false
|
14
|
+
field :description, Decidim::Core::TranslatedFieldType, "The description of this problem.", null: true
|
15
|
+
field :challenge, Decidim::Challenges::ChallengeType, "The related Challenge", null: true
|
16
|
+
field :sectorial_scope, Decidim::Core::ScopeApiType, "The object's sectorial scope", null: true
|
17
|
+
field :technological_scope, Decidim::Core::ScopeApiType, "The object's technological scope", null: true
|
18
|
+
field :tags, Decidim::Core::TranslatedFieldType, "The tags of this problem.", null: true
|
19
|
+
field :state, GraphQL::Types::String, "The state for this problem.", null: true
|
20
|
+
field :start_date, Decidim::Core::DateType, "The start date", null: true
|
21
|
+
field :end_date, Decidim::Core::DateType, "The end date", null: true
|
22
|
+
field :published_at, Decidim::Core::DateTimeType, "The moment at which it was published", null: true
|
23
|
+
field :causes, GraphQL::Types::String, "The entities proposing this problem.", null: true
|
24
|
+
field :groups_affected, GraphQL::Types::String, "The entities proposing this problem.", null: true
|
25
|
+
field :proposing_entities, GraphQL::Types::String, "The entities proposing this problem.", null: true
|
26
|
+
field :collaborating_entities, GraphQL::Types::String, "The entities collaborating with this problem.", null: true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Problems
|
5
|
+
class ProblemsType < Decidim::Api::Types::BaseObject
|
6
|
+
implements Decidim::Core::ComponentInterface
|
7
|
+
|
8
|
+
graphql_name "Problems"
|
9
|
+
description "A problems component of a participatory space."
|
10
|
+
|
11
|
+
field :problems, ProblemType.connection_type, null: true, connection: true
|
12
|
+
|
13
|
+
def problems
|
14
|
+
ProblemsTypeHelper.base_scope(object).includes(:component)
|
15
|
+
end
|
16
|
+
|
17
|
+
field(:problem, ProblemType, null: true) do
|
18
|
+
argument :id, GraphQL::Types::ID, required: true
|
19
|
+
end
|
20
|
+
|
21
|
+
def problem(**args)
|
22
|
+
ProblemsTypeHelper.base_scope(object).find_by(id: args[:id])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module ProblemsTypeHelper
|
27
|
+
def self.base_scope(component)
|
28
|
+
Problem.where(component:).published
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Solutions
|
5
|
+
class SolutionType < Decidim::Api::Types::BaseObject
|
6
|
+
implements Decidim::Core::TraceableInterface
|
7
|
+
implements Decidim::Core::TimestampsInterface
|
8
|
+
|
9
|
+
graphql_name "Solution"
|
10
|
+
description "A solution"
|
11
|
+
|
12
|
+
field :id, GraphQL::Types::ID, null: false
|
13
|
+
field :title, Decidim::Core::TranslatedFieldType, "The title of this solution (same as the component name).", null: false
|
14
|
+
field :description, Decidim::Core::TranslatedFieldType, "The description of this solution.", null: true
|
15
|
+
field :problem, Decidim::Problems::ProblemType, "The related Problem", null: true
|
16
|
+
field :tags, Decidim::Core::TranslatedFieldType, "The tags of this solution.", null: true
|
17
|
+
field :indicators, Decidim::Core::TranslatedFieldType, "The indicators of this solution.", null: true
|
18
|
+
field :beneficiaries, Decidim::Core::TranslatedFieldType, "The beneficiaries of this solution.", null: true
|
19
|
+
field :requirements, Decidim::Core::TranslatedFieldType, "The requirements of this solution.", null: true
|
20
|
+
field :financing_type, Decidim::Core::TranslatedFieldType, "The financing_type of this solution.", null: true
|
21
|
+
field :objectives, Decidim::Core::TranslatedFieldType, "The objectives of this solution.", null: true
|
22
|
+
field :published_at, Decidim::Core::DateTimeType, "The moment at which it was published", null: true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|