decidim-proposals 0.10.1 → 0.11.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/app/assets/javascripts/decidim/proposals/add_proposal.js.es6 +3 -3
  4. data/app/assets/javascripts/decidim/proposals/admin/proposals.es6 +6 -7
  5. data/app/assets/javascripts/decidim/proposals/identity_selector_dialog.js.es6 +17 -17
  6. data/app/assets/javascripts/decidim/proposals/utils.js.es6 +2 -2
  7. data/app/commands/decidim/proposals/admin/create_proposal.rb +2 -2
  8. data/app/commands/decidim/proposals/admin/import_proposals.rb +16 -8
  9. data/app/commands/decidim/proposals/create_proposal.rb +6 -6
  10. data/app/commands/decidim/proposals/destroy_proposal.rb +33 -0
  11. data/app/commands/decidim/proposals/update_proposal.rb +4 -4
  12. data/app/controllers/decidim/proposals/admin/application_controller.rb +2 -2
  13. data/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +1 -1
  14. data/app/controllers/decidim/proposals/admin/proposal_notes_controller.rb +1 -1
  15. data/app/controllers/decidim/proposals/admin/proposals_controller.rb +2 -2
  16. data/app/controllers/decidim/proposals/admin/proposals_imports_controller.rb +4 -4
  17. data/app/controllers/decidim/proposals/application_controller.rb +5 -5
  18. data/app/controllers/decidim/proposals/proposal_endorsements_controller.rb +1 -1
  19. data/app/controllers/decidim/proposals/proposal_votes_controller.rb +1 -1
  20. data/app/controllers/decidim/proposals/proposal_widgets_controller.rb +1 -1
  21. data/app/controllers/decidim/proposals/proposals_controller.rb +52 -24
  22. data/app/events/decidim/proposals/proposal_mentioned_event.rb +19 -0
  23. data/app/forms/decidim/proposals/admin/proposal_form.rb +3 -3
  24. data/app/forms/decidim/proposals/admin/proposals_import_form.rb +9 -9
  25. data/app/forms/decidim/proposals/proposal_form.rb +5 -4
  26. data/app/helpers/decidim/proposals/application_helper.rb +38 -3
  27. data/app/helpers/decidim/proposals/proposal_endorsements_helper.rb +7 -3
  28. data/app/helpers/decidim/proposals/proposal_votes_helper.rb +9 -9
  29. data/app/helpers/decidim/proposals/proposal_wizard_helper.rb +2 -1
  30. data/app/jobs/decidim/proposals/notify_proposals_mentioned_job.rb +28 -0
  31. data/app/jobs/decidim/proposals/settings_change_job.rb +4 -4
  32. data/app/models/decidim/proposals/abilities/admin_ability.rb +4 -4
  33. data/app/models/decidim/proposals/abilities/current_user_ability.rb +12 -12
  34. data/app/models/decidim/proposals/abilities/participatory_process_admin_ability.rb +8 -8
  35. data/app/models/decidim/proposals/abilities/participatory_process_moderator_ability.rb +1 -1
  36. data/app/models/decidim/proposals/proposal.rb +7 -7
  37. data/app/models/decidim/proposals/proposal_endorsement.rb +6 -2
  38. data/app/presenters/decidim/proposals/proposal_presenter.rb +12 -0
  39. data/app/queries/decidim/proposals/filtered_proposals.rb +9 -9
  40. data/app/queries/decidim/proposals/similar_proposals.rb +9 -9
  41. data/app/services/decidim/proposals/proposal_search.rb +1 -1
  42. data/app/types/decidim/proposals/proposal_type.rb +17 -2
  43. data/app/types/decidim/proposals/proposals_type.rb +6 -6
  44. data/app/views/decidim/participatory_processes/participatory_process_groups/_highlighted_proposals.html.erb +1 -1
  45. data/app/views/decidim/participatory_processes/participatory_process_groups/_proposal.html.erb +1 -1
  46. data/app/views/decidim/participatory_spaces/_highlighted_proposals.html.erb +2 -2
  47. data/app/views/decidim/participatory_spaces/_proposal.html.erb +1 -1
  48. data/app/views/decidim/proposals/admin/proposal_answers/edit.html.erb +3 -3
  49. data/app/views/decidim/proposals/admin/proposal_notes/_form.html.erb +2 -2
  50. data/app/views/decidim/proposals/admin/proposal_notes/_proposal_notes.html.erb +3 -3
  51. data/app/views/decidim/proposals/admin/proposal_notes/index.html.erb +1 -1
  52. data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +2 -2
  53. data/app/views/decidim/proposals/admin/proposals/_form.html.erb +3 -3
  54. data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +1 -1
  55. data/app/views/decidim/proposals/admin/proposals/index.html.erb +1 -1
  56. data/app/views/decidim/proposals/admin/proposals/new.html.erb +2 -2
  57. data/app/views/decidim/proposals/admin/proposals/update_category.js.erb +3 -3
  58. data/app/views/decidim/proposals/admin/proposals_imports/new.html.erb +3 -3
  59. data/app/views/decidim/proposals/admin/shared/_info_proposal.html.erb +1 -1
  60. data/app/views/decidim/proposals/proposal_endorsements/_identity.html.erb +2 -2
  61. data/app/views/decidim/proposals/proposal_endorsements/identities.html.erb +2 -2
  62. data/app/views/decidim/proposals/proposal_endorsements/update_buttons_and_counters.js.erb +19 -8
  63. data/app/views/decidim/proposals/proposals/_endorsement_button.html.erb +2 -2
  64. data/app/views/decidim/proposals/proposals/_endorsement_identities_cabin.html.erb +3 -3
  65. data/app/views/decidim/proposals/proposals/_endorsements_card_row.html.erb +4 -4
  66. data/app/views/decidim/proposals/proposals/_endorsements_count.html.erb +2 -2
  67. data/app/views/decidim/proposals/proposals/_filters.html.erb +10 -10
  68. data/app/views/decidim/proposals/proposals/_filters_small_view.html.erb +1 -1
  69. data/app/views/decidim/proposals/proposals/_identities_listing.html.erb +30 -0
  70. data/app/views/decidim/proposals/proposals/{_endorsement_xxs.html.erb → _identity_xxs.html.erb} +1 -2
  71. data/app/views/decidim/proposals/proposals/_proposal.html.erb +2 -2
  72. data/app/views/decidim/proposals/proposals/_proposal_badge.html.erb +1 -1
  73. data/app/views/decidim/proposals/proposals/_tags.html.erb +25 -0
  74. data/app/views/decidim/proposals/proposals/_vote_button.html.erb +7 -7
  75. data/app/views/decidim/proposals/proposals/_votes_count.html.erb +6 -5
  76. data/app/views/decidim/proposals/proposals/_voting_rules.html.erb +7 -7
  77. data/app/views/decidim/proposals/proposals/_wizard_header.html.erb +5 -5
  78. data/app/views/decidim/proposals/proposals/compare.html.erb +1 -1
  79. data/app/views/decidim/proposals/proposals/complete.html.erb +70 -0
  80. data/app/views/decidim/proposals/proposals/edit.html.erb +3 -3
  81. data/app/views/decidim/proposals/proposals/edit_draft.html.erb +5 -3
  82. data/app/views/decidim/proposals/proposals/index.html.erb +5 -5
  83. data/app/views/decidim/proposals/proposals/new.html.erb +1 -43
  84. data/app/views/decidim/proposals/proposals/preview.html.erb +1 -1
  85. data/app/views/decidim/proposals/proposals/show.html.erb +16 -23
  86. data/config/locales/ca.yml +69 -55
  87. data/config/locales/en.yml +64 -50
  88. data/config/locales/es.yml +73 -59
  89. data/config/locales/eu.yml +64 -50
  90. data/config/locales/fi.yml +64 -50
  91. data/config/locales/fr.yml +75 -61
  92. data/config/locales/gl.yml +64 -50
  93. data/config/locales/it.yml +64 -50
  94. data/config/locales/nl.yml +153 -139
  95. data/config/locales/pl.yml +64 -50
  96. data/config/locales/pt-BR.yml +64 -50
  97. data/config/locales/pt.yml +64 -50
  98. data/config/locales/ru.yml +0 -9
  99. data/config/locales/sv.yml +64 -50
  100. data/config/locales/uk.yml +2 -16
  101. data/db/migrate/20171212102250_enable_pg_extensions.rb +12 -1
  102. data/db/migrate/20180305133811_rename_features_to_components_at_proposals.rb +11 -0
  103. data/db/migrate/20180413135249_fix_nil_threshold_per_proposal.rb +18 -0
  104. data/lib/decidim/content_parsers/proposal_parser.rb +95 -0
  105. data/lib/decidim/content_renderers/proposal_renderer.rb +33 -0
  106. data/lib/decidim/proposals.rb +9 -1
  107. data/lib/decidim/proposals/commentable_proposal.rb +3 -3
  108. data/lib/decidim/proposals/{feature.rb → component.rb} +39 -38
  109. data/lib/decidim/proposals/engine.rb +21 -6
  110. data/lib/decidim/proposals/proposal_serializer.rb +3 -3
  111. data/lib/decidim/proposals/test/factories.rb +5 -8
  112. data/lib/decidim/proposals/version.rb +1 -1
  113. metadata +32 -23
  114. data/app/views/decidim/proposals/proposals/_endorsements_listing.html.erb +0 -34
