decidim-core 0.29.2 → 0.29.4

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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/address/show.erb +3 -3
  3. data/app/cells/decidim/author/show.erb +2 -4
  4. data/app/cells/decidim/content_blocks/participatory_space_extra_data/extra_data.erb +2 -2
  5. data/app/cells/decidim/participatory_space_dropdown_metadata/metadata.erb +4 -4
  6. data/app/cells/decidim/participatory_space_dropdown_metadata/show.erb +5 -3
  7. data/app/cells/decidim/profile_actions/show.erb +1 -1
  8. data/app/cells/decidim/report_button/already_reported_modal.erb +2 -2
  9. data/app/cells/decidim/report_button/flag_modal.erb +13 -27
  10. data/app/cells/decidim/report_button_cell.rb +2 -8
  11. data/app/cells/decidim/report_user_button/already_reported_modal.erb +11 -0
  12. data/app/cells/decidim/report_user_button/flag_modal.erb +46 -0
  13. data/app/cells/decidim/report_user_button/show.erb +2 -0
  14. data/app/cells/decidim/report_user_button_cell.rb +59 -0
  15. data/app/cells/decidim/resource_types_filter/show.erb +1 -1
  16. data/app/cells/decidim/resource_types_filter_cell.rb +6 -6
  17. data/app/cells/decidim/user_activity/show.erb +1 -1
  18. data/app/commands/decidim/create_omniauth_registration.rb +14 -8
  19. data/app/commands/decidim/create_report.rb +6 -7
  20. data/app/commands/decidim/invite_user.rb +1 -1
  21. data/app/commands/decidim/search.rb +14 -0
  22. data/app/controllers/concerns/decidim/participatory_space_context.rb +4 -1
  23. data/app/controllers/decidim/profiles_controller.rb +2 -2
  24. data/app/controllers/decidim/reports_controller.rb +7 -2
  25. data/app/controllers/decidim/user_activities_controller.rb +1 -1
  26. data/app/forms/decidim/account_form.rb +5 -2
  27. data/app/forms/decidim/omniauth_registration_form.rb +1 -1
  28. data/app/forms/decidim/registration_form.rb +1 -1
  29. data/app/helpers/decidim/menu_helper.rb +2 -2
  30. data/app/helpers/decidim/orders_helper.rb +2 -1
  31. data/app/helpers/decidim/paginate_helper.rb +1 -1
  32. data/app/helpers/decidim/participatory_space_helpers.rb +1 -1
  33. data/app/helpers/decidim/tooltip_helper.rb +4 -1
  34. data/app/jobs/decidim/hide_child_resources_job.rb +24 -0
  35. data/app/mailers/decidim/notifications_digest_mailer.rb +7 -1
  36. data/app/mailers/decidim/reported_mailer.rb +18 -2
  37. data/app/models/decidim/action_log.rb +1 -9
  38. data/app/models/decidim/report.rb +1 -1
  39. data/app/models/decidim/user.rb +0 -4
  40. data/app/models/decidim/user_base_entity.rb +4 -0
  41. data/app/packs/src/decidim/datepicker/datepicker_functions.js +3 -3
  42. data/app/packs/src/decidim/index.js +4 -2
  43. data/app/packs/src/decidim/input_character_counter.js +1 -1
  44. data/app/packs/src/decidim/map/provider/here.js +1 -1
  45. data/app/packs/stylesheets/decidim/_cards.scss +1 -1
  46. data/app/packs/stylesheets/decidim/_content_blocks.scss +4 -0
  47. data/app/packs/stylesheets/decidim/_hashtags.scss +5 -0
  48. data/app/packs/stylesheets/decidim/_header.scss +65 -40
  49. data/app/packs/stylesheets/decidim/application.scss +1 -0
  50. data/app/permissions/decidim/default_permissions.rb +2 -0
  51. data/app/presenters/decidim/log/user_presenter.rb +1 -0
  52. data/app/presenters/decidim/notification_to_mailer_presenter.rb +7 -3
  53. data/app/presenters/decidim/user_presenter.rb +1 -1
  54. data/app/queries/decidim/last_activity.rb +25 -0
  55. data/app/services/decidim/base_diff_renderer.rb +2 -0
  56. data/app/services/decidim/static_map_generator.rb +1 -1
  57. data/app/views/decidim/last_activities/index.html.erb +1 -1
  58. data/app/views/decidim/messaging/conversations/_reply_form.html.erb +1 -2
  59. data/app/views/decidim/messaging/conversations/_start.html.erb +1 -1
  60. data/app/views/decidim/reported_mailer/hidden_automatically.html.erb +25 -0
  61. data/app/views/decidim/reported_mailer/hidden_manually.html.erb +25 -0
  62. data/app/views/decidim/reported_mailer/report.html.erb +1 -1
  63. data/app/views/decidim/searches/_count.html.erb +1 -1
  64. data/app/views/decidim/searches/_filters.html.erb +40 -38
  65. data/app/views/decidim/shared/_orders.html.erb +2 -2
  66. data/app/views/decidim/shared/_results_per_page.html.erb +1 -1
  67. data/app/views/kaminari/decidim/_page.html.erb +1 -1
  68. data/app/views/kaminari/decidim/_paginator.html.erb +1 -1
  69. data/app/views/layouts/decidim/_logo.html.erb +2 -2
  70. data/app/views/layouts/decidim/footer/_main_legal.html.erb +1 -1
  71. data/app/views/layouts/decidim/header/_menu_breadcrumb_main_dropdown_desktop.html.erb +5 -11
  72. data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile_tablet.html.erb +5 -5
  73. data/config/locales/ar.yml +41 -34
  74. data/config/locales/bg.yml +10 -30
  75. data/config/locales/bs-BA.yml +2 -0
  76. data/config/locales/ca-IT.yml +2122 -0
  77. data/config/locales/ca.yml +69 -30
  78. data/config/locales/cs.yml +73 -36
  79. data/config/locales/de.yml +64 -26
  80. data/config/locales/el.yml +10 -21
  81. data/config/locales/en.yml +56 -17
  82. data/config/locales/eo.yml +2 -0
  83. data/config/locales/es-MX.yml +69 -30
  84. data/config/locales/es-PY.yml +74 -35
  85. data/config/locales/es.yml +72 -33
  86. data/config/locales/eu.yml +128 -91
  87. data/config/locales/fi-plain.yml +44 -34
  88. data/config/locales/fi.yml +46 -36
  89. data/config/locales/fr-CA.yml +72 -29
  90. data/config/locales/fr.yml +71 -28
  91. data/config/locales/ga-IE.yml +4 -4
  92. data/config/locales/gl.yml +25 -20
  93. data/config/locales/hu.yml +9 -29
  94. data/config/locales/id-ID.yml +24 -21
  95. data/config/locales/is-IS.yml +10 -6
  96. data/config/locales/it.yml +35 -32
  97. data/config/locales/ja.yml +70 -30
  98. data/config/locales/lb.yml +24 -27
  99. data/config/locales/lt.yml +5 -23
  100. data/config/locales/lv.yml +18 -20
  101. data/config/locales/nl.yml +23 -23
  102. data/config/locales/no.yml +18 -21
  103. data/config/locales/pl.yml +7 -27
  104. data/config/locales/pt-BR.yml +11 -30
  105. data/config/locales/pt.yml +18 -21
  106. data/config/locales/ro-RO.yml +239 -92
  107. data/config/locales/ru.yml +23 -13
  108. data/config/locales/sk.yml +29 -23
  109. data/config/locales/sl.yml +4 -0
  110. data/config/locales/sr-CS.yml +2 -0
  111. data/config/locales/sv.yml +49 -37
  112. data/config/locales/tr-TR.yml +25 -28
  113. data/config/locales/uk.yml +12 -7
  114. data/config/locales/zh-CN.yml +18 -20
  115. data/config/locales/zh-TW.yml +8 -22
  116. data/db/migrate/20171212103803_create_unique_nicknames.rb +1 -1
  117. data/db/migrate/20180221101934_fix_nickname_index.rb +1 -1
  118. data/db/migrate/20180706104107_add_nickname_to_managed_users.rb +1 -1
  119. data/db/migrate/20181001124950_move_users_groups_to_users_table.rb +1 -1
  120. data/db/migrate/20190412131728_fix_user_names.rb +1 -1
  121. data/lib/decidim/asset_router/storage.rb +7 -2
  122. data/lib/decidim/attributes/time_with_zone.rb +5 -1
  123. data/lib/decidim/content_parsers/blob_parser.rb +10 -8
  124. data/lib/decidim/content_parsers/user_parser.rb +1 -1
  125. data/lib/decidim/core/test/shared_examples/reports_examples.rb +48 -6
  126. data/lib/decidim/core/test/shared_examples/social_share_examples.rb +32 -0
  127. data/lib/decidim/core/test/shared_examples/uncommentable_component_examples.rb +26 -0
  128. data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +26 -0
  129. data/lib/decidim/core/version.rb +1 -1
  130. data/lib/decidim/map/provider/dynamic_map/here.rb +1 -40
  131. data/lib/decidim/map/provider/static_map/here.rb +34 -0
  132. data/lib/decidim/moderation_tools.rb +16 -2
  133. data/lib/decidim/nicknamizable.rb +6 -9
  134. data/lib/decidim/reportable.rb +6 -2
  135. data/lib/decidim/translatable_attributes.rb +5 -1
  136. data/lib/tasks/upgrade/clean_hidden_resources.rake +33 -0
  137. data/lib/tasks/upgrade/decidim_fix_nickname_uniqueness.rake +23 -20
  138. metadata +17 -15
  139. data/app/cells/decidim/author/flag.erb +0 -6
  140. data/app/cells/decidim/author/flag_user.erb +0 -14
  141. data/app/cells/decidim/flag_modal/flag_user.erb +0 -34
  142. data/app/cells/decidim/flag_modal/show.erb +0 -52
  143. data/app/cells/decidim/flag_modal_cell.rb +0 -56
  144. data/app/cells/decidim/profile_sidebar/show.erb +0 -167
  145. data/app/cells/decidim/profile_sidebar_cell.rb +0 -68
  146. data/app/packs/src/decidim/vendor/leaflet-tilelayer-here.js +0 -212
  147. data/app/views/decidim/reported_mailer/hide.html.erb +0 -9
