decidim-core 0.32.0 → 0.32.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/comments_button_cell.rb +9 -1
  3. data/app/cells/decidim/content_blocks/participatory_space_main_data/title.erb +1 -14
  4. data/app/cells/decidim/data_consent/category.erb +20 -33
  5. data/app/cells/decidim/following_cell.rb +1 -1
  6. data/app/cells/decidim/footer_topics/show.erb +5 -8
  7. data/app/cells/decidim/member/show.erb +1 -1
  8. data/app/cells/decidim/nav_links/show.erb +3 -1
  9. data/app/cells/decidim/share_text_widget/modal.erb +1 -0
  10. data/app/cells/decidim/share_widget/modal.erb +1 -0
  11. data/app/cells/decidim/share_widget/qr_code_modal.erb +2 -4
  12. data/app/commands/decidim/create_omniauth_registration.rb +17 -2
  13. data/app/controllers/concerns/decidim/devise_authentication_methods.rb +4 -0
  14. data/app/controllers/concerns/decidim/devise_controllers.rb +2 -0
  15. data/app/controllers/concerns/decidim/disable_redirection_to_external_host.rb +2 -0
  16. data/app/controllers/concerns/decidim/filter_resource.rb +2 -0
  17. data/app/controllers/concerns/decidim/impersonate_users.rb +2 -2
  18. data/app/controllers/concerns/decidim/locale_switcher.rb +12 -10
  19. data/app/controllers/concerns/decidim/needs_permission.rb +22 -10
  20. data/app/controllers/concerns/decidim/onboarding_action_methods.rb +2 -0
  21. data/app/controllers/concerns/decidim/paginable.rb +7 -3
  22. data/app/controllers/concerns/decidim/payload_info.rb +2 -0
  23. data/app/controllers/concerns/decidim/resource_versions_concern.rb +14 -0
  24. data/app/controllers/decidim/application_controller.rb +0 -6
  25. data/app/controllers/decidim/authorization_modals_controller.rb +2 -0
  26. data/app/controllers/decidim/components/base_controller.rb +2 -0
  27. data/app/controllers/decidim/devise/passwords_controller.rb +8 -0
  28. data/app/controllers/decidim/favicon_controller.rb +9 -0
  29. data/app/controllers/decidim/free_resource_authorization_modals_controller.rb +2 -0
  30. data/app/controllers/decidim/gamification/badges_controller.rb +2 -0
  31. data/app/controllers/decidim/homepage_controller.rb +4 -1
  32. data/app/controllers/decidim/likes_controller.rb +1 -1
  33. data/app/controllers/decidim/links_controller.rb +2 -0
  34. data/app/controllers/decidim/manifests_controller.rb +2 -0
  35. data/app/controllers/decidim/messaging/conversations_controller.rb +10 -4
  36. data/app/controllers/decidim/newsletters_controller.rb +4 -0
  37. data/app/controllers/decidim/notifications_subscriptions_controller.rb +4 -0
  38. data/app/controllers/decidim/offline_controller.rb +5 -1
  39. data/app/controllers/decidim/open_data_controller.rb +5 -1
  40. data/app/controllers/decidim/pages_controller.rb +31 -3
  41. data/app/controllers/decidim/private_downloads_controller.rb +2 -0
  42. data/app/controllers/decidim/profiles_controller.rb +19 -1
  43. data/app/controllers/decidim/qr_controller.rb +3 -1
  44. data/app/controllers/decidim/resource_autocomplete_controller.rb +2 -0
  45. data/app/controllers/decidim/searches_controller.rb +2 -0
  46. data/app/controllers/decidim/short_links_controller.rb +4 -0
  47. data/app/controllers/decidim/static_map_controller.rb +2 -0
  48. data/app/controllers/decidim/timeouts_controller.rb +4 -0
  49. data/app/controllers/decidim/tos_controller.rb +2 -0
  50. data/app/controllers/decidim/upload_validations_controller.rb +4 -2
  51. data/app/controllers/decidim/user_activities_controller.rb +3 -0
  52. data/app/forms/decidim/upload_validation_form.rb +16 -10
  53. data/app/helpers/concerns/decidim/user_role_checker.rb +35 -10
  54. data/app/helpers/decidim/decidim_form_helper.rb +1 -1
  55. data/app/helpers/decidim/menu_helper.rb +0 -2
  56. data/app/helpers/decidim/sanitize_helper.rb +11 -1
  57. data/app/jobs/decidim/application_job.rb +4 -0
  58. data/app/models/decidim/authorization.rb +24 -0
  59. data/app/models/decidim/oauth_application.rb +1 -0
  60. data/app/models/decidim/user.rb +3 -2
  61. data/app/models/decidim/user_base_entity.rb +1 -1
  62. data/app/packs/src/decidim/callout.js +10 -0
  63. data/app/packs/src/decidim/callout.test.js +32 -0
  64. data/app/packs/src/decidim/controllers/accordion/accordion.test.js +260 -42
  65. data/app/packs/src/decidim/controllers/accordion/controller.js +136 -17
  66. data/app/packs/src/decidim/controllers/autofocus/controller.js +30 -0
  67. data/app/packs/src/decidim/controllers/dropdown/controller.js +6 -0
  68. data/app/packs/src/decidim/controllers/dropdown/dropdown.test.js +28 -0
  69. data/app/packs/src/decidim/controllers/language_change/controller.js +21 -8
  70. data/app/packs/src/decidim/controllers/language_change/language_change.test.js +0 -1
  71. data/app/packs/src/decidim/controllers/main_menu/controller.js +4 -0
  72. data/app/packs/src/decidim/controllers/main_menu/main_menu.test.js +23 -0
  73. data/app/packs/src/decidim/controllers/mention/controller.js +32 -3
  74. data/app/packs/src/decidim/controllers/mention/input_mentions.test.js +8 -5
  75. data/app/packs/src/decidim/controllers/multiple_mentions/input_multiple_mentions.test.js +1 -1
  76. data/app/packs/src/decidim/controllers/password_toggler/controller.js +22 -1
  77. data/app/packs/src/decidim/controllers/password_toggler/password_toggler.test.js +11 -20
  78. data/app/packs/src/decidim/datepicker/datepicker_functions.js +41 -25
  79. data/app/packs/src/decidim/datepicker/generate_datepicker.js +4 -4
  80. data/app/packs/src/decidim/datepicker/test/datepicker_functions_adjust_picker_position.test.js +64 -0
  81. data/app/packs/src/decidim/datepicker/test/time.test.js +39 -24
  82. data/app/packs/src/decidim/direct_uploads/upload_modal.js +2 -1
  83. data/app/packs/src/decidim/editor/common/suggestion.js +32 -22
  84. data/app/packs/src/decidim/editor/extensions/mention/index.js +14 -3
  85. data/app/packs/src/decidim/editor/index.js +4 -0
  86. data/app/packs/src/decidim/editor/test/extensions/mention.test.js +32 -9
  87. data/app/packs/src/decidim/map/controller.js +10 -1
  88. data/app/packs/src/decidim/refactor/implementation/autofocus.js +22 -0
  89. data/app/packs/src/decidim/refactor/implementation/autofocus.test.js +171 -0
  90. data/app/packs/src/decidim/refactor/moved/focus_guard.js +12 -12
  91. data/app/packs/src/decidim/refactor/moved/focus_guard.test.js +136 -0
  92. data/app/packs/src/decidim/utilities/dom.js +2 -2
  93. data/app/packs/stylesheets/decidim/_cards.scss +1 -1
  94. data/app/packs/stylesheets/decidim/_content_blocks.scss +4 -10
  95. data/app/packs/stylesheets/decidim/_conversations.scss +0 -8
  96. data/app/packs/stylesheets/decidim/_cookies.scss +13 -5
  97. data/app/packs/stylesheets/decidim/_documents.scss +1 -1
  98. data/app/packs/stylesheets/decidim/_footer.scss +33 -1
  99. data/app/packs/stylesheets/decidim/_modal.scss +16 -8
  100. data/app/packs/stylesheets/decidim/_modal_share.scss +0 -22
  101. data/app/packs/stylesheets/decidim/_participatory_spaces.scss +12 -2
  102. data/app/packs/stylesheets/decidim/_rich_text.scss +12 -9
  103. data/app/packs/stylesheets/decidim/_typography.scss +5 -2
  104. data/app/packs/stylesheets/decidim/application.scss +1 -0
  105. data/app/packs/stylesheets/decidim/legacy/email.scss +0 -5
  106. data/app/permissions/decidim/permissions.rb +20 -0
  107. data/app/presenters/decidim/admin_log/component_presenter.rb +1 -1
  108. data/app/presenters/decidim/footer_menu_presenter.rb +2 -4
  109. data/app/presenters/decidim/log/base_presenter.rb +10 -1
  110. data/app/presenters/decidim/log/user_presenter.rb +2 -2
  111. data/app/presenters/decidim/menu_item_presenter.rb +1 -5
  112. data/app/presenters/decidim/resource_presenter.rb +11 -0
  113. data/app/resolvers/decidim/meta_image_url_resolver.rb +14 -1
  114. data/app/serializers/decidim/exporters/open_data_blocked_user_serializer.rb +11 -2
  115. data/app/serializers/decidim/exporters/open_data_moderation_serializer.rb +25 -1
  116. data/app/services/decidim/svg_content_validator.rb +554 -0
  117. data/app/uploaders/decidim/application_uploader.rb +2 -2
  118. data/app/validators/uploader_image_content_validator.rb +276 -0
  119. data/app/views/decidim/application/_radio_accordion.html.erb +1 -5
  120. data/app/views/decidim/messaging/conversations/_add_conversation_users.html.erb +1 -1
  121. data/app/views/decidim/messaging/conversations/create.js.erb +1 -3
  122. data/app/views/decidim/searches/_filters.html.erb +1 -1
  123. data/app/views/decidim/shared/_login_modal.html.erb +12 -14
  124. data/app/views/layouts/decidim/_mailer_logo.html.erb +1 -1
  125. data/app/views/layouts/decidim/footer/_main.html.erb +1 -1
  126. data/app/views/layouts/decidim/footer/_main_links.html.erb +56 -28
  127. data/app/views/layouts/decidim/header/_menu_breadcrumb_desktop.html.erb +3 -2
  128. data/config/initializers/rack_attack.rb +10 -0
  129. data/config/locales/bg.yml +0 -1
  130. data/config/locales/ca-IT.yml +9 -1
  131. data/config/locales/ca.yml +16 -6
  132. data/config/locales/cs.yml +31 -1
  133. data/config/locales/de.yml +99 -3
  134. data/config/locales/en.yml +11 -1
  135. data/config/locales/es-MX.yml +11 -1
  136. data/config/locales/es-PY.yml +11 -1
  137. data/config/locales/es.yml +15 -5
  138. data/config/locales/eu.yml +166 -161
  139. data/config/locales/fi-plain.yml +9 -1
  140. data/config/locales/fi.yml +9 -1
  141. data/config/locales/fr-CA.yml +12 -1
  142. data/config/locales/fr.yml +12 -1
  143. data/config/locales/gl.yml +1485 -33
  144. data/config/locales/hu.yml +0 -1
  145. data/config/locales/ja.yml +28 -1
  146. data/config/locales/pl.yml +2 -1
  147. data/config/locales/pt-BR.yml +0 -1
  148. data/config/locales/ro-RO.yml +0 -1
  149. data/config/locales/sk.yml +2 -1
  150. data/config/locales/sv.yml +68 -12
  151. data/config/locales/tr-TR.yml +0 -2
  152. data/config/routes.rb +11 -2
  153. data/db/migrate/20250217192438_convert_user_groups_into_users.rb +3 -2
  154. data/db/migrate/20260909000000_add_failed_attempts_and_locked_at_to_decidim_authorizations.rb +8 -0
  155. data/decidim-core.gemspec +4 -1
  156. data/lib/decidim/api/functions/user_entity_list.rb +1 -0
  157. data/lib/decidim/api/types/user_moderation_type.rb +2 -2
  158. data/lib/decidim/content_parsers/user_parser.rb +1 -1
  159. data/lib/decidim/content_parsers.rb +0 -1
  160. data/lib/decidim/content_renderers/mention_resource_renderer.rb +18 -4
  161. data/lib/decidim/content_renderers/user_renderer.rb +15 -4
  162. data/lib/decidim/core/test/shared_examples/access_mode_restricted_participatory_spaces.rb +8 -5
  163. data/lib/decidim/core/test/shared_examples/access_mode_transparent_participatory_spaces.rb +14 -11
  164. data/lib/decidim/core/test/shared_examples/comments_examples.rb +26 -0
  165. data/lib/decidim/core/test/shared_examples/participatory_space_members_page_examples.rb +77 -0
  166. data/lib/decidim/core/test/shared_examples/participatory_space_members_shared_examples.rb +58 -0
  167. data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +23 -1
  168. data/lib/decidim/core/version.rb +1 -1
  169. data/lib/decidim/core.rb +10 -1
  170. data/lib/decidim/form_builder.rb +9 -1
  171. data/lib/decidim/has_upload_validations.rb +1 -0
  172. data/lib/decidim/legacy_form_builder.rb +4 -0
  173. data/lib/decidim/map/dynamic_map.rb +3 -1
  174. metadata +33 -7
  175. data/lib/decidim/content_parsers/inline_images_parser.rb +0 -68
  176. data/lib/tasks/upgrade/decidim_active_storage_migration_tasks.rake +0 -79
