decidim-core 0.26.4 → 0.26.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/announcement_cell.rb +1 -1
  3. data/app/cells/decidim/content_blocks/cta_cell.rb +1 -1
  4. data/app/cells/decidim/content_blocks/hero/show.erb +1 -1
  5. data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +1 -1
  6. data/app/cells/decidim/content_blocks/sub_hero_cell.rb +1 -1
  7. data/app/cells/decidim/newsletter_templates/base_cell.rb +8 -0
  8. data/app/cells/decidim/newsletter_templates/basic_only_text/show.erb +4 -4
  9. data/app/cells/decidim/newsletter_templates/image_text_cta/show.erb +4 -4
  10. data/app/commands/decidim/unendorse_resource.rb +1 -1
  11. data/app/controllers/decidim/groups_controller.rb +5 -0
  12. data/app/controllers/decidim/links_controller.rb +10 -11
  13. data/app/controllers/decidim/profiles_controller.rb +1 -1
  14. data/app/helpers/decidim/cells_helper.rb +1 -0
  15. data/app/helpers/decidim/external_domain_helper.rb +14 -3
  16. data/app/helpers/decidim/icon_helper.rb +3 -3
  17. data/app/helpers/decidim/newsletters_helper.rb +1 -0
  18. data/app/helpers/decidim/sanitize_helper.rb +15 -5
  19. data/app/mailers/decidim/newsletter_mailer.rb +10 -3
  20. data/app/models/decidim/newsletter.rb +28 -0
  21. data/app/models/decidim/scope_type.rb +28 -0
  22. data/app/models/decidim/user.rb +0 -2
  23. data/app/models/decidim/user_base_entity.rb +2 -0
  24. data/app/models/decidim/user_block.rb +2 -2
  25. data/app/models/decidim/user_group.rb +1 -1
  26. data/app/packs/src/decidim/editor/clipboard_override.js +6 -2
  27. data/app/packs/src/decidim/editor.js +63 -33
  28. data/app/packs/src/decidim/form_filter.component.test.js +148 -5
  29. data/app/packs/src/decidim/form_filter.js +26 -4
  30. data/app/packs/stylesheets/decidim/_editor.scss +129 -0
  31. data/app/packs/stylesheets/decidim/email.scss +7 -0
  32. data/app/packs/stylesheets/decidim/extras/_quill.scss +0 -6
  33. data/app/packs/stylesheets/decidim/modules/_buttons.scss +10 -6
  34. data/app/packs/stylesheets/decidim/modules/_cards.scss +1 -1
  35. data/app/packs/stylesheets/decidim/modules/_comments.scss +24 -0
  36. data/app/packs/stylesheets/decidim/vizzs/_linechart.scss +2 -2
  37. data/app/packs/stylesheets/decidim/vizzs/_rowchart.scss +2 -2
  38. data/app/presenters/decidim/admin_log/user_group_presenter.rb +1 -1
  39. data/app/presenters/decidim/admin_log/user_moderation_presenter.rb +1 -1
  40. data/app/presenters/decidim/notification_presenter.rb +1 -1
  41. data/app/presenters/decidim/user_group_presenter.rb +1 -1
  42. data/app/presenters/decidim/user_presenter.rb +1 -1
  43. data/app/scrubbers/decidim/admin_input_scrubber.rb +27 -0
  44. data/app/scrubbers/decidim/user_input_scrubber.rb +32 -5
  45. data/app/services/decidim/traceability.rb +1 -0
  46. data/app/views/decidim/links/_invalid_url_modal.html.erb +17 -0
  47. data/app/views/decidim/links/_modal.html.erb +1 -1
  48. data/app/views/decidim/links/invalid_url.js.erb +24 -0
  49. data/app/views/decidim/links/new.html.erb +1 -1
  50. data/app/views/decidim/messaging/conversations/_conversation.html.erb +1 -5
  51. data/app/views/decidim/newsletter_mailer/newsletter.html.erb +3 -3
  52. data/app/views/decidim/newsletters/show.html.erb +1 -1
  53. data/app/views/decidim/pages/_standalone.html.erb +1 -1
  54. data/app/views/decidim/pages/_tabbed.html.erb +1 -1
  55. data/app/views/layouts/decidim/_mailer_logo.html.erb +2 -2
  56. data/app/views/layouts/decidim/newsletter_base.html.erb +2 -2
  57. data/config/locales/ar.yml +427 -11
  58. data/config/locales/bg.yml +6 -8
  59. data/config/locales/ca.yml +36 -30
  60. data/config/locales/cs.yml +27 -32
  61. data/config/locales/da.yml +3 -0
  62. data/config/locales/de.yml +4 -26
  63. data/config/locales/el.yml +6 -9
  64. data/config/locales/en.yml +21 -15
  65. data/config/locales/eo.yml +2 -1
  66. data/config/locales/es-MX.yml +28 -22
  67. data/config/locales/es-PY.yml +28 -22
  68. data/config/locales/es.yml +34 -28
  69. data/config/locales/et.yml +3 -0
  70. data/config/locales/eu.yml +108 -85
  71. data/config/locales/fa-IR.yml +1 -0
  72. data/config/locales/fi-plain.yml +6 -21
  73. data/config/locales/fi.yml +24 -18
  74. data/config/locales/fr-CA.yml +26 -20
  75. data/config/locales/fr.yml +24 -18
  76. data/config/locales/ga-IE.yml +1 -0
  77. data/config/locales/gl.yml +2 -26
  78. data/config/locales/gn-PY.yml +3 -0
  79. data/config/locales/hr.yml +3 -0
  80. data/config/locales/hu.yml +52 -29
  81. data/config/locales/id-ID.yml +7 -8
  82. data/config/locales/is-IS.yml +2 -2
  83. data/config/locales/it.yml +2 -16
  84. data/config/locales/ja.yml +29 -39
  85. data/config/locales/ka-GE.yml +4 -0
  86. data/config/locales/kaa.yml +1 -0
  87. data/config/locales/lb.yml +0 -8
  88. data/config/locales/lt.yml +0 -37
  89. data/config/locales/lv.yml +5 -7
  90. data/config/locales/nl.yml +1 -24
  91. data/config/locales/no.yml +3 -30
  92. data/config/locales/oc-FR.yml +2 -0
  93. data/config/locales/pl.yml +2 -38
  94. data/config/locales/pt-BR.yml +2 -10
  95. data/config/locales/pt.yml +0 -8
  96. data/config/locales/ro-RO.yml +10 -11
  97. data/config/locales/ru.yml +6 -4
  98. data/config/locales/sk.yml +8 -9
  99. data/config/locales/sl.yml +1 -0
  100. data/config/locales/sr-CS.yml +2 -0
  101. data/config/locales/sv.yml +3 -29
  102. data/config/locales/tr-TR.yml +7 -12
  103. data/config/locales/uk.yml +6 -4
  104. data/config/locales/zh-CN.yml +3 -8
  105. data/config/locales/zh-TW.yml +1712 -0
  106. data/lib/decidim/api/types/localized_string_type.rb +9 -0
  107. data/lib/decidim/api/types/translated_field_type.rb +20 -5
  108. data/lib/decidim/core/test/factories.rb +13 -6
  109. data/lib/decidim/core/test/shared_examples/comments_examples.rb +36 -0
  110. data/lib/decidim/core/test/shared_examples/editor_shared_examples.rb +10 -0
  111. data/lib/decidim/core/test/shared_examples/rich_text_editor_examples.rb +7 -3
  112. data/lib/decidim/core/test.rb +1 -0
  113. data/lib/decidim/core/version.rb +1 -1
  114. data/lib/decidim/form_builder.rb +1 -2
  115. data/lib/decidim/participatory_space_resourceable.rb +7 -1
  116. data/lib/decidim/publicable.rb +4 -0
  117. metadata +13 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1863adec9ae8ce9d4d528f247a2f18561de3618eacb84e50c03fae6a89fb2d6e