@@ -11,12 +11,6 @@ ru:
11
11
  proposal_answer:
12
12
  answer: Ответить
13
13
  decidim:
14
- features:
15
- proposals:
16
- actions:
17
- create: Внести
18
- vote: Голосовать
19
- name: Предложения
20
14
  proposals:
21
15
  actions:
22
16
  answer: Ответить
@@ -118,9 +112,6 @@ ru:
118
112
  few: голоса
119
113
  many: голоса
120
114
  other: голоса
121
- new:
122
- attachment_legend: "(Необязательно) Добавить вложение"
123
- select_a_category: Пожалуйста, выберите категорию
124
115
  orders:
125
116
  label: 'Упорядочить предложения по:'
126
117
  most_voted: С наибольшим количеством голосов
@@ -15,8 +15,45 @@ sv:
15
15
  answer: Svara
16
16
  proposals_copy:
17
17
  copy_proposals: Jag förstår att detta kommer att importera alla förslag från den valda komponenten till den nuvarande och att den här åtgärden inte kan reverseras.
18
- origin_feature_id: Komponent för att kopiera förslagen från
18
+ origin_component_id: Komponent för att kopiera förslagen från
19
19
  decidim:
20
+ components:
21
+ proposals:
22
+ actions:
23
+ create: Skapa
24
+ endorse: Stödja
25
+ vote: Rösta
26
+ withdraw: Dra tillbaka
27
+ name: Förslag
28
+ settings:
29
+ global:
30
+ announcement: Meddelande
31
+ attachments_allowed: Tillåt bifogade filer
32
+ can_accumulate_supports_beyond_threshold: Kan ackumulera stöd över gränsen
33
+ comments_enabled: Kommentarer aktiverade
34
+ geocoding_enabled: Geocoding aktiverad
35
+ new_proposal_help_text: Nytt förslag till hjälptext
36
+ official_proposals_enabled: Officiella förslag möjliga
37
+ proposal_answering_enabled: Förslagsvarning aktiverat
38
+ proposal_edit_before_minutes: Förslag kan redigeras av författare innan detta många minuter passerar
39
+ proposal_length: Maximal förslag kroppslängd
40
+ proposal_limit: Förslagsgräns per användare
41
+ proposal_wizard_step_1_help_text: Förslagsguiden "Skapa" steg hjälptext
42
+ proposal_wizard_step_2_help_text: Förslagsguiden "Jämför" steg hjälptext
43
+ proposal_wizard_step_3_help_text: Förslagsguiden "Komplett" steg hjälptext
44
+ proposal_wizard_step_4_help_text: Förslagsguiden "Publicera" steg hjälptext
45
+ threshold_per_proposal: Tröskel per förslag
46
+ vote_limit: Rösta per användare
47
+ step:
48
+ announcement: Meddelande
49
+ comments_blocked: Kommentarer blockerade
50
+ creation_enabled: Förslagstillverkning möjliggjorde
51
+ endorsements_blocked: Anmärkningar blockerade
52
+ endorsements_enabled: Anmärkningar aktiverade
53
+ proposal_answering_enabled: Förslagsvarning aktiverat
54
+ votes_blocked: Röster blockerade
55
+ votes_enabled: Röster aktiverade
56
+ votes_hidden: Röster dolda (om röster är aktiverade, kommer detta att gömma antalet röster)
20
57
  events:
21
58
  proposals:
22
59
  creation_enabled:
@@ -44,6 +81,10 @@ sv:
44
81
  email_outro: Du har fått den här meddelandet eftersom du följer "%{resource_title}". Du kan följa det från föregående länk.
45
82
  email_subject: Ett förslag som du följer utvärderas
46
83
  notification_title: <a href="%{resource_path}">%{resource_title}</a> förslaget utvärderas.
84
+ proposal_mentioned:
85
+ email_intro: Ditt förslag "%{mentioned_proposal_title}" har nämnts <a href="%{resource_path}">i det här utrymmet</a> i kommentarerna.
86
+ email_subject: Ditt förslag "%{mentioned_proposal_title}" har nämnts
87
+ notification_title: Ditt förslag "%{mentioned_proposal_title}" har nämnts <a href="%{resource_path}">i det här utrymmet</a> i kommentarerna.
47
88
  proposal_published:
48
89
  email_intro: "%{author_name} %{author_nickname}, vem du följer har publicerat ett nytt förslag, kolla in det och bidra med:"
49
90
  email_outro: Du har fått den här meddelandet eftersom du följer %{author_nickname}. Du kan sluta ta emot meddelanden efter föregående länk.
@@ -69,42 +110,6 @@ sv:
69
110
  email_outro: Du har fått den här meddelandet eftersom du följer %{participatory_space_title}. Du kan sluta ta emot meddelanden efter föregående länk.
