decidim-core 0.25.0 → 0.26.0.rc2

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 (165) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/activity_cell.rb +2 -1
  3. data/app/cells/decidim/author/flag_user.erb +1 -1
  4. data/app/cells/decidim/author/profile_inline.erb +1 -1
  5. data/app/cells/decidim/author/withdraw.erb +2 -2
  6. data/app/cells/decidim/author_cell.rb +32 -0
  7. data/app/cells/decidim/card_m_cell.rb +1 -1
  8. data/app/cells/decidim/content_blocks/cta_cell.rb +1 -1
  9. data/app/cells/decidim/content_blocks/hero_cell.rb +1 -1
  10. data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +1 -1
  11. data/app/cells/decidim/content_blocks/how_to_participate/show.erb +1 -1
  12. data/app/cells/decidim/content_blocks/last_activity_cell.rb +1 -1
  13. data/app/cells/decidim/content_blocks/stats_cell.rb +12 -0
  14. data/app/cells/decidim/endorsers_list_cell.rb +3 -1
  15. data/app/cells/decidim/flag_modal/flag_user.erb +2 -2
  16. data/app/cells/decidim/flag_modal/show.erb +2 -2
  17. data/app/cells/decidim/flag_modal_cell.rb +10 -0
  18. data/app/cells/decidim/following/show.erb +17 -8
  19. data/app/cells/decidim/following_cell.rb +6 -2
  20. data/app/cells/decidim/notification/show.erb +31 -0
  21. data/app/cells/decidim/notification_cell.rb +20 -0
  22. data/app/cells/decidim/notifications/show.erb +1 -24
  23. data/app/cells/decidim/notifications_cell.rb +0 -1
  24. data/app/cells/decidim/user_conversation/conversation_header.erb +1 -1
  25. data/app/cells/decidim/user_conversation/show.erb +4 -2
  26. data/app/cells/decidim/user_conversations/conversation_item.erb +1 -1
  27. data/app/commands/decidim/create_editor_image.rb +41 -0
  28. data/app/controllers/concerns/decidim/disable_redirection_to_external_host.rb +15 -0
  29. data/app/controllers/concerns/decidim/safe_redirect.rb +14 -3
  30. data/app/controllers/decidim/application_controller.rb +1 -0
  31. data/app/controllers/decidim/cookie_policy_controller.rb +2 -0
  32. data/app/controllers/decidim/editor_images_controller.rb +47 -0
  33. data/app/controllers/decidim/user_activities_controller.rb +2 -1
  34. data/app/forms/decidim/editor_image_form.rb +16 -0
  35. data/app/helpers/decidim/amendments_helper.rb +1 -1
  36. data/app/helpers/decidim/application_helper.rb +2 -2
  37. data/app/helpers/decidim/messaging/conversation_helper.rb +32 -3
  38. data/app/helpers/decidim/resource_versions_helper.rb +1 -1
  39. data/app/helpers/decidim/sanitize_helper.rb +65 -0
  40. data/app/models/decidim/editor_image.rb +14 -0
  41. data/app/models/decidim/messaging/conversation.rb +9 -0
  42. data/app/models/decidim/participatory_space_private_user.rb +16 -0
  43. data/app/models/decidim/user.rb +3 -9
  44. data/app/models/decidim/user_base_entity.rb +24 -13
  45. data/app/models/decidim/user_group.rb +40 -0
  46. data/app/packs/entrypoints/decidim_core.js +1 -0
  47. data/app/packs/src/decidim/dialog_mode.js +143 -0
  48. data/app/packs/src/decidim/dialog_mode.test.js +168 -0
  49. data/app/packs/src/decidim/editor.js +56 -14
  50. data/app/packs/src/decidim/form_attachments.js +5 -0
  51. data/app/packs/src/decidim/geocoding/attach_input.js +11 -2
  52. data/app/packs/src/decidim/index.js +4 -0
  53. data/app/packs/src/decidim/input_emoji.js +10 -1
  54. data/app/packs/src/decidim/vendor/image-resize.min.js +3 -0
  55. data/app/packs/src/decidim/vendor/image-upload.min.js +8 -0
  56. data/app/packs/stylesheets/decidim/extras/_extras.scss +0 -1
  57. data/app/packs/stylesheets/decidim/extras/_quill.scss +7 -0
  58. data/app/packs/stylesheets/decidim/modules/_buttons.scss +11 -4
  59. data/app/packs/stylesheets/decidim/modules/_cards.scss +4 -0
  60. data/app/packs/stylesheets/decidim/modules/_layout.scss +1 -1
  61. data/app/packs/stylesheets/decidim/modules/_timeline.scss +1 -1
  62. data/app/presenters/decidim/nil_presenter.rb +2 -2
  63. data/app/presenters/decidim/notification_presenter.rb +25 -0
  64. data/app/presenters/decidim/official_author_presenter.rb +1 -1
  65. data/app/presenters/decidim/validation_errors_presenter.rb +27 -0
  66. data/app/queries/decidim/similar_emendations.rb +1 -1
  67. data/app/resolvers/decidim/core/metric_resolver.rb +1 -1
  68. data/app/services/decidim/activity_search.rb +2 -2
  69. data/app/services/decidim/email_notification_generator.rb +4 -1
  70. data/app/services/decidim/html_truncation.rb +130 -0
  71. data/app/services/decidim/open_data_exporter.rb +29 -5
  72. data/app/services/decidim/resource_search.rb +1 -1
  73. data/app/uploaders/decidim/editor_image_uploader.rb +6 -0
  74. data/app/validators/password_validator.rb +123 -0
  75. data/app/views/decidim/account/_password_fields.html.erb +1 -1
  76. data/app/views/decidim/devise/passwords/edit.html.erb +1 -1
  77. data/app/views/decidim/devise/registrations/new.html.erb +1 -1
  78. data/app/views/decidim/devise/shared/_omniauth_buttons_mini.html.erb +6 -4
  79. data/app/views/decidim/messaging/conversations/_conversation.html.erb +9 -3
  80. data/app/views/decidim/messaging/conversations/_messages.html.erb +8 -2
  81. data/app/views/decidim/messaging/conversations/_show.html.erb +10 -12
  82. data/app/views/decidim/messaging/conversations/show.html.erb +4 -2
  83. data/app/views/decidim/newsletters/show.html.erb +1 -1
  84. data/app/views/decidim/notification_mailer/event_received.html.erb +17 -0
  85. data/app/views/decidim/pages/_tabbed.html.erb +1 -1
  86. data/app/views/decidim/searches/_filters_small_view.html.erb +3 -3
  87. data/app/views/decidim/shared/_login_modal.html.erb +5 -5
  88. data/app/views/decidim/shared/_orders.html.erb +1 -1
  89. data/app/views/decidim/shared/_results_per_page.html.erb +1 -1
  90. data/app/views/decidim/shared/participatory_space_filters/_filters_small_view.html.erb +3 -3
  91. data/app/views/layouts/decidim/_application.html.erb +1 -12
  92. data/app/views/layouts/decidim/_head.html.erb +4 -0
  93. data/app/views/layouts/decidim/_language_chooser.html.erb +1 -1
  94. data/app/views/layouts/decidim/_meta_tags_config.html.erb +11 -0
  95. data/app/views/layouts/decidim/_wrapper.html.erb +1 -1
  96. data/config/brakeman.ignore +149 -0
  97. data/config/initializers/devise.rb +1 -1
  98. data/config/initializers/rack_attack.rb +23 -21
  99. data/config/locales/ar.yml +8 -0
  100. data/config/locales/ca.yml +43 -0
  101. data/config/locales/cs.yml +61 -0
  102. data/config/locales/en.yml +47 -0
  103. data/config/locales/es-MX.yml +42 -0
  104. data/config/locales/es-PY.yml +42 -0
  105. data/config/locales/es.yml +42 -0
  106. data/config/locales/eu.yml +27 -12
  107. data/config/locales/fi-plain.yml +42 -0
  108. data/config/locales/fi.yml +42 -0
  109. data/config/locales/fr-CA.yml +43 -0
  110. data/config/locales/fr.yml +75 -28
  111. data/config/locales/gl.yml +6 -0
  112. data/config/locales/it.yml +11 -0
  113. data/config/locales/ja.yml +85 -49
  114. data/config/locales/lb-LU.yml +1354 -0
  115. data/config/locales/lb.yml +1 -1
  116. data/config/locales/nl.yml +51 -0
  117. data/config/locales/pl.yml +5 -5
  118. data/config/locales/pt-BR.yml +1 -1
  119. data/config/locales/ro-RO.yml +275 -252
  120. data/config/locales/sv.yml +45 -2
  121. data/config/locales/val-ES.yml +1 -0
  122. data/config/routes.rb +2 -0
  123. data/db/migrate/20210730112319_create_decidim_editor_images.rb +12 -0
  124. data/db/migrate/20211126183540_add_timestamps_to_content_blocks.rb +14 -0
  125. data/db/seeds.rb +16 -14
  126. data/lib/decidim/api/functions/user_entity_finder.rb +2 -1
  127. data/lib/decidim/api/functions/user_entity_list.rb +3 -1
  128. data/lib/decidim/api/input_sorts/component_input_sort.rb +1 -1
  129. data/lib/decidim/common_passwords.rb +56 -0
  130. data/lib/decidim/content_parsers/inline_images_parser.rb +68 -0
  131. data/lib/decidim/content_parsers.rb +1 -0
  132. data/lib/decidim/content_renderers/link_renderer.rb +85 -1
  133. data/lib/decidim/content_renderers/user_group_renderer.rb +1 -1
  134. data/lib/decidim/content_renderers/user_renderer.rb +1 -1
  135. data/lib/decidim/core/engine.rb +7 -12
  136. data/lib/decidim/core/test/factories.rb +7 -1
  137. data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +131 -0
  138. data/lib/decidim/core/test.rb +1 -0
  139. data/lib/decidim/core/version.rb +1 -1
  140. data/lib/decidim/core.rb +33 -5
  141. data/lib/decidim/db/common-passwords.txt +128420 -0
  142. data/lib/decidim/etherpad/pad.rb +48 -0
  143. data/lib/decidim/etherpad.rb +7 -0
  144. data/lib/decidim/events/base_event.rb +18 -0
  145. data/lib/decidim/events/machine_translated_event.rb +36 -0
  146. data/lib/decidim/events/user_group_event.rb +1 -3
  147. data/lib/decidim/events.rb +1 -0
  148. data/lib/decidim/exporters/csv.rb +7 -7
  149. data/lib/decidim/faker/localized.rb +15 -6
  150. data/lib/decidim/form_builder.rb +14 -4
  151. data/lib/decidim/has_attachments.rb +11 -4
  152. data/lib/decidim/has_component.rb +4 -0
  153. data/lib/decidim/importers/import_manifest.rb +103 -3
  154. data/lib/decidim/organization_settings.rb +1 -1
  155. data/lib/decidim/paddable.rb +1 -9
  156. data/lib/decidim/participable.rb +5 -0
  157. data/lib/decidim/resourceable.rb +2 -9
  158. data/lib/decidim/searchable.rb +2 -2
  159. data/lib/decidim/settings_manifest.rb +2 -0
  160. data/lib/decidim/translatable_attributes.rb +6 -6
  161. data/lib/decidim/view_model.rb +10 -0
  162. data/lib/tasks/decidim_active_storage_migration_tasks.rake +68 -0
  163. data/lib/tasks/decidim_webpacker_tasks.rake +4 -10
  164. metadata +70 -78
  165. data/app/packs/stylesheets/decidim/extras/_social_icons_mini.scss +0 -11