4
- data.tar.gz: 032b9cce96757af5e5d87d687f64231a1630fdc003973b3b16cc4044f7f667bb
3
+ metadata.gz: 2d573b856227ec581d40d90cff9a85c1f21502a1ed6278b82aa9768a434f0e9c
4
+ data.tar.gz: 2ca2fff70b6e6b9314450c35ab22965b3ba60af303a2839c7716e502cb566b3a
5
5
  SHA512:
6
- metadata.gz: 44579a2195e6d79ca6e5d78a1695815c4db2d2dd850b9a94e819d5219cda61cad771aa172ad99628bb9460e79a99b02fa4cd72fb377649b565b22ad010eb6924
7
- data.tar.gz: 959d4d1552af3fd6b25fb1fb27292d8d107c260bedddd5a49dce829f6271772fd8a2c043d401cdc5061a615e1de71157d0b084eeab3b794e9aa3373451ad7ef8
6
+ metadata.gz: 1000d09afe7e9af0586fa14c917c77a150bf9f55adee9d0a243744799a9cf9c84aa364b0f014cdec6eda3855c10b4b15772732c979d9f15e381c8a62e78aad8f
7
+ data.tar.gz: 1a4feafaa713a4fa540aab815e0306f125cc74d45599d5defbec2e9dd2cce8bc6223acd0148424b3973a0f1d6853b96cd3ee9a6fda7ff45cc91073fd2b84ac8a
@@ -62,7 +62,7 @@ module Decidim
62
62
  end