70
111
  email_subject: Förslagets röstning har börjat för %{participatory_space_title}
71
112
  notification_title: Du kan nu börja <a href="%{resource_path}">röstningsförslag</a> i <a href="%{participatory_space_url}">%{participatory_space_title}</a>
72
- features:
73
- proposals:
74
- actions:
75
- create: Skapa
76
- endorse: Stödja
77
- vote: Rösta
78
- withdraw: Dra tillbaka
79
- name: Förslag
80
- settings:
81
- global:
82
- announcement: Meddelande
83
- attachments_allowed: Tillåt bifogade filer
84
- can_accumulate_supports_beyond_threshold: Kan ackumulera stöd över gränsen
85
- comments_enabled: Kommentarer aktiverade
86
- geocoding_enabled: Geocoding aktiverad
87
- new_proposal_help_text: Nytt förslag till hjälptext
88
- official_proposals_enabled: Officiella förslag möjliga
89
- proposal_answering_enabled: Förslagsvarning aktiverat
90
- proposal_edit_before_minutes: Förslag kan redigeras av författare innan detta många minuter passerar
91
- proposal_length: Maximal förslag kroppslängd
92
- proposal_limit: Förslagsgräns per användare
93
- proposal_wizard_step_1_help_text: Förslagsguiden "Skapa" steg hjälptext
94
- proposal_wizard_step_2_help_text: Förslagsguiden "Jämför" steg hjälptext
95
- proposal_wizard_step_3_help_text: Förslagsguiden "Publicera" steg hjälptext
96
- threshold_per_proposal: Tröskel per förslag
97
- vote_limit: Rösta per användare
98
- step:
99
- announcement: Meddelande
100
- comments_blocked: Kommentarer blockerade
101
- creation_enabled: Förslagstillverkning möjliggjorde
102
- endorsements_blocked: Anmärkningar blockerade
103
- endorsements_enabled: Anmärkningar aktiverade
104
- proposal_answering_enabled: Förslagsvarning aktiverat
105
- votes_blocked: Röster blockerade
106
- votes_enabled: Röster aktiverade
107
- votes_hidden: Röster dolda (om röster är aktiverade, kommer detta att gömma antalet röster)
108
113
  participatory_processes:
109
114
  participatory_process_groups:
110
115
  highlighted_proposals:
@@ -182,8 +187,8 @@ sv:
182
187
  success: "%{number} Förslag som framgångsrikt importerats"
183
188
  new:
184
189
  create: Importera förslag
185
- no_features: Det finns inga andra förslagsfunktioner i detta deltagande utrymme för att importera förslagen från.
186
- select_feature: Välj en komponent
190
+ no_components: Det finns inga andra förslagskomponenter i detta deltagande utrymme för att importera förslagen från.
191
+ select_component: Välj en komponent
187
192
  select_states: Kontrollera tillstånden för de förslag som ska importeras
188
193
  shared:
189
194
  info_proposal:
@@ -206,6 +211,9 @@ sv:
206
211
  create:
207
212
  error: Det har varit fel när du lagrade förslaget.
208
213
  success: Förslaget skapades framgångsrikt. Sparat som ett formulär.
214
+ destroy_draft:
215
+ error: Det har funnits fel att radera förslaget.
216
+ success: Förslagsförslaget blev framgångsrikt förstört.
209
217
  models:
210
218
  proposal:
211
219
  fields:
@@ -229,7 +237,7 @@ sv:
229
237
  select_identity: Välj identitet
230
238
  proposal_endorsements_helper:
231
239
  endorsement_button:
232
- already_endorsed: Redan godkänd
240
+ already_endorsed: Stött
233
241
  endorse: Stödja
234
242
  proposal_votes:
235
243
  create:
@@ -239,6 +247,11 @@ sv:
239
247
  mine_is_different: Mitt förslag är annorlunda
240
248
  no_similars_found: Bra gjort! Inga liknande förslag hittades
241
249
  title: Liknande förslag
250
+ complete:
251
+ attachment_legend: "(Valfritt) Lägg till en bilaga"
252
+ select_a_category: Var god välj en kategori
253
+ send: Skicka
254
+ title: Fyll i ditt förslag
242
255
  count:
243
256
  proposals_count:
244
257
  one: 1 förslag
@@ -249,19 +262,14 @@ sv:
249
262
  send: Skicka
250
263
  title: Redigera förslag
251
264
  edit_draft:
265
+ discard: Kassera detta utkast
266
+ discard_confirmation: Är du säker på att du vill kassera förslaget till förslag?
252
267
  send: Förhandsvisa
253
268
  title: Redigera förslagskoncept
254
- endorsement_button:
255
- already_endorsed: Redan godkänd
256
- already_endorsed_hover: Unendorse
257
269
  endorsement_identities_cabin:
258
270
  endorse: Stödja
259
271
  endorsements_card_row:
260
272
  endorse: Stödja
261
- endorsements_listing:
262
- see_all: Se alla
263
- see_less: Se mindre
264
- title: Förteckning över godkännanden
265
273
  filters:
266
274
  accepted: Accepterad
267
275
  activity: Aktivitet
@@ -282,6 +290,10 @@ sv:
282
290
  filter: Filtrera
283
291
  filter_by: Filtrera efter
284
292
  unfold: Veckla ut
293
+ identities_listing:
294
+ see_all: Se alla
295
+ see_less: Se mindre
296
+ title: Förteckning över godkännanden
285
297
  index:
286
298
  new_proposal: Nytt förslag
287
299
  see_all_withdrawn: Se alla återtagna förslag
@@ -291,8 +303,6 @@ sv:
291
303
  one: röst
292
304
  other: röster
293
305
  new:
294
- attachment_legend: "(Valfritt) Lägg till en bilaga"
295
- select_a_category: Välj en kategori
296
306
  send: Fortsätt
297
307
  title: Skapa ditt förslag
298
308
  orders:
@@ -322,6 +332,9 @@ sv:
322
332
  withdraw_btn_hint: Du kan dra tillbaka ditt förslag om du ändrar dig, så länge du inte har fått något stöd. Förslaget är inte borttaget, det kommer att visas i listan över återkallade förslag.
323
333
  withdraw_confirmation: Är du säker på att dra tillbaka detta förslag?
324
334
  withdraw_proposal: Dra ut förslaget
335
+ tags:
336
+ changed_from: "(ändrad från <u>%{previous_category}</u> av en administratör)"
337
+ filed_as: Filed as
325
338
  vote_button:
326
339
  already_voted: Redan röstat
327
340
  already_voted_hover: Ta bort sin röst
@@ -354,7 +367,8 @@ sv:
354
367
  see_steps: se steg
355
368
  step_1: Skapa ditt förslag
356
369
  step_2: Jämföra
357
- step_3: Publicera ditt förslag
370
+ step_3: Komplett
371
+ step_4: Publicera ditt förslag
358
372
  step_of: Steg %{current_step_num} av %{total_steps}
359
373
  publish:
360
374
  error: Det har varit fel vid publicering av förslaget.
@@ -11,13 +11,6 @@ uk:
11
11
  proposal_answer:
12
12
  answer: Відповісти
13
13
  decidim:
14
- features:
15
- proposals:
16
- actions:
17
- create: Внести
18
- endorse: Підтримати
19
- vote: Голосувати
20
- name: Пропозиції
21
14
  proposals:
22
15
  actions:
23
16
  answer: Відповісти
@@ -102,7 +95,6 @@ uk:
102
95
  select_identity: Оберіть особу
103
96
  proposal_endorsements_helper:
104
97
  endorsement_button:
105
- already_endorsed: Вже підтримано
106
98
  endorse: Підтримати
107
99
  proposal_votes:
108
100
  create:
@@ -126,13 +118,8 @@ uk:
126
118
  edit_draft:
127
119
  send: Попередній перегляд
128
120
  title: Редагувати чернетку пропозиції
129
- endorsement_button:
130
- already_endorsed: Вже підтримано
131
- already_endorsed_hover: Відкликати підтримку
132
121
  endorsement_identities_cabin:
133
122
  endorse: Підтримати
134
- endorsements_listing:
135
- title: Перелік підтримок
136
123
  filters:
137
124
  accepted: Прийнято
138
125
  activity: Діяльність
@@ -153,6 +140,8 @@ uk:
153
140
  filter: Відібрати
154
141
  filter_by: 'Відібрати за ознакою:'
155
142
  unfold: Розгорнути
143
+ identities_listing:
144
+ title: Перелік підтримок
156
145
  index:
157
146
  new_proposal: Нова пропозиція
158
147
  see_all_withdrawn: Переглянути всі відкликані пропозиції
@@ -164,8 +153,6 @@ uk:
164
153
  many: голоси
165
154
  other: голоси
166
155
  new:
167
- attachment_legend: "(Необов'язково) Додати вкладений файл"
168
- select_a_category: Будь ласка, оберіть розділ
169
156
  send: Продовжити
170
157
  title: Внести власну пропозицію
171
158
  orders:
@@ -217,7 +204,6 @@ uk:
217
204
  see_steps: переглянути кроки
218
205
  step_1: Внести власну пропозицію
219
206
  step_2: Порівняти
220
- step_3: Опублікувати свою пропозицію
221
207
  publish:
222
208
  success: Пропозицію успішно опубліковано.
223
209
  update:
@@ -2,6 +2,17 @@
2
2
 
3
3
  class EnablePgExtensions < ActiveRecord::Migration[5.1]
4
4
  def change
5
- enable_extension "pg_trgm"
5
+ return if extension_enabled?("pg_trgm")
6
+
7
+ begin
8
+ # required so that test suite works in ci env
9
+ enable_extension "pg_trgm"
10
+ rescue StandardError
11
+ raise <<-MSG.squish
12
+ Decidim requires the pg_trgm extension to be enabled in your PostgreSQL.
13
+ You can do so by running `CREATE EXTENSION IF NOT EXISTS "pg_trgm";` on the current DB as a PostgreSQL
14
+ super user.
15
+ MSG
16
+ end
6
17
  end
