decidim-core 0.26.2 → 0.26.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of decidim-core might be problematic. Click here for more details.

Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/amendable/announcement_cell.rb +1 -1
  3. data/app/cells/decidim/card_m_cell.rb +1 -1
  4. data/app/cells/decidim/content_blocks/cta/show.erb +1 -1
  5. data/app/cells/decidim/content_blocks/hero/show.erb +1 -1
  6. data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +1 -1
  7. data/app/cells/decidim/content_blocks/stats_cell.rb +1 -0
  8. data/app/controllers/concerns/decidim/resource_versions_concern.rb +4 -0
  9. data/app/controllers/decidim/devise/invitations_controller.rb +9 -2
  10. data/app/controllers/decidim/devise/registrations_controller.rb +5 -1
  11. data/app/events/decidim/resource_endorsed_event.rb +2 -1
  12. data/app/forms/decidim/account_form.rb +8 -7
  13. data/app/forms/decidim/amendable/form.rb +2 -1
  14. data/app/forms/decidim/registration_form.rb +11 -5
  15. data/app/helpers/decidim/filters_helper.rb +5 -1
  16. data/app/mailers/decidim/notification_mailer.rb +1 -0
  17. data/app/models/decidim/action_log.rb +9 -9
  18. data/app/models/decidim/user_base_entity.rb +1 -0
  19. data/app/packs/src/decidim/editor/clipboard_override.js +143 -0
  20. data/app/packs/src/decidim/editor/clipboard_utilities.js +119 -0
  21. data/app/packs/src/decidim/editor/linebreak_module.js +0 -8
  22. data/app/packs/src/decidim/editor.js +9 -2
  23. data/app/packs/src/decidim/map/factory.js +3 -1
  24. data/app/packs/src/decidim/map/legacy.js +2 -2
  25. data/app/packs/src/decidim/map.js +2 -2
  26. data/app/packs/stylesheets/decidim/modules/_cards.scss +2 -0
  27. data/app/packs/stylesheets/decidim/modules/_comments.scss +2 -0
  28. data/app/packs/stylesheets/decidim/modules/_forms.scss +5 -0
  29. data/app/permissions/decidim/permissions.rb +4 -2
  30. data/app/presenters/decidim/home_stats_presenter.rb +11 -4
  31. data/app/presenters/decidim/stats_presenter.rb +7 -8
  32. data/app/presenters/decidim/user_presenter.rb +12 -4
  33. data/app/services/decidim/activity_search.rb +1 -0
  34. data/app/validators/etiquette_validator.rb +7 -3
  35. data/app/views/decidim/data_portability/show.html.erb +1 -1
  36. data/app/views/decidim/notification_mailer/event_received.html.erb +1 -1
  37. data/app/views/decidim/notifications_settings/show.html.erb +49 -51
  38. data/app/views/decidim/user_interests/show.html.erb +11 -13
  39. data/config/locales/ar.yml +0 -24
  40. data/config/locales/bg.yml +1 -23
  41. data/config/locales/ca.yml +5 -25
  42. data/config/locales/cs.yml +13 -33
  43. data/config/locales/de.yml +64 -25
  44. data/config/locales/el.yml +0 -22
  45. data/config/locales/en.yml +2 -22
  46. data/config/locales/es-MX.yml +5 -25
  47. data/config/locales/es-PY.yml +5 -25
  48. data/config/locales/es.yml +10 -30
  49. data/config/locales/eu.yml +5 -26
  50. data/config/locales/fi-plain.yml +2 -22
  51. data/config/locales/fi.yml +2 -22
  52. data/config/locales/fr-CA.yml +4 -24
  53. data/config/locales/fr.yml +11 -31
  54. data/config/locales/ga-IE.yml +1 -5
  55. data/config/locales/gl.yml +0 -24
  56. data/config/locales/gn-PY.yml +1 -0
  57. data/config/locales/hu.yml +173 -23
  58. data/config/locales/id-ID.yml +0 -24
  59. data/config/locales/is-IS.yml +2 -1
  60. data/config/locales/it.yml +3 -25
  61. data/config/locales/ja.yml +4 -24
  62. data/config/locales/lb.yml +1 -23
  63. data/config/locales/lo-LA.yml +1 -0
  64. data/config/locales/lt.yml +1780 -0
  65. data/config/locales/lv.yml +0 -22
  66. data/config/locales/nl.yml +3 -25
  67. data/config/locales/no.yml +1 -23
  68. data/config/locales/oc-FR.yml +1 -0
  69. data/config/locales/pl.yml +50 -23
  70. data/config/locales/pt-BR.yml +3 -25
  71. data/config/locales/pt.yml +2 -24
  72. data/config/locales/ro-RO.yml +1 -23
  73. data/config/locales/ru.yml +0 -5
  74. data/config/locales/sk.yml +1 -26
  75. data/config/locales/sv.yml +2 -23
  76. data/config/locales/tr-TR.yml +2 -24
  77. data/config/locales/uk.yml +1 -2
  78. data/config/locales/zh-CN.yml +2 -24
  79. data/config/routes.rb +20 -2
  80. data/lib/decidim/attributes/localized_date.rb +9 -1
  81. data/lib/decidim/attributes/time_with_zone.rb +13 -1
  82. data/lib/decidim/content_parsers/hashtag_parser.rb +1 -1
  83. data/lib/decidim/core/engine.rb +1 -6
  84. data/lib/decidim/core/test/shared_examples/mcell_examples.rb +17 -0
  85. data/lib/decidim/core/test/shared_examples/resource_endorsed_event_examples.rb +60 -0
  86. data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +40 -0
  87. data/lib/decidim/core/test/shared_examples/with_endorsable_permissions_examples.rb +1 -1
  88. data/lib/decidim/core/test.rb +3 -0
  89. data/lib/decidim/core/version.rb +1 -1
  90. data/lib/decidim/events/simple_event.rb +8 -1
  91. data/lib/decidim/form_builder.rb +8 -1
  92. data/lib/decidim/has_resource_permission.rb +0 -2
  93. data/lib/decidim/map/provider/dynamic_map/here.rb +46 -1
  94. data/lib/decidim/nicknamizable.rb +1 -1
  95. data/lib/decidim/resourceable.rb +5 -4
  96. data/lib/decidim/settings_manifest.rb +1 -1
  97. data/lib/decidim/translatable_attributes.rb +8 -1
  98. metadata +14 -8
  99. data/app/packs/images/decidim/gamification/badges/decidim_gamification_badges_invitations.svg +0 -1
  100. data/app/views/decidim/devise/registrations/edit.html.erb +0 -41
