decidim-decidim_awesome 0.10.1 → 0.10.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -1
  3. data/README.md +134 -15
  4. data/app/cells/concerns/decidim/decidim_awesome/proposal_m_cell_override.rb +4 -24
  5. data/app/cells/decidim/decidim_awesome/content_blocks/map_cell.rb +9 -5
  6. data/app/commands/concerns/decidim/decidim_awesome/admin/needs_constraint_helpers.rb +1 -1
  7. data/app/commands/concerns/decidim/decidim_awesome/proposals/admin/update_proposal_override.rb +31 -0
  8. data/app/commands/concerns/decidim/decidim_awesome/proposals/create_collaborative_draft_override.rb +27 -0
  9. data/app/commands/concerns/decidim/decidim_awesome/proposals/create_proposal_override.rb +27 -0
  10. data/app/commands/concerns/decidim/decidim_awesome/proposals/update_collaborative_draft_override.rb +27 -0
  11. data/app/commands/concerns/decidim/decidim_awesome/proposals/update_proposal_override.rb +26 -0
  12. data/app/commands/decidim/decidim_awesome/admin/create_proposal_custom_field.rb +4 -3
  13. data/app/commands/decidim/decidim_awesome/admin/destroy_proposal_custom_field.rb +6 -3
  14. data/app/controllers/concerns/decidim/decidim_awesome/admin/maintenance_context.rb +43 -0
  15. data/app/controllers/concerns/decidim/decidim_awesome/admin_accountability/admin/filterable_helper.rb +3 -2
  16. data/app/controllers/concerns/decidim/decidim_awesome/limit_pending_amendments.rb +35 -0
  17. data/app/controllers/concerns/decidim/decidim_awesome/proposals/orderable_override.rb +9 -22
  18. data/app/controllers/decidim/decidim_awesome/admin/admin_accountability_controller.rb +7 -7
  19. data/app/controllers/decidim/decidim_awesome/admin/application_controller.rb +2 -0
  20. data/app/controllers/decidim/decidim_awesome/admin/checks_controller.rb +7 -3
  21. data/app/controllers/decidim/decidim_awesome/admin/config_controller.rb +8 -5
  22. data/app/controllers/decidim/decidim_awesome/admin/constraints_controller.rb +3 -1
  23. data/app/controllers/decidim/decidim_awesome/admin/custom_redirects_controller.rb +0 -2
  24. data/app/controllers/decidim/decidim_awesome/admin/maintenance_controller.rb +76 -0
  25. data/app/controllers/decidim/decidim_awesome/admin/menu_hacks_controller.rb +0 -2
  26. data/app/controllers/decidim/decidim_awesome/admin/proposal_custom_fields_controller.rb +12 -4
  27. data/app/controllers/decidim/decidim_awesome/iframe_component/iframe_controller.rb +8 -1
  28. data/app/forms/concerns/decidim/decidim_awesome/proposals/proposal_form_override.rb +21 -0
  29. data/app/forms/{decidim → concerns/decidim}/decidim_awesome/proposals/proposal_wizard_create_step_form_override.rb +1 -0
  30. data/app/forms/decidim/decidim_awesome/admin/config_form.rb +35 -9
  31. data/app/helpers/{decidim → concerns/decidim}/decidim_awesome/amendments_helper_override.rb +17 -7
  32. data/app/helpers/concerns/decidim/decidim_awesome/proposals/application_helper_override.rb +126 -0
  33. data/app/helpers/decidim/decidim_awesome/admin/config_constraints_helpers.rb +5 -26
  34. data/app/jobs/decidim/decidim_awesome/destroy_private_data_job.rb +22 -0
  35. data/app/models/concerns/decidim/decidim_awesome/has_proposal_extra_fields.rb +38 -9
  36. data/app/models/decidim/decidim_awesome/paper_trail_version.rb +5 -1
  37. data/app/models/decidim/decidim_awesome/proposal_extra_field.rb +35 -1
  38. data/app/overrides/decidim/proposals/admin/proposals/show/add_private_body.html.erb.deface +7 -0
  39. data/app/overrides/decidim/proposals/admin/proposals/show/replace_body.html.erb.deface +5 -0
  40. data/app/overrides/decidim/proposals/proposals/show/limit_amendments_modal.html.erb.deface +5 -0
  41. data/app/overrides/layouts/decidim/admin/_header/replace_scripts.html.erb.deface +3 -0
  42. data/app/packs/entrypoints/decidim_decidim_awesome_map.scss +1 -1
  43. data/app/packs/src/decidim/decidim_awesome/admin/auto_edit.js +5 -3
  44. data/app/packs/src/decidim/decidim_awesome/admin/constraints.js +1 -1
  45. data/app/packs/src/decidim/decidim_awesome/admin/custom_fields_builder.js +5 -4
  46. data/app/packs/src/decidim/decidim_awesome/amendments/show_modal_on_limits.js +30 -0
  47. data/app/packs/src/decidim/decidim_awesome/awesome_application.js +1 -0
  48. data/app/packs/src/decidim/decidim_awesome/editors/editor.js +1 -6
  49. data/app/packs/src/decidim/decidim_awesome/editors/tabs_focus.js +18 -9
  50. data/app/packs/src/decidim/decidim_awesome/forms/custom_fields_renderer.js +35 -26
  51. data/app/packs/src/decidim/decidim_awesome/proposals/custom_fields.js +31 -15
  52. data/app/packs/stylesheets/decidim/decidim_awesome/admin/codemirror.scss +12 -7
  53. data/app/packs/stylesheets/decidim/decidim_awesome/admin/constraints.scss +69 -25
  54. data/app/packs/stylesheets/decidim/decidim_awesome/admin/custom_fields.scss +34 -27
  55. data/app/packs/stylesheets/decidim/decidim_awesome/admin/user_picker.scss +2 -2
  56. data/app/packs/stylesheets/decidim/decidim_awesome/awesome_admin.scss +3 -3
  57. data/app/packs/stylesheets/decidim/decidim_awesome/awesome_admin_global.scss +28 -0
  58. data/app/packs/stylesheets/decidim/decidim_awesome/awesome_application.scss +3 -2
  59. data/app/packs/stylesheets/decidim/decidim_awesome/awesome_map/map.scss +15 -15
  60. data/app/packs/stylesheets/decidim/decidim_awesome/editors/quill_editor.scss +3 -3
  61. data/app/packs/stylesheets/decidim/decidim_awesome/forms/autosave.scss +3 -3
  62. data/app/packs/stylesheets/decidim/decidim_awesome/forms/custom_fields.scss +187 -0
  63. data/app/packs/stylesheets/decidim/decidim_awesome/shared/spinner.scss +47 -0
  64. data/app/packs/stylesheets/decidim/decidim_awesome/voting/voting_cards.scss +7 -7
  65. data/app/permissions/decidim/decidim_awesome/admin/permissions.rb +14 -3
  66. data/app/presenters/concerns/decidim/decidim_awesome/proposals/proposal_presenter_override.rb +20 -0
  67. data/app/presenters/decidim/decidim_awesome/admin_log/component_presenter_override.rb +30 -0
  68. data/app/presenters/decidim/decidim_awesome/private_data_presenter.rb +70 -0
  69. data/app/queries/decidim/decidim_awesome/private_data_finder.rb +19 -0
  70. data/app/serializers/concerns/decidim/decidim_awesome/proposal_serializer_override.rb +1 -0
  71. data/app/serializers/concerns/decidim/decidim_awesome/proposals/proposal_serializer_methods.rb +72 -0
  72. data/app/serializers/concerns/decidim/decidim_awesome/proposals/proposal_serializer_override.rb +38 -0
  73. data/app/serializers/decidim/decidim_awesome/proposals/private_proposal_serializer.rb +42 -0
  74. data/app/types/concerns/decidim/decidim_awesome/add_proposal_type_custom_fields.rb +59 -0
  75. data/app/types/concerns/decidim/decidim_awesome/{proposal_type_override.rb → add_proposal_type_vote_weights.rb} +3 -1
  76. data/app/views/decidim/decidim_awesome/admin/checks/index.html.erb +52 -48
  77. data/app/views/decidim/decidim_awesome/admin/config/_autoedit_box_label.html.erb +7 -2
  78. data/app/views/decidim/decidim_awesome/admin/config/_constraints.html.erb +16 -8
  79. data/app/views/decidim/decidim_awesome/admin/config/_form_admins.html.erb +1 -1
  80. data/app/views/decidim/decidim_awesome/admin/config/_form_editors.html.erb +12 -16
  81. data/app/views/decidim/decidim_awesome/admin/config/_form_proposal_custom_fields.html.erb +35 -15
  82. data/app/views/decidim/decidim_awesome/admin/config/_form_proposal_private_custom_fields.html.erb +1 -0
  83. data/app/views/decidim/decidim_awesome/admin/config/_form_proposals.html.erb +22 -22
  84. data/app/views/decidim/decidim_awesome/admin/config/_form_styles.html.erb +1 -1
  85. data/app/views/decidim/decidim_awesome/admin/config/show.html.erb +1 -1
  86. data/app/views/decidim/decidim_awesome/admin/custom_redirects/index.html.erb +14 -13
  87. data/app/views/decidim/decidim_awesome/admin/maintenance/_private_data.html.erb +44 -0
  88. data/app/views/decidim/decidim_awesome/admin/maintenance/show.html.erb +44 -0
  89. data/app/views/decidim/decidim_awesome/admin/menu_hacks/index.html.erb +28 -29
  90. data/app/views/decidim/decidim_awesome/admin/proposals/_editor.html.erb +8 -5
  91. data/app/views/decidim/decidim_awesome/admin/proposals/_private_body.html.erb +20 -0
  92. data/app/views/decidim/decidim_awesome/amendments/_modal.html.erb +16 -0
  93. data/app/views/decidim/decidim_awesome/custom_fields/_form_render.html.erb +10 -2
  94. data/app/views/layouts/decidim/decidim_awesome/admin/_base.html.erb +21 -0
  95. data/app/views/layouts/decidim/decidim_awesome/admin/application.html.erb +1 -73
  96. data/app/views/layouts/decidim/decidim_awesome/admin/maintenance.html.erb +19 -0
  97. data/config/i18n-tasks.yml +22 -3
  98. data/config/locales/ca.yml +97 -9
  99. data/config/locales/cs.yml +109 -6
  100. data/config/locales/de.yml +92 -6
  101. data/config/locales/en.yml +102 -8
  102. data/config/locales/es.yml +96 -8
  103. data/config/locales/eu.yml +15 -1
  104. data/config/locales/fr.yml +94 -6
  105. data/config/locales/hu.yml +53 -4
  106. data/config/locales/it.yml +16 -6
  107. data/config/locales/ja.yml +94 -6
  108. data/config/locales/lt.yml +0 -2
  109. data/config/locales/nl.yml +9 -4
  110. data/config/locales/pt-BR.yml +16 -7
  111. data/config/locales/ro-RO.yml +11 -2
  112. data/config/locales/sv.yml +17 -6
  113. data/db/migrate/20240531224204_add_decidim_awesome_proposal_private_fields.rb +29 -0
  114. data/db/migrate/20240729164227_add_decidim_awesome_proposal_private_fields_date.rb +20 -0
  115. data/lib/decidim/decidim_awesome/admin_engine.rb +22 -6
  116. data/lib/decidim/decidim_awesome/api/types/localized_custom_fields_type.rb +22 -0
  117. data/lib/decidim/decidim_awesome/api/types/translated_custom_fields_type.rb +52 -0
  118. data/lib/decidim/decidim_awesome/awesome.rb +45 -8
  119. data/lib/decidim/decidim_awesome/awesome_helpers.rb +5 -1
  120. data/lib/decidim/decidim_awesome/checksums.yml +23 -0
  121. data/lib/decidim/decidim_awesome/custom_fields.rb +8 -0
  122. data/lib/decidim/decidim_awesome/engine.rb +143 -52
  123. data/lib/decidim/decidim_awesome/lock.rb +47 -0
  124. data/lib/decidim/decidim_awesome/menu.rb +146 -0
  125. data/lib/decidim/decidim_awesome/test/initializer.rb +4 -1
  126. data/lib/decidim/decidim_awesome/test/shared_examples/{box_label_editor.rb → box_label_editor_examples.rb} +1 -1
  127. data/lib/decidim/decidim_awesome/test/shared_examples/config_examples.rb +20 -2
  128. data/lib/decidim/decidim_awesome/test/shared_examples/custom_fields_examples.rb +155 -0
  129. data/lib/decidim/decidim_awesome/test/shared_examples/editor_examples.rb +24 -0
  130. data/lib/decidim/decidim_awesome/test/shared_examples/menu_hack_contexts.rb +2 -2
  131. data/lib/decidim/decidim_awesome/test/shared_examples/scoped_admins_examples.rb +3 -5
  132. data/lib/decidim/decidim_awesome/test/shared_examples/summary_examples.rb +78 -12
  133. data/lib/decidim/decidim_awesome/version.rb +1 -1
  134. data/package.json +3 -3
  135. metadata +52 -14
  136. data/app/helpers/decidim/decidim_awesome/proposals/application_helper_override.rb +0 -78
  137. data/app/overrides/layouts/decidim/admin/_application/add_intergram.html.erb.deface +0 -5
  138. /data/app/presenters/{decidim → concerns/decidim}/decidim_awesome/menu_item_presenter_override.rb +0 -0
  139. /data/app/presenters/{decidim → concerns/decidim}/decidim_awesome/menu_presenter_override.rb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 57d57565e1a7e62042eeb2bdd7a80d4679e68cac296cc1162a4bf86333ea2059