@@ -5,7 +5,10 @@ module Decidim
5
5
  # on the layout.
6
6
  module TooltipHelper
7
7
  def with_tooltip(title, opts = {}, &)
8
- content_tag(:span, title:, data: { tooltip: content_tag(:div, title, id: opts[:id], class: opts[:class] || "bottom", role: "tooltip", "aria-hidden": "true") }) do
8
+ content_tag(:p,
9
+ title:,
10
+ class: "inline-block",
11
+ data: { tooltip: content_tag(:p, title, id: opts[:id], class: opts[:class] || "bottom", role: "tooltip", "aria-hidden": "true") }) do
9
12
  capture(&).html_safe
10
13
  end
11
14
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ class HideChildResourcesJob < ApplicationJob
5
+ queue_as :user_report
6
+
7
+ def perform(resource, user_id)
8
+ spam_user = (resource.organization.users.find_by(email: Decidim::Ai::SpamDetection.reporting_user_email) if Decidim.module_installed?(:ai))
9
+ spam_user = resource.organization.admins.find(user_id) if spam_user.nil?
10
+
11
+ tool = Decidim::ModerationTools.new(resource, spam_user)
12
+
13
+ unless Decidim::Report.exists?("decidim_moderation_id" => tool.moderation.id, "decidim_user_id" => spam_user.id)
14
+ tool.create_report!({
15
+ reason: "parent_hidden",
16
+ details: I18n.t("report_details", scope: "decidim.reports.parent_hidden")
17
+ })
18
+ end
19
+
20
+ tool.update_report_count!
21
+ tool.hide!
22
+ end
23
+ end
24
+ end
@@ -14,7 +14,13 @@ module Decidim
14
14
  @organization = user.organization