@@ -729,18 +729,6 @@ tr:
729
729
  how: Nasıl kazanabilirsin
730
730
  page_description: Rozetler, katılımcı eylemleri ve platformdaki ilerlemeleri tanımaktadır. Platformda keşfetmeye, katılmaya ve etkileşim kurmaya başladığınızda farklı rozetler kazanacaksınız. İşte rozetlerin listesi ve bunları kazanmanın bazı yolları.
731
731
  title: Rozetler
732
- invitations:
733
- conditions:
734
- - Arkadaşlarınızı davet etmek için kullanıcı sayfanızdaki “arkadaşlarını davet et” bağlantısını kullanın.
735
- - İsterseniz, göndermek istediğiniz mesajı özelleştirin
736
- - Davetiyeler göndererek ve onları kayıt altına alarak seviye atlayacaksınız.
737
- description: Bu rozeti, bazı kişileri davet ettiğinizde ve %{organization_name} kaydolmak ve katılımcı olmak için biraz zaman ayırdıklarında verilir. Yaptığınız için teşekkür ederiz %{organization_name} başkalarına bilinen ve topluluğu genişletmek için yardımcı!
738
- description_another: Bu kullanıcı %{score} kullanıcı davet etti.
739
- description_own: '%{score} kullanıcıyı davet ettiniz.'
740
- name: Davetiyeler
741
- next_level_in: Bir sonraki seviyeye ulaşmak için %{score} kullanıcı daha davet edin!
742
- unearned_another: Bu kullanıcı henüz bir kullanıcıyı davet etmedi.
743
- unearned_own: Henüz hiç kullanıcı davet etmediniz.
744
732
  description: Rozetler, katılımcı eylemleri ve platformdaki ilerlemeleri tanımaktadır. Platformda keşfetmeye, katılmaya ve etkileşim kurmaya başladığınızda farklı rozetler kazanacaksınız.