@@ -173,6 +173,16 @@ shared_examples "comments" do
173
173
  expect(page).to have_css(".comment-thread")
174
174
  end
175
175
 
176
+ it "opens the login modal when clicking the comment button" do
177
+ visit resource_path
178
+
179
+ expect(page).to have_no_css("#loginModal-content", visible: :visible)
180
+
181
+ find(".add-comment-mobile").click
182
+
183
+ expect(page).to have_css("#loginModal-content", visible: :visible)
184
+ end
185
+
176
186
  context "when user visit a mobile browser" do
177
187
  before do
178
188
  driven_by(:iphone)
@@ -202,6 +212,22 @@ shared_examples "comments" do
202
212
  expect(page).to have_css(".add-comment form")
203
213
  end
204
214
 
215
+ it "does not show login modal when clicking the comment button" do
216
+ visit resource_path
217
+
218
+ find("a.add-comment-mobile").click
219
+
220
+ expect(page).to have_no_css("#loginModal-content", visible: :visible)
221
+ end
222
+
223
+ it "guides the user to the comment form when clicking the comment button" do
224
+ visit resource_path
225
+
226
+ find("a.add-comment-mobile").click
227
+
228
+ expect(page).to have_css("#add-comment-anchor")
229
+ end
230
+
205
231
  context "when user visit a computer browser" do