@@ -33,7 +33,6 @@ module Decidim
33
33
  open_data_component_manifests.each do |manifest|
34
34
  add_file_to_output(out, format(FILE_NAME_PATTERN, { host: organization.host, entity: manifest.name }), data_for_component(manifest))
35
35
  end
36
-
37
36
  open_data_participatory_space_manifests.each do |manifest|
38
37
  add_file_to_output(out, format(FILE_NAME_PATTERN, { host: organization.host, entity: manifest.name }), data_for_participatory_space(manifest))
39
38
  end
@@ -42,12 +41,37 @@ module Decidim
42
41
  buffer.string
43
42
  end
44
43
 
45
- def data_for_component(export_manifest)
46
- collection = components.where(manifest_name: export_manifest.manifest.name).find_each.flat_map do |component|
47
- export_manifest.collection.call(component)
44
+ def data_for_component(export_manifest, col_sep = Decidim.default_csv_col_sep)
45
+ headers = []
46
+ collection = []
47
+ ActiveRecord::Base.uncached do
48
+ components.where(manifest_name: export_manifest.manifest.name).find_each do |component|
49
+ export_manifest.collection.call(component).find_in_batches(batch_size: 100) do |batch|
50
+ exporter = Decidim::Exporters::CSV.new(batch, export_manifest.serializer)
51
+ headers.push(*exporter.headers)
52
+ exported = exporter.export
53
+
54
+ tmpfile = Tempfile.new("#{export_manifest.name}-#{component.id}-")
55
+ tmpfile.write(exported.read)
56
+ # Do not delete the file when the reference is deleted
57
+ ObjectSpace.undefine_finalizer(tmpfile)
58
+ tmpfile.close
59
+
60
+ collection.push(tmpfile.path)
61
+ end
62
+ end
48
63
  end