745
733
  level: Seviye %{level}
746
734
  reached_top: Bu rozetin en üst seviyesine ulaştınız.
@@ -929,7 +917,7 @@ tr:
929
917
  ok: OK
930
918
  index:
931
919
  ago: önce
932
- close: Pencereyi kapat
920
+ close: Yakın kalıcı
933
921
  from: Gönderen
934
922
  groups: Gruplarım
935
923
  last_message: Son mesaj
@@ -947,7 +935,7 @@ tr:
947
935
  title: '%{usernames} ile görüşme'
948
936
  start:
949
937
  send: Gönder
950
- title: Bir görüşme başlat
938
+ title: Bir görüşme başlatın
951
939
  update:
952
940
  error: Bir hata nedeniyle mesaj gönderilemedi
953
941
  metrics:
@@ -1446,15 +1434,6 @@ tr:
1446
1434
  updated_not_active: Şifreniz başarıyla değiştirildi.
1447
1435
  registrations:
1448
1436
  destroyed: Hoşçakal! Hesabınız başarıyla iptal edildi. Kısa süre sonra tekrar görmeyi umuyoruz.
1449
- edit:
1450
- are_you_sure: Emin misiniz?
1451
- cancel_my_account: Hesabımı iptal et
1452
- currently_waiting_confirmation_for_email: 'Şu an için bekleme onayı: %{email}'
1453
- leave_blank_if_you_don_t_want_to_change_it: değiştirmek istemiyorsanız boş bırakın
1454
- title: '%{resource}düzenle'
1455
- unhappy: Mutsuz?
1456
- update: Güncelleştirme
1457
- we_need_your_current_password_to_confirm_your_changes: değişikliklerinizi onaylamak için mevcut şifrenize ihtiyacımız var
1458
1437
  new:
1459
1438
  sign_up: kaydol
1460
1439
  signed_up: Hoşgeldiniz! Başarıyla kaydoldunuz.
@@ -1509,7 +1488,6 @@ tr:
1509
1488
  other: 'İsteğinizi işlerken birden çok hata oluştu:'
1510
1489
  too_many_marks: çok fazla ardışık noktalama işareti kullanıyor (örneğin! ve?)