4
- data.tar.gz: db65b2c7349f9970c1c07bd8dc67a0c0a35c6f2dd126f65848e4f49033a72bf8
3
+ metadata.gz: 2cf1da76fd4803091a1a436c61708acfffe4ce1766227e0dcdef5a03d43adb00
4
+ data.tar.gz: f6dbf35fc450c203eea9db332372c26432fb171d9a057fbdc44bd1725d319963
5
5
  SHA512:
6
- metadata.gz: 20a186cf440f3cba697dca7ae3878ebf60843696d22c609527873768666c83790915881b0bb887fa39b2c06b46f388edd909cd9a6b319d82fde3ac8c7cbacb24
7
- data.tar.gz: e67a6fb46eb983d3f9f2204017407316f6afe38786a52950e73b40f23fad5c062e75b5bbb4329fadecbf0bc57d87567d454cfa3c977ee363b704689af598eb85
6
+ metadata.gz: '01794da0b71c3719eab36c0c7a7107bd4873fa08bc78d78d61723cc6b238ad68eaed5bd281729c652e50c1afa0acdc0af2a47cbd1f2a0dea4fa7d40856dd5f5e'
7
+ data.tar.gz: 519112bb3fd8422b23c2fb36330e80ee18a2b5d3dc08f2c27bddf5c4e2be53e619cfc056a101fe8c37e7a903a160c4e57c0d9023c8919457d9cceaa94cfa1559
data/CHANGELOG.md CHANGED
@@ -1,6 +1,32 @@
1
1
  CHANGELOG