15
15
  @notifications_digest = Decidim::NotificationsDigestPresenter.new(user)
16
16
  @display_see_more_message = notifications.size > SIZE_LIMIT
17
- @notifications = notifications[0...SIZE_LIMIT].map { |notification| Decidim::NotificationToMailerPresenter.new(notification) }
17
+ # Note that this could be improved by adding a "type" column to the notifications table
18
+ # This fix can generate lists of notifications that are below the SIZE_LIMIT
19
+ @notifications = notifications[0...SIZE_LIMIT].filter_map do |notification|
20
+ next unless notification.event_class_instance.respond_to?(:email_intro)
21
+
22
+ Decidim::NotificationToMailerPresenter.new(notification)
23
+ end
18
24
 
19
25
  mail(to: user.email, subject: @notifications_digest.subject)
20
26
  end
@@ -21,13 +21,29 @@ module Decidim
21
21
  end
22
22
  end
23
23
 
24
- def hide(user, report)
24
+ # This is used when a user with special rights (like an administrator, a space administrator or a moderator) hides a resource
25
+ def hidden_manually(user, report, current_user)
25
26
  with_user(user) do
26
27
  @report = report
27
28
  @participatory_space = @report.moderation.participatory_space
29
+ @reportable = @report.moderation.reportable
30
+ @organization = user.organization
31
+ @user = user
32
+ @moderator = current_user
33
+ subject = I18n.t("hidden_manually.subject", scope: "decidim.reported_mailer", moderator: @moderator.name)
34
+ mail(to: user.email, subject:)
35
+ end
36
+ end
37
+
38
+ # This is meant to be used when a resource is hidden by an algorithm, such as the `decidim-ai` module, or the `Decidim.max_reports_before_hiding` feature.
39
+ def hidden_automatically(user, report)
40
+ with_user(user) do
41
+ @report = report
42
+ @participatory_space = @report.moderation.participatory_space
43
+ @reportable = @report.moderation.reportable
28
44
  @organization = user.organization
29
45
  @user = user
30
- subject = I18n.t("hide.subject", scope: "decidim.reported_mailer")
46
+ subject = I18n.t("hidden_automatically.subject", scope: "decidim.reported_mailer")
31
47
  mail(to: user.email, subject:)
32
48
  end
33
49
  end
@@ -156,15 +156,7 @@ module Decidim
156
156
 
157
157
  def self.publicable_public_resource_types
158
158
  @publicable_public_resource_types ||= public_resource_types