1511
1490
  too_much_caps: çok fazla büyük harf kullanıyor (metnin% 25'inden fazlası)
1512
- too_short: çok kısa (15 karakterin altında)
1513
1491
  forms:
1514
1492
  correct_errors: Aşağıdaki formda hatalar oluştu, Devam etmek için lütfen bunları düzeltin.
1515
1493
  required: gereklidir
@@ -385,10 +385,9 @@ uk:
385
385
  close: Закрити віконце
386
386
  no_conversations: У вас ще немає бесід
387
387
  reply:
388
- title: Відповісти
388
+ send: Надіслати
389
389
  start:
390
390
  send: Надіслати
391
- title: Почати бесіду
392
391
  newsletter_mailer:
393
392
  newsletter:
394
393
  note: Ви отримали цього електронного листа, оскільки ви підписалися на новини щодо %{organization_name}. Ви можете змінити свої налаштування на <a href="%{link}">сторінці сповіщень</a>.
@@ -656,18 +656,6 @@ zh-CN:
656
656
  how: 你如何赚钱
657
657
  page_description: 徽章是对参与者行动和平台进展的承认。 当您开始发现、参与和互动平台时,您将获得不同的徽章。 这里是徽章列表和您可以赚取它们的某些方式。
658
658
  title: 徽章
659
- invitations:
660
- conditions:
661
- - 使用您用户页面上的“邀请好友”链接来邀请您的朋友
662
- - 自定义,如果您想要,您正在发送的消息
663
- - 您将通过发送邀请和注册来提高等级。
664
- description: 当您已经邀请了一些人并且他们花了一些时间在 %{organization_name} 注册并成为参与者时,这个徽章将被授予。 感谢您向其他人宣传了 %{organization_name} 并帮助扩展社区!
665
- description_another: 此参与者已邀请了 %{score} 人。
666
- description_own: 您已邀请了 %{score} 人。
667
- name: 邀请
668
- next_level_in: 邀请更多 %{score} 人到达下一个关卡!
669
- unearned_another: 此参与者尚未邀请任何人。
670
- unearned_own: 你还没有邀请任何人。
671
659
  description: 徽章是对参与者行动和平台进展的承认。 当您开始发现、参与和互动平台时,您将获得不同的徽章。
672
660
  level: 等级 %{level}
673
661
  reached_top: 你已经达到了这个徽章的顶级了。
@@ -1350,15 +1338,6 @@ zh-CN:
1350
1338
  updated_not_active: 您的密码已成功更改。
1351
1339
  registrations:
1352
1340
  destroyed: 您的帐户已成功取消。我们希望很快再见到您。
1353
- edit:
1354
- are_you_sure: 您确定吗?
1355
- cancel_my_account: 取消我的帐户
1356
- currently_waiting_confirmation_for_email: '正在等待确认: %{email}'
1357
- leave_blank_if_you_don_t_want_to_change_it: 如果您不想更改它,请留空
1358
- title: 编辑 %{resource}
1359
- unhappy: 不愉快?
1360
- update: 更新
1361
- we_need_your_current_password_to_confirm_your_changes: 我们需要您当前的密码来确认您的更改
1362
1341
  new:
1363
1342
  sign_up: 注册
1364
1343
  signed_up: 欢迎!您已成功注册。
@@ -1411,7 +1390,6 @@ zh-CN:
1411
1390
  other: '处理您的请求时发生多个错误:'
1412
1391
  too_many_marks: 正在使用太多连续标点符号(例如! 和 ?)
1413
1392
  too_much_caps: 正在使用太多大写字母(超过25%文本)
1414
- too_short: 太短(低于15个字符)
1415
1393
  forms:
1416
1394
  correct_errors: 表单上有错误,请更正以继续。
1417
1395
  required: 必填字段
@@ -1472,8 +1450,8 @@ zh-CN:
1472
1450
  widget:
1473
1451
  see_more: 查看更多
1474
1452
  locale:
1475
- name: Distr.
1476
- name_with_error: 英文(错误!)
1453
+ name: 中文
1454
+ name_with_error: 中文(错误!)
1477
1455
  password_validator:
1478
1456
  domain_included_in_password: 与这个域名太近了
1479
1457
  email_included_in_password: 与您的电子邮件太相似了
data/config/routes.rb CHANGED
@@ -11,11 +11,29 @@ Decidim::Core::Engine.routes.draw do
11
11
  invitations: "decidim/devise/invitations",
12
12
  sessions: "decidim/devise/sessions",
13
13
  confirmations: "decidim/devise/confirmations",
14
- registrations: "decidim/devise/registrations",
15
14
  passwords: "decidim/devise/passwords",
16
15
  unlocks: "decidim/devise/unlocks",
17
16
  omniauth_callbacks: "decidim/devise/omniauth_registrations"
18
- }
17
+ },
18
+ skip: [:registrations]
19
+
20
+ # Manually define the registration routes because otherwise the default "edit"
21
+ # route would be exposed through Devise while we already have the edit and
22
+ # destroy routes available through the account pages.
23
+ resource(
24
+ :registration,
25
+ only: [:new, :create],
26
+ as: :user_registration,
27
+ path: "/users",
28
+ path_names: { new: "sign_up" },
29
+ controller: "devise/registrations"
30
+ ) do
31
+ # The "cancel" route forces the session data which is usually expired after
32
+ # sign in to be expired now. This is useful if the user wants to cancel
33
+ # OAuth signing in/up in the middle of the process, removing all OAuth
34
+ # session data. @see [Devise::RegistrationsController#cancel]
35
+ get :cancel
36
+ end
19
37
 