2
2
  =========
3
3
 
4
+ v0.10.3
5
+ ------
6
+
7
+ Compatibility:
8
+ - Decidim v0.27.4
9
+
10
+ Features:
11
+ - Added Private Custom Fields feature
12
+ - Added GraphQL types for weighted voting in the API
13
+ - Added GraphQL types for custom fields in the API
14
+ - Adds parsed information about custom fields in the Proposals export
15
+ - Adds parsed information bout private custom fields when admins exports private data
16
+ - Adds a maintenance menu with tools to remove old private
17
+ - SQL vulnerability fix for admin accountability
18
+
19
+ v0.10.2
20
+ ------
21
+
22
+ Compatibility:
23
+ - Decidim v0.27.4
24
+ - Decidim v0.26.8
25
+
26
+ Features:
27
+ - Added translations
28
+ - Fix deface override updating <body> tag in the admin
29
+
4
30
  v0.10.1
5
31
  ------
6
32
 
@@ -45,7 +71,7 @@ Compatibility:
45
71
 
46
72
  Features:
47
73
  - Fixes for the menu hacker
48
-
74
+
49
75
  v0.9.1
50
76
  ------
51
77
 
data/README.md CHANGED
@@ -121,12 +121,77 @@ Technically, the content is stored in the database as an XML document compatible
121
121
  ![Custom fields screenshot](examples/custom-fields-2.png)