49
64
 
50
- Decidim::Exporters::CSV.new(collection, export_manifest.serializer).export
65
+ headers.uniq!
66
+
67
+ data = CSV.generate_line(headers, col_sep: col_sep)
68
+ collection.each do |content|
69
+ CSV.foreach(content, headers: true, col_sep: col_sep) do |row|
70
+ data << CSV.generate_line(row.values_at(*headers), col_sep: col_sep)
71
+ end
72
+ File.unlink(content)
73
+ end
74
+ Decidim::Exporters::ExportData.new(data, "csv")
51
75
  end
52
76
 
53
77
  def data_for_participatory_space(export_manifest)
@@ -75,7 +75,7 @@ module Decidim
75
75
  conditions << "#{query.model_name.plural}.decidim_scope_id IS NULL" if clean_scope_ids.delete("global")
76
76
  conditions.concat(["? = ANY(decidim_scopes.part_of)"] * clean_scope_ids.count) if clean_scope_ids.any?
77
77
 
78
- query.includes(:scope).references(:decidim_scopes).where(conditions.join(" OR "), *clean_scope_ids.map(&:to_i))
78
+ query.includes(:scope).references(:decidim_scopes).where(Arel.sql(conditions.join(" OR ")).to_s, *clean_scope_ids.map(&:to_i))
79
79
  end
80
80
 