206
232
  before do
207
233
  switch_to_host(organization.host)
@@ -42,5 +42,82 @@ shared_examples "participatory space members page examples" do
42
42
  end
43
43
  end
44
44
  end
45
+
46
+ context "when participatory space has paginated members" do
47
+ let(:users) { create_list(:user, 30, organization: participatory_space.organization) }
48
+ let!(:members) do
49
+ users.map do |user|
50
+ create(:member, participatory_space:, user:, published: true)
51
+ end
52
+ end
53
+
54
+ context "with default pagination" do
55
+ it "returns first page with 25 members" do
56
+ get :index, params: { slug_param => slug, :locale => I18n.locale }
57
+
58
+ expect(assigns(:members).count).to eq(25)
59
+ expect(assigns(:members).current_page).to eq(1)
60
+ expect(assigns(:members).total_count).to eq(30)
61
+ end
62
+ end
63
+
64
+ context "with page parameter" do
65
+ it "returns second page with remaining members" do
66
+ get :index, params: { slug_param => slug, :locale => I18n.locale, :page => 2 }
67
+
68
+ expect(assigns(:members).count).to eq(5)
69
+ expect(assigns(:members).current_page).to eq(2)
70
+ expect(assigns(:members).total_count).to eq(30)
71
+ end
72
+
73
+ it "returns empty collection for out-of-range page" do
74
+ get :index, params: { slug_param => slug, :locale => I18n.locale, :page => 999 }
75
+
76
+ expect(assigns(:members).count).to eq(0)
77
+ expect(assigns(:members).current_page).to eq(999)
78
+ expect(assigns(:members).total_count).to eq(30)
79
+ end
80
+ end
81
+
82
+ context "with per_page parameter" do
83
+ it "returns all members when per_page is 50" do
84
+ get :index, params: { slug_param => slug, :locale => I18n.locale, :per_page => 50 }
85
+
86
+ expect(assigns(:members).count).to eq(30)
87
+ expect(assigns(:members).current_page).to eq(1)
88
+ expect(assigns(:members).limit_value).to eq(50)
89
+ expect(assigns(:members).total_count).to eq(30)
90
+ end
91
+
92
+ it "returns first 25 members when per_page is 25" do
93
+ get :index, params: { slug_param => slug, :locale => I18n.locale, :per_page => 25 }
94
+
95
+ expect(assigns(:members).count).to eq(25)
96
+ expect(assigns(:members).limit_value).to eq(25)
97
+ end
98
+
99
+ it "limits per_page to maximum allowed value" do
100
+ get :index, params: { slug_param => slug, :locale => I18n.locale, :per_page => 200 }
101
+
102
+ expect(assigns(:members).limit_value).to eq(100)
103
+ end
104
+
105
+ it "limit per_page to minimum allowed value" do
106
+ get :index, params: { slug_param => slug, :locale => I18n.locale, :per_page => 5 }
107
+
108
+ expect(assigns(:members).limit_value).to eq(25)
109
+ end
110
+ end
111
+
112
+ context "with both page and per_page parameters" do
113
+ it "returns correct page with custom per_page" do
114
+ get :index, params: { slug_param => slug, :locale => I18n.locale, :page => 2, :per_page => 50 }
115
+
116
+ expect(assigns(:members).count).to eq(0)
117
+ expect(assigns(:members).current_page).to eq(2)
118
+ expect(assigns(:members).limit_value).to eq(50)
119
+ end
120
+ end
121
+ end
45
122
  end
