decidim-core 0.32.0.rc2 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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/card_metadata_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/cta_settings_form/show.erb +1 -1
- data/app/cells/decidim/content_blocks/hero_settings_form/show.erb +1 -1
- 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/participatory_space_hero_settings_form/show.erb +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_settings_form/show.erb +3 -1
- data/app/cells/decidim/content_blocks/static_page/two_pane_section_settings_form/show.erb +4 -2
- data/app/cells/decidim/resource_types_filter/show.erb +2 -2
- 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 +9 -0
- data/app/events/decidim/amendable/amendment_base_event.rb +7 -1
- 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/moderation.rb +1 -1
- data/app/models/decidim/participatory_space/member.rb +1 -1
- 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/breadcrumb_truncate/breadcrumb_truncate.test.js +230 -0
- data/app/packs/src/decidim/controllers/breadcrumb_truncate/controller.js +172 -0
- 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/main_menu/controller.js +33 -0
- data/app/packs/src/decidim/controllers/main_menu/main_menu.test.js +77 -0
- 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/editor/common/suggestion.js +3 -1
- data/app/packs/src/decidim/editor/extensions/indent/index.js +9 -0
- 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/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/_dropdown.scss +1 -1
- 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/_header.scss +41 -8
- 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/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/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.html.erb +1 -1
- data/app/views/layouts/decidim/header/_menu_breadcrumb_desktop.html.erb +31 -4
- data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile.html.erb +18 -13
- 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/initializers/decidim_locale_aware_named_route_helper.rb +16 -0
- data/config/locales/ar.yml +0 -25
- data/config/locales/bg.yml +0 -25
- data/config/locales/ca-IT.yml +46 -35
- data/config/locales/ca.yml +46 -35
- data/config/locales/cs.yml +12 -34
- data/config/locales/de.yml +5 -46
- data/config/locales/el.yml +0 -22
- data/config/locales/en.yml +45 -34
- data/config/locales/es-MX.yml +45 -34
- data/config/locales/es-PY.yml +45 -34
- data/config/locales/es.yml +45 -34
- data/config/locales/eu.yml +85 -74
- data/config/locales/fi-plain.yml +46 -34
- data/config/locales/fi.yml +46 -34
- data/config/locales/fr-CA.yml +24 -30
- data/config/locales/fr.yml +24 -30
- data/config/locales/gl.yml +0 -22
- data/config/locales/hu.yml +0 -22
- data/config/locales/id-ID.yml +0 -21
- data/config/locales/is-IS.yml +0 -6
- data/config/locales/it.yml +1 -20
- data/config/locales/ja.yml +55 -44
- data/config/locales/lb.yml +0 -23
- data/config/locales/lt.yml +0 -24
- data/config/locales/lv.yml +0 -21
- data/config/locales/nl.yml +0 -23
- data/config/locales/no.yml +0 -23
- data/config/locales/pl.yml +2 -27
- data/config/locales/pt-BR.yml +2 -40
- data/config/locales/pt.yml +0 -23
- data/config/locales/ro-RO.yml +1 -32
- data/config/locales/ru.yml +0 -8
- data/config/locales/sk.yml +1 -43
- data/config/locales/sv.yml +6 -40
- data/config/locales/tr-TR.yml +0 -24
- data/config/locales/uk.yml +0 -6
- data/config/locales/zh-CN.yml +0 -21
- data/config/locales/zh-TW.yml +0 -24
- data/decidim-core.gemspec +1 -1
- 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/amendable/amendment_event_examples.rb +2 -2
- data/lib/decidim/core/test/shared_examples/amendable/amendment_promoted_event_examples.rb +3 -3
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +6 -6
- data/lib/decidim/core/test/shared_examples/has_space_in_mcell_examples.rb +2 -1
- data/lib/decidim/core/test/shared_examples/resource_liked_event_examples.rb +3 -3
- 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 +13 -9
- 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/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) 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
|
|
@@ -45,11 +45,11 @@ module Decidim
|
|
|
45
45
|
]
|
|
46
46
|
|
|
47
47
|
content_block.settings do |settings|
|
|
48
|
-
settings.attribute :title, type: :text, translated: true
|
|
48
|
+
settings.attribute :title, type: :text, translated: true, required: true
|
|
49
49
|
settings.attribute :short_description, type: :text, translated: true
|
|
50
|
-
settings.attribute :action_button_title, type: :text, translated: true
|
|
51
|
-
settings.attribute :action_button_subtitle, type: :text, translated: true
|
|
52
|
-
settings.attribute :action_button_url, type: :text
|
|
50
|
+
settings.attribute :action_button_title, type: :text, translated: true, required: true
|
|
51
|
+
settings.attribute :action_button_subtitle, type: :text, translated: true, required: true
|
|
52
|
+
settings.attribute :action_button_url, type: :text, required: true
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
content_block.default!
|
data/lib/decidim/core/engine.rb
CHANGED
|
@@ -463,6 +463,14 @@ module Decidim
|
|
|
463
463
|
end
|
|
464
464
|
end
|
|
465
465
|
|
|
466
|
+
initializer "decidim_core.delete_account" do
|
|
467
|
+
config.to_prepare do
|
|
468
|
+
ActiveSupport::Notifications.subscribe("decidim.destroy_account:after") do |_event_name, data|
|
|
469
|
+
Decidim::DeleteUserMailer.delete(user_email: data[:user_email], user_name: data[:user_name], locale: data[:locale], organization: data[:organization]).deliver_later
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
|
|
466
474
|
initializer "decidim_core.add_cells_view_paths" do
|
|
467
475
|
Cell::ViewModel.view_paths << Rails.root.join("app/views") # for partials
|
|
468
476
|
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 }
|
|
@@ -469,6 +471,7 @@ FactoryBot.define do
|
|
|
469
471
|
manifest_name { "dummy" }
|
|
470
472
|
published_at { Time.current }
|
|
471
473
|
deleted_at { nil }
|
|
474
|
+
weight { generate(:component_position) }
|
|
472
475
|
settings do
|
|
473
476
|
{
|
|
474
477
|
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)
|
|
@@ -8,7 +8,7 @@ shared_examples "amendment event" do
|
|
|
8
8
|
it_behaves_like "a simple event email"
|
|
9
9
|
it_behaves_like "a simple event notification"
|
|
10
10
|
|
|
11
|
-
let(:
|
|
11
|
+
let(:emendation_author_name) { emendation.creator_author.name }
|
|
12
12
|
let(:emendation_path) { Decidim::ResourceLocatorPresenter.new(emendation).path }
|
|
13
13
|
let(:emendation_author_path) { Decidim::UserPresenter.new(emendation.creator_author).profile_path }
|
|
14
14
|
let(:amendable_path) { Decidim::ResourceLocatorPresenter.new(amendable).path }
|
|
@@ -16,5 +16,5 @@ shared_examples "amendment event" do
|
|
|
16
16
|
let(:email_intro) { "An amendment has been #{amendment_type} for #{amendable_title}. You can see it from this page:" }
|
|
17
17
|
let(:email_outro) { "You have received this notification because you are following #{amendable_title}. You can stop receiving notifications following the previous link." }
|
|
18
18
|
|
|
19
|
-
let(:notification_title) { "The <a href=\"#{emendation_path}\">amendment</a> created by <a href=\"#{emendation_author_path}\">#{
|
|
19
|
+
let(:notification_title) { "The <a href=\"#{emendation_path}\">amendment</a> created by <a href=\"#{emendation_author_path}\">#{emendation_author_name}</a> has been #{amendment_type} for <a href=\"#{amendable_path}\">#{amendable_title}</a>." } # rubocop:disable Layout/LineLength
|
|
20
20
|
end
|
|
@@ -10,15 +10,15 @@ shared_examples "amendment promoted event" do
|
|
|
10
10
|
it_behaves_like "a simple event email"
|
|
11
11
|
it_behaves_like "a simple event notification"
|
|
12
12
|
|
|
13
|
-
let(:
|
|
13
|
+
let(:emendation_author_name) { emendation.creator_author.name }
|
|
14
14
|
let(:emendation_path) { Decidim::ResourceLocatorPresenter.new(emendation).path }
|
|
15
15
|
let(:emendation_author_path) { Decidim::UserPresenter.new(emendation.creator_author).profile_path }
|
|
16
16
|
let(:amendable_path) { Decidim::ResourceLocatorPresenter.new(amendable).path }
|
|
17
17
|
|
|
18
|
-
let(:email_subject) { "An amendment from #{
|
|
18
|
+
let(:email_subject) { "An amendment from #{emendation_author_name} has been published as a new proposal" }
|
|
19
19
|
let(:email_intro) { "A rejected amendment for #{amendable_title} has been published as a new #{amendable_type}. You can see it from this page:" }
|
|
20
20
|
let(:email_outro) { "You have received this notification because you are following #{amendable_title}. You can stop receiving notifications following the previous link." }
|
|
21
21
|
# rubocop:disable Layout/LineLength
|
|
22
|
-
let(:notification_title) { "A <a href=\"#{emendation_path}\">rejected amendment</a> for <a href=\"#{amendable_path}\">#{amendable_title}</a> has been published as a new #{amendable_type} by <a href=\"#{emendation_author_path}\">#{
|
|
22
|
+
let(:notification_title) { "A <a href=\"#{emendation_path}\">rejected amendment</a> for <a href=\"#{amendable_path}\">#{amendable_title}</a> has been published as a new #{amendable_type} by <a href=\"#{emendation_author_path}\">#{emendation_author_name}</a>." }
|
|
23
23
|
# rubocop:enable Layout/LineLength
|
|
24
24
|
end
|
|
@@ -990,16 +990,16 @@ shared_examples "comments" do
|
|
|
990
990
|
let(:content) { "A valid user mention: @#{mentioned_user.nickname}" }
|
|
991
991
|
|
|
992
992
|
context "when text finish with a mention" do
|
|
993
|
-
it "shows the
|
|
994
|
-
expect(page).to have_css(".
|
|
993
|
+
it "shows the suggestions menu" do
|
|
994
|
+
expect(page).to have_css(".editor-suggestions-item", text: "@#{mentioned_user.nickname} (#{mentioned_user.name})", wait: 10)
|
|
995
995
|
end
|
|
996
996
|
end
|
|
997
997
|
|
|
998
998
|
context "when text contains a mention" do
|
|
999
999
|
let(:content) { "A valid user mention: @#{mentioned_user.nickname}." }
|
|
1000
1000
|
|
|
1001
|
-
it "
|
|
1002
|
-
expect(page).to have_no_css(".
|
|
1001
|
+
it "hides the suggestions menu" do
|
|
1002
|
+
expect(page).to have_no_css(".editor-suggestions-item", text: "@#{mentioned_user.nickname} (#{mentioned_user.name})")
|
|
1003
1003
|
end
|
|
1004
1004
|
end
|
|
1005
1005
|
end
|
|
@@ -1008,8 +1008,8 @@ shared_examples "comments" do
|
|
|
1008
1008
|
let!(:mentioned_user) { create(:user, organization:) }
|
|
1009
1009
|
let(:content) { "A unconfirmed user mention: @#{mentioned_user.nickname}" }
|
|
1010
1010
|
|
|
1011
|
-
it "
|
|
1012
|
-
expect(page).to have_no_css(".
|
|
1011
|
+
it "does not show 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
|
|
@@ -8,7 +8,8 @@ shared_examples_for "has space in m-cell" do
|
|
|
8
8
|
let(:show_space) { true }
|
|
9
9
|
|
|
10
10
|
it "renders the space where the model belongs to" do
|
|
11
|
-
expect(cell_html).to have_content(
|
|
11
|
+
expect(cell_html).to have_content(translated_attribute(model.component.participatory_space.title))
|
|
12
|
+
expect(cell_html.to_s).to include(decidim_escape_translated(model.component.participatory_space.title).gsub(""", "\""))
|
|
12
13
|
end
|
|
13
14
|
end
|
|
14
15
|
end
|
|
@@ -30,7 +30,7 @@ shared_examples_for "resource liked event" do
|
|
|
30
30
|
|
|
31
31
|
describe "email_subject" do
|
|
32
32
|
it "is generated correctly" do
|
|
33
|
-
expect(subject.email_subject).to eq("#{author_presenter.
|
|
33
|
+
expect(subject.email_subject).to eq("#{author_presenter.name} has performed a new like")
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -38,7 +38,7 @@ shared_examples_for "resource liked event" do
|
|
|
38
38
|
let(:resource_title) { decidim_sanitize_translated(resource.title) }
|
|
39
39
|
it "is generated correctly" do
|
|
40
40
|
expect(subject.email_intro)
|
|
41
|
-
.to eq("#{author.name}
|
|
41
|
+
.to eq("#{author.name}, who you are following, " \
|
|
42
42
|
"has just liked \"#{resource_title}\" and we think it may be interesting to you. Check it out and contribute:")
|
|
43
43
|
end
|
|
44
44
|
end
|
|
@@ -51,7 +51,7 @@ shared_examples_for "resource liked event" do
|
|
|
51
51
|
.to include("The <a href=\"#{resource_path}\">#{resource_title}</a> #{resource_type} has been liked by ")
|
|
52
52
|
|
|
53
53
|
expect(subject.notification_title)
|
|
54
|
-
.to include("<a href=\"/en/profiles/#{author.nickname}\">#{author.name}
|
|
54
|
+
.to include("<a href=\"/en/profiles/#{author.nickname}\">#{author.name}</a>.")
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
|
data/lib/decidim/core/version.rb
CHANGED
|
@@ -37,19 +37,20 @@ module Decidim
|
|
|
37
37
|
template.snippets.add(:decidim_geocoding_scripts, template.append_javascript_pack_tag("decidim_geocoding"))
|
|
38
38
|
template.snippets.add(:decidim_geocoding_styles, template.append_stylesheet_pack_tag("decidim_geocoding"))
|
|
39
39
|
|
|
40
|
-
template.content_tag(:div, class: "geocoding
|
|
40
|
+
template.content_tag(:div, class: "geocoding") do
|
|
41
41
|
template.text_field(
|
|
42
42
|
object_name,
|
|
43
43
|
method,
|
|
44
44
|
options.merge("data-decidim-geocoding" => view_options.to_json)
|
|
45
45
|
) +
|
|
46
|
-
template.content_tag(:div, class: "input-group-button
|
|
47
|
-
template.content_tag(:button, class: "button button__sm md:button__sm button__text-secondary", type: "button", data: {
|
|
46
|
+
template.content_tag(:div, class: "input-group-button geocoding__locate") do
|
|
47
|
+
template.content_tag(:button, class: "button button__sm md:button__sm button__text-secondary geocoding__button", type: "button", data: {
|
|
48
48
|
input: "#{object_name}_#{method}",
|
|
49
49
|
latitude: "#{object_name}_latitude",
|
|
50
50
|
longitude: "#{object_name}_longitude",
|
|
51
51
|
error_no_location: I18n.t("errors.no_device_location", scope: "decidim.proposals.forms"),
|
|
52
52
|
error_unsupported: I18n.t("errors.device_not_supported", scope: "decidim.proposals.forms"),
|
|
53
|
+
locating_text: I18n.t("locating", scope: "decidim.proposals.forms"),
|
|
53
54
|
url: Decidim::Core::Engine.routes.url_helpers.locate_path
|
|
54
55
|
}) do
|
|
55
56
|
icon("map-pin-line", role: "img", "aria-hidden": true) + " #{I18n.t("use_my_location", scope: "decidim.proposals.forms")}"
|
data/lib/decidim/searchable.rb
CHANGED
|
@@ -117,6 +117,11 @@ module Decidim
|
|
|
117
117
|
searchables_in_org.find_each do |sr|
|
|
118
118
|
next if sr.blank?
|
|
119
119
|
|
|
120
|
+
unless sr.locale.in?(org.available_locales)
|
|
121
|
+
sr.destroy
|
|
122
|
+
next
|
|
123
|
+
end
|
|
124
|
+
|
|
120
125
|
sr.update(contents_to_searchable_resource_attributes(fields, sr.locale))
|
|
121
126
|
end
|
|
122
127
|
end
|
data/lib/decidim/view_model.rb
CHANGED
|
@@ -4,20 +4,42 @@ namespace :decidim do
|
|
|
4
4
|
namespace :mailers do
|
|
5
5
|
desc "Sends the notification digest email with the daily report"
|
|
6
6
|
task notifications_digest_daily: :environment do
|
|
7
|
-
|
|
7
|
+
time = Time.now.utc
|
|
8
|
+
target_users = Decidim::User.where(notifications_sending_frequency: :daily)
|
|
9
|
+
|
|
10
|
+
target_users.find_in_batches do |batch|
|
|
11
|
+
notification_users =
|
|
12
|
+
Decidim::Notification
|
|
13
|
+
.daily(time)
|
|
14
|
+
.where(decidim_user_id: batch.pluck(:id))
|
|
15
|
+
.select(:decidim_user_id)
|
|
16
|
+
.distinct
|
|
17
|
+
.pluck(:decidim_user_id)
|
|
18
|
+
|
|
19
|
+
notification_users.each do |user_id|
|
|
20
|
+
Decidim::EmailNotificationsDigestGeneratorJob.perform_later(user_id, :daily, time:)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
8
23
|
end
|
|
9
24
|
|
|
10
25
|
desc "Sends the notification digest email with the weekly report"
|
|
11
26
|
task notifications_digest_weekly: :environment do
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
27
|
+
time = Time.now.utc
|
|
28
|
+
target_users = Decidim::User.where(notifications_sending_frequency: :weekly)
|
|
29
|
+
|
|
30
|
+
target_users.find_in_batches do |batch|
|
|
31
|
+
notification_users =
|
|
32
|
+
Decidim::Notification
|
|
33
|
+
.weekly(time)
|
|
34
|
+
.where(decidim_user_id: batch.pluck(:id))
|
|
35
|
+
.select(:decidim_user_id)
|
|
36
|
+
.distinct
|
|
37
|
+
.pluck(:decidim_user_id)
|
|
15
38
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
Decidim::EmailNotificationsDigestGeneratorJob.perform_later(user.id, frequency, time:)
|
|
39
|
+
notification_users.each do |user_id|
|
|
40
|
+
Decidim::EmailNotificationsDigestGeneratorJob.perform_later(user_id, :weekly, time:)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
21
43
|
end
|
|
22
44
|
end
|
|
23
45
|
end
|