81
81
  # Handle the origin filter.
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # This class deals with uploading images to WYSIWYG editor.
5
+ class EditorImageUploader < ImageUploader; end
6
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Class is used to verify that the user's password is strong enough
4
+ class PasswordValidator < ActiveModel::EachValidator
5
+ MINIMUM_LENGTH = 10
6
+ MAX_LENGTH = 256
7
+ MIN_UNIQUE_CHARACTERS = 5
8
+ IGNORE_SIMILARITY_SHORTER_THAN = 4
9
+ VALIDATION_METHODS = [
10
+ :password_too_short?,
11
+ :password_too_long?,
12
+ :not_enough_unique_characters?,
13
+ :name_included_in_password?,
14
+ :nickname_included_in_password?,
15
+ :email_included_in_password?,
16
+ :domain_included_in_password?,
17
+ :password_too_common?,
18
+ :blacklisted?
19
+ ].freeze
20
+
21
+ # Check if user's password is strong enough
22
+ #
23
+ # record - Instance of a form (e.g. Decidim::RegistrationForm) or model
24
+ # attribute - "password"
25
+ # value - Actual password
26
+ # Returns true if password is strong enough
27
+ def validate_each(record, attribute, value)
28
+ return false if value.blank?
29
+
30
+ @record = record
31
+ @attribute = attribute
32
+ @value = value
33
+ @weak_password_reasons = []
34
+
35
+ return true if strong?
36
+
37
+ @weak_password_reasons.each do |reason|
38
+ record.errors[attribute] << get_message(reason)
39
+ end
40
+
41
+ false
42
+ end
43
+
44
+ private
45
+
46
+ attr_reader :record, :attribute, :value
47
+
48
+ def get_message(reason)
49
+ I18n.t "password_validator.#{reason}"
50
+ end
51
+
52
+ def strong?
53
+ VALIDATION_METHODS.each do |method|
54
+ @weak_password_reasons << method.to_s.sub(/\?$/, "").to_sym if send(method.to_s)
55
+ end
56
+
57
+ @weak_password_reasons.empty?
58
+ end
59
+
60
+ def password_too_short?
61
+ value.length < MINIMUM_LENGTH
62
+ end
63
+
64
+ def password_too_long?
65
+ value.length > MAX_LENGTH
66
+ end
67
+
68
+ def not_enough_unique_characters?
69
+ value.chars.uniq.length < MIN_UNIQUE_CHARACTERS
70
+ end
71
+
72
+ def name_included_in_password?
73
+ return false if !record.respond_to?(:name) || record.name.blank?
74
+ return true if value.include?(record.name.delete(" "))
75
+
76
+ record.name.split(" ").each do |part|
77
+ next if part.length < IGNORE_SIMILARITY_SHORTER_THAN
78
+
79
+ return true if value.include?(part)
80
+ end
81
+
82
+ false
83
+ end
84
+
85
+ def nickname_included_in_password?
86
+ return false if !record.respond_to?(:nickname) || record.nickname.blank?
87
+
88
+ value.include?(record.nickname)
89
+ end
90
+
91
+ def email_included_in_password?
92
+ return false if !record.respond_to?(:email) || record.email.blank?
93
+
94
+ name, domain, _whatever = record.email.split("@")
95
+ value.include?(name) || (domain && value.include?(domain.split(".").first))
96
+ end
97
+
98
+ def domain_included_in_password?
99
+ return false unless record&.current_organization&.host
100
+ return true if value.include?(record.current_organization.host)
101
+
102
+ record.current_organization.host.split(".").each do |part|
103
+ next if part.length < IGNORE_SIMILARITY_SHORTER_THAN
104
+
105
+ return true if value.include?(part)
106
+ end
107
+
108
+ false
109
+ end
110
+
111
+ def blacklisted?
112
+ Array(Decidim.password_blacklist).each do |expression|
113
+ return true if expression.is_a?(Regexp) && value.match?(expression)
114
+ return true if expression.to_s == value
115
+ end
116
+
117
+ false
118
+ end
119
+
120
+ def password_too_common?
121
+ Decidim::CommonPasswords.instance.passwords.include?(value)
122
+ end
123
+ end
@@ -1,2 +1,2 @@
1
- <%= form.password_field :password, value: form.object.password, autocomplete: "off", help_text: t("devise.passwords.edit.password_help", minimun_characters: NOBSPW.configuration.min_password_length) %>
1
+ <%= form.password_field :password, value: form.object.password, autocomplete: "off", help_text: t("devise.passwords.edit.password_help", minimun_characters: ::PasswordValidator::MINIMUM_LENGTH) %>
2
2
  <%= form.password_field :password_confirmation, value: form.object.password_confirmation, autocomplete: "off" %>
@@ -16,7 +16,7 @@
16
16
  <%= f.hidden_field :reset_password_token %>
17
17
 
18
18
  <div class="field">
19
- <%= f.password_field :password, autocomplete: "off", help_text: t("devise.passwords.edit.password_help", minimun_characters: NOBSPW.configuration.min_password_length) %>
19
+ <%= f.password_field :password, autocomplete: "off", help_text: t("devise.passwords.edit.password_help", minimun_characters: ::PasswordValidator::MINIMUM_LENGTH) %>
20
20
  </div>