46
123
  end
@@ -117,5 +117,63 @@ shared_examples "participatory space members" do
117
117
  expect(page).to have_content("Profile")
118
118
  end
119
119
  end
120
+
121
+ context "when there are more members than the pagination per_page limit" do
122
+ let(:per_page) { Decidim::Paginable::OPTIONS.first }
123
+ let(:users) { create_list(:user, per_page + 5, organization: participatory_space.organization) }
124
+ let!(:extra_members) do
125
+ users.map do |user|
126
+ create(:member, participatory_space:, user:, published: true)
127
+ end
128
+ end
129
+
130
+ before do
131
+ visit members_path
132
+ end
133
+
134
+ it "paginates the members list" do
135
+ within ".layout-main__section" do
136
+ expect(page).to have_css(".profile__user", count: per_page)
137
+ end
138
+ end
139
+
140
+ it "shows pagination controls" do
141
+ within("div[data-pagination]") do
142
+ expect(page).to have_css('nav[aria-label="Pagination"]')
143
+ end
144
+ end
145
+
146
+ it "navigates to the next page" do
147
+ within "nav[aria-label=\"Pagination\"]" do
148
+ click_on "Next"
149
+ end
150
+
151
+ within ".layout-main__section" do
152
+ expect(page).to have_css(".profile__user", count: 6)
153
+ end
154
+ end
155
+
156
+ it "maintains pagination when navigating back" do
157
+ within "nav[aria-label=\"Pagination\"]" do
158
+ click_on "Next"
159
+ end
160
+
161
+ within "nav[aria-label=\"Pagination\"]" do
162
+ click_on "Prev"
163
+ end
164
+
165
+ within ".layout-main__section" do
166
+ expect(page).to have_css(".profile__user", count: per_page)
167
+ end
168
+ end
169
+
170
+ it "shows the correct page number in the URL" do
171
+ within "nav[aria-label=\"Pagination\"]" do
172
+ click_on "Next"
173
+ end
174
+
175
+ expect(page).to have_current_path(/page=2/)
176
+ end
177
+ end
120
178
  end
