decidim-core 0.31.4 → 0.31.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/cells/decidim/amendable/amend_button_card/show.erb +2 -2
- data/app/cells/decidim/author_cell.rb +0 -4
- data/app/cells/decidim/content_blocks/cta_settings_form/show.erb +1 -1
- data/app/cells/decidim/content_blocks/hero_settings_form/show.erb +2 -2
- data/app/cells/decidim/content_blocks/highlighted_content_banner_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/highlighted_content_banner_settings_form/show.erb +1 -1
- data/app/cells/decidim/content_blocks/highlighted_participatory_spaces_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/html_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/participatory_space_hero_settings_form/show.erb +1 -1
- data/app/cells/decidim/content_blocks/static_page/section_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/static_page/section_settings_form/show.erb +3 -1
- data/app/cells/decidim/content_blocks/static_page/summary_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/static_page/summary_settings_form/show.erb +3 -1
- data/app/cells/decidim/content_blocks/static_page/two_pane_section_cell.rb +2 -2
- data/app/cells/decidim/content_blocks/static_page/two_pane_section_settings_form/show.erb +4 -2
- data/app/cells/decidim/data_consent/category.erb +5 -5
- data/app/cells/decidim/resource_types_filter/show.erb +2 -2
- data/app/cells/decidim/upload_modal_cell.rb +5 -0
- data/app/commands/decidim/destroy_account.rb +12 -1
- data/app/commands/decidim/multiple_attachments_methods.rb +28 -27
- data/app/controllers/concerns/decidim/devise_controllers.rb +10 -0
- data/app/controllers/decidim/download_your_data_controller.rb +1 -1
- data/app/controllers/decidim/notifications_subscriptions_controller.rb +8 -0
- data/app/controllers/decidim/private_downloads_controller.rb +29 -0
- data/app/jobs/decidim/process_inactive_participant_job.rb +0 -7
- data/app/mailers/decidim/delete_user_mailer.rb +14 -0
- data/app/mailers/decidim/participants_account_mailer.rb +0 -16
- data/app/models/decidim/attachment.rb +20 -2
- data/app/models/decidim/authorization.rb +7 -0
- data/app/models/decidim/moderation.rb +1 -1
- data/app/models/decidim/participatory_space_private_user.rb +1 -1
- data/app/models/decidim/private_download.rb +61 -0
- data/app/models/decidim/private_export.rb +6 -0
- data/app/models/decidim/user_base_entity.rb +17 -2
- data/app/models/decidim/user_moderation.rb +1 -1
- data/app/packs/src/decidim/controllers/form_validator/form_validator.js +6 -6
- data/app/packs/src/decidim/controllers/form_validator/form_validator.test.js +23 -1
- data/app/packs/src/decidim/controllers/mention/controller.js +296 -140
- data/app/packs/src/decidim/controllers/mention/input_mentions.test.js +120 -457
- data/app/packs/src/decidim/controllers/multiple_mentions/controller.js +68 -32
- data/app/packs/src/decidim/controllers/multiple_mentions/input_multiple_mentions.test.js +30 -23
- data/app/packs/src/decidim/direct_uploads/upload_field.js +4 -4
- data/app/packs/src/decidim/direct_uploads/upload_modal.js +11 -7
- data/app/packs/src/decidim/geocoding/reverse_geocoding.js +15 -5
- data/app/packs/src/decidim/geocoding/reverse_geocoding.test.js +197 -0
- data/app/packs/src/decidim/index.js +4 -3
- data/app/packs/src/decidim/sw/push-permissions.js +48 -13
- data/app/packs/src/decidim/sw/sw.js +1 -1
- data/app/packs/src/decidim/utilities/text.js +6 -6
- data/app/packs/stylesheets/decidim/_conversations.scss +14 -0
- data/app/packs/stylesheets/decidim/_editor_suggestions.scss +49 -0
- data/app/packs/stylesheets/decidim/_floating_help.scss +1 -1
- data/app/packs/stylesheets/decidim/_tom_select.scss +23 -0
- data/app/packs/stylesheets/decidim/application.scss +2 -0
- data/app/packs/stylesheets/decidim/editor.scss +2 -33
- data/app/packs/stylesheets/decidim/geocoding_addons.scss +10 -2
- data/app/presenters/decidim/menu_item_presenter.rb +9 -3
- data/app/presenters/decidim/stats_presenter.rb +1 -1
- data/app/services/decidim/notifications_subscriptions_persistor.rb +6 -0
- data/app/services/decidim/push_subscription_endpoint_validator.rb +34 -0
- data/app/services/decidim/send_push_notification.rb +5 -1
- data/app/uploaders/decidim/image_uploader.rb +1 -1
- data/app/views/decidim/delete_user_mailer/delete.html.erb +6 -0
- data/app/views/decidim/gamification/badges/index.html.erb +1 -1
- data/app/views/decidim/homepage/show.html.erb +1 -1
- data/app/views/decidim/last_activities/index.html.erb +1 -1
- data/app/views/decidim/messaging/conversations/_error_modal.html.erb +11 -19
- data/app/views/decidim/messaging/conversations/error.js.erb +12 -7
- data/app/views/decidim/newsletters/unsubscribe.html.erb +1 -1
- data/app/views/decidim/notifications_settings/show.html.erb +5 -5
- data/app/views/decidim/offline/show.html.erb +1 -1
- data/app/views/decidim/pages/index.html.erb +1 -1
- data/app/views/decidim/profiles/show.html.erb +1 -1
- data/app/views/decidim/shared/_resource_actions.html.erb +4 -4
- data/app/views/decidim/user_activities/index.html.erb +1 -1
- data/app/views/layouts/decidim/_wrapper.html.erb +2 -2
- data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile_tablet.html.erb +1 -1
- data/app/views/layouts/decidim/shared/_layout_center.html.erb +1 -1
- data/app/views/layouts/decidim/shared/_layout_item.html.erb +1 -1
- data/app/views/layouts/decidim/shared/_layout_two_col.html.erb +1 -1
- data/config/locales/ar.yml +0 -5
- data/config/locales/bg.yml +0 -6
- data/config/locales/ca-IT.yml +10 -10
- data/config/locales/ca.yml +10 -10
- data/config/locales/cs.yml +4 -13
- data/config/locales/de.yml +5 -17
- data/config/locales/el.yml +0 -4
- data/config/locales/en.yml +9 -9
- data/config/locales/es-MX.yml +9 -9
- data/config/locales/es-PY.yml +9 -9
- data/config/locales/es.yml +9 -9
- data/config/locales/eu.yml +49 -49
- data/config/locales/fi-plain.yml +9 -9
- data/config/locales/fi.yml +11 -11
- data/config/locales/fr-CA.yml +10 -9
- data/config/locales/fr.yml +10 -9
- data/config/locales/gl.yml +0 -3
- data/config/locales/hu.yml +0 -5
- data/config/locales/id-ID.yml +0 -3
- data/config/locales/it.yml +11 -3
- data/config/locales/ja.yml +24 -21
- data/config/locales/lb.yml +0 -5
- data/config/locales/lt.yml +0 -5
- data/config/locales/lv.yml +0 -3
- data/config/locales/nl.yml +0 -5
- data/config/locales/no.yml +0 -5
- data/config/locales/pl.yml +2 -8
- data/config/locales/pt-BR.yml +3 -16
- data/config/locales/pt.yml +0 -5
- data/config/locales/ro-RO.yml +1 -14
- data/config/locales/sk.yml +1408 -4
- data/config/locales/sv.yml +3 -11
- data/config/locales/tr-TR.yml +0 -6
- data/config/locales/zh-CN.yml +0 -5
- data/config/locales/zh-TW.yml +0 -5
- data/config/routes.rb +1 -0
- data/lib/decidim/api/functions/user_entity_list.rb +2 -0
- data/lib/decidim/attachment_attributes.rb +58 -9
- data/lib/decidim/command.rb +1 -1
- data/lib/decidim/content_renderers/base_renderer.rb +112 -0
- data/lib/decidim/content_renderers/blob_renderer.rb +4 -7
- data/lib/decidim/content_renderers/mention_resource_renderer.rb +10 -6
- data/lib/decidim/content_renderers/resource_renderer.rb +16 -7
- data/lib/decidim/content_renderers/user_renderer.rb +11 -9
- data/lib/decidim/core/content_blocks/registry_manager.rb +4 -4
- data/lib/decidim/core/engine.rb +8 -0
- data/lib/decidim/core/test/factories.rb +3 -0
- data/lib/decidim/core/test/shared_examples/admin_resource_gallery_examples.rb +10 -10
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +6 -6
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/map/autocomplete.rb +4 -3
- data/lib/decidim/searchable.rb +5 -0
- data/lib/decidim/view_model.rb +1 -1
- data/lib/tasks/decidim_mailers_tasks.rake +31 -9
- metadata +14 -10
- data/app/commands/decidim/gallery_methods.rb +0 -107
- data/app/packs/src/decidim/vendor/tribute.js +0 -1890
- data/app/packs/stylesheets/decidim/_tribute.scss +0 -36
- data/app/views/decidim/participants_account_mailer/removal_notification.html.erb +0 -11
data/config/locales/sv.yml
CHANGED
|
@@ -422,8 +422,8 @@ sv:
|
|
|
422
422
|
success: Ändringsförslaget har dragits tillbaka.
|
|
423
423
|
wizard_step_form:
|
|
424
424
|
steps:
|
|
425
|
-
'1': Skapa
|
|
426
|
-
'2': Publicera
|
|
425
|
+
'1': Skapa din korrigering
|
|
426
|
+
'2': Publicera din korrigering
|
|
427
427
|
anonymous_user: Anonym
|
|
428
428
|
application:
|
|
429
429
|
document:
|
|
@@ -556,7 +556,6 @@ sv:
|
|
|
556
556
|
global:
|
|
557
557
|
amendments_enabled: Aktivera ändringsförslag
|
|
558
558
|
comments_enabled: Aktivera kommentarer
|
|
559
|
-
comments_max_length: Maximal längd på kommentarer
|
|
560
559
|
define_taxonomy_filters: Ställ in filter innan du använder den här inställningen.
|
|
561
560
|
dummy_global_attribute1: Dummy Attribut 1
|
|
562
561
|
dummy_global_attribute2: Dummy Attribut 2
|
|
@@ -1215,7 +1214,6 @@ sv:
|
|
|
1215
1214
|
create:
|
|
1216
1215
|
error: Konversationen har inte startat. Försök igen senare.
|
|
1217
1216
|
error_modal:
|
|
1218
|
-
close: Stäng fönster
|
|
1219
1217
|
correct_errors: Vänligen korrigera felen och försök igen.
|
|
1220
1218
|
intro: 'Det fanns följande fel med ditt meddelande:'
|
|
1221
1219
|
ok: Ok
|
|
@@ -1341,6 +1339,7 @@ sv:
|
|
|
1341
1339
|
own_activity: Min egen verksamhet, som när någon kommenterar mitt förslag eller nämner mig
|
|
1342
1340
|
push_notifications: Push-meddelanden
|
|
1343
1341
|
push_notifications_reminder: För att få aviseringar från plattformen måste du först tillåta dem i webbläsarens inställningar.
|
|
1342
|
+
push_notifications_unsupported_browser: Din webbläsare stöds inte.
|
|
1344
1343
|
receive_notifications_about: Jag vill få notiser om
|
|
1345
1344
|
update_notifications_settings: Spara ändringar
|
|
1346
1345
|
update:
|
|
@@ -1526,13 +1525,6 @@ sv:
|
|
|
1526
1525
|
log_in: logga in
|
|
1527
1526
|
never_logged_in: har aldrig loggat in
|
|
1528
1527
|
subject: Varning om inaktivt konto
|
|
1529
|
-
removal_notification:
|
|
1530
|
-
body: Ditt %{organization_name}-konto har tagits bort på grund av inaktivitet.
|
|
1531
|
-
greetings_html: |
|
|
1532
|
-
Vänliga hälsningar,<br>
|
|
1533
|
-
%{organization_name}
|
|
1534
|
-
hello: Hej %{username},
|
|
1535
|
-
subject: Inaktivt konto raderat
|
|
1536
1528
|
passwords:
|
|
1537
1529
|
update:
|
|
1538
1530
|
error: Det gick inte att uppdatera lösenordet.
|
data/config/locales/tr-TR.yml
CHANGED
|
@@ -202,10 +202,6 @@ tr:
|
|
|
202
202
|
update_draft:
|
|
203
203
|
error: Değişiklik taslağı güncellenirken bir hata oluştu.
|
|
204
204
|
success: Değişiklik taslağı başarıyla güncellendi.
|
|
205
|
-
wizard_step_form:
|
|
206
|
-
steps:
|
|
207
|
-
'1': Değişikliğinizi oluşturun
|
|
208
|
-
'2': Değişikliğinizi yayınlayın
|
|
209
205
|
anonymous_user: Anonim
|
|
210
206
|
application:
|
|
211
207
|
document:
|
|
@@ -305,7 +301,6 @@ tr:
|
|
|
305
301
|
global:
|
|
306
302
|
amendments_enabled: Değişiklikler etkinleştirildi
|
|
307
303
|
comments_enabled: Yorumlar etkin
|
|
308
|
-
comments_max_length: Maksimum yorum uzunluğu
|
|
309
304
|
dummy_global_attribute1: Sahet Özellik 1
|
|
310
305
|
dummy_global_attribute2: Sahte Özellik 2
|
|
311
306
|
dummy_global_translatable_text: Sahte Çevrilebilir Metin
|
|
@@ -633,7 +628,6 @@ tr:
|
|
|
633
628
|
modal_title: Yeni görüşme
|
|
634
629
|
no_results: Sonuç bulunamadı
|
|
635
630
|
error_modal:
|
|
636
|
-
close: Pencereyi kapat
|
|
637
631
|
correct_errors: Lütfen hataları düzeltip tekrar deneyin.
|
|
638
632
|
intro: 'Mesajınızda aşağıdaki hatalar vardı:'
|
|
639
633
|
ok: OK
|
data/config/locales/zh-CN.yml
CHANGED
|
@@ -176,9 +176,6 @@ zh-CN:
|
|
|
176
176
|
update_draft:
|
|
177
177
|
error: 更新修正草案时遇到问题。
|
|
178
178
|
success: 修正草稿已成功更新。
|
|
179
|
-
wizard_step_form:
|
|
180
|
-
steps:
|
|
181
|
-
'1': 创建您的修改
|
|
182
179
|
anonymous_user: 匿名的
|
|
183
180
|
application:
|
|
184
181
|
document:
|
|
@@ -266,7 +263,6 @@ zh-CN:
|
|
|
266
263
|
global:
|
|
267
264
|
amendments_enabled: 修改已启用
|
|
268
265
|
comments_enabled: 评论已启用
|
|
269
|
-
comments_max_length: 评论最大长度
|
|
270
266
|
dummy_global_attribute1: 虚拟属性 1
|
|
271
267
|
dummy_global_attribute2: 虚拟属性 2
|
|
272
268
|
dummy_global_translatable_text: 虚拟可翻译文本
|
|
@@ -546,7 +542,6 @@ zh-CN:
|
|
|
546
542
|
modal_title: 新建对话
|
|
547
543
|
no_results: 没有结果
|
|
548
544
|
error_modal:
|
|
549
|
-
close: 关闭模式
|
|
550
545
|
correct_errors: 请更正错误,然后重试。
|
|
551
546
|
intro: '您的消息有以下错误:'
|
|
552
547
|
ok: 好的
|
data/config/locales/zh-TW.yml
CHANGED
|
@@ -293,9 +293,6 @@ zh-TW:
|
|
|
293
293
|
success: 修正案草稿成功更新。
|
|
294
294
|
withdraw:
|
|
295
295
|
success: 修正案已成功撤回.
|
|
296
|
-
wizard_step_form:
|
|
297
|
-
steps:
|
|
298
|
-
'1': 創建您的修正案
|
|
299
296
|
anonymous_user: 匿名
|
|
300
297
|
application:
|
|
301
298
|
document:
|
|
@@ -409,7 +406,6 @@ zh-TW:
|
|
|
409
406
|
global:
|
|
410
407
|
amendments_enabled: 修改功能已啟用
|
|
411
408
|
comments_enabled: 啟用評論功能
|
|
412
|
-
comments_max_length: 評論最大長度
|
|
413
409
|
dummy_global_attribute1: 虛擬屬性 1
|
|
414
410
|
dummy_global_attribute2: 虛擬屬性 2
|
|
415
411
|
dummy_global_translatable_text: 虛擬可翻譯文字
|
|
@@ -819,7 +815,6 @@ zh-TW:
|
|
|
819
815
|
create:
|
|
820
816
|
error: 對話未開始。請稍後再試。
|
|
821
817
|
error_modal:
|
|
822
|
-
close: 關閉視窗
|
|
823
818
|
correct_errors: 請修正錯誤後再試一次。
|
|
824
819
|
intro: '您的訊息有以下錯誤:'
|
|
825
820
|
ok: 好的
|
data/config/routes.rb
CHANGED
|
@@ -11,6 +11,7 @@ module Decidim
|
|
|
11
11
|
#
|
|
12
12
|
class UserEntityList
|
|
13
13
|
include NeedsApiFilterAndOrder
|
|
14
|
+
include NeedsApiDefaultOrder
|
|
14
15
|
|
|
15
16
|
def initialize
|
|
16
17
|
@model_class = Decidim::UserBaseEntity
|
|
@@ -24,6 +25,7 @@ module Decidim
|
|
|
24
25
|
.includes(avatar_attachment: :blob)
|
|
25
26
|
add_filter_keys(args[:filter])
|
|
26
27
|
add_order_keys(args[:order].to_h)
|
|
28
|
+
add_default_order
|
|
27
29
|
@query
|
|
28
30
|
end
|
|
29
31
|
end
|
|
@@ -15,24 +15,39 @@ module Decidim
|
|
|
15
15
|
#
|
|
16
16
|
# name - The attribute's name
|
|
17
17
|
#
|
|
18
|
-
#
|
|
19
18
|
# Example:
|
|
20
19
|
#
|
|
21
|
-
#
|
|
20
|
+
# attachments_attribute :photos
|
|
22
21
|
# # This will create two attributes of the following types:
|
|
23
22
|
# # attribute :photos, Array[Integer]
|
|
24
23
|
# # attribute :add_photos, Array
|
|
25
|
-
# # In addition, it will generate
|
|
26
|
-
# #
|
|
24
|
+
# # In addition, it will generate:
|
|
25
|
+
# # - A setter that handles String (JSON/CSV), Integer, or Array inputs.
|
|
26
|
+
# # - A getter that falls back to add_photos when the attribute is blank.
|
|
27
|
+
# # - Private helpers for parsing and extracting IDs.
|
|
27
28
|
#
|
|
28
29
|
# Returns nothing.
|
|
29
|
-
def attachments_attribute(name)
|
|
30
|
+
def attachments_attribute(name) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
30
31
|
attribute name, Array[Integer]
|
|
31
32
|
attribute :"add_#{name}", Array
|
|
32
33
|
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
34
|
+
# Setter: coerces String (JSON or comma-separated IDs) and bare Integer
|
|
35
|
+
# values into the expected Array[Integer] format before delegating to super.
|
|
36
|
+
define_method :"#{name}=" do |value|
|
|
37
|
+
case value
|
|
38
|
+
when String
|
|
39
|
+
parsed = send(:"parse_string_#{name}", value)
|
|
40
|
+
parsed.any? ? super(parsed) : super(value)
|
|
41
|
+
when Integer
|
|
42
|
+
super([value])
|
|
43
|
+
else
|
|
44
|
+
super(value)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Getter: resolves stored integer IDs to Decidim::Attachment records,
|
|
49
|
+
# caching the result on the instance. Falls back to extracting IDs from
|
|
50
|
+
# add_<name> when the attribute itself is blank, then resolves those too.
|
|
36
51
|
variable_name = "@#{name}_records"
|
|
37
52
|
define_method name do
|
|
38
53
|
return instance_variable_get(variable_name) if instance_variable_defined?(variable_name)
|
|
@@ -40,9 +55,15 @@ module Decidim
|
|
|
40
55
|
original = @attributes[name.to_s].value_before_type_cast
|
|
41
56
|
return original if original && !original.is_a?(Array)
|
|
42
57
|
|
|
58
|
+
ids = if super().blank? && send(:"add_#{name}").present?
|
|
59
|
+
send(:"extract_ids_from_add_#{name}")
|
|
60
|
+
else
|
|
61
|
+
super()
|
|
62
|
+
end
|
|
63
|
+
|
|
43
64
|
instance_variable_set(
|
|
44
65
|
variable_name,
|
|
45
|
-
|
|
66
|
+
ids.map do |attachment|
|
|
46
67
|
if attachment.is_a?(Integer)
|
|
47
68
|
Decidim::Attachment.find_by(id: attachment)
|
|
48
69
|
else
|
|
@@ -51,6 +72,34 @@ module Decidim
|
|
|
51
72
|
end.compact
|
|
52
73
|
)
|
|
53
74
|
end
|
|
75
|
+
|
|
76
|
+
# Private helpers -------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
define_method :"extract_ids_from_add_#{name}" do
|
|
79
|
+
send(:"add_#{name}")
|
|
80
|
+
.select { |item| item.is_a?(Hash) && (item[:id].present? || item["id"].present?) }
|
|
81
|
+
.map { |item| (item[:id] || item["id"]).to_i }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
define_method :"parse_string_#{name}" do |value|
|
|
85
|
+
return [] if value.blank?
|
|
86
|
+
|
|
87
|
+
send(:"parse_#{name}_ids", value)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
define_method :"parse_#{name}_ids" do |value|
|
|
91
|
+
ids = begin
|
|
92
|
+
Array(JSON.parse(value))
|
|
93
|
+
rescue JSON::ParserError
|
|
94
|
+
value.split(",").map(&:strip)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
ids.map(&:to_i).reject(&:zero?)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private :"extract_ids_from_add_#{name}"
|
|
101
|
+
private :"parse_string_#{name}"
|
|
102
|
+
private :"parse_#{name}_ids"
|
|
54
103
|
end
|
|
55
104
|
end
|
|
56
105
|
end
|
data/lib/decidim/command.rb
CHANGED
|
@@ -12,6 +12,16 @@ module Decidim
|
|
|
12
12
|
class BaseRenderer
|
|
13
13
|
include Decidim::ContentProcessor::Common
|
|
14
14
|
|
|
15
|
+
ReplacementContext = Struct.new(:placement, :node_name, :attribute_name, :ancestor_names, keyword_init: true) do
|
|
16
|
+
def text?
|
|
17
|
+
placement == :text
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def attribute?
|
|
21
|
+
placement == :attribute
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
15
25
|
# @return [String] the content to be formatted
|
|
16
26
|
attr_reader :content
|
|
17
27
|
|
|
@@ -34,6 +44,108 @@ module Decidim
|
|
|
34
44
|
def render(_options = nil)
|
|
35
45
|
content
|
|
36
46
|
end
|
|
47
|
+
|
|
48
|
+
protected
|
|
49
|
+
|
|
50
|
+
def replace_pattern_by_context(text, pattern, skip_ancestor_tags: %w(code pre script style), on_missing: "")
|
|
51
|
+
return text unless text.respond_to?(:gsub)
|
|
52
|
+
|
|
53
|
+
skip_ancestor_tags = Array(skip_ancestor_tags).map(&:to_s)
|
|
54
|
+
|
|
55
|
+
has_match = pattern.is_a?(String) ? text.include?(pattern) : pattern.match?(text)
|
|
56
|
+
return text unless has_match
|
|
57
|
+
|
|
58
|
+
fragment = html_fragment(text)
|
|
59
|
+
attr_modified = replace_pattern_in_attributes(fragment, pattern, skip_ancestor_tags:, on_missing:) do |match, context|
|
|
60
|
+
yield(match, context)
|
|
61
|
+
end
|
|
62
|
+
text_modified = replace_pattern_in_text_nodes(fragment, pattern, skip_ancestor_tags:, on_missing:) do |match, context|
|
|
63
|
+
yield(match, context)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
return text unless attr_modified || text_modified
|
|
67
|
+
|
|
68
|
+
fragment.to_s
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def replace_pattern_in_attributes(fragment, pattern, skip_ancestor_tags:, on_missing:)
|
|
74
|
+
modified = false
|
|
75
|
+
fragment.xpath(".//*").each do |node|
|
|
76
|
+
next if skip_replacement_for_node?(node, skip_ancestor_tags)
|
|
77
|
+
|
|
78
|
+
node.attribute_nodes.each do |attribute|
|
|
79
|
+
replaced_value = attribute.value.gsub(pattern) do |match|
|
|
80
|
+
replace_match(match, replacement_context(node, placement: :attribute, attribute_name: attribute.name), on_missing:) do |resolved_match, context|
|
|
81
|
+
yield(resolved_match, context)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
unless replaced_value == attribute.value
|
|
85
|
+
attribute.value = replaced_value
|
|
86
|
+
modified = true
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
modified
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def replace_pattern_in_text_nodes(fragment, pattern, skip_ancestor_tags:, on_missing:)
|
|
94
|
+
modified = false
|
|
95
|
+
fragment.xpath(".//text()").each do |node|
|
|
96
|
+
parent = node.parent
|
|
97
|
+
next if skip_replacement_for_node?(parent, skip_ancestor_tags)
|
|
98
|
+
|
|
99
|
+
original_text = node.text
|
|
100
|
+
has_node_match = pattern.is_a?(String) ? original_text.include?(pattern) : pattern.match?(original_text)
|
|
101
|
+
next unless has_node_match
|
|
102
|
+
|
|
103
|
+
doc = node.document
|
|
104
|
+
context = replacement_context(parent, placement: :text)
|
|
105
|
+
last_pos = 0
|
|
106
|
+
|
|
107
|
+
original_text.scan(pattern) do
|
|
108
|
+
m = Regexp.last_match
|
|
109
|
+
node.add_previous_sibling(Nokogiri::XML::Text.new(original_text[last_pos...m.begin(0)], doc)) if m.begin(0) > last_pos
|
|
110
|
+
|
|
111
|
+
replacement = replace_match(m[0], context, on_missing:) do |resolved_match, ctx|
|
|
112
|
+
yield(resolved_match, ctx)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
Loofah.fragment(replacement.to_s).children.to_a.each do |child|
|
|
116
|
+
node.add_previous_sibling(child)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
last_pos = m.end(0)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
node.add_previous_sibling(Nokogiri::XML::Text.new(original_text[last_pos..], doc)) if last_pos < original_text.length
|
|
123
|
+
node.remove
|
|
124
|
+
modified = true
|
|
125
|
+
end
|
|
126
|
+
modified
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def replace_match(match, context, on_missing:)
|
|
130
|
+
yield(match, context)
|
|
131
|
+
rescue ActiveRecord::RecordNotFound
|
|
132
|
+
on_missing.respond_to?(:call) ? on_missing.call(match, context) : on_missing
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def replacement_context(node, placement:, attribute_name: nil)
|
|
136
|
+
ReplacementContext.new(
|
|
137
|
+
placement:,
|
|
138
|
+
node_name: node&.name,
|
|
139
|
+
attribute_name:,
|
|
140
|
+
ancestor_names: node ? node.ancestors.map(&:name) : []
|
|
141
|
+
)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def skip_replacement_for_node?(node, skip_ancestor_tags)
|
|
145
|
+
return false unless node
|
|
146
|
+
|
|
147
|
+
([node.name] + node.ancestors.map(&:name)).any? { |name| skip_ancestor_tags.include?(name) }
|
|
148
|
+
end
|
|
37
149
|
end
|
|
38
150
|
end
|
|
39
151
|
end
|
|
@@ -33,11 +33,10 @@ module Decidim
|
|
|
33
33
|
protected
|
|
34
34
|
|
|
35
35
|
def replace_pattern(text, pattern)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
variation_key = Regexp.last_match(3)
|
|
36
|
+
replace_pattern_by_context(text, pattern) do |match, _context|
|
|
37
|
+
match_data = match.match(GLOBAL_ID_REGEX)
|
|
38
|
+
blob_gid = match_data[1]
|
|
39
|
+
variation_key = match_data[3]
|
|
41
40
|
|
|
42
41
|
blob = GlobalID::Locator.locate(blob_gid)
|
|
43
42
|
if variation_key
|
|
@@ -50,8 +49,6 @@ module Decidim
|
|
|
50
49
|
else
|
|
51
50
|
blob_url(blob)
|
|
52
51
|
end
|
|
53
|
-
rescue ActiveRecord::RecordNotFound => _e
|
|
54
|
-
""
|
|
55
52
|
end
|
|
56
53
|
end
|
|
57
54
|
|
|
@@ -27,17 +27,15 @@ module Decidim
|
|
|
27
27
|
protected
|
|
28
28
|
|
|
29
29
|
def replace_pattern(text, pattern, editor:)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
text.gsub(pattern) do |resource_gid|
|
|
30
|
+
replace_pattern_by_context(text, pattern) do |resource_gid, context|
|
|
33
31
|
resource = GlobalID::Locator.locate(resource_gid)
|
|
34
|
-
if
|
|
32
|
+
if context.attribute?
|
|
33
|
+
render_resource_url(resource, editor:)
|
|
34
|
+
elsif editor
|
|
35
35
|
render_editor(resource_gid, resource)
|
|
36
36
|
else
|
|
37
37
|
render_resource_link(resource)
|
|
38
38
|
end
|
|
39
|
-
rescue ActiveRecord::RecordNotFound => _e
|
|
40
|
-
""
|
|
41
39
|
end
|
|
42
40
|
end
|
|
43
41
|
|
|
@@ -50,6 +48,12 @@ module Decidim
|
|
|
50
48
|
link_to mention_title(resource), resource_path(resource)
|
|
51
49
|
end
|
|
52
50
|
|
|
51
|
+
def render_resource_url(resource, editor:)
|
|
52
|
+
return resource_path(resource) if editor
|
|
53
|
+
|
|
54
|
+
Decidim::ResourceLocatorPresenter.new(resource).url
|
|
55
|
+
end
|
|
56
|
+
|
|
53
57
|
def mention_title(resource)
|
|
54
58
|
title = presenter_for(resource).title
|
|
55
59
|
|
|
@@ -11,17 +11,26 @@ module Decidim
|
|
|
11
11
|
#
|
|
12
12
|
# @return [String] the content ready to display (contains HTML)
|
|
13
13
|
def render(_options = nil)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
content.gsub(regex) do |resource_gid|
|
|
14
|
+
replace_pattern_by_context(content, regex, on_missing: proc { |match, _| "~#{match.split("/").last}" }) do |resource_gid, context|
|
|
17
15
|
resource = GlobalID::Locator.locate(resource_gid)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
|
|
17
|
+
if context.attribute?
|
|
18
|
+
resource_attribute_value(resource)
|
|
19
|
+
else
|
|
20
|
+
resource.presenter.display_mention
|
|
21
|
+
end
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
protected
|
|
26
|
+
|
|
27
|
+
def resource_attribute_value(resource)
|
|
28
|
+
presenter = resource.presenter
|
|
29
|
+
return presenter.profile_path if presenter.respond_to?(:profile_path)
|
|
30
|
+
|
|
31
|
+
Decidim::ResourceLocatorPresenter.new(resource).path
|
|
32
|
+
end
|
|
33
|
+
|
|
25
34
|
def regex
|
|
26
35
|
raise "Not implemented"
|
|
27
36
|
end
|
|
@@ -24,17 +24,15 @@ module Decidim
|
|
|
24
24
|
protected
|
|
25
25
|
|
|
26
26
|
def replace_pattern(text, pattern, editor:)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
render_editor(
|
|
27
|
+
replace_pattern_by_context(text, pattern) do |user_gid, context|
|
|
28
|
+
user = GlobalID::Locator.locate(user_gid)
|
|
29
|
+
if context.attribute?
|
|
30
|
+
render_profile_path(user)
|
|
31
|
+
elsif editor
|
|
32
|
+
render_editor(user)
|
|
33
33
|
else
|
|
34
|
-
render_text(
|
|
34
|
+
render_text(user)
|
|
35
35
|
end
|
|
36
|
-
rescue ActiveRecord::RecordNotFound => _e
|
|
37
|
-
""
|
|
38
36
|
end
|
|
39
37
|
end
|
|
40
38
|
|
|
@@ -55,6 +53,10 @@ module Decidim
|
|
|
55
53
|
presenter_for(user).display_mention
|
|
56
54
|
end
|
|
57
55
|
end
|
|
56
|
+
|
|
57
|
+
def render_profile_path(user)
|
|
58
|
+
presenter_for(user).profile_path
|
|
59
|
+
end
|
|
58
60
|
end
|
|
59
61
|
end
|
|
60
62
|
end
|
|
@@ -51,11 +51,11 @@ module Decidim
|
|
|
51
51
|
]
|
|
52
52
|
|
|
53
53
|
content_block.settings do |settings|
|
|
54
|
-
settings.attribute :title, type: :text, translated: true
|
|
54
|
+
settings.attribute :title, type: :text, translated: true, required: true
|
|
55
55
|
settings.attribute :short_description, type: :text, translated: true
|
|
56
|
-
settings.attribute :action_button_title, type: :text, translated: true
|
|
57
|
-
settings.attribute :action_button_subtitle, type: :text, translated: true
|
|
58
|
-
settings.attribute :action_button_url, type: :text
|
|
56
|
+
settings.attribute :action_button_title, type: :text, translated: true, required: true
|
|
57
|
+
settings.attribute :action_button_subtitle, type: :text, translated: true, required: true
|
|
58
|
+
settings.attribute :action_button_url, type: :text, required: true
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
content_block.default!
|
data/lib/decidim/core/engine.rb
CHANGED
|
@@ -495,6 +495,14 @@ module Decidim
|
|
|
495
495
|
end
|
|
496
496
|
end
|
|
497
497
|
|
|
498
|
+
initializer "decidim_core.delete_account" do
|
|
499
|
+
config.to_prepare do
|
|
500
|
+
ActiveSupport::Notifications.subscribe("decidim.destroy_account:after") do |_event_name, data|
|
|
501
|
+
Decidim::DeleteUserMailer.delete(user_email: data[:user_email], user_name: data[:user_name], locale: data[:locale], organization: data[:organization]).deliver_later
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
|
|
498
506
|
initializer "decidim_core.add_cells_view_paths" do
|
|
499
507
|
Cell::ViewModel.view_paths << Rails.root.join("app/views") # for partials
|
|
500
508
|
Cell::ViewModel.view_paths << File.expand_path("#{Decidim::Core::Engine.root}/app/cells")
|
|
@@ -85,6 +85,8 @@ FactoryBot.define do
|
|
|
85
85
|
"#{Faker::Lorem.sentence(word_count: 1, supplemental: true, random_words_to_add: 3)} #{n}"
|
|
86
86
|
end
|
|
87
87
|
|
|
88
|
+
sequence(:component_position)
|
|
89
|
+
|
|
88
90
|
factory :category, class: "Decidim::Category" do
|
|
89
91
|
transient do
|
|
90
92
|
skip_injection { false }
|
|
@@ -463,6 +465,7 @@ FactoryBot.define do
|
|
|
463
465
|
manifest_name { "dummy" }
|
|
464
466
|
published_at { Time.current }
|
|
465
467
|
deleted_at { nil }
|
|
468
|
+
weight { generate(:component_position) }
|
|
466
469
|
settings do
|
|
467
470
|
{
|
|
468
471
|
dummy_global_translatable_text: generate_localized_title(:dummy_global_translatable_text, skip_injection:),
|
|
@@ -87,7 +87,7 @@ end
|
|
|
87
87
|
|
|
88
88
|
shared_examples "admin creates resource gallery" do
|
|
89
89
|
context "when uploading images" do
|
|
90
|
-
let(:
|
|
90
|
+
let(:uploaded_attachments) do
|
|
91
91
|
[
|
|
92
92
|
{
|
|
93
93
|
title: "Picture of the city",
|
|
@@ -99,10 +99,10 @@ shared_examples "admin creates resource gallery" do
|
|
|
99
99
|
}
|
|
100
100
|
]
|
|
101
101
|
end
|
|
102
|
-
let(:
|
|
102
|
+
let(:current_attachments) { [] }
|
|
103
103
|
|
|
104
104
|
it "creates a gallery for the resource" do
|
|
105
|
-
expect { command.call }.to change(Decidim::Attachment, :count).by(
|
|
105
|
+
expect { command.call }.to change(Decidim::Attachment, :count).by(uploaded_attachments.count)
|
|
106
106
|
|
|
107
107
|
resource = resource_class.last
|
|
108
108
|
expect(resource.photos.count).to eq(2)
|
|
@@ -111,7 +111,7 @@ shared_examples "admin creates resource gallery" do
|
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
context "when gallery is left blank" do
|
|
114
|
-
let(:
|
|
114
|
+
let(:uploaded_attachments) { [] }
|
|
115
115
|
|
|
116
116
|
it "broadcasts ok" do
|
|
117
117
|
expect { command.call }.to broadcast(:ok)
|
|
@@ -122,7 +122,7 @@ end
|
|
|
122
122
|
|
|
123
123
|
shared_examples "admin manages resource gallery" do
|
|
124
124
|
context "when managing images" do
|
|
125
|
-
let(:
|
|
125
|
+
let(:uploaded_attachments) do
|
|
126
126
|
[
|
|
127
127
|
{
|
|
128
128
|
title: "Picture of the city",
|
|
@@ -134,10 +134,10 @@ shared_examples "admin manages resource gallery" do
|
|
|
134
134
|
}
|
|
135
135
|
]
|
|
136
136
|
end
|
|
137
|
-
let(:
|
|
137
|
+
let(:current_attachments) { [] }
|
|
138
138
|
|
|
139
139
|
it "creates a gallery for the resource" do
|
|
140
|
-
expect { command.call }.to change(Decidim::Attachment, :count).by(
|
|
140
|
+
expect { command.call }.to change(Decidim::Attachment, :count).by(uploaded_attachments.count)
|
|
141
141
|
resource = resource_class.last
|
|
142
142
|
expect(resource.photos.count).to eq(2)
|
|
143
143
|
last_attachment = Decidim::Attachment.last
|
|
@@ -145,7 +145,7 @@ shared_examples "admin manages resource gallery" do
|
|
|
145
145
|
end
|
|
146
146
|
|
|
147
147
|
context "when gallery is left blank" do
|
|
148
|
-
let(:
|
|
148
|
+
let(:uploaded_attachments) { [] }
|
|
149
149
|
|
|
150
150
|
it "broadcasts ok" do
|
|
151
151
|
expect { command.call }.to broadcast(:ok)
|
|
@@ -155,8 +155,8 @@ shared_examples "admin manages resource gallery" do
|
|
|
155
155
|
context "when images are removed" do
|
|
156
156
|
let!(:image1) { create(:attachment, :with_image, attached_to: resource) }
|
|
157
157
|
let!(:image2) { create(:attachment, :with_image, attached_to: resource) }
|
|
158
|
-
let(:
|
|
159
|
-
let(:
|
|
158
|
+
let(:uploaded_attachments) { [] }
|
|
159
|
+
let(:current_attachments) { [image1.id] }
|
|
160
160
|
|
|
161
161
|
it "to decrease the number of photos in the gallery" do
|
|
162
162
|
expect(resource.attachments.count).to eq(2)
|
|
@@ -1000,16 +1000,16 @@ shared_examples "comments" do
|
|
|
1000
1000
|
let(:content) { "A valid user mention: @#{mentioned_user.nickname}" }
|
|
1001
1001
|
|
|
1002
1002
|
context "when text finish with a mention" do
|
|
1003
|
-
it "shows the
|
|
1004
|
-
expect(page).to have_css(".
|
|
1003
|
+
it "shows the suggestions menu" do
|
|
1004
|
+
expect(page).to have_css(".editor-suggestions-item", text: "@#{mentioned_user.nickname} (#{mentioned_user.name})", wait: 10)
|
|
1005
1005
|
end
|
|
1006
1006
|
end
|
|
1007
1007
|
|
|
1008
1008
|
context "when text contains a mention" do
|
|
1009
1009
|
let(:content) { "A valid user mention: @#{mentioned_user.nickname}." }
|
|
1010
1010
|
|
|
1011
|
-
it "
|
|
1012
|
-
expect(page).to have_no_css(".
|
|
1011
|
+
it "hides the suggestions menu" do
|
|
1012
|
+
expect(page).to have_no_css(".editor-suggestions-item", text: "@#{mentioned_user.nickname} (#{mentioned_user.name})")
|
|
1013
1013
|
end
|
|
1014
1014
|
end
|
|
1015
1015
|
end
|
|
@@ -1018,8 +1018,8 @@ shared_examples "comments" do
|
|
|
1018
1018
|
let!(:mentioned_user) { create(:user, organization:) }
|
|
1019
1019
|
let(:content) { "A unconfirmed user mention: @#{mentioned_user.nickname}" }
|
|
1020
1020
|
|
|
1021
|
-
it "
|
|
1022
|
-
expect(page).to have_no_css(".
|
|
1021
|
+
it "does not show the suggestions menu" do
|
|
1022
|
+
expect(page).to have_no_css(".editor-suggestions-item", text: "@#{mentioned_user.nickname} (#{mentioned_user.name})")
|
|
1023
1023
|
end
|
|
1024
1024
|
end
|
|
1025
1025
|
end
|