21
21
 
22
22
  <div class="field">
@@ -49,7 +49,7 @@
49
49
  </div>
50
50
 
51
51
  <div class="field">
52
- <%= f.password_field :password, help_text: t(".password_help", minimun_characters: NOBSPW.configuration.min_password_length), autocomplete: "off" %>
52
+ <%= f.password_field :password, help_text: t(".password_help", minimun_characters: ::PasswordValidator::MINIMUM_LENGTH), autocomplete: "off" %>
53
53
  </div>
54
54
 
55
55
  <div class="field">
@@ -1,21 +1,23 @@
1
1
  <% if Devise.mappings[:user].omniauthable? && current_organization.enabled_omniauth_providers.any? %>
2
2
  <div class="row">
3
3
  <div class="columns medium-8 medium-centered">
4
- <span class="register__separator">
5
- <span class="register__separator__text"><%= t("or", scope: "decidim.devise.shared.omniauth_buttons") %></span>
6
- </span>
7
4
  <div class="text-center">
8
5
  <%- current_organization.enabled_omniauth_providers.keys.each do |provider| %>
6
+ <div class="social-register">
9
7
  <%= link_to decidim.send("user_#{provider}_omniauth_authorize_path"), class: "button button--social button--#{normalize_provider_name(provider)} button--social--mini", method: :post do %>
10
8
  <span class="button--social__icon" aria-hidden="true">
11
9
  <%= oauth_icon provider %>
12
10
  </span>
13
- <span class="show-for-sr">
11
+ <span class="button--social__text">
14
12
  <%= t("devise.shared.links.sign_in_with_provider", provider: normalize_provider_name(provider).titleize) %>
15
13
  </span>
16
14
  <% end %>
15
+ </div>
17
16
  <% end %>
18
17
  </div>
18
+ <span class="register__separator">
19
+ <span class="register__separator__text"><%= t("or", scope: "decidim.devise.shared.omniauth_buttons") %></span>
20
+ </span>
19
21
  </div>
20
22
  </div>
21
23
  <% end %>
@@ -14,10 +14,16 @@
14
14
  </li>
15
15
  <li class="card-data__item card--list__item card-data__item--expand absolutes">
16
16
  <div class="mr-s">
17
+ <% if conversation.messages.last.decidim_sender_id == current_user.id %>
18
+ <%= t("to", scope: "decidim.messaging.conversations.index") %>:
19
+ <% else %>
20
+ <%= t("from", scope: "decidim.messaging.conversations.index") %>:
21
+ <% end %>
22
+
17
23
  <% if conversation.interlocutors(current_user).count == 1 %>
18
- <%= t("from", scope: "decidim.messaging.conversations.index") %>: <strong><%= conversation.interlocutors(current_user).first.name %> <span class="muted">@<%= conversation.interlocutors(current_user).first.nickname %></span></strong>
24
+ <%= conversation_name_for(conversation.interlocutors(current_user)) %>
19
25
  <% else %>
20
- <%= t("from", scope: "decidim.messaging.conversations.index") %>: <strong><%= username_list(conversation.interlocutors(current_user), shorten: true) %></strong>
26
+ <strong><%= username_list(conversation.interlocutors(current_user), shorten: true).html_safe %></strong>
21
27
  <% end %>
22
28
  <br>
23
29
  <span class="muted">
@@ -45,7 +51,7 @@
45
51
  <% if conversation.interlocutors(current_user).count == 1 %>
46
52
  <%= icon "chevron-right", class: "card__link icon--big", role: "img", aria_label: t(".show", sender: conversation.interlocutors(current_user).first.name) %>
47
53
  <% else %>
48
- <%= icon "chevron-right", class: "card__link icon--big", role: "img", aria_label: t(".show", sender: username_list(conversation.interlocutors(current_user))) %>
54
+ <%= icon "chevron-right", class: "card__link icon--big", role: "img", aria_label: t(".show", sender: strip_tags(username_list(conversation.interlocutors(current_user)))) %>
49
55
  <% end %>
50
56
  <% end %>
51
57
  </div>
@@ -1,6 +1,12 @@
1
1
  <div class="conversation-chat<%= " conversation-chat--offset" if sender_is_user?(sender) %>">
2
- <%= link_to profile_path(sender.nickname) do %>
3
- <%= image_tag present(sender).avatar_url, alt: t("decidim.author.avatar", name: decidim_sanitize(sender.name)) %>
2
+ <% if sender.deleted? %>
3
+ <span class="label label--small label--basic">
4
+ <%= t("deleted", scope: "decidim.profile") %>
5
+ </span>
6
+ <% else %>
7
+ <%= link_to profile_path(sender.nickname) do %>
8
+ <%= image_tag present(sender).avatar_url, alt: t("decidim.author.avatar", name: decidim_sanitize(sender.name)) %>
9
+ <% end %>
4
10
  <% end %>
5
11
  <div>
6
12
  <% messages.each do |message| %>