121
179
  end
@@ -28,7 +28,7 @@ shared_examples "a version of a hidden object" do
28
28
  end
29
29
  end
30
30
 
31
- shared_examples "versions controller" do
31
+ shared_context "versions controller resource" do
32
32
  let(:base_params) do
33
33
  if resource.is_a?(Decidim::Participable)
34
34
  { :"#{resource.model_name.singular_route_key}_slug" => resource.slug, :locale => I18n.locale }
@@ -45,6 +45,10 @@ shared_examples "versions controller" do
45
45
  request.env["decidim.current_component"] = resource.component
46
46
  end
47
47
  end
48
+ end
49
+
50
+ shared_examples "versions controller" do
51
+ include_context "versions controller resource"
48
52
 
49
53
  describe "GET show" do
50
54
  context "with an existing version" do
@@ -64,3 +68,21 @@ shared_examples "versions controller" do
64
68
  end
65
69
  end
66
70
  end
71
+
72
+ # The versions of a resource must be readable with the same `:read` permission
73
+ # as the resource itself. This ensures that a resource that is hidden, private,
74
+ # deleted or unpublished cannot be reached through its versions.
75
+ #
76
+ # Requires a `resource` that is not readable through its public `:read`
77
+ # permission.
78
+ shared_examples "versions controller denying unreadable resources" do
79
+ include_context "versions controller resource"
80
+
81
+ it "does not expose the versions" do
82
+ get :show, params: base_params.merge(id: 1)
83
+
84
+ expect(response).not_to have_http_status(:ok)
85
+ rescue ActiveRecord::RecordNotFound
86
+ # The resource is filtered out before the permission is evaluated.
87
+ end
88
+ end
@@ -4,7 +4,7 @@ module Decidim
4
4
  # This holds the decidim-core version.
5
5
  module Core
6
6
  def self.version
7
- "0.32.0"
7
+ "0.32.2"
8
8
  end
9
9
  end
10
10
  end
data/lib/decidim/core.rb CHANGED
@@ -288,7 +288,7 @@ module Decidim
288
288
  mattr_accessor :default_locale, default: (Decidim::Env.new("DECIDIM_DEFAULT_LOCALE", "en").presence || :en).to_s
289
289
 
290
290
  # Users that have not logged in for this period of time will be deleted
291
- mattr_accessor :delete_inactive_users_after_days, default: Decidim::Env.new("DELETE_INACTIVE_USERS_AFTER_DAYS", 365).to_i
291
+ mattr_accessor :delete_inactive_users_after_days, default: Decidim::Env.new("DECIDIM_DELETE_INACTIVE_USERS_AFTER_DAYS", 365).to_i
292
292
 
293
293
  # The minimum allowed inactivity period for deleting participants.
294
294
  mattr_accessor :minimum_inactivity_period, default: Decidim::Env.new("DECIDIM_MINIMUM_INACTIVITY_PERIOD_IN_DAYS", 30).to_i
@@ -447,6 +447,15 @@ module Decidim
447
447
  # Time window in which the throttling is applied.
448
448
  mattr_accessor :throttling_period, default: Decidim::Env.new("DECIDIM_THROTTLING_PERIOD", "1").to_i.minutes
449
449
 
450
+ # Max failed attempts for verification code confirmation before lockout.
451
+ mattr_accessor :verification_max_failed_attempts, default: Decidim::Env.new("DECIDIM_VERIFICATION_MAX_FAILED_ATTEMPTS", "5").to_i
452
+
453
+ # Time window after which a locked verification is automatically unlocked.
454
+ mattr_accessor :verification_unlock_in, default: Decidim::Env.new("DECIDIM_VERIFICATION_UNLOCK_IN", "30").to_i.minutes
455
+
456
+ # Time window (in minutes) after which a verification code expires (SMS only).
457
+ mattr_accessor :verification_code_expiry_minutes, default: Decidim::Env.new("DECIDIM_VERIFICATION_CODE_EXPIRY_MINUTES", "10").to_i
458
+
450
459
  # Time window were users can access the website even if their email is not confirmed.
451
460
  mattr_accessor :unconfirmed_access_for, default: Decidim::Env.new("DECIDIM_UNCONFIRMED_ACCESS_FOR", "0").to_i.days
452
461
 
@@ -886,12 +886,20 @@ module Decidim
886
886
  upload_dialog_selector: "##{upload_options[:modal_id]}"
887
887
  }.transform_keys { |key| key.to_s.camelize(:lower) }
888
888
 
889
- editor_options[:mention] = options.delete(:mentionable)
889
+ mentionable = options.delete(:mentionable)
890
+ editor_options[:mention] = mention_options(mentionable) if mentionable
890
891
  editor_options[:emoji] = options.delete(:emojiable)
891
892
 
892
893
  { editor: editor_options, upload: upload_options }
893
894
  end
894
895
 