159
- .select { |klass| klass.constantize.column_names.include?("published_at") } - publicable_exceptions
160
- end
161
-
162
- def self.publicable_exceptions
163
- @publicable_exceptions = %w(
164
- Decidim::Blogs::Post
165
- ).select do |klass|
166
- klass.safe_constantize.present?
167
- end
159
+ .select { |klass| klass.constantize.column_names.include?("published_at") }
168
160
  end
169
161
 
170
162
  def self.ransackable_scopes(auth_object = nil)
@@ -5,7 +5,7 @@ module Decidim
5
5
  class Report < ApplicationRecord
6
6
  include Decidim::DownloadYourData
7
7
 
8
- REASONS = %w(spam offensive does_not_belong hidden_during_block).freeze
8
+ REASONS = %w(spam offensive does_not_belong hidden_during_block parent_hidden).freeze
9
9
 
10
10
  belongs_to :moderation, foreign_key: "decidim_moderation_id", class_name: "Decidim::Moderation"
11
11
  belongs_to :user, foreign_key: "decidim_user_id", class_name: "Decidim::User"
@@ -13,8 +13,6 @@ module Decidim
13
13
  include Decidim::UserReportable
14
14
  include Decidim::Traceable
15
15
 
16
- REGEXP_NICKNAME = /\A[\w-]+\z/
17
-
18
16
  class Roles
19
17
  def self.all
20
18
  Decidim.config.user_roles
@@ -51,8 +49,6 @@ module Decidim
51
49
 
52
50
  has_one_attached :download_your_data_file
53
51
 
54
- scope :not_deleted, -> { where(deleted_at: nil) }
55
-
56
52
  scope :managed, -> { where(managed: true) }
57
53
  scope :not_managed, -> { where(managed: false) }
58
54
 
@@ -21,11 +21,13 @@ module Decidim
21
21
 
22
22
  # Regex for name & nickname format validations