63
63
 
64
64
  def clean(value)
65
- decidim_sanitize(translated_attribute(value))
65
+ decidim_sanitize_admin(translated_attribute(value))
66
66
  end
67
67
  end
68
68
  end
@@ -16,7 +16,7 @@ module Decidim
16
16
  end
17
17
 
18
18
  def translated_description
19
- @translated_description ||= decidim_sanitize_editor(translated_attribute(model.settings.description))
19
+ @translated_description ||= decidim_sanitize_editor_admin(translated_attribute(model.settings.description))
20
20
  end
21
21
 
22
22
  def button_url
@@ -6,7 +6,7 @@
6
6
  <% if translated_welcome_text.blank? %>
7
7
  <%= t("decidim.pages.home.hero.welcome", organization: current_organization.name) %>
8
8
  <% else %>
9
- <%= decidim_sanitize translated_welcome_text %>
9
+ <%= decidim_sanitize_admin translated_welcome_text %>
10
10
  <% end %>
11
11
  </h1>
12
12
  </div>
@@ -7,7 +7,7 @@
7
7
  <%= translated_attribute current_organization.highlighted_content_banner_title %>
8
8
  </h1>
9
9
  <span class="text-highlight">
10
- <%= decidim_sanitize_editor translated_attribute current_organization.highlighted_content_banner_short_description %>
10
+ <%= decidim_sanitize_editor_admin translated_attribute current_organization.highlighted_content_banner_short_description %>
11
11
  </span>
12
12
  </div>
13
13
  <div class="columns large-2">
@@ -15,7 +15,7 @@ module Decidim
15
15
  private
16
16
 
17
17
  def organization_description
18
- desc = decidim_sanitize(translated_attribute(current_organization.description))
18
+ desc = decidim_sanitize_admin(translated_attribute(current_organization.description))
19
19
 
20
20
  # Strip the surrounding paragraph tag because it is not allowed within
21
21
  # a <hN> element.
@@ -25,6 +25,14 @@ module Decidim
25
25
  def recipient_user
26
26
  options[:recipient_user]
27
27
  end
28
+
29
+ def custom_url_for_mail_root
30
+ options[:custom_url_for_mail_root]
31
+ end
32
+
33
+ def decidim
34
+ @decidim ||= EngineRouter.new("decidim", {})
35
+ end
28
36
  end