896
+ def mention_options(mentionable)
897
+ mention_options = mentionable.is_a?(Hash) ? mentionable.dup : {}
898
+ mention_options[:searchPromptMessage] ||= I18n.t("decidim.shared.mentions.search_prompt")
899
+
900
+ mention_options
901
+ end
902
+
895
903
  # Private: creates an upload modal for the editor that we use to dynamically
896
904
  # upload the images to the editor.
897
905
  def editor_upload(editor_image, options = {})
@@ -15,6 +15,7 @@ module Decidim
15
15
  file_size: { less_than_or_equal_to: max_size },
16
16
  organization_present: true,
17
17
  uploader_content_type: true,
18
+ uploader_image_content: true,
18
19
  uploader_image_dimensions: true
19
20
  )
20
21
 
@@ -32,6 +32,10 @@ module Decidim
32
32
  options[:data][:controller] ||= ""
33
33
  options[:data][:controller] += " date-picker"
34
34
 
35
+ if (default_time = options.delete(:default_time))
36
+ options[:data][:default_time] = default_time
37
+ end
38
+
35
39
  field(attribute, options) do |opts|
36
40
  super(attribute, opts)
37
41
  end
@@ -30,7 +30,9 @@ module Decidim
30
30
  def builder_options
31
31
  {
32
32
  marker_color: organization.colors.fetch("primary", "#e02d2d"),
33
- tile_layer: tile_layer_configuration
33
+ tile_layer: tile_layer_configuration,
34
+ zoom_in_text: I18n.t("zoom_in", scope: "decidim.map.dynamic"),
35
+ zoom_out_text: I18n.t("zoom_out", scope: "decidim.map.dynamic")
34
36
  }
35
37
  end
36
38
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decidim-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.32.0
4
+ version: 0.32.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josep Jaume Rey Peroy
@@ -681,6 +681,26 @@ dependencies:
681
681
  - - "<"
682
682
  - !ruby/object:Gem::Version
683
683
  version: '6.9'
684
+ - !ruby/object:Gem::Dependency
685
+ name: rack-proxy
686
+ requirement: !ruby/object:Gem::Requirement
687
+ requirements:
688
+ - - "~>"
689
+ - !ruby/object:Gem::Version
690
+ version: 0.8.3
691
+ - - "<"
692
+ - !ruby/object:Gem::Version
693
+ version: '1.0'
694
+ type: :runtime
695
+ prerelease: false
696
+ version_requirements: !ruby/object:Gem::Requirement
697
+ requirements:
698
+ - - "~>"
699
+ - !ruby/object:Gem::Version
700
+ version: 0.8.3
701
+ - - "<"
702
+ - !ruby/object:Gem::Version
703
+ version: '1.0'
684
704
  - !ruby/object:Gem::Dependency
685
705
  name: rails
686
706
  requirement: !ruby/object:Gem::Requirement
@@ -893,28 +913,28 @@ dependencies:
893
913
  requirements:
894
914
  - - '='
895
915
  - !ruby/object:Gem::Version
896
- version: 0.32.0
916
+ version: 0.32.2
897
917
  type: :development
898
918
  prerelease: false
899
919
  version_requirements: !ruby/object:Gem::Requirement
900
920
  requirements:
901
921
  - - '='
902
922
  - !ruby/object:Gem::Version
903
- version: 0.32.0
923
+ version: 0.32.2
904
924
  - !ruby/object:Gem::Dependency
905
925
  name: decidim-dev
906
926
  requirement: !ruby/object:Gem::Requirement
907
927
  requirements:
908
928
  - - '='
909
929
  - !ruby/object:Gem::Version
910
- version: 0.32.0
930
+ version: 0.32.2
911
931
  type: :development
912
932
  prerelease: false
913
933
  version_requirements: !ruby/object:Gem::Requirement
914
934
  requirements:
915
935
  - - '='
916
936
  - !ruby/object:Gem::Version
917
- version: 0.32.0
937
+ version: 0.32.2
918
938
  description: Adds core features so other engines can hook into the framework.
919
939
  email:
920
940
  - josepjaume@gmail.com
@@ -1637,6 +1657,7 @@ files:
1637
1657
  - app/packs/src/decidim/attachments/file_or_link_tabs.js
1638
1658
  - app/packs/src/decidim/attachments/index.js
1639
1659
  - app/packs/src/decidim/callout.js
1660
+ - app/packs/src/decidim/callout.test.js
1640
1661
  - app/packs/src/decidim/confirm.js
1641
1662
  - app/packs/src/decidim/confirm.test.js
1642
1663
  - app/packs/src/decidim/controllers/.keep
@@ -1646,6 +1667,7 @@ files:
1646
1667
  - app/packs/src/decidim/controllers/account_form/controller.js
1647
1668
  - app/packs/src/decidim/controllers/assign_role/assign_role.test.js
1648
1669
  - app/packs/src/decidim/controllers/assign_role/controller.js
1670
+ - app/packs/src/decidim/controllers/autofocus/controller.js
1649
1671
  - app/packs/src/decidim/controllers/breadcrumb_truncate/breadcrumb_truncate.test.js