23
23
  REGEXP_NAME = /\A(?!.*[<>?%&\^*#@()\[\]=+:;"{}\\|])/
24
+ REGEXP_NICKNAME = /\A[a-z0-9_-]+\z/
24
25
 
25
26
  has_one_attached :avatar
26
27
  validates_avatar :avatar, uploader: Decidim::AvatarUploader
27
28
 
28
29
  validates :name, format: { with: REGEXP_NAME }
30
+ validates :nickname, format: { with: REGEXP_NICKNAME }, unless: -> { deleted? || managed? }
29
31
 
30
32
  scope :confirmed, -> { where.not(confirmed_at: nil) }
31
33
  scope :not_confirmed, -> { where(confirmed_at: nil) }
@@ -34,6 +36,8 @@ module Decidim
34
36
  scope :not_blocked, -> { where(blocked: false) }
35
37
  scope :available, -> { where(deleted_at: nil, blocked: false, managed: false) }
36
38
 
39
+ scope :not_deleted, -> { where(deleted_at: nil) }
40
+
37
41
  # Public: Returns a collection with all the public entities this user is following.
38
42
  #
39
43
  # This cannot be done as with a `has_many :following, through: :following_follows`
@@ -29,12 +29,12 @@ export const formatInputDate = (date, formats) => {
29
29
  const month = dateList[1];
30
30
  const day = dateList[2];
31
31
 
32
- if (formats.order === "d-m-y") {
33
- return `${day}${formats.separator}${month}${formats.separator}${year}`;
32
+ if (formats.order === "m-d-y") {
33
+ return `${month}${formats.separator}${day}${formats.separator}${year}`;
34
34
  } else if (formats.order === "y-m-d") {
35
35
  return `${year}${formats.separator}${month}${formats.separator}${day}`;
36
36
  };
37
- return `${month}${formats.separator}${day}${formats.separator}${year}`;
37
+ return `${day}${formats.separator}${month}${formats.separator}${year}`;
38
38
  };
39
39
 
40
40
  export const formatInputTime = (time, format, input) => {
@@ -69,7 +69,8 @@ import handleNotificationActions from "src/decidim/notifications_actions"
69
69
  import RemoteModal from "src/decidim/remote_modal"
70
70
  import selectActiveIdentity from "src/decidim/identity_selector_dialog"
71
71
  import createTooltip from "src/decidim/tooltips"
72
- import fetchRemoteTooltip from "src/decidim/remote_tooltips"
72
+ // Temporary disabling this feature because we have a poor performance. See https://github.com/decidim/decidim/issues/14431
73
+ // import fetchRemoteTooltip from "src/decidim/remote_tooltips"
73
74
  import createToggle from "src/decidim/toggle"
74
75
  import {
75
76
  createAccordion,
@@ -196,7 +197,8 @@ const initializer = (element = document) => {
196
197
  // Initialize data-toggles
197
198
  element.querySelectorAll("[data-toggle]").forEach((elem) => createToggle(elem))
198
199
 
199
- element.querySelectorAll("[data-remote-tooltip]").forEach((elem) => fetchRemoteTooltip(elem))
200
+ // Temporary disabling this feature because we have a poor performance. See https://github.com/decidim/decidim/issues/14431
201
+ // element.querySelectorAll("[data-remote-tooltip]").forEach((elem) => fetchRemoteTooltip(elem))
200
202
 
201
203
  element.querySelectorAll(".new_report").forEach((elem) => changeReportFormBehavior(elem))
202
204
  }
@@ -93,7 +93,7 @@ export default class InputCharacterCounter {
93
93
  this.$srTarget = $(`#${screenReaderId}`);
94
94
  if (!this.$srTarget.length) {
95
95
  this.$srTarget = $(
96
- `<span role="status" id="${screenReaderId}" class="sr-only remaining-character-count-sr" />`
96
+ `<span role="status" id="${screenReaderId}" class="sr-only remaining-character-count-sr" aria-hidden="true"/>`
97
97
  );
98
98
  this.$target.before(this.$srTarget);
99
99
  }
@@ -1,5 +1,5 @@
1
1
  import "leaflet"
2
- import "src/decidim/vendor/leaflet-tilelayer-here"
2
+ import "leaflet-tilelayer-here"
3
3
 
4
4
  /**
5
5
  * NOTE:
@@ -159,7 +159,7 @@
159
159
  /* shared styles */
160
160
  &__highlight-metadata,
161
161
  &__grid-metadata {
162
- @apply mt-auto flex items-center justify-between flex-wrap text-sm text-gray-2 [&>*]:flex [&>*]:items-center [&>*]:gap-1 first:[&>*]:flex-none;
162
+ @apply mt-auto flex items-center justify-between flex-wrap w-full text-sm text-gray-2 [&>*]:flex [&>*]:items-center [&>*]:gap-1 first:[&>*]:w-4/5;
163
163
 
164
164
  svg {
165
165
  @apply flex-none text-gray fill-current;
@@ -27,6 +27,10 @@
27
27
  @apply block;
28
28
  }
29
29
  }
30
+
31
+ > h3:not([class~="not-prose"]) {
32
+ @apply mb-[-0.4rem] pt-4 pb-2;
33
+ }
30
34
  }
31
35
 
32
36
  &__span {
@@ -0,0 +1,5 @@
1
+ .hashtags {
2
+ > label {
3
+ @apply ml-4;
4
+ }
5
+ }
@@ -115,7 +115,7 @@ header {
115
115
  @apply fixed bottom-0 left-0 z-40 bg-white w-full px-4 py-3 flex justify-between text-secondary shadow-[0_-4px_6px_rgba(198,198,198,0.25)];
116
116
 
117
117
  &__trigger {
118
- @apply flex flex-col items-center text-secondary cursor-pointer pl-4 border-l border-gray-3;
118
+ @apply flex flex-col items-center text-secondary cursor-pointer md:pl-4 md:border-l border-gray-3;
119
119
 
120
120
  svg {
121
121
  @apply w-6 h-6 fill-current;
@@ -167,7 +167,7 @@ header {
167
167
  }
168
168
 
169
169
  &__item {
170
- @apply relative;
170
+ @apply flex relative;
171
171
  }
172
172
 
173
173
  &__search {
@@ -175,14 +175,16 @@ header {
175
175
  }
176
176
 
177
177
  &__login {
178
- @apply w-20 h-full flex flex-row items-center relative text-secondary gap-1;
178
+ @apply w-auto h-full flex flex-row items-center relative text-secondary gap-1 pl-2 pr-2;
179
179
 
180
180
  svg {
181
181
  @apply w-8 h-6 fill-current;
182
182
  }
183
183
 
184
184
  svg + span {
185
- @apply text-sm first-letter:uppercase pr-4 w-16;
185
+ @apply text-sm first-letter:uppercase w-auto;
186
+
187
+ flex-shrink: 0;
186
188
  }
187
189
  }
188
190
  }
@@ -332,10 +334,6 @@ header {
332
334
  &__dropdown-trigger {
333
335
  @apply flex items-center justify-between text-white;
334
336
 
335
- span {
336
- @apply flex flex-wrap md:flex-nowrap gap-x-2.5 overflow-hidden text-white;
337
- }
338
-
339
337
  svg {
340
338
  @apply w-6 h-6 fill-current;
341
339
  }
@@ -371,54 +369,77 @@ header {
371
369
  @apply absolute top-full left-0 bg-white rounded w-full bg-gray-5;
372
370
  }
373
371
 
374
- &__main-dropdown {
375
- @apply bg-white divide-y divide-gray-3 rounded-b shadow-lg text-black w-full lg:w-[1280px] h-screen md:h-auto;
372
+ &__dropdown-menu {
373
+ @apply w-full md:w-1/4 bg-primary px-4 md:px-8 pt-0 pb-3 md:py-3 divide-y divide-gray-3 text-white;
376
374
 
377
- &__bottom,
378
- &__top {
379
- @apply flex flex-col md:flex-row justify-between p-4 md:p-8 gap-x-8;
375
+ > * {
376
+ @apply py-3 md:py-3.5;
377
+ }
380
378
 
381
- &-right {
382
- @apply hidden md:block md:w-1/2;
379
+ a {
380
+ @apply flex items-center justify-start gap-1 font-semibold text-lg text-white;
381
+
382
+ span {
383
+ @apply min-w-0 truncate;
383
384
  }
384
- }
385
385
 
386
- &__bottom {
387
- @apply hidden md:flex;
386
+ svg {
387
+ @apply flex-none fill-current;
388
+ }
388
389
  }
390
+ }
389
391
 
390
- &__title {
391
- @apply hidden h4 md:flex md:h3;
392
- }
392
+ &__main-dropdown {
393
+ @apply bg-white flex flex-row rounded-b shadow-lg text-black w-full lg:w-[1280px] h-screen md:h-auto;
393
394
 
394
- &__subtitle {
395
- @apply hidden text-md md:flex md:text-lg text-gray-2 mt-5;
395
+ &__left {
396
+ @apply flex flex-col justify-between p-4 md:p-8 space-y-5 hidden md:block md:w-3/4;
397
+
398
+ &-top {
399
+ @apply border-b-4 border-gray-3 pb-3;
400
+ }
396
401
  }
397
402
 
398
- &__menu {
399
- @apply w-full md:w-1/2 mt-0 grid md:grid-cols-2 gap-x-6 text-secondary;
403
+ &__top {
404
+ @apply w-full px-4;
400
405
 
401
- > * {
402
- @apply py-3 md:py-3.5 border-b last:border-0 border-gray-3;
406
+ &-menu {
407
+ @apply w-full md:w-1/2 mt-0 grid md:grid-cols-2 gap-x-6 text-secondary;
408
+
409
+ > * {
410
+ @apply py-3 md:py-3.5 border-b last:border-0 border-gray-3;
403
411
 
404
- /* since the grid has 2 columns, remove the border for these last 2 columns */
405
- &:nth-last-child(-n + 2) {
406
- @apply md:border-0;
412
+ /* since the grid has 2 columns, remove the border for these last 2 columns */
413
+ &:nth-last-child(-n + 2) {
414
+ @apply md:border-0;
415
+ }
407
416
  }
408
- }
409
417
 
410
- a {
411
- @apply flex items-center justify-start gap-1 font-semibold text-lg text-secondary;
418
+ a {
419
+ @apply flex items-center justify-start gap-1 font-semibold text-lg text-secondary;
412
420
 
413
- span {
414
- @apply min-w-0 truncate;
415
- }
421
+ span {
422
+ @apply min-w-0 truncate;
423
+ }
416
424
 
417
- svg {
418
- @apply flex-none fill-current;
425
+ svg {
426
+ @apply flex-none fill-current;
427
+ }
419
428
  }
420
429
  }
421
430
  }
431
+
432
+ &__bottom {
433
+ @apply hidden md:flex;
434
+ }
435
+
436
+ &__title {
437
+ @apply hidden h4 md:flex md:h3;
438
+ }
439
+
440
+ &__subtitle {
441
+ @apply hidden text-md md:flex md:text-lg text-gray-2 mt-5;
442
+ }
422
443
  }
423
444
 
424
445
  &__secondary-dropdown {
@@ -432,8 +453,12 @@ header {
432
453
  @apply h4 md:h3;
433
454
  }
434
455
 
456
+ nav {
457
+ @apply w-full md:w-1/4;
458
+ }
459
+
435
460
  &__menu {
436
- @apply w-full md:w-1/4 bg-primary px-4 md:px-8 pt-0 pb-3 md:py-3 divide-y divide-gray-3 text-white;
461
+ @apply w-full bg-primary px-4 md:px-8 pt-0 pb-3 md:py-3 divide-y divide-gray-3 text-white;
437
462
 
438
463
  > * {
439
464
  @apply py-3 md:py-3.5;
@@ -453,7 +478,7 @@ header {
453
478
  }
454
479
 
455
480
  &__metadata {
456
- @apply flex items-center text-sm space-x-6 py-8;
481
+ @apply flex items-center text-sm space-x-6 pb-6;
457
482
 
458
483
  > span {
459
484
  @apply flex items-center space-x-2;
@@ -58,6 +58,7 @@
58
58
  @import "stylesheets/decidim/_hero.scss";
59
59
  @import "stylesheets/decidim/_actions.scss";
60
60
  @import "stylesheets/decidim/_emoji.scss";
61
+ @import "stylesheets/decidim/_hashtags.scss";
61
62
  }
62
63
 
63
64
  @import "stylesheets/decidim/vendor/datepicker_light.scss";
@@ -5,6 +5,8 @@ module Decidim
5
5
  # actions by any kind of user. Also works as a default implementation so other
6
6
  # components can inherit from it and get some convenience methods.
7
7
  class DefaultPermissions
8
+ include Decidim::UserRoleChecker
9
+
8
10
  def initialize(user, permission_action, context = {})
9
11
  @user = user
10
12
  @permission_action = permission_action
@@ -46,6 +46,7 @@ module Decidim
46
46
  # Returns an HTML-safe String.
47
47
  def present_user
48
48
  return h.content_tag(:span, present_user_name, class: "logs__log__author") if user.blank?
49
+ return I18n.t("decidim.profile.deleted") if user.respond_to?(:deleted?) && user.deleted?
49
50
 
50
51
  h.link_to(
51
52
  present_user_name,
@@ -14,15 +14,19 @@ module Decidim
14
14
  delegate :url_helpers, to: "Decidim::Core::Engine.routes"
15
15
  delegate :resource_title, to: :event
16
16
  delegate :resource_url, to: :event
17
- delegate :email_intro, to: :event
18
17
  delegate :resource_path, to: :event
19
18
  delegate :safe_resource_text, to: :event
20
19
 
20
+ def email_intro
21
+ event.email_intro if event.respond_to?(:email_intro)
22
+ end
23
+
21
24
  def date_time
25
+ created_at_in_time_zone = created_at.in_time_zone(resource.organization.time_zone)
22
26
  if frequency == :daily
23
- created_at.strftime("%H:%M")
27
+ I18n.l(created_at_in_time_zone, format: :time_of_day)
24
28
  else
25
- I18n.l(created_at, format: :decidim_short)
29
+ I18n.l(created_at_in_time_zone, format: :decidim_short)
26
30
  end
27
31
  end
28
32
 
@@ -37,7 +37,7 @@ module Decidim
37
37
  return default_avatar_url if __getobj__.blocked?
38
38
  return default_avatar_url unless avatar.attached?
39
39
 
40
- avatar.path(variant:)
40
+ avatar.url(variant:)
41
41
  end
42
42
 
43
43
  def default_avatar_url
@@ -18,6 +18,7 @@ module Decidim
18
18
  query = filter_moderated(query)
19
19
  query = filter_spaces(query)
20
20
  query = filter_deleted(query)
21
+ query = filter_withdrawn(query)
21
22
  query.with_new_resource_type("all")
22
23
  end
23
24
  end
@@ -48,6 +49,30 @@ module Decidim
48
49
  ).where(decidim_moderations: { id: nil })
49
50
  end
50
51
 
52
+ def filter_withdrawn(query)
53
+ # Filter out the items that have been withdrawn.
54
+ conditions = []
55
+
56
+ ActionLog.public_resource_types.each do |resource_type|
57
+ klass = resource_type.constantize
58
+
59
+ condition = if klass.respond_to?(:not_withdrawn)
60
+ Arel.sql(
61
+ [
62
+ "decidim_action_logs.resource_type = '#{resource_type}'",
63
+ "decidim_action_logs.resource_id IN (#{Arel.sql(klass.not_withdrawn.select(:id).to_sql)})"
64
+ ].join(" AND ")
65
+ ).to_s
66
+ else
67
+ Arel.sql("decidim_action_logs.resource_type = '#{resource_type}'").to_s
68
+ end
69
+
70
+ conditions << "(#{condition})"
71
+ end
72
+
73
+ query.where(Arel.sql(conditions.join(" OR ")).to_s)
74
+ end
75
+
51
76
  def filter_spaces(query)
52
77
  conditions = []
53
78
 
@@ -41,6 +41,8 @@ module Decidim
41
41
  end
42
42
 
43
43
  def parse_i18n_changeset(attribute, values, type, diff)
44
+ return diff unless values.last.is_a?(Hash)
45
+
44
46
  (values.last.keys - ["machine_translations"]).each do |locale, _value|
45
47
  first_value = values.first.try(:[], locale)
46
48
  last_value = values.last.try(:[], locale)
@@ -15,7 +15,7 @@ module Decidim
15
15
  def data
16
16
  return if @resource.blank? || map_utility.nil?
17
17
 
18
- Rails.cache.fetch(@resource.cache_key) do
18
+ Rails.cache.fetch(@resource.cache_key_with_version) do
19
19
  map_utility.image_data(
20
20
  latitude: @resource.latitude,
21
21
  longitude: @resource.longitude,
@@ -5,7 +5,7 @@
5
5
  <h1 class="title-decorator my-12"><%= t("last_activity", scope: "decidim.last_activities.index") %></h1>
6
6
 
7
7
  <div class="profile__activity pb-16">
8
- <%= cell "decidim/resource_types_filter", resource_types, form_path: last_activities_path, filter_param_key: :with_resource_type, filter: %>
8
+ <%= cell "decidim/resource_types_filter", resource_types, source: :last_activities, filter_param_key: :with_resource_type %>
9
9
  <div id="activities">
10
10
  <%= render partial: "activities" %>
11
11
  </div>
@@ -1,8 +1,7 @@
1
1
  <div data-conversation-reply>
2
2
  <%= decidim_form_for form, url: decidim.conversation_path(conversation.id), method: :put, remote: true do |f| %>
3
3
  <div class="conversation__reply">
4
- <%= f.label :body, nil, class: "sr-only" %>
5
- <%= f.text_area :body, label: false, rows: 4, required: true, placeholder: t(".placeholder"), data: { "input-emoji": true } %>
4
+ <%= f.text_area :body, label: false, rows: 4, required: true, placeholder: t(".placeholder"), data: { "input-emoji": true }, aria: { label: t(".placeholder") } %>
6
5
  <%= f.submit "#{t(".send")} #{icon "arrow-right-line", class: "fill-current"}".html_safe, class: "button button__sm button__secondary self-end mt-4" %>
7
6
  </div>
8
7
  <% end %>
@@ -5,7 +5,7 @@
5
5
  <%= f.hidden_field :recipient_id, id: nil, name: "conversation[recipient_id][]", value: recipient.id %>
6
6
  <% end %>
7
7
  <%= f.label :body, nil, class: "sr-only" %>
8
- <%= f.text_area :body, label: false, rows: 4, required: true, placeholder: t(".placeholder"), data: { "input-emoji": true } %>
8
+ <%= f.text_area :body, label: false, rows: 4, required: true, placeholder: t(".placeholder"), data: { "input-emoji": true }, aria: { label: t(".placeholder") } %>
9
9
  <%= f.submit "#{t(".send")} #{icon "arrow-right-line", class: "fill-current"}".html_safe, class: "button button__sm button__secondary self-end mt-4" %>
10
10
  </div>
11
11
  <% end %>
@@ -0,0 +1,25 @@
1
+ <p class="email-greeting"><%= t(".hello", name: @user.name) %></p>
2
+
3
+ <p class="email-instructions">
4
+ <%= t(".report_html", url: report_url ) %>
5
+ </p>
6
+
7
+ <p><b><%= t(".participatory_space") %></b></p>
8
+ <p><%= link_to translated_attribute(@participatory_space.title), resource_locator(@participatory_space).url %></p>
9
+
10
+ <p><b><%= t(".reason") %></b></p>
11
+ <p><%= t(@report.reason, organization_name: organization_name(@participatory_space.organization), scope: "decidim.shared.flag_modal") %></p>
12
+
13
+ <% if @report.details.present? %>
14
+ <p><b><%= t(".details") %></b></p>
15
+ <blockquote>
16
+ <%= @report.details %>
17
+ </blockquote>
18
+ <% end %>
19
+
20
+ <p><b><%= t(".content") %></b></p>
21
+ <%= reported_content_cell %>
22
+
23
+ <p class="email-button email-button__cta">
24
+ <%= link_to t(".manage_moderations"), manage_moderations_url %>
25
+ </p>
@@ -0,0 +1,25 @@
1
+ <p class="email-greeting"><%= t(".hello", name: @user.name) %></p>
2
+
3
+ <p class="email-instructions">
4
+ <%= t(".report_html", url: reported_content_url, moderator: @moderator.name) %>
5
+ </p>
6
+
7
+ <p><b><%= t(".participatory_space") %></b></p>
8
+ <p><%= link_to translated_attribute(@participatory_space.title), resource_locator(@participatory_space).url %></p>
9
+
10
+ <p><b><%= t(".reason") %></b></p>
11
+ <p><%= t(@report.reason, organization_name: organization_name(@participatory_space.organization), scope: "decidim.shared.flag_modal") %></p>
12
+
13
+ <% if @report.details.present? %>
14
+ <p><b><%= t(".details") %></b></p>
15
+ <blockquote>
16
+ <%= @report.details %>
17
+ </blockquote>
18
+ <% end %>
19
+
20
+ <p><b><%= t(".content") %></b></p>
21
+ <%= reported_content_cell %>
22
+
23
+ <p class="email-button email-button__cta">
24
+ <%= link_to t(".manage_moderations"), manage_moderations_url %>
25
+ </p>
@@ -1,7 +1,7 @@
1
1
  <p class="email-greeting"><%= t(".hello", name: @user.name) %></p>
2
2
 
3
3
  <p class="email-instructions">
4
- <%= t(".report_html", url: reported_content_url) %>
4
+ <%= t(".report_html", url: report_url) %>
5
5
  </p>
6
6
 
7
7
  <br>
@@ -15,6 +15,6 @@
15
15
  <% end %>
16
16
  </div>
17
17
 
18
- <h1 class="h3 decorator mb-10 md:my-10">
18
+ <h1 id="search-results-title" class="h3 decorator mb-10 md:my-10">
19
19
  <%= t("decidim.search.results_found_for_term", count: @results_count, term:) %>
20
20
  </h1>