@@ -1,12 +1,6 @@
1
- <% if participants.count == 1 %>
2
- <% conversation_label = t(".chat_with") + " #{participants.first.name} (@#{participants.first.nickname})" %>
3
- <% else %>
4
- <% conversation_label = t(".title", usernames: username_list(participants)) %>
5
- <% end %>
6
-
7
1
  <div class="wrapper">
8
2
  <div class="row">
9
- <div class="columns medium-9 medium-centered tabs-panel is-active" id="conversations" role="tabpanel" aria-label="<%= conversation_label %>">
3
+ <div class="columns medium-9 medium-centered tabs-panel is-active" id="conversations" role="tabpanel" aria-label="<%= strip_tags(conversation_label_for(participants)) %>">
10
4
  <div class="conversation">
11
5
 
12
6
  <div class="conversation-header flex--cc absolutes">
@@ -15,20 +9,24 @@
15
9
  <%= icon "chevron-left", role: "img", aria_label: t(".back") %>
16
10
  <% end %>
17
11
  </div>
12
+
18
13
  <% if participants.count == 1 %>
19
- <%= link_to profile_path(participants.first.nickname) do %>
20
- <%= image_tag present(participants.first).avatar_url, alt: t("decidim.author.avatar", name: decidim_sanitize(participants.first.name)) %>
14
+ <% if participants.first.deleted? %>
15
+ <%= image_tag present(participants.first).avatar_url, alt: t("decidim.author.avatar", name: t("decidim.profile.deleted")) %>
16
+ <% else %>
17
+ <%= link_to profile_path(participants.first.nickname) do %>
18
+ <%= image_tag present(participants.first).avatar_url, alt: t("decidim.author.avatar", name: decidim_sanitize(participants.first.name)) %>
19
+ <% end %>
21
20
  <% end %>
22
21
  <% else %>
23
22
  <%= image_tag present(current_user).avatar.default_multiuser_url, alt: t("decidim.author.avatar_multiuser") %>
24
23
  <% end %>
25
-
26
24
  <div class="ml-s">
27
25
  <h1>
28
26
  <% if participants.count == 1 %>
29
- <%= t(".chat_with") %> <strong><%= participants.first.name %></strong><br><span class="muted">@<%= participants.first.nickname %></span>
27
+ <%= t(".chat_with") %> <%= conversation_name_for(participants) %>
30
28
  <% else %>
31
- <%= t(".title", usernames: username_list(participants)) %>
29
+ <%= t(".title", usernames: username_list(participants)).html_safe %>
32
30
  <% end %>
33
31
  </h1>
34
32
  </div>
@@ -5,9 +5,11 @@
5
5
  <% end %>
6
6
  </div>
7
7
 
8
- <% if conversation.accept_user?(current_user) %>
8
+ <% if conversation.with_deleted_users?(current_user) %>
9
+ <div class="callout warning margin-top-2"><%= t ".deleted_accounts" %></div>
10
+ <% elsif conversation.accept_user?(current_user) %>
9
11
  <%= render "reply", form: @form, conversation: conversation %>
10
12
  <% else %>
11
- <em><%= t ".not_allowed" %></em>
13
+ <div class="callout warning margin-top-2"><%= t ".not_allowed" %></div>
12
14
  <% end %>
13
15
  <% end %>
@@ -5,7 +5,7 @@
5
5
  newsletter: newsletter,
6
6
  recipient_user: @user
7
7
  ) %>
8
- <%= decidim_sanitize @cell.to_s %>
8
+ <%= decidim_sanitize_editor @cell.to_s %>
9
9
 
10
10
  <% content_for :note do %>
11
11
  <%== t "note", scope: "decidim.newsletter_mailer.newsletter", organization_name: h(@organization.name), link: decidim.notifications_settings_url(host: @organization.host) %>
@@ -9,6 +9,10 @@
9
9
  <% end %>
10
10
 
11
11
  <% if @event_instance.try(:safe_resource_text).present? %>
12
+ <% if @event_instance.perform_translation? %>
13
+ <p style="font-weight: bold"><%= t(".original_text") %></p>
14
+ <% end %>
15
+
12
16
  <blockquote>
13
17
  <p>
14
18
  <%= @event_instance.safe_resource_text %>
@@ -16,6 +20,19 @@
16
20
  </blockquote>
17
21
  <% end %>
18
22
 
23
+ <% if @event_instance.content_in_same_language? %>
24
+ <p><%= t(".same_language", language: I18n.locale.to_s ) %></p>
25
+ <% elsif @event_instance.translation_missing? %>
26
+ <p><%= t(".no_translation_available", link: @event_instance.resource_url ) %></p>
27
+ <% elsif @event_instance.perform_translation? %>
28
+ <p style="font-weight: bold"><%= t(".translated_text") %></p>
29
+ <blockquote>
30
+ <p>
31
+ <%= @event_instance.safe_resource_translated_text %>
32
+ </p>
33
+ </blockquote>
34
+ <% end %>
35
+
19
36
  <% if @event_instance.has_button? %>
20
37
  <table class="button expanded radius">