122
122
  ![Custom fields screenshot](examples/custom-fields-1.gif)
123
123
 
124
+ Note that the custom fields are build using the jQuery library [formBuilder](https://formbuilder.online). This package is included in Decidim Awesome but the i18n translations are not. By default they are dynamically downloaded from the CDN https://cdn.jsdelivr.net/npm/formbuilder-languages@1.1.0/.
125
+ If you wish to provide an alternative place for those files, you can configure the variable `form_builder_langs_location` in an initializer:
126
+
127
+ ```ruby
128
+ # config/initializers/awesome_defaults.rb
129
+
130
+ # A URL where to obtain the translations for the FormBuilder component
131
+ # you can a custom place if you are worried about the CDN geolocation
132
+ # Download them from https://github.com/kevinchappell/formBuilder-languages
133
+
134
+ # For instance, copy them to your /public/fb_locales/ directory and set the path here:
135
+ Decidim::DecidimAwesome.configure do |config|
136
+ config.form_builder_langs_location = "/fb_locales/"
137
+ end
138
+ ```
139
+
140
+ ##### 12.1. GraphQL types for custom fields
141
+
142
+ Custom fields are displayed in the GaphQL API according to their definition in a formatted array of objects in the attribute `bodyFields`.
143
+
144
+ A query to extract this information could look like this (see that the original `body` is also available):
145
+
146
+ ```graphql
147
+ {
148
+ component(id: 999) {
149
+ ... on Proposals {
150
+ proposals {
151
+ edges {
152
+ node {
153
+ id
154
+ bodyFields {
155
+ locales
156
+ translation(locale: "en")
157
+ translations {
158
+ locale
159
+ fields
160
+ machineTranslated
161
+ }
162
+ }
163
+ body {
164
+ locales
165
+ translations {
166
+ locale
167
+ text
168
+ machineTranslated
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+ }
175
+ }
176
+ }
177
+ ```
178
+
179
+ You can then use this custom type in your GraphQL queries and mutations to handle the custom fields in proposals.
180
+
181
+
182
+ ##### 12.2. Private Custom fields
183
+
184
+ Similar to the custom fields feature, but only admins can see the content of the fields. This is useful for adding metadata to proposals that should not be visible to the public (such as contact data).
185
+ Data is stored encrypted in the database.
186
+
187
+ ![Private Custom fields screenshot](examples/private_custom_fields.png)
188
+
124
189
  #### 13. Custom Redirections (or URL shortener feature)
125
190
 
126
191
  Admins can create custom paths that redirect to other places. Destinations can be internal absolute paths or external sites.
127
192
  There's also possible to choose to sanitize (ie: remove) any query string or to maintain it (so you can decide to use).
128
193
 
129
- For instance you can create a redirection like
194
+ For instance you can create a redirection like
130
195
 
131
196
  * `/take-me-somewhere` => `/processes/canary-islands`
132
197
 
@@ -274,6 +339,49 @@ This view is used by the proposal cell in lists. It must implement the vote butt
274
339
 
275
340
  Note that, it is strongly recommended to add and HTML tag element with the id `proposal-<%= proposal.id %>-votes-count` so the Ajax vote re-loader can work. Even if you don't use (in this case use a `style="display:none"` attribute), this is because the Ajax reloader always look for this element and throw JavaScript errors if not.
276
341
 
342
+ ##### 17.1 GraphQL Types for weighted voting
343
+
344
+ When a weighed voting mechanism is selected, the GraphQL API will show those weights separated in each proposal.
345
+ The attribute that holds this information is `vote_weights`, a query example could look like this:
346
+
347
+ ```graphql
348
+ {
349
+ component(id: 999) {
350
+ ... on Proposals {
351
+ proposals {
352
+ edges {
353
+ node {
354
+ id
355
+ voteWeights
356
+ }
357
+ }
358
+ }
359
+ }
360
+ }
361
+ }
362
+ ```
363
+
364
+ #### 18. Limiting amendments in proposals
365
+
366
+ By default, when proposals can be amended, any number of amendments can be created.
367
+
368
+ This feature allows admins to configure a specific Proposal's component to limit the number of evaluating amendments that can be created to one.
369
+ Note that this only applies to amendments being in the state "evaluating", not to accepted or rejected.
370
+
371
+ This option is disable by default, must be enabled in the component's configuration:
372
+
373
+ ![Limiting amendments](examples/limit_amendments.png)
374
+
375
+ #### 18. Maintenance tools
376
+
377
+ The awesome admin provides with some maintenance tools (more to come in the future);
378
+
379
+ ##### 18.1 Old private data removal
380
+
381
+ These tools are designed to help remove old data as required by laws such as GDPR, particularly in relation to private custom fields.
382
+ This menu will show if there's any data older than 6 months (configurable) and will let admins remove it component by component.
383
+
384
+ ![Private data](examples/private_data.png)
277
385
 
278
386
  #### To be continued...
279
387
 
@@ -298,6 +406,17 @@ bundle exec rails decidim:upgrade
298
406
  bundle exec rails db:migrate
299
407
  ```
300
408
 
409
+ Go to `yourdomain/admin/decidim_awesome` and start tweaking things!
410
+
411
+ > **EXPERTS ONLY**
412
+ >
413
+ > Under the hood, when running `bundle exec rails decidim:upgrade` the `decidim-decidim_awesome` gem will run the following two tasks (that can also be run manually if you consider):
414
+ >
415
+ > ```bash
416
+ > bin/rails decidim_decidim_awesome:install:migrations
417
+ > bin/rails decidim_decidim_awesome:webpacker:install
418
+ > ```
419
+
301
420
  If you are upgrading from a version prior to 0.8, make sure to visit the URL `/admin/decidim_awesome/checks` and run image migrations for the old images:
302
421
 
303
422
  ![Check image migrations](examples/check_image_migrations.png)
@@ -319,20 +438,20 @@ However you can force some specific version using `gem "decidim-decidim_awesome"
319
438
  Depending on your Decidim version, choose the corresponding Awesome version to ensure compatibility:
320
439
 
321
440
  | Awesome version | Compatible Decidim versions |
322
- |---|---|
323
- | 0.10.0 | >= 0.26.7, >= 0.27.3 |
324
- | 0.9.2 | >= 0.26.7, >= 0.27.3 |
325
- | 0.9.x | 0.26.x, 0.27.x |
326
- | 0.8.x | 0.25.x, 0.26.x |
327
- | 0.7.x | 0.23.x, 0.24.x |
328
- | 0.6.x | 0.22.x, 0.23.x |
329
- | 0.5.x | 0.21.x, 0.22.x |
330
-
331
- > *Heads up!*
441
+ |-----------------|-----------------------------|
442
+ | 0.10.x | >= 0.26.7, >= 0.27.3 |
443
+ | 0.9.2 | >= 0.26.7, >= 0.27.3 |
444
+ | 0.9.x | 0.26.x, 0.27.x |
445
+ | 0.8.x | 0.25.x, 0.26.x |
446
+ | 0.7.x | 0.23.x, 0.24.x |
447
+ | 0.6.x | 0.22.x, 0.23.x |
448
+ | 0.5.x | 0.21.x, 0.22.x |
449
+
450
+ > *Heads up!*
332
451
  > * version 0.10.0 requires database migrations! Don't forget the migrations step when updating.
333
452
  > * version 0.8.0 removes CSS Themes for tenants. If you have been using them you will have to manually migrate them to custom styles.
334
- > * version 0.8.0 uses ActiveStorage, same as Decidim 0.25. 2 new rake task have been introduced to facilitate the migration: `bin/rails decidim_awesome:active_storage_migrations:check_migration_from_carrierwave` and
335
- `bin/rails decidim_awesome:active_storage_migrations:migrate_from_carrierwave`
453
+ > * version 0.8.0 uses ActiveStorage, same as Decidim 0.25. 2 new rake task have been introduced to facilitate the migration: `bin/rails decidim_awesome:active_storage_migrations:check_migration_from_carrierwave` and
454
+ `bin/rails decidim_awesome:active_storage_migrations:migrate_from_carrierwave`
336
455
  > * version 0.7.1 requires database migrations! Don't forget the migrations step when updating.
337
456
 
338
457
  ## Configuration
@@ -453,8 +572,8 @@ However, this project works with different versions of Decidim. In order to test
453
572
  You can run run tests against the legacy Decidim versions by using:
454
573
 
455
574
  ```bash
456
- export DATABASE_USERNAME=<username>
457
- export DATABASE_PASSWORD=<password>
575
+ export DATABASE_USERNAME=<username>
576
+ export DATABASE_PASSWORD=<password>
458
577
  RBENV_VERSION=2.7.6 BUNDLE_GEMFILE=Gemfile.legacy bundle
459
578
  RBENV_VERSION=2.7.6 BUNDLE_GEMFILE=Gemfile.legacy bundle exec rake test_app
460
579
  RBENV_VERSION=2.7.6 BUNDLE_GEMFILE=Gemfile.legacy bundle exec rspec
@@ -6,32 +6,12 @@ module Decidim
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  included do
9
- # rubocop:disable Metrics/CyclomaticComplexity
10
- def cache_hash
11
- hash = []
12
- hash << I18n.locale.to_s
13
- hash << model.cache_key_with_version
14
- hash << model.proposal_votes_count
15
- hash << model.extra_fields&.vote_weight_totals
16
- hash << model.endorsements_count
17
- hash << model.comments_count
18
- hash << Digest::MD5.hexdigest(model.component.cache_key_with_version)
19
- hash << Digest::MD5.hexdigest(resource_image_path) if resource_image_path
20
- hash << render_space? ? 1 : 0
21
- if current_user
22
- hash << current_user.cache_key_with_version
23
- hash << current_user.follows?(model) ? 1 : 0
24
- end
25
- hash << model.follows_count
26
- hash << Digest::MD5.hexdigest(model.authors.map(&:cache_key_with_version).to_s)
27
- hash << (model.must_render_translation?(model.organization) ? 1 : 0) if model.respond_to?(:must_render_translation?)
28
- hash << model.component.participatory_space.active_step.id if model.component.participatory_space.try(:active_step)
29
- hash << has_footer?
30
- hash << has_actions?
9
+ alias_method :decidim_original_cache_hash, :cache_hash
31
10
 
32
- hash.join(Decidim.cache_key_separator)
11
+ def cache_hash
12
+ extra_hash = model.extra_fields&.reload&.vote_weight_totals
13
+ "#{decidim_original_cache_hash}#{Decidim.cache_key_separator}#{extra_hash}"
33
14
  end
34
- # rubocop:enable Metrics/CyclomaticComplexity
35
15
  end
36
16
  end
37
17
  end
@@ -40,11 +40,15 @@ module Decidim
40
40
 
41
41
  def global_map_components
42
42
  @global_map_components ||= Decidim::Component.where(manifest_name: [:meetings, :proposals]).published.filter do |component|
43
- case component.manifest.name
44
- when :meetings
45
- true
46
- when :proposals
47
- component.settings.geocoding_enabled
43
+ if component.organization == current_organization
44
+ case component.manifest.name
45
+ when :meetings
46
+ true
47
+ when :proposals
48
+ component.settings.geocoding_enabled
49
+ else
50
+ false
51
+ end
48
52
  else
49
53
  false
50
54
  end
@@ -20,7 +20,7 @@ module Decidim
20
20
  return true if constraint.awesome_config.constraints.count > 1
21
21
 
22
22
  case constraint.awesome_config.var.to_s
23
- when /^proposal_custom_field/
23
+ when /^proposal_(private_)?custom_field/
24
24
  false
25
25
  else
26
26
  true
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ module Proposals
6
+ module Admin
7
+ ##
8
+ # Decorates update draft and update proposal
9
+ # to avoid private field to be logged in PaperTrail.
10
+ module UpdateProposalOverride
11
+ extend ActiveSupport::Concern
12
+
13
+ included do
14
+ private
15
+
16
+ alias_method :decidim_original_update_proposal, :update_proposal
17
+
18
+ def update_proposal
19
+ decidim_original_update_proposal
20
+ update_private_field!
21
+ end
22
+
23
+ def update_private_field!
24
+ @proposal.update_private_body!(form.private_body) if form.private_body.present?
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ module Proposals
6
+ ##
7
+ # Decorate create_collaborative_draft to avoid
8
+ # private data to be in PaperTrail
9
+ module CreateCollaborativeDraftOverride
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ private
14
+
15
+ alias_method :decidim_original_create_collaborative_draft, :create_collaborative_draft
16
+
17
+ def create_collaborative_draft
18
+ created_draft = decidim_original_create_collaborative_draft
19
+ # Update the proposal with the private body, to
20
+ # avoid tracebility on private fields.
21
+ created_draft.update_private_body!(form.private_body) if form.private_body.present?
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ module Proposals
6
+ ##
7
+ # Decorate create_proposal to avoid
8
+ # private data to be in PaperTrail
9
+ module CreateProposalOverride
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ private
14
+
15
+ alias_method :decidim_original_create_proposal, :create_proposal
16
+
17
+ def create_proposal
18
+ decidim_original_create_proposal
19
+ # Update the proposal with the private body, to
20
+ # avoid tracebility on private fields.
21
+ @proposal.update_private_body!(form.private_body) if form.private_body.present?
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ module Proposals
6
+ ##
7
+ # Decorates update draft and update proposal
8
+ # to avoid private field to be logged in PaperTrail.
9
+ module UpdateCollaborativeDraftOverride
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ private
14
+
15
+ alias_method :decidim_original_update_collaborative_draft, :update_collaborative_draft
16
+
17
+ def update_collaborative_draft
18
+ decidim_original_update_collaborative_draft
19
+ # Update the proposal with the private body, to
20
+ # avoid tracebility on private fields.
21
+ @collaborative_draft.update_private_body!(form.private_body) if form.private_body.present?
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ module Proposals
6
+ ##
7
+ # Decorates update draft and update proposal
8
+ # to avoid private field to be logged in PaperTrail.
9
+ module UpdateProposalOverride
10
+ extend ActiveSupport::Concern
11
+ include Admin::UpdateProposalOverride
12
+
13
+ included do
14
+ private
15
+
16
+ alias_method :decidim_original_update_draft, :update_draft
17
+
18
+ def update_draft
19
+ decidim_original_update_draft
20
+ update_private_field!
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -8,9 +8,10 @@ module Decidim
8
8
 
9
9
  # Public: Initializes the command.
10
10
  #
11
- def initialize(organization)
11
+ def initialize(organization, config_var = :proposal_custom_fields)
12
12
  @organization = organization
13
13
  @ident = rand(36**8).to_s(36)
14
+ @config_var = config_var
14
15
  end
15
16
 
16
17
  # Executes the command. Broadcasts these events:
@@ -20,13 +21,13 @@ module Decidim
20
21
  #
21
22
  # Returns nothing.
22
23
  def call
23
- fields = AwesomeConfig.find_or_initialize_by(var: :proposal_custom_fields, organization: @organization)
24
+ fields = AwesomeConfig.find_or_initialize_by(var: @config_var, organization: @organization)
24
25
  fields.value = {} unless fields.value.is_a? Hash
25
26
  # TODO: prevent (unlikely) colisions with exisiting values
26
27
  fields.value[@ident] = default_definition
27
28
  fields.save!
28
29
 
29
- create_constraint_never(:proposal_custom_field)
30
+ create_constraint_never(@config_var == :proposal_custom_fields ? :proposal_custom_field : :proposal_private_custom_field)
30
31
 
31
32
  broadcast(:ok, @ident)
32
33
  rescue StandardError => e
@@ -8,9 +8,10 @@ module Decidim
8
8
  #
9
9
  # key - the key to destroy inise proposal_custom_fields
10
10
  # organization
11
- def initialize(key, organization)
11
+ def initialize(key, organization, config_var = :proposal_custom_fields)
12
12
  @key = key
13
13
  @organization = organization
14
+ @config_var = config_var
14
15
  end
15
16
 
16
17
  # Executes the command. Broadcasts these events:
@@ -20,14 +21,16 @@ module Decidim
20
21
  #
21
22
  # Returns nothing.
22
23
  def call
23
- fields = AwesomeConfig.find_by(var: :proposal_custom_fields, organization: @organization)
24
+ fields = AwesomeConfig.find_by(var: @config_var, organization: @organization)
24
25
  return broadcast(:invalid, "Not a hash") unless fields&.value.is_a? Hash
25
26
  return broadcast(:invalid, "#{key} key invalid") unless fields.value.has_key?(@key)
26
27
 
27
28
  fields.value.except!(@key)
28
29
  fields.save!
30
+
29
31
  # remove constrains associated (a new config var is generated automatically, by removing it, it will trigger destroy on dependents)
30
- constraint = AwesomeConfig.find_by(var: "proposal_custom_field_#{@key}", organization: @organization)
32
+ constraint = @config_var == :proposal_custom_fields ? :proposal_custom_field : :proposal_private_custom_field
33
+ constraint = AwesomeConfig.find_by(var: "#{constraint}_#{@key}", organization: @organization)
31
34
  constraint.destroy! if constraint.present?
32
35
 
33
36
  broadcast(:ok, @key)
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ module Admin
6
+ module MaintenanceContext
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ layout "decidim/decidim_awesome/admin/maintenance"
11
+ helper_method :current_view, :available_views, :present_private_data
12
+
13
+ private
14
+
15
+ def present_private_data(model)
16
+ PrivateDataPresenter.new(model)
17
+ end
18
+
19
+ def current_view
20
+ return params[:id] if available_views.include?(params[:id])
21
+
22
+ available_views.keys.first
23
+ end
24
+
25
+ def available_views
26
+ {
27
+ "private_data" => {
28
+ title: I18n.t("private_data", scope: "decidim.decidim_awesome.admin.menu.maintenance"),
29
+ icon: "lock-locked",
30
+ path: decidim_admin_decidim_awesome.maintenance_path("private_data")
31
+ },
32
+ "checks" => {
33
+ title: I18n.t("checks", scope: "decidim.decidim_awesome.admin.menu.maintenance"),
34
+ icon: "pulse",
35
+ path: decidim_admin_decidim_awesome.checks_maintenance_index_path
36
+ }
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -13,10 +13,11 @@ module Decidim
13
13
  end
14
14
 
15
15
  def applied_filters_tags(i18n_ctx)
16
- if global? && params[:admin_role_type].present?
16
+ admin_role_type = PaperTrailVersion.safe_admin_role_type(params[:admin_role_type])
17
+ if global? && admin_role_type.present?
17
18
  content_tag(:span, class: "label secondary") do
18
19
  concat "#{i18n_filter_label(:admin_role_type, filterable_i18n_scope_from_ctx(i18n_ctx))}: "
19
- concat t("decidim.decidim_awesome.admin.admin_accountability.admin_roles.#{params[:admin_role_type]}", default: params[:admin_role_type])
20
+ concat t("decidim.decidim_awesome.admin.admin_accountability.admin_roles.#{admin_role_type}", default: admin_role_type)
20
21
  concat icon_link_to(
21
22
  "circle-x",
22
23
  url_for(export_params.except(:admin_role_type)),
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ module LimitPendingAmendments
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ # rubocop:disable Rails/LexicallyScopedActionFilter
10
+ before_action :limit_pending_amendments, only: [:new, :create]
11
+ # rubocop:enable Rails/LexicallyScopedActionFilter
12
+
13
+ private
14
+
15
+ def limit_pending_amendments
16
+ return unless amendable&.amendments && amendable&.component&.settings.try(:limit_pending_amendments)
17
+ return unless amendable.component.settings.try(:amendments_enabled)
18
+ return unless amendable.component.current_settings.try(:amendment_creation_enabled)
19
+
20
+ return unless existing_emendations.any?
21
+
22
+ flash[:alert] = t("pending_limit_reached", scope: "decidim.decidim_awesome.amendments", emendation: translated_attribute(existing_emendations.first.title))
23
+ redirect_back(fallback_location: Decidim::ResourceLocatorPresenter.new(amendable).path)
24
+ end
25
+
26
+ def existing_emendations
27
+ @existing_emendations ||= begin
28
+ existing = amendable.amendments.where(state: :evaluating)
29
+ existing.filter_map { |amendment| !amendment.emendation&.hidden? && amendment.emendation }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -14,6 +14,8 @@ module Decidim
14
14
 
15
15
  private
16
16
 
17
+ alias_method :decidim_original_reorder, :reorder
18
+
17
19
  # read order from session if available
18
20
  def order
19
21
  @order ||= detect_order(session[:order]) || default_order
@@ -31,38 +33,23 @@ module Decidim
31
33
  end
32
34
  end
33
35
 
34
- # rubocop:disable Metrics/CyclomaticComplexity
35
36
  def reorder(proposals)
37
+ title_by_locale = Arel.sql(proposals.sanitize_sql(["decidim_proposals_proposals.title->>? #{collation}", locale]))
38
+ title_by_machine_translation = Arel.sql(proposals.sanitize_sql(["decidim_proposals_proposals.title->'machine_translations'->>? #{collation}", locale]))
39
+ title_by_default_locale = Arel.sql(proposals.sanitize_sql(["decidim_proposals_proposals.title->>? #{collation}", default_locale]))
36
40
  case order
37
41
  when "az"
38
- proposals.order(Arel.sql("CONCAT(decidim_proposals_proposals.title->>'#{locale}',
39
- decidim_proposals_proposals.title->'machine_translations'->>'#{locale}',
40
- decidim_proposals_proposals.title->>'#{default_locale}') #{collation} ASC"))
42
+ proposals.order(title_by_locale => :asc, title_by_machine_translation => :asc, title_by_default_locale => :asc)
41
43
  when "za"
42
- proposals.order(Arel.sql("CONCAT(decidim_proposals_proposals.title->>'#{locale}',
43
- decidim_proposals_proposals.title->'machine_translations'->>'#{locale}',
44
- decidim_proposals_proposals.title->>'#{default_locale}') #{collation} DESC"))
44
+ proposals.order(title_by_locale => :desc, title_by_machine_translation => :desc, title_by_default_locale => :desc)
45
45
  when "supported_first"
46
46
  proposals.joins(my_votes_join).group(:id).order(Arel.sql("COUNT(decidim_proposals_proposal_votes.id) DESC"))
47
47
  when "supported_last"
48
48
  proposals.joins(my_votes_join).group(:id).order(Arel.sql("COUNT(decidim_proposals_proposal_votes.id) ASC"))
49
- when "most_commented"
50
- proposals.left_joins(:comments).group(:id).order(Arel.sql("COUNT(decidim_comments_comments.id) DESC"))
51
- when "most_endorsed"
52
- proposals.order(endorsements_count: :desc)
53
- when "most_followed"
54
- proposals.left_joins(:follows).group(:id).order(Arel.sql("COUNT(decidim_follows.id) DESC"))
55
- when "most_voted"
56
- proposals.order(proposal_votes_count: :desc)
57
- when "random"
58
- proposals.order_randomly(random_seed)
59
- when "recent"
60
- proposals.order(published_at: :desc)
61
- when "with_more_authors"
62
- proposals.order(coauthorships_count: :desc)
49
+ else
50
+ decidim_original_reorder(proposals)
63
51
  end
64
52
  end
65
- # rubocop:enable Metrics/CyclomaticComplexity
66
53
 
67
54
  def collation
68
55
  @collation ||= begin