20
38
  devise_for :user_groups,
21
39
  class_name: "Decidim::UserGroup",
@@ -10,12 +10,20 @@ module Decidim
10
10
 
11
11
  Date.strptime(value, I18n.t("date.formats.decidim_short"))
12
12
  rescue ArgumentError
13
- nil
13
+ coerce_fallback(value)
14
14
  end
15
15
 
16
16
  def type
17
17
  Axiom::Types::Date
18
18
  end
19
+
20
+ private
21
+
22
+ def coerce_fallback(value)
23
+ coercer.coercers[DateTime].public_send(type.coercion_method, value)
24
+ rescue Date::Error
25
+ nil
26
+ end
19
27
  end
20
28
  end
21
29
  end
@@ -10,12 +10,24 @@ module Decidim
10
10
 
11
11
  Time.zone.strptime(value, I18n.t("time.formats.decidim_short"))
12
12
  rescue ArgumentError
13
- nil
13
+ coerce_fallback(value)
14
14
  end
15
15
 
16
16
  def type
17
17
  Axiom::Types::Time
18
18
  end
19
+
20
+ private
21
+
22
+ def coerce_fallback(value)
23
+ fallback = coercer.coercers[Time].public_send(type.coercion_method, value)
24
+ return Time.zone.strptime(fallback.split(".").first, "%FT%R:%S") if fallback.is_a?(String)
25
+ return nil unless fallback.is_a?(Time)
26
+
27
+ ActiveSupport::TimeWithZone.new(fallback, Time.zone)
28
+ rescue ArgumentError, TypeError
29
+ nil
30
+ end
19
31
  end
20
32
  end
21
33
  end
@@ -18,7 +18,7 @@ module Decidim
18
18
 
19
19
  # Matches a hashtag if it starts with a letter or number
20
20
  # and only contains letters, numbers or underscores.
21
- HASHTAG_REGEX = /\s\K\B#([[:alnum:]](?:[[:alnum:]]|_)*)\b/i.freeze
21
+ HASHTAG_REGEX = /(?:\A|\s\K)\B#([[:alnum:]](?:[[:alnum:]]|_)*)\b/i.freeze
22
22
 
23
23
  # Replaces hashtags name with new or existing hashtags models global ids.
24
24
  #
@@ -254,7 +254,7 @@ module Decidim
254
254
  Cell::ViewModel.view_paths << File.expand_path("#{Decidim::Core::Engine.root}/app/views") # for partials
255
255
  end
256
256
 
257
- initializer "doorkeeper" do
257
+ initializer "doorkeeper", before: "doorkeeper.params.filter" do
258
258
  Doorkeeper.configure do
259
259
  orm :active_record
260
260
 
@@ -531,11 +531,6 @@ module Decidim
531
531
  end
532
532
 
533
533
  initializer "decidim.core.add_badges" do
534
- Decidim::Gamification.register_badge(:invitations) do |badge|
535
- badge.levels = [1, 5, 10, 30, 50]
536
- badge.reset = ->(user) { Decidim::User.where(invited_by: user.id).count }
537
- end
538
-
539
534
  Decidim::Gamification.register_badge(:followers) do |badge|
540
535
  badge.levels = [1, 15, 30, 60, 100]