1650
1672
  - app/packs/src/decidim/controllers/breadcrumb_truncate/controller.js
1651
1673
  - app/packs/src/decidim/controllers/character_counter/controller.js
@@ -1788,6 +1810,8 @@ files:
1788
1810
  - app/packs/src/decidim/map/provider/default.js
1789
1811
  - app/packs/src/decidim/map/provider/here.js
1790
1812
  - app/packs/src/decidim/notifications.js
1813
+ - app/packs/src/decidim/refactor/implementation/autofocus.js
1814
+ - app/packs/src/decidim/refactor/implementation/autofocus.test.js
1791
1815
  - app/packs/src/decidim/refactor/implementation/configuration.js
1792
1816
  - app/packs/src/decidim/refactor/implementation/external_domain_warning.js
1793
1817
  - app/packs/src/decidim/refactor/implementation/external_link.js
@@ -1796,6 +1820,7 @@ files:
1796
1820
  - app/packs/src/decidim/refactor/moved/check_boxes_tree.js
1797
1821
  - app/packs/src/decidim/refactor/moved/delayed.js
1798
1822
  - app/packs/src/decidim/refactor/moved/focus_guard.js
1823
+ - app/packs/src/decidim/refactor/moved/focus_guard.test.js
1799
1824
  - app/packs/src/decidim/refactor/moved/history.js
1800
1825
  - app/packs/src/decidim/refactor/moved/i18n.js
1801
1826
  - app/packs/src/decidim/refactor/moved/i18n.test.js
@@ -2014,6 +2039,7 @@ files:
2014
2039
  - app/services/decidim/send_push_notification.rb
2015
2040
  - app/services/decidim/settings_change.rb
2016
2041
  - app/services/decidim/static_map_generator.rb
2042
+ - app/services/decidim/svg_content_validator.rb
2017
2043
  - app/services/decidim/tokenizer.rb
2018
2044
  - app/services/decidim/traceability.rb
2019
2045
  - app/uploaders/decidim/application_uploader.rb
@@ -2041,6 +2067,7 @@ files:
2041
2067
  - app/validators/translatable_presence_validator.rb
2042
2068
  - app/validators/translated_etiquette_validator.rb
2043
2069
  - app/validators/uploader_content_type_validator.rb
2070
+ - app/validators/uploader_image_content_validator.rb
2044
2071
  - app/validators/uploader_image_dimensions_validator.rb
2045
2072
  - app/validators/url_validator.rb
2046
2073
  - app/views/decidim/account/_account_notification.js.erb
@@ -2589,6 +2616,7 @@ files:
2589
2616
  - db/migrate/20260208201407_remove_user_group_organizations.rb
2590
2617
  - db/migrate/20260217152425_remove_enable_participatory_space_filters_from_decidim_organizations.rb
2591
2618
  - db/migrate/20260314081619_add_index_on_decidim_members.rb
2619
+ - db/migrate/20260909000000_add_failed_attempts_and_locked_at_to_decidim_authorizations.rb
2592
2620
  - db/seeds.rb
2593
2621
  - db/seeds/Exampledocument.pdf
2594
2622
  - db/seeds/avatars/001.jpg
@@ -2838,7 +2866,6 @@ files:
2838
2866
  - lib/decidim/content_parsers.rb
2839
2867
  - lib/decidim/content_parsers/base_parser.rb
2840
2868
  - lib/decidim/content_parsers/blob_parser.rb
2841
- - lib/decidim/content_parsers/inline_images_parser.rb
2842
2869
  - lib/decidim/content_parsers/link_parser.rb
2843
2870
  - lib/decidim/content_parsers/mention_resource_parser.rb
2844
2871
  - lib/decidim/content_parsers/newline_parser.rb
@@ -3158,7 +3185,6 @@ files:
3158
3185
  - lib/tasks/decidim_taxonomies.rake
3159
3186
  - lib/tasks/upgrade/clean.rake
3160
3187
  - lib/tasks/upgrade/decidim_action_log_valuation_assignment.rake
3161
- - lib/tasks/upgrade/decidim_active_storage_migration_tasks.rake
3162
3188
  - lib/tasks/upgrade/decidim_attachments.rake
3163
3189
  - lib/tasks/upgrade/decidim_change_valuator_tasks.rake