29
37
  end
30
38
  end
@@ -16,7 +16,7 @@
16
16
  <tr>
17
17
  <th>
18
18
  <center>
19
- <%= render partial: "layouts/decidim/mailer_logo.html", locals: { organization: organization } %>
19
+ <%= render partial: "layouts/decidim/mailer_logo.html", locals: { organization: organization, custom_url_for_mail_root: custom_url_for_mail_root } %>
20
20
  </center>
21
21
  </th>
22
22
  </tr>
@@ -27,7 +27,7 @@
27
27
  <tr>
28
28
  <th>
29
29
  <% if organization.official_img_header.attached? %>
30
- <%= link_to organization.official_url do %>
30
+ <%= link_to newsletter.organization_official_url do %>
31
31
  <%= image_tag organization.attached_uploader(:official_img_header).path, alt: "", style: "max-height: 50px", class: "float-right" %>
32
32
  <% end %>
33
33
  <% end %>
@@ -72,8 +72,8 @@
72
72
  <th class="expander"></th>
73
73
  <th class="small-12 first columns cityhall-bar">
74
74
  <div class="decidim-logo" style="float: right; text-align: right; padding-right: 16px">
75
- <% if @custom_url_for_mail_root.present? %>
76
- <%= link_to organization.name.html_safe, @custom_url_for_mail_root %>
75
+ <% if custom_url_for_mail_root.present? %>
76
+ <%= link_to organization.name.html_safe, custom_url_for_mail_root %>
77
77
  <% else %>
78
78
  <%= link_to organization.name.html_safe, decidim.root_url(host: organization.host) %>
79
79
  <% end %>