541
536
  badge.reset = ->(user) { user.followers.count }
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_examples_for "m-cell" do |model_name|
6
+ context "with decorated title" do
7
+ let(:cell_model) { send(model_name) }
8
+
9
+ before do
10
+ cell_model.update!(title: { en: "Model <strong>decorated title</strong>" })
11
+ end
12
+
13
+ it "renders the escaped title correctly" do
14
+ expect(cell_html.to_s).to include("Model &lt;strong&gt;decorated title&lt;/strong&gt;")
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_examples_for "resource endorsed event" do
6
+ include_context "when a simple event"
7
+
8
+ let(:event_name) { "decidim.events.resource_endorsed" }
9
+ let(:author) { create :user, organization: resource.organization }
10
+
11
+ let(:extra) { { endorser_id: author.id } }
12
+ let(:endorsement) { create :endorsement, resource: resource, author: author }
13
+ let(:resource_path) { resource_locator(resource).path }
14
+ let(:follower) { create(:user, organization: resource.organization) }
15
+ let(:follow) { create(:follow, followable: author, user: follower) }
16
+
17
+ it_behaves_like "a simple event"
18
+
19
+ describe "types" do
20
+ subject { described_class }
21
+
22
+ it "supports notifications" do
23
+ expect(subject.types).to include :notification
24
+ end
25
+
26
+ it "supports emails" do
27
+ expect(subject.types).to include :email
28
+ end
29
+ end
30
+
31
+ describe "email_subject" do
32
+ it "is generated correctly" do
33
+ expect(subject.email_subject).to eq("#{author_presenter.nickname} has performed a new endorsement")
34
+ end
35
+ end
36
+
37
+ describe "email_intro" do
38
+ it "is generated correctly" do
39
+ expect(subject.email_intro)
40
+ .to eq("#{author.name} #{author_presenter.nickname}, who you are following," \
41
+ " has just endorsed \"#{translated resource.title}\" and we think it may be interesting to you. Check it out and contribute:")
42
+ end
43
+ end
44
+
45
+ describe "notification_title" do
46
+ it "is generated correctly" do
47
+ expect(subject.notification_title)
48
+ .to include("The <a href=\"#{resource_path}\">#{translated resource.title}</a> #{resource_type} has been endorsed by ")
49
+
50
+ expect(subject.notification_title)
51
+ .to include("<a href=\"/profiles/#{author.nickname}\">#{author.name} #{author_presenter.nickname}</a>.")
52
+ end
53
+ end
54
+
55
+ describe "resource_text" do
56
+ it "shows the resource text" do
57
+ expect(subject.resource_text).to eq resource_text
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_examples "versions controller" do
6
+ let(:base_params) do
7
+ if resource.is_a?(Decidim::Participable)
8
+ { "#{resource.model_name.singular_route_key}_slug".to_sym => resource.slug }
9
+ else
10
+ { "#{resource.model_name.singular_route_key}_id".to_sym => resource.id }
11
+ end
12
+ end
13
+
14
+ before do
15
+ request.env["decidim.current_organization"] = resource.organization
16
+
17
+ if resource.is_a?(Decidim::HasComponent)
18
+ request.env["decidim.current_participatory_space"] = resource.participatory_space
19
+ request.env["decidim.current_component"] = resource.component
20
+ end
21
+ end
22
+
23
+ describe "GET show" do
24
+ context "with an existing version" do
25
+ it "returns a HTTP 200" do
26
+ get :show, params: base_params.merge(id: 1)
27
+
28
+ expect(response).to have_http_status(:ok)
29
+ end
30
+ end
31
+
32
+ context "when the resource does not exist" do
33
+ it "raises a routing error" do
34
+ expect do
35
+ get :show, params: base_params.merge(id: 999_999_999)
36
+ end.to raise_error(ActionController::RoutingError)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -5,7 +5,7 @@ require "spec_helper"
5
5
  # users of this test should delare the `subject` variable.
6
6
  shared_examples "with endorsable permissions can perform actions related to endorsable" do
7
7
  let(:action_subject) { :endorsement }
8
- let(:resource) { create :dummy_resource }
8
+ let(:resource) { create :dummy_resource, component: component }
9
9
  before do
10
10
  context[:current_settings] = double(current_settings)
11
11
  context[:resource] = resource
@@ -71,3 +71,6 @@ require "decidim/core/test/shared_examples/categories_container_examples"
71
71
  require "decidim/core/test/shared_examples/assembly_announcements_examples"