3164
3190
  - lib/tasks/upgrade/decidim_content_blocks_tasks.rake
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Decidim
4
- module ContentParsers
5
- # A parser that searches for inline images in an html content and
6
- # replaces them with EditorImage attachments. Note that rewrite method may
7
- # create EditorImage instances
8
- #
9
- # @see BaseParser Examples of how to use a content parser
10
- class InlineImagesParser < BaseParser
11
- # @return [String] the content with the inline images replaced.
12
- def rewrite
13
- return content unless inline_images?
14
-
15
- replace_inline_images
16
- parsed_content.to_html
17
- end
18
-
19
- def inline_images?
20
- parsed_content.search(:img).find do |image|
21
- image.attr(:src).start_with?(%r{data:image/[a-z]{3,4};base64,})
22
- end
23
- end
24
-
25
- private
26
-
27
- def parsed_content
28
- @parsed_content ||= Nokogiri::HTML(content)
29
- end
30
-
31
- def replace_inline_images
32
- parsed_content.search(:img).each do |image|
33
- next unless image.attr(:src).start_with?(%r{data:image/[a-z]{3,4};base64,})
34
-
35
- file = base64_tempfile(image.attr(:src))
36
- editor_image = EditorImage.create!(
37
- decidim_author_id: context[:user]&.id,
38
- organization: context[:user].organization,
39
- file:
40
- )
41
-
42
- image.set_attribute(:src, editor_image.attached_uploader(:file).path)
43
- end
44
- end
45
-
46
- def base64_tempfile(base64_data, filename = nil)
47
- return base64_data unless base64_data.is_a? String
48
-
49
- start_regex = %r{data:image/[a-z]{3,4};base64,}
50
- filename ||= SecureRandom.hex
51
-
52
- regex_result = start_regex.match(base64_data)
53
-
54
- return unless base64_data && regex_result
55
-
56
- start = regex_result.to_s
57
- tempfile = Tempfile.new(filename)
58
- tempfile.binmode
59
- tempfile.write(Base64.decode64(base64_data[start.length..-1]))
60
- ActionDispatch::Http::UploadedFile.new(
61
- tempfile:,
62
- filename:,
63
- original_filename: filename
64
- )
65
- end
66
- end
67
- end
68
- end
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- namespace :decidim do
4
- namespace :upgrade do
5
- namespace :active_storage_migrations do
6
- desc "Migrates inline images to ActiveStorage editor_image attachments"
7
- task :migrate_inline_images_to_active_storage, [:admin_email] => :environment do |_t, args|
8
- user = Decidim::User.find_by(email: args[:admin_email])
9
-
10
- raise "Invalid admin. Please, provide the email of an admin with permissions to create editor images" unless user&.admin? && user.admin_terms_accepted?
11
-
12
- inline_images_available_attributes.each do |model, attributes|
13
- puts "=== Updating model #{model.name} (attributes: #{attributes.join(", ")})..."
14
- model.all.each do |item|
15
- attributes.each do |attribute|
16
- item.update(attribute => rewrite_value(item.send(attribute), user))
17
- end
18
- end
19
- puts "=== Finished update of model #{model.name}\n\n"
20
- end
21
- end
22
-
23
- def rewrite_value(value, user)
24
- if value.is_a?(Hash)
25
- value.transform_values do |nested_value|
26
- rewrite_value(nested_value, user)
27
- end
28
- else
29
- parser = Decidim::ContentParsers::InlineImagesParser.new(value, user:)
30
- parser.rewrite
31
- end
32
- end
33
-
34
- def inline_images_available_attributes
35
- {
36
- "Decidim::Accountability::Result" => %w(description),
37
- "Decidim::Proposals::Proposal" => %w(body answer cost_report execution_period),
38
- "Decidim::Votings::Voting" => %w(description),
39
- "Decidim::Elections::Question" => %w(description),
40
- "Decidim::Elections::Answer" => %w(description),
41
- "Decidim::Elections::Election" => %w(description),
42
- "Decidim::Initiative" => %w(description answer),
43
- "Decidim::InitiativesType" => %w(description extra_fields_legal_information),
44
- "Decidim::Assembly" => %w(short_description description purpose_of_action composition internal_organisation announcement closing_date_reason special_features),
45
- "Decidim::Forms::Questionnaire" => %w(description tos),
46
- "Decidim::Forms::Question" => %w(description),
47
- "Decidim::Organization" => %w(
48
- welcome_notification_body
49
- admin_terms_of_use_body
50
- admin_terms_of_service_body
51
- description
52
- highlighted_content_banner_short_description
53
- id_documents_explanation_text
54
- ),
55
- "Decidim::StaticPage" => %w(content),
56
- "Decidim::ContextualHelpSection" => %w(content),
57
- "Decidim::Category" => %w(description),
58
- "Decidim::Blogs::Post" => %w(body),
59
- "Decidim::Pages::Page" => %w(body),
60
- "Decidim::Debates::Debate" => %w(description instructions information_updates conclusions),
61
- "Decidim::Budgets::Budget" => %w(description),
62
- "Decidim::Budgets::Project" => %w(description),
63
- "Decidim::ConferenceSpeaker" => %w(short_bio),
64
- "Decidim::Conferences::RegistrationType" => %w(description),
65
- "Decidim::Conference" => %w(short_description description objectives registration_terms),
66
- "Decidim::ParticipatoryProcessGroup" => %w(description),
67
- "Decidim::ParticipatoryProcess" => %w(short_description description announcement),
68
- "Decidim::ParticipatoryProcessStep" => %w(description),
69
- "Decidim::Meetings::AgendaItem" => %w(description),
70
- "Decidim::Meetings::Meeting" => %w(registration_terms description registration_email_custom_content closing_report)
71
- }.each_with_object({}) do |(main_model, attributes), hash|
72
- hash[main_model.constantize] = attributes
73
- rescue NameError
74
- hash
75
- end
76
- end
77
- end
78
- end
79
- end