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.
Files changed (231) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-AGPLv3.txt +661 -0
  3. data/README.md +49 -0
  4. data/Rakefile +9 -0
  5. data/app/cells/decidim/challenges/challenge_cell.rb +21 -0
  6. data/app/cells/decidim/challenges/challenge_g/show.erb +47 -0
  7. data/app/cells/decidim/challenges/challenge_g_cell.rb +69 -0
  8. data/app/cells/decidim/problems/problem_cell.rb +21 -0
  9. data/app/cells/decidim/problems/problem_g/show.erb +35 -0
  10. data/app/cells/decidim/problems/problem_g_cell.rb +61 -0
  11. data/app/cells/decidim/solutions/solution_cell.rb +21 -0
  12. data/app/cells/decidim/solutions/solution_g/show.erb +30 -0
  13. data/app/cells/decidim/solutions/solution_g_cell.rb +84 -0
  14. data/app/commands/decidim/challenges/admin/create_challenge.rb +67 -0
  15. data/app/commands/decidim/challenges/admin/destroy_challenge.rb +49 -0
  16. data/app/commands/decidim/challenges/admin/export_challenge_surveys.rb +45 -0
  17. data/app/commands/decidim/challenges/admin/publish_challenge.rb +40 -0
  18. data/app/commands/decidim/challenges/admin/unpublish_challenge.rb +40 -0
  19. data/app/commands/decidim/challenges/admin/update_challenge.rb +72 -0
  20. data/app/commands/decidim/challenges/admin/update_surveys.rb +43 -0
  21. data/app/commands/decidim/challenges/survey_challenge.rb +67 -0
  22. data/app/commands/decidim/command_utils.rb +20 -0
  23. data/app/commands/decidim/problems/admin/create_problem.rb +66 -0
  24. data/app/commands/decidim/problems/admin/destroy_problem.rb +49 -0
  25. data/app/commands/decidim/problems/admin/publish_problem.rb +40 -0
  26. data/app/commands/decidim/problems/admin/unpublish_problem.rb +40 -0
  27. data/app/commands/decidim/problems/admin/update_problem.rb +69 -0
  28. data/app/commands/decidim/solutions/admin/create_solution.rb +65 -0
  29. data/app/commands/decidim/solutions/admin/destroy_solution.rb +43 -0
  30. data/app/commands/decidim/solutions/admin/publish_solution.rb +40 -0
  31. data/app/commands/decidim/solutions/admin/unpublish_solution.rb +40 -0
  32. data/app/commands/decidim/solutions/admin/update_solution.rb +67 -0
  33. data/app/commands/decidim/solutions/create_solution.rb +67 -0
  34. data/app/controllers/concerns/decidim/challenges/admin/filterable.rb +27 -0
  35. data/app/controllers/concerns/decidim/challenges/orderable_challenges.rb +37 -0
  36. data/app/controllers/concerns/decidim/problems/admin/filterable.rb +27 -0
  37. data/app/controllers/concerns/decidim/problems/orderable_problems.rb +37 -0
  38. data/app/controllers/concerns/decidim/solutions/admin/filterable.rb +27 -0
  39. data/app/controllers/concerns/decidim/solutions/orderable_solutions.rb +37 -0
  40. data/app/controllers/concerns/decidim/with_default_filters.rb +23 -0
  41. data/app/controllers/concerns/decidim/with_sdgs.rb +19 -0
  42. data/app/controllers/decidim/challenges/admin/application_controller.rb +15 -0
  43. data/app/controllers/decidim/challenges/admin/challenge_publications_controller.rb +53 -0
  44. data/app/controllers/decidim/challenges/admin/challenges_controller.rb +108 -0
  45. data/app/controllers/decidim/challenges/admin/survey_form_controller.rb +43 -0
  46. data/app/controllers/decidim/challenges/admin/surveys_controller.rb +104 -0
  47. data/app/controllers/decidim/challenges/application_controller.rb +13 -0
  48. data/app/controllers/decidim/challenges/challenges_controller.rb +70 -0
  49. data/app/controllers/decidim/challenges/surveys_controller.rb +61 -0
  50. data/app/controllers/decidim/problems/admin/application_controller.rb +15 -0
  51. data/app/controllers/decidim/problems/admin/problem_publications_controller.rb +53 -0
  52. data/app/controllers/decidim/problems/admin/problems_controller.rb +102 -0
  53. data/app/controllers/decidim/problems/application_controller.rb +13 -0
  54. data/app/controllers/decidim/problems/problems_controller.rb +62 -0
  55. data/app/controllers/decidim/sdgs/admin/application_controller.rb +15 -0
  56. data/app/controllers/decidim/sdgs/admin/sdgs_controller.rb +18 -0
  57. data/app/controllers/decidim/sdgs/application_controller.rb +13 -0
  58. data/app/controllers/decidim/sdgs/sdgs_controller.rb +24 -0
  59. data/app/controllers/decidim/solutions/admin/application_controller.rb +15 -0
  60. data/app/controllers/decidim/solutions/admin/solution_publications_controller.rb +53 -0
  61. data/app/controllers/decidim/solutions/admin/solutions_controller.rb +106 -0
  62. data/app/controllers/decidim/solutions/application_controller.rb +13 -0
  63. data/app/controllers/decidim/solutions/solutions_controller.rb +115 -0
  64. data/app/forms/decidim/challenges/admin/challenge_surveys_form.rb +35 -0
  65. data/app/forms/decidim/challenges/admin/challenges_form.rb +78 -0
  66. data/app/forms/decidim/problems/admin/problems_form.rb +90 -0
  67. data/app/forms/decidim/solutions/admin/solutions_form.rb +71 -0
  68. data/app/forms/decidim/solutions/solutions_form.rb +50 -0
  69. data/app/helpers/decidim/challenges/application_helper.rb +25 -0
  70. data/app/helpers/decidim/challenges/challenge_cells_helper.rb +57 -0
  71. data/app/helpers/decidim/challenges/challenges_helper.rb +39 -0
  72. data/app/helpers/decidim/problems/application_helper.rb +10 -0
  73. data/app/helpers/decidim/problems/problem_cells_helper.rb +23 -0
  74. data/app/helpers/decidim/problems/problems_helper.rb +24 -0
  75. data/app/helpers/decidim/sdgs/sdgs_helper.rb +28 -0
  76. data/app/helpers/decidim/show_filters_helper.rb +13 -0
  77. data/app/helpers/decidim/solutions/application_helper.rb +27 -0
  78. data/app/helpers/decidim/solutions/solution_cells_helper.rb +56 -0
  79. data/app/helpers/decidim/solutions/solutions_helper.rb +21 -0
  80. data/app/models/decidim/application_record.rb +8 -0
  81. data/app/models/decidim/challenges/challenge.rb +82 -0
  82. data/app/models/decidim/challenges/survey.rb +19 -0
  83. data/app/models/decidim/problems/problem.rb +118 -0
  84. data/app/models/decidim/sdgs/sdg.rb +47 -0
  85. data/app/models/decidim/solutions/application_record.rb +10 -0
  86. data/app/models/decidim/solutions/solution.rb +69 -0
  87. data/app/packs/entrypoints/decidim_challenges.js +4 -0
  88. data/app/packs/entrypoints/decidim_challenges.scss +1 -0
  89. data/app/packs/entrypoints/decidim_problems.js +1 -0
  90. data/app/packs/entrypoints/decidim_problems.scss +1 -0
  91. data/app/packs/entrypoints/decidim_sdgs.js +6 -0
  92. data/app/packs/entrypoints/decidim_sdgs.scss +3 -0
  93. data/app/packs/entrypoints/decidim_shared.js +1 -0
  94. data/app/packs/entrypoints/decidim_shared.scss +1 -0
  95. data/app/packs/entrypoints/decidim_solutions.js +4 -0
  96. data/app/packs/entrypoints/decidim_solutions.scss +1 -0
  97. data/app/packs/fonts/Oswald-Medium.ttf +0 -0
  98. data/app/packs/images/decidim/challenges/decidim_challenges_icon.svg +1 -0
  99. data/app/packs/images/decidim/sdgs/ods-01.svg +11 -0
  100. data/app/packs/images/decidim/sdgs/ods-02.svg +11 -0
  101. data/app/packs/images/decidim/sdgs/ods-03.svg +11 -0
  102. data/app/packs/images/decidim/sdgs/ods-04.svg +12 -0
  103. data/app/packs/images/decidim/sdgs/ods-05.svg +12 -0
  104. data/app/packs/images/decidim/sdgs/ods-06.svg +20 -0
  105. data/app/packs/images/decidim/sdgs/ods-07.svg +18 -0
  106. data/app/packs/images/decidim/sdgs/ods-08.svg +13 -0
  107. data/app/packs/images/decidim/sdgs/ods-09.svg +25 -0
  108. data/app/packs/images/decidim/sdgs/ods-10.svg +13 -0
  109. data/app/packs/images/decidim/sdgs/ods-11.svg +41 -0
  110. data/app/packs/images/decidim/sdgs/ods-12.svg +11 -0
  111. data/app/packs/images/decidim/sdgs/ods-13.svg +57 -0
  112. data/app/packs/images/decidim/sdgs/ods-14.svg +14 -0
  113. data/app/packs/images/decidim/sdgs/ods-15.svg +11 -0
  114. data/app/packs/images/decidim/sdgs/ods-16.svg +14 -0
  115. data/app/packs/images/decidim/sdgs/ods-17.svg +39 -0
  116. data/app/packs/images/decidim/sdgs/sdg-wheel.png +0 -0
  117. data/app/packs/images/decidim/sdgs/un_emblem_square.png +0 -0
  118. data/app/packs/src/decidim/challenges/add_challenge.js +3 -0
  119. data/app/packs/src/decidim/challenges/admin/challenges_form.js +3 -0
  120. data/app/packs/src/decidim/sdgs/filter.js +75 -0
  121. data/app/packs/stylesheets/decidim/challenges/challenges.scss +3 -0
  122. data/app/packs/stylesheets/decidim/problems/problems.scss +3 -0
  123. data/app/packs/stylesheets/decidim/sdgs/ods.scss +185 -0
  124. data/app/packs/stylesheets/decidim/sdgs/sdgs_filter/button.scss +27 -0
  125. data/app/packs/stylesheets/decidim/sdgs/sdgs_filter/modal.scss +60 -0
  126. data/app/packs/stylesheets/decidim/shared/_cards.scss +52 -0
  127. data/app/packs/stylesheets/decidim/shared/base.scss +9 -0
  128. data/app/packs/stylesheets/decidim/solutions/solutions.scss +3 -0
  129. data/app/permissions/decidim/challenges/admin/permissions.rb +88 -0
  130. data/app/permissions/decidim/challenges/permissions.rb +27 -0
  131. data/app/permissions/decidim/problems/admin/permissions.rb +52 -0
  132. data/app/permissions/decidim/problems/permissions.rb +16 -0
  133. data/app/permissions/decidim/solutions/admin/permissions.rb +58 -0
  134. data/app/permissions/decidim/solutions/permissions.rb +17 -0
  135. data/app/presenters/decidim/challenges/challenge_presenter.rb +134 -0
  136. data/app/presenters/decidim/problems/problem_presenter.rb +108 -0
  137. data/app/presenters/decidim/solutions/solution_presenter.rb +198 -0
  138. data/app/serializers/decidim/challenges/data_serializer.rb +46 -0
  139. data/app/serializers/decidim/challenges/survey_serializer.rb +37 -0
  140. data/app/types/decidim/challenges/challenge_type.rb +28 -0
  141. data/app/types/decidim/challenges/challenges_type.rb +32 -0
  142. data/app/types/decidim/problems/problem_type.rb +29 -0
  143. data/app/types/decidim/problems/problems_type.rb +32 -0
  144. data/app/types/decidim/solutions/solution_type.rb +25 -0
  145. data/app/types/decidim/solutions/solutions_type.rb +32 -0
  146. data/app/views/decidim/challenges/admin/challenges/_form.html.erb +78 -0
  147. data/app/views/decidim/challenges/admin/challenges/edit.html.erb +24 -0
  148. data/app/views/decidim/challenges/admin/challenges/index.html.erb +88 -0
  149. data/app/views/decidim/challenges/admin/challenges/new.html.erb +18 -0
  150. data/app/views/decidim/challenges/admin/surveys/_form.html.erb +9 -0
  151. data/app/views/decidim/challenges/admin/surveys/edit.html.erb +39 -0
  152. data/app/views/decidim/challenges/admin/surveys/index.html.erb +49 -0
  153. data/app/views/decidim/challenges/admin/surveys/show.html.erb +43 -0
  154. data/app/views/decidim/challenges/challenges/_challenge.html.erb +1 -0
  155. data/app/views/decidim/challenges/challenges/_challenges.html.erb +11 -0
  156. data/app/views/decidim/challenges/challenges/_related_problems.html.erb +14 -0
  157. data/app/views/decidim/challenges/challenges/_sidebar_data.html.erb +60 -0
  158. data/app/views/decidim/challenges/challenges/index.html.erb +29 -0
  159. data/app/views/decidim/challenges/challenges/index.js.erb +5 -0
  160. data/app/views/decidim/challenges/challenges/show.html.erb +41 -0
  161. data/app/views/decidim/problems/admin/problems/_form.html.erb +79 -0
  162. data/app/views/decidim/problems/admin/problems/edit.html.erb +24 -0
  163. data/app/views/decidim/problems/admin/problems/index.html.erb +93 -0
  164. data/app/views/decidim/problems/admin/problems/new.html.erb +18 -0
  165. data/app/views/decidim/problems/problems/_problem.html.erb +1 -0
  166. data/app/views/decidim/problems/problems/_problems.html.erb +11 -0
  167. data/app/views/decidim/problems/problems/_sidebar_data.html.erb +70 -0
  168. data/app/views/decidim/problems/problems/index.html.erb +28 -0
  169. data/app/views/decidim/problems/problems/index.js.erb +5 -0
  170. data/app/views/decidim/problems/problems/show.html.erb +38 -0
  171. data/app/views/decidim/sdgs/sdgs/_objectives.html.erb +320 -0
  172. data/app/views/decidim/sdgs/sdgs/_ods.html.erb +132 -0
  173. data/app/views/decidim/sdgs/sdgs/index.html.erb +64 -0
  174. data/app/views/decidim/sdgs/sdgs_filter/_filter_selector.html.erb +7 -0
  175. data/app/views/decidim/sdgs/sdgs_filter/_modal.html.erb +35 -0
  176. data/app/views/decidim/shared/_related_solutions.html.erb +14 -0
  177. data/app/views/decidim/solutions/admin/solutions/_documents.html.erb +13 -0
  178. data/app/views/decidim/solutions/admin/solutions/_form.html.erb +70 -0
  179. data/app/views/decidim/solutions/admin/solutions/_photos.html.erb +13 -0
  180. data/app/views/decidim/solutions/admin/solutions/edit.html.erb +24 -0
  181. data/app/views/decidim/solutions/admin/solutions/index.html.erb +97 -0
  182. data/app/views/decidim/solutions/admin/solutions/new.html.erb +18 -0
  183. data/app/views/decidim/solutions/admin/solutions/show.html.erb +114 -0
  184. data/app/views/decidim/solutions/solutions/_form.html.erb +22 -0
  185. data/app/views/decidim/solutions/solutions/_sidebar_data.html.erb +114 -0
  186. data/app/views/decidim/solutions/solutions/_solution.html.erb +1 -0
  187. data/app/views/decidim/solutions/solutions/_solutions.html.erb +13 -0
  188. data/app/views/decidim/solutions/solutions/index.html.erb +37 -0
  189. data/app/views/decidim/solutions/solutions/index.js.erb +5 -0
  190. data/app/views/decidim/solutions/solutions/new.html.erb +20 -0
  191. data/app/views/decidim/solutions/solutions/show.html.erb +72 -0
  192. data/config/assets.rb +27 -0
  193. data/config/i18n-tasks.yml +10 -0
  194. data/config/locales/ca.yml +1244 -0
  195. data/config/locales/cs.yml +668 -0
  196. data/config/locales/en.yml +1245 -0
  197. data/config/locales/es.yml +1250 -0
  198. data/config/locales/oc.yml +1229 -0
  199. data/db/migrate/20201014125000_create_decidim_challenges_challenges.rb +23 -0
  200. data/db/migrate/20201103155100_create_decidim_problems_problems.rb +25 -0
  201. data/db/migrate/20201116111200_create_decidim_solutions_solutions.rb +21 -0
  202. data/db/migrate/20210413083244_create_decidim_challenges_surveys.rb +14 -0
  203. data/db/migrate/20210413083507_add_survey_attributes_to_challenges.rb +7 -0
  204. data/db/migrate/20210413083604_add_questionnaire_to_existing_challenges.rb +15 -0
  205. data/db/migrate/20210413112229_add_challenge_reference_to_solutions.rb +7 -0
  206. data/db/migrate/20210427091033_remove_require_null_in_problems_for_solutions.rb +7 -0
  207. data/db/migrate/20220407110503_add_card_image_to_challenges.rb +7 -0
  208. data/db/migrate/20240919094714_add_public_fields_to_solutions.rb +10 -0
  209. data/lib/decidim/challenges/admin.rb +10 -0
  210. data/lib/decidim/challenges/admin_engine.rb +37 -0
  211. data/lib/decidim/challenges/component.rb +65 -0
  212. data/lib/decidim/challenges/engine.rb +39 -0
  213. data/lib/decidim/challenges/test/factories.rb +59 -0
  214. data/lib/decidim/challenges/version.rb +14 -0
  215. data/lib/decidim/challenges.rb +13 -0
  216. data/lib/decidim/problems/admin.rb +10 -0
  217. data/lib/decidim/problems/admin_engine.rb +25 -0
  218. data/lib/decidim/problems/component.rb +51 -0
  219. data/lib/decidim/problems/engine.rb +31 -0
  220. data/lib/decidim/problems/test/factories.rb +39 -0
  221. data/lib/decidim/sdgs/admin.rb +10 -0
  222. data/lib/decidim/sdgs/admin_engine.rb +28 -0
  223. data/lib/decidim/sdgs/component.rb +44 -0
  224. data/lib/decidim/sdgs/engine.rb +23 -0
  225. data/lib/decidim/sdgs/test/factories.rb +13 -0
  226. data/lib/decidim/solutions/admin.rb +10 -0
  227. data/lib/decidim/solutions/admin_engine.rb +25 -0
  228. data/lib/decidim/solutions/component.rb +52 -0
  229. data/lib/decidim/solutions/engine.rb +31 -0
  230. data/lib/decidim/solutions/test/factories.rb +28 -0
  231. metadata +316 -0
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Solutions
5
+ module Admin
6
+ # Controller that allows managing admin problems.
7
+ #
8
+ class SolutionsController < Decidim::Solutions::Admin::ApplicationController
9
+ include Decidim::ApplicationHelper
10
+
11
+ helper Challenges::ApplicationHelper
12
+ helper Decidim::PaginateHelper
13
+
14
+ helper_method :solution, :solution, :form_presenter
15
+
16
+ def index
17
+ enforce_permission_to :read, :solutions
18
+ @solutions = solutions
19
+ end
20
+
21
+ def show
22
+ enforce_permission_to :show, :solution
23
+ @solution = Decidim::Solutions::Solution.find(params[:id])
24
+ end
25
+
26
+ def new
27
+ enforce_permission_to :create, :solution
28
+ @form = form(Decidim::Solutions::Admin::SolutionsForm).instance
29
+ end
30
+
31
+ def edit
32
+ enforce_permission_to(:edit, :solution, solution:)
33
+ @form = form(Decidim::Solutions::Admin::SolutionsForm).from_model(solution)
34
+ end
35
+
36
+ def create
37
+ enforce_permission_to :create, :solution
38
+ @form = form(Decidim::Solutions::Admin::SolutionsForm).from_params(params.merge({ author_id: current_user.id }))
39
+
40
+ Decidim::Solutions::Admin::CreateSolution.call(@form) do
41
+ on(:ok) do
42
+ flash[:notice] = I18n.t("solutions.create.success", scope: "decidim.solutions.admin")
43
+ redirect_to solutions_path(assembly_slug: -1, component_id: -1)
44
+ end
45
+
46
+ on(:invalid) do
47
+ flash.now[:alert] = I18n.t("solutions.create.error", scope: "decidim.solutions.admin")
48
+ render action: "new"
49
+ end
50
+ end
51
+ end
52
+
53
+ def update
54
+ enforce_permission_to(:edit, :solution, solution:)
55
+ @form = form(Decidim::Solutions::Admin::SolutionsForm).from_params(params.merge({ author_id: current_user.id }))
56
+
57
+ Decidim::Solutions::Admin::UpdateSolution.call(@form, solution) do
58
+ on(:ok) do |_solution|
59
+ flash[:notice] = t("solutions.update.success", scope: "decidim.solutions.admin")
60
+ redirect_to solutions_path(assembly_slug: -1, component_id: -1)
61
+ end
62
+
63
+ on(:invalid) do
64
+ flash.now[:alert] = t("solutions.update.error", scope: "decidim.solutions.admin")
65
+ render :edit
66
+ end
67
+ end
68
+ end
69
+
70
+ def destroy
71
+ enforce_permission_to(:destroy, :solution, solution:)
72
+
73
+ Decidim::Solutions::Admin::DestroySolution.call(solution, current_user) do
74
+ on(:ok) do
75
+ flash[:notice] = I18n.t("solutions.destroy.success", scope: "decidim.solutions.admin")
76
+ redirect_to solutions_path(assembly_slug: -1, component_id: -1)
77
+ end
78
+
79
+ on(:invalid) do
80
+ flash.now[:alert] = t("solutions.destroy.error", scope: "decidim.solutions.admin")
81
+ redirect_to solutions_path(assembly_slug: -1, component_id: -1)
82
+ end
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def collection
89
+ @collection ||= Solution.where(component: current_component)
90
+ end
91
+
92
+ def solutions
93
+ @solutions ||= collection.page(params[:page]).per(10)
94
+ end
95
+
96
+ def solution
97
+ @solution ||= collection.find(params[:id])
98
+ end
99
+
100
+ def form_presenter
101
+ @form_presenter ||= present(@form, presenter_class: Decidim::Solutions::SolutionPresenter)
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Solutions
5
+ # This controller is the abstract class from which all other controllers of
6
+ # this engine inherit.
7
+ #
8
+ # Note that it inherits from `Decidim::Components::BaseController`, which
9
+ # override its layout and provide all kinds of useful methods.
10
+ class ApplicationController < Decidim::Components::BaseController
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Solutions
5
+ # Controller that allows browsing solutions.
6
+ #
7
+ class SolutionsController < Decidim::Solutions::ApplicationController
8
+ include Decidim::ApplicationHelper
9
+ include FilterResource
10
+ include Paginable
11
+ include OrderableSolutions
12
+ include FormFactory
13
+ include WithSdgs
14
+ include WithDefaultFilters
15
+
16
+ helper Decidim::CheckBoxesTreeHelper
17
+ helper Decidim::Sdgs::SdgsHelper
18
+ helper Decidim::ShowFiltersHelper
19
+ helper SolutionsHelper
20
+ helper Decidim::Challenges::ApplicationHelper
21
+
22
+ helper_method :solutions, :form_presenter, :has_sdgs?, :has_problem?, :default_filter_scope_params
23
+
24
+ def index
25
+ @solutions = search.result
26
+ @solutions = reorder(@solutions)
27
+ @solutions = paginate(@solutions)
28
+ end
29
+
30
+ def show
31
+ @solution = solution
32
+ if @solution.problem.present?
33
+ @sectorial_scope = sectorial_scope
34
+ @technological_scope = technological_scope
35
+ end
36
+ @sdg_index = sdg_index if @solution.problem.present? || @solution.challenge.present?
37
+ @challenge_scope = challenge_scope
38
+ end
39
+
40
+ def new
41
+ enforce_permission_to :create, :solution
42
+ @form = form(Decidim::Solutions::SolutionsForm).instance
43
+ end
44
+
45
+ def create
46
+ enforce_permission_to :create, :solution
47
+ @form = form(Decidim::Solutions::SolutionsForm).from_params(params.merge({ author_id: current_user.id }))
48
+
49
+ Decidim::Solutions::CreateSolution.call(@form) do
50
+ on(:ok) do
51
+ flash[:notice] = I18n.t("solutions.create.success", scope: "decidim.solutions")
52
+ redirect_to solutions_path
53
+ end
54
+
55
+ on(:invalid) do
56
+ flash.now[:alert] = I18n.t("solutions.create.error", scope: "decidim.solutions")
57
+ render action: "new"
58
+ end
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def default_filter_params
65
+ {
66
+ search_text_cont: "",
67
+ with_any_territorial_scope: default_filter_scope_params,
68
+ with_any_sdgs_codes: [],
69
+ related_to: "",
70
+ }
71
+ end
72
+
73
+ def solutions
74
+ @solutions ||= reorder(paginate(search.result))
75
+ end
76
+
77
+ def solution
78
+ @solution ||= Solution.find(params[:id])
79
+ end
80
+
81
+ def sdg_index
82
+ challenge = @solution.problem ? @solution.problem.challenge : @solution.challenge
83
+ @sdg_index ||= challenge.sdg_code ? (1 + Decidim::Sdgs::Sdg.index_from_code(challenge.sdg_code.to_sym)).to_s.rjust(2, "0") : nil
84
+ end
85
+
86
+ def challenge_scope
87
+ @challenge_scope ||= if @solution.problem.present?
88
+ current_organization.scopes.find_by(id: @solution.problem.challenge.decidim_scope_id)
89
+ else
90
+ current_organization.scopes.find_by(id: @solution.challenge&.decidim_scope_id)
91
+ end
92
+ end
93
+
94
+ def sectorial_scope
95
+ @sectorial_scope ||= current_organization.scopes.find_by(id: @solution.problem.decidim_sectorial_scope_id)
96
+ end
97
+
98
+ def technological_scope
99
+ @technological_scope ||= current_organization.scopes.find_by(id: @solution.problem.decidim_technological_scope_id)
100
+ end
101
+
102
+ def search_collection
103
+ ::Decidim::Solutions::Solution.where(component: current_component).published
104
+ end
105
+
106
+ def form_presenter
107
+ @form_presenter ||= present(@form, presenter_class: Decidim::Solutions::SolutionPresenter)
108
+ end
109
+
110
+ def has_problem?
111
+ current_participatory_space.components.where(manifest_name: "problems").present? && @solution.problem.present?
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Challenges
5
+ module Admin
6
+ # This class holds a Form to update challenges surveys from Decidim's admin panel.
7
+ class ChallengeSurveysForm < Decidim::Form
8
+ mimic :challenge
9
+
10
+ attribute :survey_enabled, Boolean
11
+
12
+ # We need this method to ensure the form object will always have an ID,
13
+ # and thus its `to_param` method will always return a significant value.
14
+ # If we remove this method, get an error onn the `update` action and try
15
+ # to resubmit the form, the form will not hold an ID, so the `to_param`
16
+ # method will return an empty string and Rails will treat this as a
17
+ # `create` action, thus raising an error since this action is not defined
18
+ # for the controller we're using.
19
+ #
20
+ # TL;DR: if you remove this method, we'll get errors, so don't.
21
+ def id
22
+ return super if super.present?
23
+
24
+ challenge.id
25
+ end
26
+
27
+ private
28
+
29
+ def challenge
30
+ @challenge ||= context[:challenge]
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Challenges
5
+ module Admin
6
+ # A form object used to create challenges from the admin dashboard.
7
+ #
8
+ class ChallengesForm < Decidim::Form
9
+ include TranslatableAttributes
10
+ include Decidim::Sdgs::SdgsHelper
11
+ include Decidim::HasUploadValidations
12
+
13
+ mimic :challenge
14
+
15
+ translatable_attribute :title, String do |field, _locale|
16
+ validates field, length: { in: 5..150 }, if: proc { |resource| resource.send(field).present? }
17
+ end
18
+ translatable_attribute :local_description, String
19
+ translatable_attribute :global_description, String
20
+
21
+ attribute :decidim_component_id, Integer
22
+ attribute :decidim_scope_id, Integer
23
+ attribute :tags, String
24
+ attribute :sdg_code, String
25
+ attribute :state, Integer
26
+ attribute :end_date, Decidim::Attributes::LocalizedDate
27
+ attribute :start_date, Decidim::Attributes::LocalizedDate
28
+ attribute :coordinating_entities, String
29
+ attribute :collaborating_entities, String
30
+
31
+ attribute :card_image
32
+ attribute :remove_card_image, Boolean, default: false
33
+
34
+ validates :title, :local_description, :global_description, translatable_presence: true
35
+ validates :scope, presence: true, if: ->(form) { form.decidim_scope_id.present? }
36
+ validate :valid_state
37
+
38
+ validates :start_date, presence: true, date: { before_or_equal_to: :end_date }
39
+ validates :end_date, presence: true, date: { after_or_equal_to: :start_date }
40
+
41
+ validates :card_image,
42
+ presence: false,
43
+ passthru: { to: Decidim::Attachment }
44
+
45
+ alias organization current_organization
46
+
47
+ def select_states_collection
48
+ Decidim::Challenges::Challenge::VALID_STATES.map.with_index do |state, idx|
49
+ [I18n.t(state, scope: "decidim.challenges.states"), idx]
50
+ end
51
+ end
52
+
53
+ def select_sdg_collection
54
+ Decidim::Sdgs::Sdg::SDGS.map do |sdg_code|
55
+ [I18n.t("#{sdg_code}.objectives.subtitle", scope: "decidim.components.sdgs"), sdg_code]
56
+ end
57
+ end
58
+
59
+ # Finds the Scope from the given decidim_scope_id, uses participatory space scope if missing.
60
+ #
61
+ # Returns a Decidim::Scope
62
+ def scope
63
+ @scope ||= current_organization.scopes.find_by(id: decidim_scope_id)
64
+ end
65
+
66
+ def map_model(model); end
67
+
68
+ private
69
+
70
+ def valid_state
71
+ return if state && Decidim::Challenges::Challenge::VALID_STATES[state].present?
72
+
73
+ errors.add(:state, :invalid)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Problems
5
+ module Admin
6
+ # A form object used to create problems from the admin dashboard.
7
+ #
8
+ class ProblemsForm < Decidim::Form
9
+ include TranslatableAttributes
10
+
11
+ mimic :problem
12
+
13
+ translatable_attribute :title, String do |field, _locale|
14
+ validates field, length: { in: 5..150 }, if: proc { |resource| resource.send(field).present? }
15
+ end
16
+ translatable_attribute :description, String
17
+
18
+ attribute :decidim_challenges_challenge_id, Integer
19
+ attribute :decidim_sectorial_scope_id, Integer
20
+ attribute :decidim_technological_scope_id, Integer
21
+ attribute :tags, String
22
+ attribute :causes, String
23
+ attribute :groups_affected, String
24
+ attribute :state, Integer
25
+ attribute :end_date, Decidim::Attributes::LocalizedDate
26
+ attribute :start_date, Decidim::Attributes::LocalizedDate
27
+ attribute :proposing_entities, String
28
+ attribute :collaborating_entities, String
29
+
30
+ validates :title, :description, translatable_presence: true
31
+ validates :sectorial_scope, presence: true, if: ->(form) { form.decidim_sectorial_scope_id.present? }
32
+ validates :technological_scope, presence: true, if: ->(form) { form.decidim_technological_scope_id.present? }
33
+ validate :valid_state
34
+ validates :decidim_challenges_challenge_id, presence: true
35
+
36
+ validates :start_date, presence: true, date: { before_or_equal_to: :end_date }
37
+ validates :end_date, presence: true, date: { after_or_equal_to: :start_date }
38
+
39
+ alias organization current_organization
40
+
41
+ # Return a problem's valid states list
42
+ def select_states_collection
43
+ Decidim::Problems::Problem::VALID_STATES.map.with_index do |state, idx|
44
+ [I18n.t(state, scope: "decidim.problems.states"), idx]
45
+ end
46
+ end
47
+
48
+ # Return a challenge's list filtered by participatory's space component
49
+ def select_challenge_collection
50
+ participatory_space = Decidim::Component.find(current_component.id).participatory_space
51
+ challenge_component = Decidim::Component.where(participatory_space:).where(manifest_name: "challenges")
52
+ Decidim::Challenges::Challenge.where(component: challenge_component).map do |ch|
53
+ [translated_attribute(ch.title), ch.id]
54
+ end
55
+ end
56
+
57
+ # Finds the Sectorial Scope from the given decidim_sectorial_scope_id
58
+ #
59
+ # Returns a Decidim::Scope
60
+ def sectorial_scope
61
+ @sectorial_scope ||= current_organization.scopes.find_by(id: decidim_sectorial_scope_id)
62
+ end
63
+
64
+ # Finds the Technological Scope from the given decidim_technological_scope_id
65
+ #
66
+ # Returns a Decidim::Scope
67
+ def technological_scope
68
+ @technological_scope ||= current_organization.scopes.find_by(id: decidim_technological_scope_id)
69
+ end
70
+
71
+ # Finds the Challenge from the given decidim_challenges_challenge_id
72
+ #
73
+ # Returns a Decidim::Challenges::Challenge
74
+ def challenge
75
+ @challenge ||= @decidim_challenges_challenge_id ? Decidim::Challenges::Challenge.find(@decidim_challenges_challenge_id) : false
76
+ end
77
+
78
+ def map_model(model); end
79
+
80
+ private
81
+
82
+ def valid_state
83
+ return if state.present? && Decidim::Problems::Problem::VALID_STATES[state].present?
84
+
85
+ errors.add(:state, :invalid)
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Solutions
5
+ module Admin
6
+ # A form object used to create solutions from the admin dashboard.
7
+ #
8
+ class SolutionsForm < Decidim::Form
9
+ include TranslatableAttributes
10
+
11
+ mimic :solution
12
+
13
+ translatable_attribute :title, String do |field, _locale|
14
+ validates field, length: { in: 5..150 }, if: proc { |resource| resource.send(field).present? }
15
+ end
16
+ translatable_attribute :description, String
17
+
18
+ attribute :decidim_problems_problem_id, Integer
19
+ attribute :decidim_challenges_challenge_id, Integer
20
+ attribute :author_id, Integer
21
+ attribute :tags, String
22
+ translatable_attribute :objectives, String
23
+ translatable_attribute :indicators, String
24
+ translatable_attribute :beneficiaries, String
25
+ translatable_attribute :requirements, String
26
+ translatable_attribute :financing_type, String
27
+
28
+ validates :title, :description, translatable_presence: true
29
+ validates :decidim_challenges_challenge_id, presence: false
30
+ validates :decidim_problems_problem_id, presence: false
31
+ validates :author_id, presence: true
32
+
33
+ alias organization current_organization
34
+
35
+ # Return a problem's list filtered by participatory's space component
36
+ def select_problem_collection
37
+ participatory_space = Decidim::Component.find(current_component.id).participatory_space
38
+ problem_component = Decidim::Component.where(participatory_space:).where(manifest_name: "problems")
39
+ Decidim::Problems::Problem.where(component: problem_component).map do |p|
40
+ [translated_attribute(p.title), p.id]
41
+ end
42
+ end
43
+
44
+ # Return a challenges's list filtered by participatory's space component
45
+ def select_challenge_collection
46
+ participatory_space = Decidim::Component.find(current_component.id).participatory_space
47
+ challenge_component = Decidim::Component.where(participatory_space:).where(manifest_name: "challenges")
48
+ Decidim::Challenges::Challenge.where(component: challenge_component).map do |p|
49
+ [translated_attribute(p.title), p.id]
50
+ end
51
+ end
52
+
53
+ # Finds the Problem from the given decidim_problems_problem_id
54
+ #
55
+ # Returns a Decidim::Problems::Problem
56
+ def problem
57
+ @problem ||= decidim_problems_problem_id.present? ? Decidim::Problems::Problem.find(decidim_problems_problem_id) : false
58
+ end
59
+
60
+ # Finds the Challenge from the given decidim_challenges_challenge_id
61
+ #
62
+ # Returns a Decidim::Challenges::Challenge
63
+ def challenge
64
+ @challenge ||= @problem.present? ? Decidim::Challenges::Challenge.find(@problem.challenge.id) : false
65
+ end
66
+
67
+ def map_model(model); end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Solutions
5
+ # A form object to be used when public users want to create a solution.
6
+ #
7
+ class SolutionsForm < Decidim::Form
8
+ include Decidim::AttachmentAttributes
9
+ include Decidim::HasUploadValidations
10
+
11
+ mimic :solution
12
+
13
+ attribute :title, String
14
+ attribute :description, Decidim::Attributes::CleanString
15
+ attribute :project_status, String
16
+ attribute :project_url, String
17
+ attribute :coordinating_entity, String
18
+ attribute :decidim_challenges_challenge_id, Integer
19
+ attribute :decidim_problems_problem_id, Integer
20
+ attribute :author_id, Integer
21
+ attribute :attachment, AttachmentForm
22
+
23
+ attachments_attribute :documents
24
+
25
+ validates :title, :description, presence: true, etiquette: true
26
+ validates :project_status, :coordinating_entity, presence: true
27
+ validates :decidim_challenges_challenge_id, :author_id, presence: true
28
+ validates :decidim_problems_problem_id, presence: false
29
+
30
+ def map_model(model)
31
+ self.title = translated_attribute(model.title)
32
+ self.description = translated_attribute(model.description)
33
+
34
+ self.documents = model.attachments
35
+ return unless model.categorization
36
+ end
37
+
38
+ # Finds the Challenge from the given decidim_challenges_challenge_id
39
+ #
40
+ # Returns a Decidim::Challenges::Challenge
41
+ def challenge
42
+ @challenge ||= @problem.present? ? Decidim::Challenges::Challenge.find(@problem.challenge.id) : Decidim::Challenges::Challenge.find(@decidim_challenges_challenge_id)
43
+ end
44
+
45
+ def author
46
+ Decidim::User.find(author_id)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Challenges
5
+ # Custom helpers, scoped to the challenges engine.
6
+ #
7
+ module ApplicationHelper
8
+ def component_name
9
+ i18n_key = "decidim.components.challenges.name"
10
+ (defined?(current_component) && translated_attribute(current_component&.name).presence) || t(i18n_key)
11
+ end
12
+
13
+ def filter_custom_state_values
14
+ Decidim::CheckBoxesTreeHelper::TreeNode.new(
15
+ Decidim::CheckBoxesTreeHelper::TreePoint.new("", t("decidim.challenges.challenges_helper.filter_state_values.all")),
16
+ [
17
+ Decidim::CheckBoxesTreeHelper::TreePoint.new("proposal", t("decidim.challenges.challenges_helper.filter_state_values.proposal")),
18
+ Decidim::CheckBoxesTreeHelper::TreePoint.new("execution", t("decidim.challenges.challenges_helper.filter_state_values.execution")),
19
+ Decidim::CheckBoxesTreeHelper::TreePoint.new("finished", t("decidim.challenges.challenges_helper.filter_state_values.finished")),
20
+ ]
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Challenges
5
+ # Custom helpers, scoped to the challenges engine.
6
+ #
7
+ module ChallengeCellsHelper
8
+ include Decidim::Challenges::ApplicationHelper
9
+ include Decidim::Challenges::Engine.routes.url_helpers
10
+ include Decidim::LayoutHelper
11
+ include Decidim::ApplicationHelper
12
+ include Decidim::TranslationsHelper
13
+ include Decidim::ResourceReferenceHelper
14
+ include Decidim::TranslatableAttributes
15
+ include Decidim::CardHelper
16
+ include WithSdgs
17
+
18
+ delegate :title, :state, :published_state?, :withdrawn?, :amendable?, :emendation?, to: :model
19
+
20
+ def has_actions?
21
+ return context[:has_actions] if context[:has_actions].present?
22
+
23
+ challenges_controller? && index_action? && current_settings.votes_enabled? && !model.draft?
24
+ end
25
+
26
+ def has_footer?
27
+ return context[:has_footer] if context[:has_footer].present?
28
+
29
+ challenges_controller? && index_action? && current_settings.votes_enabled? && !model.draft?
30
+ end
31
+
32
+ def challenges_controller?
33
+ context[:controller].instance_of?(::Decidim::Challenges::ChallengesController)
34
+ end
35
+
36
+ def index_action?
37
+ context[:controller].action_name == "index"
38
+ end
39
+
40
+ def current_settings
41
+ model.component.current_settings
42
+ end
43
+
44
+ def component_settings
45
+ model.component.settings
46
+ end
47
+
48
+ def current_component
49
+ model.component
50
+ end
51
+
52
+ def from_context
53
+ options[:from]
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Challenges
5
+ # Custom helpers, scoped to the challenges engine.
6
+ #
7
+ module ChallengesHelper
8
+ def filter_sections
9
+ items = []
10
+ items.append(method: :with_any_state, collection: filter_custom_state_values, label_scope: "decidim.shared.filters", id: "state")
11
+ items.append(method: :related_to, collection: linked_classes_filter_values_for(Decidim::Challenges::Challenge), label_scope: "decidim.shared.filters", id: "related_to",
12
+ type: :radio_buttons)
13
+ if current_participatory_space.has_subscopes?
14
+ items.append(method: :with_any_scope, collection: filter_global_scopes_values, label_scope: "decidim.shared.filters",
15
+ id: "scope")
16
+ end
17
+
18
+ items.reject { |item| item[:collection].blank? }
19
+ end
20
+
21
+ def challenge_associated_solutions(challenge)
22
+ solutions_component = Decidim::Component.find_by(participatory_space: challenge.participatory_space, manifest_name: "solutions")
23
+ return [] unless solutions_component&.published?
24
+
25
+ problems_component = Decidim::Component.find_by(participatory_space: challenge.participatory_space, manifest_name: "problems")
26
+ if problems_component&.published?
27
+ challenge.problems.published.map { |problem| problem.solutions.published }.flatten
28
+ else
29
+ challenge.solutions.published
30
+ end
31
+ end
32
+
33
+ def truncate_description(description)
34
+ translated_description = raw translated_attribute description
35
+ decidim_sanitize(html_truncate(translated_description, length: 200))
36
+ end
37
+ end
38
+ end
39
+ end