7
18
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RenameFeaturesToComponentsAtProposals < ActiveRecord::Migration[5.1]
4
+ def change
5
+ rename_column :decidim_proposals_proposals, :decidim_feature_id, :decidim_component_id
6
+
7
+ if index_name_exists?(:decidim_proposals_proposals, "index_decidim_proposals_proposals_on_decidim_feature_id")
8
+ rename_index :decidim_proposals_proposals, "index_decidim_proposals_proposals_on_decidim_feature_id", "index_decidim_proposals_proposals_on_decidim_component_id"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FixNilThresholdPerProposal < ActiveRecord::Migration[5.1]
4
+ class Component < ApplicationRecord
5
+ self.table_name = :decidim_components
6
+ end
7
+
8
+ def change
9
+ proposal_components = Component.where(manifest_name: "proposals")
10
+
11
+ proposal_components.each do |component|
12
+ settings = component.attributes["settings"]
13
+ settings["global"]["threshold_per_proposal"] ||= 0
14
+ component.settings = settings
15
+ component.save
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ContentParsers
5
+ # A parser that searches mentions of Proposals in content.
6
+ #
7
+ # This parser accepts two ways for linking Proposals.
8
+ # - Using a standard url starting with http or https.
9
+ # - With a word starting with `~` and digits afterwards will be considered a possible mentioned proposal.
10
+ # For example `~1234`, but no `~ 1234`.
11
+ #
12
+ # Also fills a `Metadata#linked_proposals` attribute.
13
+ #
14
+ # @see BaseParser Examples of how to use a content parser
15
+ class ProposalParser < BaseParser
16
+ # Class used as a container for metadata
17
+ #
18
+ # @!attribute linked_proposals
19
+ # @return [Array] an array of Decidim::Proposals::Proposal mentioned in content
20
+ Metadata = Struct.new(:linked_proposals)
21
+
22
+ # Matches a URL
23
+ URL_REGEX_PART1 = '(?i)\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|'
24
+ URL_REGEX_PART2 = '\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))'
25
+ URL_REGEX = /#{URL_REGEX_PART1}#{URL_REGEX_PART2}/i
26
+ # Matches a mentioned Proposal ID (~(d)+ expression)
27
+ ID_REGEX = /~(\d+)/
28
+
29
+ def initialize(content, context)
30
+ super
31
+ @metadata = Metadata.new([])
32
+ end
33
+
34
+ # Replaces found mentions matching an existing
35
+ # Proposal with a global id for that Proposal. Other mentions found that doesn't
36
+ # match an existing Proposal are returned as they are.
37
+ #
38
+ # @return [String] the content with the valid mentions replaced by a global id.
39
+ def rewrite
40
+ rewrited_content = parse_for_urls(content)
41
+ parse_for_ids(rewrited_content)
42
+ end
43
+
44
+ # (see BaseParser#metadata)
45
+ attr_reader :metadata
46
+
47
+ private
48
+
49
+ def parse_for_urls(content)
50
+ content.gsub(URL_REGEX) do |match|
51
+ proposal = proposal_from_url_match(match)
52
+ if proposal
53
+ @metadata.linked_proposals << proposal.id
54
+ proposal.to_global_id
55
+ else
56
+ match
57
+ end
58
+ end
59
+ end
60
+
61
+ def parse_for_ids(content)
62
+ content.gsub(ID_REGEX) do |match|
63
+ proposal = proposal_from_id_match(Regexp.last_match(1))
64
+ if proposal
65
+ @metadata.linked_proposals << proposal.id
66
+ proposal.to_global_id
67
+ else
68
+ match
69
+ end
70
+ end
71
+ end
72
+
73
+ def proposal_from_url_match(match)
74
+ uri = URI.parse(match)
75
+ proposal_id = uri.path.split("/").last
76
+ find_proposal_by_id(proposal_id)
77
+ end
78
+
79
+ def proposal_from_id_match(match)
80
+ proposal_id = match
81
+ find_proposal_by_id(proposal_id)
82
+ end
83
+
84
+ def find_proposal_by_id(id)
85
+ if id.present?
86
+ spaces = Decidim.participatory_space_manifests.flat_map do |manifest|
87
+ manifest.participatory_spaces.call(context[:current_organization]).public_spaces
88
+ end
89
+ components = Component.where(participatory_space: spaces).published
90
+ Decidim::Proposals::Proposal.where(component: components).find_by(id: id)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ContentRenderers
5
+ # A renderer that searches Global IDs representing proposals in content
6
+ # and replaces it with a link to their show page.
7
+ #
8
+ # e.g. gid://<APP_NAME>/Decidim::Proposals::Proposal/1
9
+ #
10
+ # @see BaseRenderer Examples of how to use a content renderer
11
+ class ProposalRenderer < BaseRenderer
12
+ # Matches a global id representing a Decidim::User
13
+ GLOBAL_ID_REGEX = %r{gid:\/\/([\w-]*\/Decidim::Proposals::Proposal\/(\d+))}i
14
+
15
+ # Replaces found Global IDs matching an existing proposal with
16
+ # a link to its show page. The Global IDs representing an
17
+ # invalid Decidim::Proposals::Proposal are replaced with '???' string.
18
+ #
19
+ # @return [String] the content ready to display (contains HTML)
20
+ def render
21
+ content.gsub(GLOBAL_ID_REGEX) do |proposal_gid|
22
+ begin
23
+ proposal = GlobalID::Locator.locate(proposal_gid)
24
+ Decidim::Proposals::ProposalPresenter.new(proposal).display_mention
25
+ rescue ActiveRecord::RecordNotFound
26
+ proposal_id = proposal_gid.split("/").last
27
+ "~#{proposal_id}"
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end