21
38
  <tr>
@@ -32,7 +32,7 @@
32
32
  <h2>
33
33
  <%= translated_attribute page.title %>
34
34
  </h2>
35
- <%= decidim_sanitize translated_attribute page.content %>
35
+ <%= decidim_sanitize_editor translated_attribute page.content %>
36
36
  </div>
37
37
  </div>
38
38
  </div>
@@ -1,13 +1,13 @@
1
1
  <div class="filters-controls hide-for-mediumlarge">
2
- <button data-open="filter-box" class="filters-controls__trigger">
2
+ <button data-open="filter-box" class="filters-controls__trigger" aria-controls="filter-box" aria-haspopup="dialog">
3
3
  <%= t ".filter" %>
4
4
  <%= icon "caret-bottom", class: "icon--small float-right", aria_label: t(".unfold"), role: "img" %>
5
5
  </button>
6
6
  </div>
7
7
 
8
- <div class="reveal" id="filter-box" data-reveal>
8
+ <div class="reveal" id="filter-box" data-reveal role="dialog" aria-modal="true" aria-labelledby="filter-box-label">
9
9
  <div class="reveal__header">
10
- <h3 class="reveal__title"><%= t ".filter_by" %>:</h3>
10
+ <h3 id="filter-box-label" class="reveal__title"><%= t ".filter_by" %>:</h3>
11
11
  <button class="close-button" data-close aria-label="<%= t(".close_modal") %>" type="button">
12
12
  <span aria-hidden="true">&times;</span>
13
13
  </button>
@@ -1,12 +1,15 @@
1
- <div class="reveal" id="loginModal" data-reveal>
1
+ <div class="reveal" id="loginModal" data-reveal role="dialog" aria-modal="true" aria-labelledby="loginModal-label">
2
2
  <div class="reveal__header">
3
- <h2 class="reveal__title"><%= t(".please_sign_in") %></h2>
3
+ <h2 id="loginModal-label" class="reveal__title"><%= t(".please_sign_in") %></h2>
4
4
  <button class="close-button" data-close aria-label="<%= t(".close_modal") %>"
5
5
  type="button">
6
6
  <span aria-hidden="true">&times;</span>
7
7
  </button>
8
8
  </div>
9
9
  <% if current_organization.sign_in_enabled? %>
10
+ <% cache current_organization do %>
11
+ <%= render "decidim/devise/shared/omniauth_buttons_mini" %>
12
+ <% end %>
10
13
  <div class="row">
11
14
  <div class="columns medium-8 medium-centered">
12
15
  <%
@@ -39,9 +42,6 @@
39
42
  </p>
40
43
  </div>
41
44
  </div>
42
- <% cache current_organization do %>
43
- <%= render "decidim/devise/shared/omniauth_buttons_mini" %>
44
- <% end %>
45
45
  <% else %>
46
46
  <div class="row">
47
47
  <div class="columns medium-8 medium-centered">
@@ -9,7 +9,7 @@
9
9
  data-close-on-click="true"
10
10
  role="menubar">
11
11
  <li class="is-dropdown-submenu-parent" role="presentation">
12
- <a href="#" id="<%= menu_id %>-control" aria-controls="<%= menu_id %>" aria-haspopup="true" title="<%= t("#{i18n_scope}.label") %>" role="menuitem"><%= t("#{i18n_scope}.#{order}") %></a>
12
+ <a href="#" id="<%= menu_id %>-control" aria-controls="<%= menu_id %>" aria-haspopup="menu" title="<%= t("#{i18n_scope}.label") %>" role="menuitem"><%= t("#{i18n_scope}.#{order}") %></a>
13
13
 
14
14
  <ul id="<%= menu_id %>" class="menu" role="menu" aria-labelledby="<%= menu_id %>-control">
15
15
  <% orders.each do |order_name| %>
@@ -9,7 +9,7 @@
9
9
  data-close-on-click="true"
10
10
  role="menubar">
11
11
  <li class="is-dropdown-submenu-parent" role="presentation">
12
- <a href="#" id="<%= menu_id %>-control" aria-controls="<%= menu_id %>" aria-haspopup="true" title="<%= t("decidim.shared.results_per_page.title") %>" role="menuitem"><%= per_page %></a>
12
+ <a href="#" id="<%= menu_id %>-control" aria-controls="<%= menu_id %>" aria-haspopup="menu" title="<%= t("decidim.shared.results_per_page.title") %>" role="menuitem"><%= per_page %></a>
13
13
  <ul id="<%= menu_id %>" class="menu" role="menu" aria-labelledby="<%= menu_id %>-control">
14
14
  <% Decidim::Paginable::OPTIONS.each do |per_page_option| %>
15
15
  <li role="presentation">
@@ -1,13 +1,13 @@
1
1
  <div class="filters-controls hide-for-mediumlarge">
2
- <button data-open="filter-box" class="filters-controls__trigger">
2
+ <button data-open="filter-box" class="filters-controls__trigger" aria-controls="filter-box" aria-haspopup="dialog">
3
3
  <%= t("filter", scope: "decidim.searches.filters_small_view") %>