@@ -24,7 +24,7 @@ table.button table td {
24
24
  <tr>
25
25
  <th>
26
26
  <center>
27
- <%= render partial: "layouts/decidim/mailer_logo.html", locals: { organization: organization } %>
27
+ <%= render partial: "layouts/decidim/mailer_logo.html", locals: { organization: organization, custom_url_for_mail_root: custom_url_for_mail_root } %>
28
28
  </center>
29
29
  </th>
30
30
  </tr>
@@ -35,7 +35,7 @@ table.button table td {
35
35
  <tr>
36
36
  <th>
37
37
  <% if organization.official_img_header.attached? %>
38
- <%= link_to organization.official_url do %>
38
+ <%= link_to newsletter.organization_official_url do %>
39
39
  <%= image_tag organization.attached_uploader(:official_img_header).url(host: organization.host), alt: "", style: "max-height: 50px", class: "float-right" %>
40
40
  <% end %>
41
41
  <% end %>
@@ -111,8 +111,8 @@ table.button table td {
111
111
  <th class="expander"></th>
112
112
  <th class="small-12 first columns cityhall-bar">
113
113
  <div class="decidim-logo" style="float: right; text-align: right; padding-right: 16px">
114
- <% if @custom_url_for_mail_root.present? %>
115
- <%= link_to organization.name.html_safe, @custom_url_for_mail_root %>
114
+ <% if custom_url_for_mail_root.present? %>
115
+ <%= link_to organization.name.html_safe, custom_url_for_mail_root %>
116
116
  <% else %>
117
117
  <%= link_to organization.name.html_safe, decidim.root_url(host: organization.host) %>
118
118
  <% end %>
@@ -31,7 +31,7 @@ module Decidim
31
31
  query = if @current_group.present?
32
32
  @resource.endorsements.where(decidim_user_group_id: @current_group&.id)
33
33
  else
34
- @resource.endorsements.where(author: @current_user)
34
+ @resource.endorsements.where(author: @current_user, decidim_user_group_id: nil)
35
35
  end
36
36
  query.destroy_all
37
37
  end
@@ -7,6 +7,7 @@ module Decidim
7
7
  include UserGroups
8
8
 
9
9
  before_action :enforce_user_groups_enabled
10
+ before_action :ensure_user_group_not_blocked
10
11
 
11
12
  def new
12
13
  enforce_permission_to :create, :user_group, current_user: current_user
@@ -73,6 +74,10 @@ module Decidim
73
74
 
74
75
  private
75
76
 
77
+ def ensure_user_group_not_blocked
78
+ raise ActionController::RoutingError, "Blocked User Group" if user_group&.blocked?
79
+ end
80
+
76
81
  def accepted_user_group
77
82
  @accepted_user_group ||= Decidim::UserGroups::AcceptedUserGroups.for(current_user).find_by(nickname: params[:id])
78
83
  end
@@ -7,9 +7,11 @@ module Decidim
7
7
  skip_before_action :store_current_location
8
8
 
9
9
  helper Decidim::ExternalDomainHelper
10
+ helper_method :external_url
10
11
 
11
12
  before_action :parse_url
12
13
  rescue_from Decidim::InvalidUrlError, with: :invalid_url
14
+ rescue_from URI::InvalidURIError, with: :invalid_url
13
15
 
14
16
  def new
15
17
  headers["X-Robots-Tag"] = "noindex"
@@ -19,24 +21,21 @@ module Decidim
19
21
 
20
22
  def invalid_url
21
23
  flash[:alert] = I18n.t("decidim.links.invalid_url")
22
- redirect_to decidim.root_path
24
+ if request.xhr?
25
+ render "invalid_url"
26
+ else
27
+ redirect_to decidim.root_path
28
+ end
23
29
  end
24
30
 
25
31
  def parse_url
32
+ raise Decidim::InvalidUrlError if params[:external_url].blank?
26
33
  raise Decidim::InvalidUrlError unless external_url
27
-
28
- parts = external_url.match %r{^(([a-z]+):)?//([^/]+)(/.*)?$}
29
- raise Decidim::InvalidUrlError unless parts
30
-
31
- @url_parts = {
32
- protocol: parts[1],
33
- domain: parts[3],
34
- path: parts[4]
35
- }
34
+ raise Decidim::InvalidUrlError unless %w(http https).include?(external_url.scheme)
36
35
  end
37
36
 
38
37
  def external_url
39
- @external_url ||= params[:external_url]
38
+ @external_url ||= URI.parse(params[:external_url])
40
39
  end
41
40
  end
42
41
  end
@@ -13,7 +13,7 @@ module Decidim
13
13
  before_action :ensure_profile_holder
14
14
  before_action :ensure_profile_holder_is_a_group, only: [:members]
15
15
  before_action :ensure_profile_holder_is_a_user, only: [:groups, :following]
16
- before_action :ensure_user_not_blocked, only: [:following, :followers, :badges]
16
+ before_action :ensure_user_not_blocked
17
17
 
18
18
  def show
19
19
  return redirect_to profile_timeline_path(nickname: params[:nickname]) if profile_holder == current_user
@@ -35,6 +35,7 @@ module Decidim
35
35
  end
36
36
 
37
37
  def user_flaggable?
38
+ return if (try(:profile_holder) || try(:profile_user) || try(:model)).try(:blocked)
38
39
  return unless context[:controller].try(:flaggable_controller?)
39
40
 
40
41
  true
@@ -3,10 +3,21 @@
3
3
  module Decidim
4
4
  module ExternalDomainHelper
5
5
  def highlight_domain
6
+ highlighted_domain = [
7
+ external_url.host,
8
+ (external_url.port && [80, 443].include?(external_url.port) ? "" : ":#{external_url.port}")
9
+ ].join
10
+
11
+ path = [
12
+ external_url.path,
13
+ (external_url.query ? "?#{external_url.query}" : ""),
14
+ (external_url.fragment ? "##{external_url.fragment}" : "")
15
+ ].join
16
+
6
17
  tag.div do
7
- content_tag(:span, "#{@url_parts[:protocol]}//") +
8
- content_tag(:span, @url_parts[:domain], class: "alert") +
9
- content_tag(:span, @url_parts[:path])
18
+ content_tag(:span, "#{external_url.scheme}://") +
19
+ content_tag(:span, highlighted_domain, class: "text-alert") +
20
+ content_tag(:span, path)
10
21
  end
11
22
  end
12
23
  end
@@ -24,7 +24,7 @@ module Decidim
24
24
  #
25
25
  # Returns an HTML tag with the icon.
26
26
  def manifest_icon(manifest, options = {})
27
- if manifest.icon
27
+ if manifest.respond_to?(:icon) && manifest.icon.present?
28
28
  external_icon manifest.icon, options
29
29
  else
30
30
  icon "question-mark", options
@@ -42,9 +42,9 @@ module Decidim
42
42
  def resource_icon(resource, options = {})
43
43
  if resource.class.name == "Decidim::Comments::Comment"
44
44
  icon "comment-square", options
45
- elsif resource.respond_to?(:component)
45
+ elsif resource.respond_to?(:component) && resource.component.present?
46
46
  component_icon(resource.component, options)
47
- elsif resource.respond_to?(:manifest)
47
+ elsif resource.respond_to?(:manifest) && resource.manifest.present?
48
48
  manifest_icon(resource.manifest, options)
49
49
  elsif resource.is_a?(Decidim::User)
50
50
  icon "person", options
@@ -31,6 +31,7 @@ module Decidim
31
31
  # this method is used to generate the root link on mail with the utm_codes
32
32
  # If the newsletter_id is nil, it returns the root_url
33
33
  def custom_url_for_mail_root(organization, newsletter_id = nil)
34
+ decidim = EngineRouter.new("decidim", {})
34
35
  if newsletter_id.present?
35
36
  decidim.root_url(host: organization.host) + utm_codes(organization.host, newsletter_id.to_s)
36
37
  else
@@ -16,13 +16,18 @@ module Decidim
16
16
  #
17
17
  # Returns an HTML-safe String.
18
18
  def decidim_sanitize(html, options = {})
19
+ scrubber = options[:scrubber] || Decidim::UserInputScrubber.new
19
20
  if options[:strip_tags]
20
- strip_tags sanitize(html, scrubber: Decidim::UserInputScrubber.new)
21
+ strip_tags sanitize(html, scrubber: scrubber)
21
22
  else
22
- sanitize(html, scrubber: Decidim::UserInputScrubber.new)
23
+ sanitize(html, scrubber: scrubber)
23
24
  end
24
25
  end
25
26
 
27
+ def decidim_sanitize_admin(html, options = {})
28
+ decidim_sanitize(html, { scrubber: Decidim::AdminInputScrubber.new }.merge(options))
29
+ end
30
+
26
31
  def decidim_sanitize_newsletter(html, options = {})
27
32
  if options[:strip_tags]
28
33
  strip_tags sanitize(html, scrubber: Decidim::NewsletterScrubber.new)
@@ -32,7 +37,11 @@ module Decidim
32
37
  end
33
38
 
34
39
  def decidim_sanitize_editor(html, options = {})
35
- content_tag(:div, decidim_sanitize(html, options), class: %w(ql-editor ql-reset-decidim))
40
+ content_tag(:div, decidim_sanitize(html, options), class: %w(ql-editor-display))
41
+ end
42
+
43
+ def decidim_sanitize_editor_admin(html, options = {})
44
+ decidim_sanitize_editor(html, { scrubber: Decidim::AdminInputScrubber.new }.merge(options))
36
45
  end
37
46
 
38
47
  def decidim_html_escape(text)
@@ -102,9 +111,10 @@ module Decidim
102
111
  #
103
112
  # @return ActiveSupport::SafeBuffer
104
113
  def render_sanitized_content(resource, method)
105
- content = present(resource).send(method, links: true, strip_tags: !safe_content?)
114
+ content = present(resource).send(method, links: true, strip_tags: !try(:safe_content?))
106
115
 
107
- return decidim_sanitize(content, {}) unless safe_content?
116
+ return decidim_sanitize(content, {}) unless try(:safe_content?)
117
+ return decidim_sanitize_editor_admin(content, {}) if try(:safe_content_admin?)
108
118
 
109
119
  decidim_sanitize_editor(content)
110
120
  end
@@ -11,14 +11,20 @@ module Decidim
11
11
 
12
12
  helper_method :cell
13
13
 
14
- def newsletter(user, newsletter)
14
+ def newsletter(user, newsletter, preview: false)
15
15
  return if user.email.blank?
16
16
 
17
17
  @organization = user.organization
18
18
  @newsletter = newsletter
19
19
  @user = user
20
-
21
- @custom_url_for_mail_root = custom_url_for_mail_root(@organization, @newsletter.id) if Decidim.config.track_newsletter_links
20
+ @preview = preview
21
+
22
+ @custom_url_for_mail_root =
23
+ if @preview
24
+ "#"
25
+ elsif Decidim.config.track_newsletter_links
26
+ custom_url_for_mail_root(@organization, @newsletter.id)
27
+ end
22
28
  @encrypted_token = Decidim::NewsletterEncryptor.sent_at_encrypted(@user.id, @newsletter.sent_at)
23
29
 
24
30
  with_user(user) do
@@ -40,6 +46,7 @@ module Decidim
40
46
  organization: @organization,
41
47
  newsletter: @newsletter,
42
48
  recipient_user: @user,
49
+ custom_url_for_mail_root: @custom_url_for_mail_root,
43
50
  context: {
44
51
  controller: self
45
52
  }
@@ -56,6 +56,24 @@ module Decidim
56
56
  .find_by(scoped_resource_id: id)
57
57
  end
58
58
 
59
+ def url(**kwargs)
60
+ proxy_url(:newsletter_url, id: id, **kwargs)
61
+ end
62
+
63
+ def notifications_settings_url(**kwargs)
64
+ proxy_url(__method__, **kwargs)
65
+ end
66
+
67
+ def unsubscribe_newsletters_url(**kwargs)
68
+ proxy_url(__method__, **kwargs)
69
+ end
70
+
71
+ def organization_official_url
72
+ return "#" unless sent?
73
+
74
+ organization.official_url || proxy_url(:root_url)
75
+ end
76
+
59
77
  private
60
78
 
61
79
  def author_belongs_to_organization
@@ -63,5 +81,15 @@ module Decidim
63
81
 
64
82
  errors.add(:author, :invalid) unless author.organization == organization
65
83
  end
84
+
85
+ def proxy_url(method, **kwargs)
86
+ return "#" unless sent?
87
+
88
+ router.public_send(method, host: organization.host, **kwargs)
89
+ end
90
+
91
+ def router
92
+ @router ||= EngineRouter.new("decidim", {})
93
+ end
66
94
  end
67
95
  end
@@ -15,5 +15,33 @@ module Decidim
15
15
  has_many :scopes, class_name: "Decidim::Scope", inverse_of: :scope_type, dependent: :nullify
16
16
 
17
17
  validates :name, presence: true
18
+
19
+ before_destroy :detach_dynamic_associations
20
+
21
+ def self.log_presenter_class_for(_log)
22
+ Decidim::AdminLog::ScopeTypePresenter
23
+ end
24
+
25
+ private
26
+
27
+ # This method detaches all records that may have association with the scope
28
+ # type. This cannot be done directly using the `dependent` option in the
29
+ # `has_many` relation in order to avoid tight coupling between the modules.
30
+ #
31
+ # This logic does not have to be applied to any classes that have been
32
+ # defined as `has_many` associations within this model already as they are
33
+ # already handled by the `dependent` option.
34
+ def detach_dynamic_associations
35
+ ActiveRecord::Base.descendants.each do |cls|
36
+ next if cls.abstract_class? || !cls.name&.match?(/^Decidim::/)
37
+ next if [self.class, Decidim::Scope].include?(cls)
38
+
39
+ cls.reflect_on_all_associations(:belongs_to).each do |ref|
40
+ next unless ref.options[:class_name] == self.class.name
41
+
42
+ cls.where(ref.options[:foreign_key] => id).update_all(ref.options[:foreign_key] => nil) # rubocop:disable Rails/SkipsModelValidations
43
+ end
44
+ end
45
+ end
18
46
  end
19
47
  end
@@ -35,8 +35,6 @@ module Decidim
35
35
  has_many :access_grants, class_name: "Doorkeeper::AccessGrant", foreign_key: :resource_owner_id, dependent: :destroy
36
36
  has_many :access_tokens, class_name: "Doorkeeper::AccessToken", foreign_key: :resource_owner_id, dependent: :destroy
37
37
 
38
- has_one :blocking, class_name: "Decidim::UserBlock", foreign_key: :id, primary_key: :block_id, dependent: :destroy
39
-
40
38
  validates :name, presence: true, unless: -> { deleted? }
41
39
  validates :nickname,
42
40
  presence: true,
@@ -17,6 +17,8 @@ module Decidim
17
17
  has_many :notifications, foreign_key: "decidim_user_id", class_name: "Decidim::Notification", dependent: :destroy
18
18
  has_many :following_follows, foreign_key: "decidim_user_id", class_name: "Decidim::Follow", dependent: :destroy
19
19
 
20
+ has_one :blocking, class_name: "Decidim::UserBlock", foreign_key: :id, primary_key: :block_id, dependent: :destroy
21
+
20
22
  # Regex for name & nickname format validations
21
23
  REGEXP_NAME = /\A(?!.*[<>?%&\^*#@()\[\]=+:;"{}\\|])/.freeze
22
24
 
@@ -4,7 +4,7 @@ module Decidim
4
4
  class UserBlock < ApplicationRecord
5
5
  MINIMUM_JUSTIFICATION_LENGTH = 15
6
6
 
7
- belongs_to :user, class_name: "Decidim::User", foreign_key: :decidim_user_id
8
- belongs_to :blocking_user, class_name: "Decidim::User"
7
+ belongs_to :user, class_name: "Decidim::UserBaseEntity", foreign_key: :decidim_user_id
8
+ belongs_to :blocking_user, class_name: "Decidim::UserBaseEntity"
9
9
  end
10
10
  end
@@ -21,7 +21,7 @@ module Decidim
21
21
  foreign_key: :decidim_user_id,
22
22
  source: :user
23
23
 
24
- validates :name, presence: true, uniqueness: { scope: :decidim_organization_id }
24
+ validates :name, presence: true, uniqueness: { scope: :decidim_organization_id }, unless: -> { blocked? }
25
25
 
26
26
  validate :correct_state
27
27
  validate :unique_document_number, if: :has_document_number?
@@ -70,7 +70,9 @@ export default class ClipboardOverride extends Clipboard {
70
70
  const text = ev.clipboardData.getData("text/plain");
71
71
  const files = Array.from(ev.clipboardData.files || []);
72
72
  if (!html && files.length > 0) {
73
- this.quill.uploader.upload(range, files);
73
+ if (typeof this.quill.uploader !== "undefined") {
74
+ this.quill.uploader.upload(range, files);
75
+ }
74
76
  return;
75
77
  }
76
78
  if (html && files.length > 0) {
@@ -79,7 +81,9 @@ export default class ClipboardOverride extends Clipboard {
79
81
  doc.body.childElementCount === 1 &&
80
82
  doc.body.firstElementChild.tagName === "IMG"
81
83
  ) {
82
- this.quill.uploader.upload(range, files);
84
+ if (typeof this.quill.uploader !== "undefined") {
85
+ this.quill.uploader.upload(range, files);
86
+ }
83
87
  return;
84
88
  }
85
89
  }