72
72
  require "decidim/core/test/shared_examples/translated_event_examples"
73
73
  require "decidim/core/test/shared_examples/conversations_examples"
74
+ require "decidim/core/test/shared_examples/versions_controller_examples"
75
+ require "decidim/core/test/shared_examples/resource_endorsed_event_examples"
76
+ require "decidim/core/test/shared_examples/mcell_examples"
@@ -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.26.2"
7
+ "0.26.4"
8
8
  end
9
9
  end
10
10
  end
@@ -32,7 +32,14 @@ module Decidim
32
32
  end
33
33
 
34
34
  def email_subject
35
- I18n.t("email_subject", i18n_options).html_safe
35
+ I18n.t("email_subject", email_subject_i18n_options).html_safe
36
+ end
37
+
38
+ def email_subject_i18n_options
39
+ sanitized_values = { resource_title: decidim_sanitize(resource_title) }
40
+ sanitized_values[:mentioned_proposal_title] = decidim_sanitize(mentioned_proposal_title) if i18n_options.has_key?(:mentioned_proposal_title)
41
+ sanitized_values[:participatory_space_title] = decidim_sanitize(participatory_space_title) if i18n_options.has_key?(:participatory_space_title)
42
+ i18n_options.merge(sanitized_values)
36
43
  end
37
44
 
38
45
  def email_intro
@@ -380,7 +380,14 @@ module Decidim
380
380
  def datetime_field(attribute, options = {})
381
381
  value = object.send(attribute)
382
382
  data = { datepicker: "", timepicker: "" }
383
- data[:startdate] = I18n.l(value, format: :decidim_short) if value.present? && value.is_a?(ActiveSupport::TimeWithZone)
383
+ if value.present?
384
+ case value
385
+ when ActiveSupport::TimeWithZone
386
+ data[:startdate] = I18n.l(value, format: :decidim_short)
387
+ when Time, DateTime
388
+ data[:startdate] = I18n.l(value.in_time_zone(Time.zone), format: :decidim_short)
389
+ end
390
+ end
384
391
  datepicker_format = ruby_format_to_datepicker(I18n.t("time.formats.decidim_short"))
385
392
  data[:"date-format"] = datepicker_format
386
393
 
@@ -14,8 +14,6 @@ module Decidim
14
14
 
15
15
  delegate :resource_manifest, :resource_key, to: :class
16
16
 
17
- alias_method :manifest, :resource_manifest
18
-
19
17
  # Public: Whether the permissions for this object actions can be set at resource level.
20
18
  def allow_resource_permissions?
21
19
  false
@@ -33,7 +33,7 @@ module Decidim
33
33
  )
34
34
  end
35
35
 
36
- base_config.merge(api_key: api_key)
36
+ base_config.merge(api_key: api_key, language: language_code)
37
37
  end
38
38
 
39
39
  # A builder for the HERE maps which needs to be configured differently
@@ -44,6 +44,51 @@ module Decidim
44
44
  template.javascript_pack_tag("decidim_map_provider_here", defer: false)
45
45
  end
46
46
  end