4
4
  <%= icon "caret-bottom", class: "icon--small float-right", aria_label: t("unfold", scope: "decidim.searches.filters_small_view"), role: "img" %>
5
5
  </button>
6
6
  </div>
7
7
 
8
- <div class="reveal" id="filter-box" data-reveal>
8
+ <div class="reveal" id="filter-box" data-reveal role="dialog" aria-modal="true" aria-labelledby="filter-box-label">
9
9
  <div class="reveal__header">
10
- <h3 class="reveal__title"><%= t("filter_by", scope: "decidim.searches.filters_small_view") %>:</h3>
10
+ <h3 id="filter-box-label" class="reveal__title"><%= t("filter_by", scope: "decidim.searches.filters_small_view") %>:</h3>
11
11
  <button class="close-button" data-close aria-label="<%= 't("close_modal", scope: "decidim.searches.filters_small_view")' %>" type="button">
12
12
  <span aria-hidden="true">&times;</span>
13
13
  </button>
@@ -1,15 +1,4 @@
1
- <% add_decidim_meta_tags({
2
- description: strip_tags(translated_attribute(current_organization.description)),
3
- title: current_organization.name,
4
- url: request.original_url,
5
- twitter_handler: current_organization.twitter_handler,
6
- image_url: Decidim::ContentBlock.published.find_by(
7
- organization: current_organization,
8
- scope_name: :homepage,
9
- manifest_name: :hero
10
- ).try(:images_container).try(:attached_uploader, :background_image).try(:path)
11
- }) %>
12
-
1
+ <%= render partial: "layouts/decidim/meta_tags_config" %>
13
2
  <!DOCTYPE html>
14
3
  <html lang="<%= I18n.locale %>" class="no-js">
15
4
  <head>
@@ -17,6 +17,10 @@
17
17
  <meta property="og:description" content="<%= decidim_meta_description %>">
18
18
  <meta property="og:image" content="<%= decidim_meta_image_url %>">
19
19
 
20
+ <% if current_organization.colors["theme"] %>
21
+ <meta name="theme-color" content="<%= current_organization.colors["theme"] %>">
22
+ <% end %>
23
+
20
24
  <%= favicon %>
21
25
  <%= stylesheet_pack_tag "decidim_core", media: "all" %>
22
26
  <%= invisible_captcha_styles %>
@@ -7,7 +7,7 @@
7
7
  data-close-on-click="true"
8
8
  role="menubar">
9
9
  <li class="is-dropdown-submenu-parent" role="presentation">
10
- <%= link_to t("name", scope: "locale"), "#language-chooser-menu", id: "language-chooser-control", "aria-label": t("layouts.decidim.language_chooser.choose_language"), "aria-controls": "language-chooser-menu", "aria-haspopup": "true", role: "menuitem" %>
10
+ <%= link_to t("name", scope: "locale"), "#language-chooser-menu", id: "language-chooser-control", "aria-label": t("layouts.decidim.language_chooser.choose_language"), "aria-controls": "language-chooser-menu", "aria-haspopup": "menu", role: "menuitem" %>
11
11
  <ul class="menu is-dropdown-submenu" id="language-chooser-menu" role="menu" aria-labelledby="language-chooser-control">
12
12
  <% (available_locales - [I18n.locale.to_s]).each do |locale| %>
13
13
  <li lang="<%= locale %>" role="presentation"><%= link_to locale_name(locale), decidim.locale_path(locale: locale), method: :post, role: "menuitem" %></li>
@@ -0,0 +1,11 @@
1
+ <% add_decidim_meta_tags({
2
+ description: strip_tags(translated_attribute(current_organization.description)),
3
+ title: current_organization.name,
4
+ url: request.original_url,
5
+ twitter_handler: current_organization.twitter_handler,
6
+ image_url: Decidim::ContentBlock.published.find_by(
7
+ organization: current_organization,
8
+ scope_name: :homepage,
9
+ manifest_name: :hero
10
+ ).try(:images_container).try(:attached_uploader, :background_image).try(:path)
11
+ }) %>
@@ -66,7 +66,7 @@ end
66
66
  data-close-on-click="true"
67
67
  role="menubar">
68
68
  <li class="is-dropdown-submenu-parent show-for-medium" role="presentation">
69
- <%= link_to current_user.name, decidim.account_path, id: "user-menu-control", "aria-controls": "user-menu", "aria-haspopup": "true", "aria-label": t("layouts.decidim.user_menu.account", name: current_user.name), "role": "menuitem" %>
69
+ <%= link_to current_user.name, decidim.account_path, id: "user-menu-control", "aria-controls": "user-menu", "aria-haspopup": "menu", "aria-label": t("layouts.decidim.user_menu.account", name: current_user.name), "role": "menuitem" %>
70
70
  <ul class="menu is-dropdown-submenu" id="user-menu" role="menu" aria-labelledby="user-menu-control">
71
71
  <%= render partial: "layouts/decidim/user_menu" %>
72
72
  </ul>