47
+
48
+ private
49
+
50
+ def language_code
51
+ primary = I18n.locale.to_s
52
+ secondary = primary.split("-")[0]
53
+ available_language_codes[primary] || available_language_codes[secondary] || ""
54
+ end
55
+
56
+ def available_language_codes
57
+ @available_language_codes ||= {
58
+ "ar" => "ara", # Arabic
59
+ "eu" => "baq", # Basque
60
+ "ca" => "cat", # Catalan
61
+ "zh" => "chi", # Chinese (simplified)
62
+ # "" => "cht", # Chinese (traditional)
63
+ "cs" => "cze", # Czech
64
+ "da" => "dan", # Danish
65
+ "nl" => "dut", # Dutch
66
+ "en" => "eng", # English
67
+ "fi" => "fin", # Finnish
68
+ "fr" => "fre", # French
69
+ "de" => "ger", # German
70
+ "ga" => "gle", # Gaelic
71
+ "el" => "gre", # Greek
72
+ "he" => "heb", # Hebrew
73
+ "hi" => "hin", # Hindi
74
+ "id" => "ind", # Indonesian
75
+ "it" => "ita", # Italian
76
+ "no" => "nor", # Norwegian
77
+ "fa" => "per", # Persian
78
+ "pl" => "pol", # Polish
79
+ "pt" => "por", # Portuguese
80
+ "ru" => "rus", # Russian
81
+ "si" => "sin", # Sinhalese
82
+ "es" => "spa", # Spanish
83
+ "sv" => "swe", # Swedish
84
+ "th" => "tha", # Thai
85
+ "tr" => "tur", # Turkish
86
+ "uk" => "ukr", # Ukrainian
87
+ "ur" => "urd", # Urdu
88
+ "vi" => "vie", # Vietnamese
89
+ "cy" => "wel" # Welsh
90
+ }
91
+ end
47
92
  end
48
93
  end
49
94
  end
@@ -52,7 +52,7 @@ module Decidim
52
52
  candidate = name
53
53
 
54
54
  2.step do |n|
55
- return candidate unless exists?(scope.merge(nickname: candidate))
55
+ return candidate if Decidim::UserBaseEntity.where("nickname ILIKE ?", candidate.downcase).where(scope).empty?
56
56
 
57
57
  candidate = numbered_variation_of(name, n)
58
58
  end
@@ -25,8 +25,8 @@ module Decidim
25
25
  # link_name - The String name of the link between this model and the target resource.
26
26
  #
27
27
  # Returns an ActiveRecord::Relation.
28
- def linked_resources(resource_name, link_name)
29
- scope = sibling_scope(resource_name)
28
+ def linked_resources(resource_name, link_name, component_published: true)
29
+ scope = sibling_scope(resource_name, component_published: component_published)
30
30
 
31
31
  from = scope
32
32
  .joins(:resource_links_from)
@@ -45,14 +45,15 @@ module Decidim
45
45
  # resource_name - The String name of the resource manifest exposed by a component.
46
46
  #
47
47
  # Returns an ActiveRecord::Relation.
48
- def sibling_scope(resource_name)
48
+ def sibling_scope(resource_name, component_published: true)
49
49
  manifest = Decidim.find_resource_manifest(resource_name)
50
50
  return self.class.none unless manifest
51
51
 
52
52
  scope = manifest.resource_scope(component)
53
53
  scope = scope.where("#{self.class.table_name}.id != ?", id) if manifest.model_class == self.class
54
54
  scope = scope.not_hidden if manifest.model_class.respond_to?(:not_hidden)
55
- scope.includes(:component).where.not(decidim_components: { published_at: nil })
55
+ scope = scope.includes(:component).where.not(decidim_components: { published_at: nil }) if component_published
56
+ scope
56
57
  end
57
58
 
58
59
  # Links the given resources to this model, replaces any previous links with the same name.
@@ -97,7 +97,7 @@ module Decidim
97
97
  enum: { klass: String, default: nil },
98
98
  select: { klass: String, default: nil },
99
99
  scope: { klass: Integer, default: nil },
100
- time: { klass: Time, default: nil }
100
+ time: { klass: Decidim::Attributes::TimeWithZone, default: nil }
101
101
  }.freeze
102
102
 
103
103
  attribute :type, Symbol, default: :boolean
@@ -43,7 +43,14 @@ module Decidim
43
43
 
44
44
  define_method attribute_name do
45
45
  field = public_send(name) || {}
46
- value = field[locale.to_s] || field[locale.to_sym]
46
+ value =
47
+ if field.is_a?(Hash)
48
+ field[locale.to_s] || field[locale.to_sym]
49
+ else
50
+ # The value may not be a hash in case the attribute type was
51
+ # changed and the old value is still stored against the record.
52
+ field
53
+ end
47
54
  attribute_set[attribute_name].coerce(value)
48
55
  end
49
56