decidim-core 0.28.1 → 0.28.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/cells/decidim/address/online.erb +2 -2
- data/app/cells/decidim/address_cell.rb +4 -0
- data/app/cells/decidim/announcement/show.erb +2 -2
- data/app/cells/decidim/author/show.erb +5 -5
- data/app/cells/decidim/card/show.erb +1 -1
- data/app/cells/decidim/card_g/show.erb +1 -1
- data/app/cells/decidim/card_g_cell.rb +5 -2
- data/app/cells/decidim/card_l/image.erb +2 -2
- data/app/cells/decidim/card_l_cell.rb +5 -2
- data/app/cells/decidim/card_metadata/show.erb +2 -2
- data/app/cells/decidim/content_blocks/hero_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +1 -1
- data/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb +2 -2
- data/app/cells/decidim/data_consent/category.erb +1 -1
- data/app/cells/decidim/nav_links/show.erb +2 -2
- data/app/cells/decidim/notification/moderated.erb +12 -0
- data/app/cells/decidim/notification_cell.rb +5 -1
- data/app/cells/decidim/profile/details.erb +1 -1
- data/app/cells/decidim/progress_bar/show.erb +1 -1
- data/app/cells/decidim/progress_bar_cell.rb +2 -0
- data/app/cells/decidim/report_button/flag_modal.erb +5 -1
- data/app/cells/decidim/resource_types_filter/show.erb +3 -3
- data/app/cells/decidim/statistic/show.erb +2 -2
- data/app/cells/decidim/upload_modal/modal.erb +3 -4
- data/app/commands/decidim/create_omniauth_registration.rb +10 -4
- data/app/controllers/concerns/decidim/devise_controllers.rb +1 -0
- data/app/controllers/concerns/decidim/force_authentication.rb +1 -1
- data/app/controllers/concerns/decidim/paginable.rb +1 -1
- data/app/controllers/concerns/decidim/use_organization_time_zone.rb +1 -1
- data/app/controllers/decidim/application_controller.rb +1 -0
- data/app/controllers/decidim/gamification/badges_controller.rb +2 -0
- data/app/controllers/decidim/links_controller.rb +15 -2
- data/app/helpers/concerns/decidim/flash_helper_extensions.rb +2 -2
- data/app/helpers/decidim/check_boxes_tree_helper.rb +1 -2
- data/app/helpers/decidim/paginate_helper.rb +3 -5
- data/app/mailers/decidim/application_mailer.rb +40 -6
- data/app/models/decidim/attachment.rb +3 -3
- data/app/models/decidim/component.rb +4 -1
- data/app/models/decidim/content_block.rb +2 -2
- data/app/models/decidim/user.rb +12 -12
- data/app/packs/src/decidim/a11y.js +14 -0
- data/app/packs/src/decidim/abide_form_validator_fixer.js +44 -0
- data/app/packs/src/decidim/direct_uploads/upload_modal.js +2 -6
- data/app/packs/src/decidim/index.js +29 -1
- data/app/packs/src/decidim/input_character_counter.js +1 -1
- data/app/packs/stylesheets/decidim/_accordion.scss +2 -2
- data/app/packs/stylesheets/decidim/_cards.scss +2 -2
- data/app/packs/stylesheets/decidim/_dropdown.scss +9 -9
- data/app/packs/stylesheets/decidim/_forms.scss +4 -4
- data/app/packs/stylesheets/decidim/_layout.scss +3 -3
- data/app/packs/stylesheets/decidim/_modal_update.scss +1 -3
- data/app/packs/stylesheets/decidim/_tooltip.scss +10 -10
- data/app/packs/stylesheets/decidim/editor.scss +1 -1
- data/app/presenters/decidim/admin_log/organization_presenter.rb +1 -1
- data/app/presenters/decidim/log/resource_presenter.rb +7 -1
- data/app/services/decidim/download_your_data_exporter.rb +36 -25
- data/app/services/decidim/log/diff_changeset_calculator.rb +1 -1
- data/app/services/decidim/open_data_exporter.rb +8 -7
- data/app/views/decidim/account/show.html.erb +2 -2
- data/app/views/decidim/application/_document.html.erb +2 -2
- data/app/views/decidim/endorsements/update_buttons_and_counters.js.erb +2 -1
- data/app/views/decidim/gamification/badges/index.html.erb +34 -33
- data/app/views/decidim/links/_modal.html.erb +1 -1
- data/app/views/decidim/links/new.html.erb +3 -1
- data/app/views/decidim/manifests/show.json.erb +5 -5
- data/app/views/decidim/messaging/conversations/create.js.erb +1 -1
- data/app/views/decidim/notifications_settings/show.html.erb +6 -6
- data/app/views/decidim/pages/_tabbed.html.erb +2 -2
- data/app/views/decidim/searches/_filters.html.erb +2 -2
- data/app/views/decidim/shared/_filters.html.erb +2 -2
- data/app/views/decidim/shared/_orders.html.erb +2 -2
- data/app/views/decidim/shared/filters/_collection.html.erb +5 -3
- data/app/views/decidim/shared/filters/_dropdown_label.html.erb +21 -19
- data/app/views/layouts/decidim/_logo.html.erb +1 -1
- data/app/views/layouts/decidim/_wrapper.html.erb +1 -1
- data/app/views/layouts/decidim/footer/_main_intro.html.erb +1 -1
- data/app/views/layouts/decidim/footer/_main_links.html.erb +3 -1
- data/app/views/layouts/decidim/header/_main_links_desktop.html.erb +5 -3
- data/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb +1 -1
- data/app/views/layouts/decidim/header/_menu_breadcrumb_items.html.erb +2 -0
- data/app/views/layouts/decidim/shared/_layout_user_profile.html.erb +2 -2
- data/config/locales/ar.yml +1 -5
- data/config/locales/bg.yml +878 -1
- data/config/locales/ca.yml +5 -3
- data/config/locales/cs.yml +3 -1
- data/config/locales/de.yml +3 -1
- data/config/locales/el.yml +8 -1
- data/config/locales/en.yml +3 -1
- data/config/locales/es-MX.yml +8 -6
- data/config/locales/es-PY.yml +8 -6
- data/config/locales/es.yml +32 -30
- data/config/locales/eu.yml +4 -2
- data/config/locales/fi-plain.yml +6 -4
- data/config/locales/fi.yml +32 -30
- data/config/locales/fr-CA.yml +2 -0
- data/config/locales/fr.yml +2 -0
- data/config/locales/ga-IE.yml +8 -0
- data/config/locales/gl.yml +1 -0
- data/config/locales/hu.yml +1 -2
- data/config/locales/is-IS.yml +3 -0
- data/config/locales/it.yml +7 -1
- data/config/locales/ja.yml +3 -1
- data/config/locales/kaa.yml +5 -0
- data/config/locales/lb.yml +7 -1
- data/config/locales/lt.yml +8 -2
- data/config/locales/lv.yml +8 -1
- data/config/locales/nl.yml +7 -1
- data/config/locales/no.yml +7 -1
- data/config/locales/pl.yml +35 -0
- data/config/locales/pt-BR.yml +0 -1
- data/config/locales/pt.yml +7 -1
- data/config/locales/ro-RO.yml +8 -0
- data/config/locales/ru.yml +8 -0
- data/config/locales/sk.yml +8 -1
- data/config/locales/sl.yml +8 -0
- data/config/locales/sv.yml +132 -88
- data/config/locales/tr-TR.yml +21 -4
- data/config/locales/uk.yml +10 -0
- data/config/locales/zh-CN.yml +0 -1
- data/config/locales/zh-TW.yml +8 -1
- data/db/migrate/20181025082245_add_timestamps_to_components.rb +5 -1
- data/decidim-core.gemspec +0 -1
- data/lib/decidim/asset_router/storage.rb +214 -11
- data/lib/decidim/core/engine.rb +8 -0
- data/lib/decidim/core/seeds.rb +1 -1
- data/lib/decidim/core/test/shared_examples/attachable_interface_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +76 -6
- data/lib/decidim/core/test/shared_examples/follows_examples.rb +8 -3
- data/lib/decidim/core/test/shared_examples/logo_email.rb +2 -2
- data/lib/decidim/core/test/shared_examples/paginated_resource_examples.rb +5 -5
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/core.rb +6 -1
- data/lib/decidim/events/base_event.rb +4 -0
- data/lib/decidim/organization_settings.rb +10 -2
- data/lib/decidim/seven_zip_wrapper.rb +29 -0
- data/lib/tasks/upgrade/decidim_fix_categorization.rake +101 -1
- metadata +13 -25
- data/app/services/decidim/zip_stream/writer.rb +0 -39
data/config/locales/tr-TR.yml
CHANGED
@@ -71,6 +71,7 @@ tr:
|
|
71
71
|
accessibility:
|
72
72
|
external_link: Dış bağlantı
|
73
73
|
logo: "%{organization} resmi logosu"
|
74
|
+
opens_in_new_tab: Yeni Seçmede Aç
|
74
75
|
skip_button: Ana içeriğe geç
|
75
76
|
account:
|
76
77
|
delete:
|
@@ -416,6 +417,7 @@ tr:
|
|
416
417
|
hide_password: Şifrenizi Gizleyin
|
417
418
|
show_password: Şifreyi Göster
|
418
419
|
shown_password: Şifreniz Gösteriliyor
|
420
|
+
placeholder_email: selam@example.org
|
419
421
|
doorkeeper:
|
420
422
|
authorizations:
|
421
423
|
new:
|
@@ -746,6 +748,7 @@ tr:
|
|
746
748
|
admin_in_group: Bunu, %{group} grubunun yöneticisi olduğunuz için alıyorsunuz.
|
747
749
|
greeting: Merhaba, %{recipient}!
|
748
750
|
intro: "%{manager}, %{group} adına yeni bir görüşme başlattı. Görmek için buraya tıklayın:"
|
751
|
+
outro: Platformun tadını çıkarın!
|
749
752
|
subject: "%{manager}, %{group} olarak yeni bir görüşme başlattı"
|
750
753
|
comanagers_new_message:
|
751
754
|
admin_in_group: Bunu, %{group} grubunun yöneticisi olduğunuz için alıyorsunuz.
|
@@ -755,20 +758,24 @@ tr:
|
|
755
758
|
new_conversation:
|
756
759
|
greeting: Merhaba %{recipient}!
|
757
760
|
intro: "%{sender} sizinle yeni bir sohbet başlattı. Görmek için buraya tıklayın:"
|
761
|
+
outro: Platformun tadını çıkarın!
|
758
762
|
subject: "%{sender} sizinle bir konuşma başlattı"
|
759
763
|
new_group_conversation:
|
760
764
|
admin_in_group: Bunu, %{group} grubunun yöneticisi olduğunuz için alıyorsunuz.
|
761
765
|
greeting: Merhaba, %{recipient}!
|
762
766
|
intro: "%{sender}, %{group} adına yeni bir görüşme başlattı. Görmek için buraya tıklayın:"
|
767
|
+
outro: Platformun tadını çıkarın!
|
763
768
|
subject: "%{sender}, %{group} olarak yeni bir görüşme başlattı"
|
764
769
|
new_group_message:
|
765
770
|
admin_in_group: Bunu, %{group} grubunun yöneticisi olduğunuz için alıyorsunuz.
|
766
771
|
greeting: Merhaba, %{recipient}!
|
767
772
|
intro: "%{sender}, %{group} grubuyla bir görüşmede yeni mesajlar yayınladı. Görmek için buraya tıklayın:"
|
773
|
+
outro: Platformun tadını çıkarın!
|
768
774
|
subject: "%{group}, %{sender} adlı kişiden yeni mesajlar aldı"
|
769
775
|
new_message:
|
770
776
|
greeting: Merhaba %{recipient}!
|
771
777
|
intro: "%{sender}, konuşmanıza yeni mesajlar gönderdi. Görmek için buraya tıklayın:"
|
778
|
+
outro: Platformun tadını çıkarın!
|
772
779
|
subject: '%{sender}, size yeni mesaj gönderdi'
|
773
780
|
conversations:
|
774
781
|
add_conversation_users:
|
@@ -844,6 +851,8 @@ tr:
|
|
844
851
|
subject: '%{organization_name} ile ilgili bilgileri almaya devam etmek istiyor musunuz?'
|
845
852
|
notifications:
|
846
853
|
no_notifications: Henüz bildirim yok.
|
854
|
+
show:
|
855
|
+
moderated: İçerik Denetlendi
|
847
856
|
notifications_settings:
|
848
857
|
show:
|
849
858
|
direct_messages: Herkesten doğrudan mesaj alın
|
@@ -1019,6 +1028,7 @@ tr:
|
|
1019
1028
|
filters:
|
1020
1029
|
areas: alanlar
|
1021
1030
|
select_an_area: Bir bölge seçin
|
1031
|
+
progress: "Süreç\nİlerleme"
|
1022
1032
|
reference:
|
1023
1033
|
reference: 'Referans: %{reference}'
|
1024
1034
|
represent_user_group:
|
@@ -1182,13 +1192,13 @@ tr:
|
|
1182
1192
|
sessions:
|
1183
1193
|
already_signed_out: Başarıyla Çıkış Yapıldı
|
1184
1194
|
new:
|
1185
|
-
log_in: Giriş Yapın
|
1195
|
+
log_in: "Giriş \nGiriş Yapın "
|
1186
1196
|
signed_out:
|
1187
1197
|
shared:
|
1188
1198
|
links:
|
1189
1199
|
back: Geri
|
1190
1200
|
forgot_your_password: Parolanızı mı unuttunuz?
|
1191
|
-
log_in: Giriş Yapın
|
1201
|
+
log_in: "Giriş \nGiriş Yapın "
|
1192
1202
|
log_in_with_provider: '%{provider} ile giriş yapın'
|
1193
1203
|
sign_up: kaydol
|
1194
1204
|
minimum_password_length:
|
@@ -1229,6 +1239,8 @@ tr:
|
|
1229
1239
|
timestamp_error_message: Üzgünüm, bu çok hızlıydı! Lütfen yeniden gönderin.
|
1230
1240
|
layouts:
|
1231
1241
|
decidim:
|
1242
|
+
announcements:
|
1243
|
+
view_less: Daha Az Göster
|
1232
1244
|
data_consent:
|
1233
1245
|
details:
|
1234
1246
|
columns:
|
@@ -1239,11 +1251,11 @@ tr:
|
|
1239
1251
|
cc_by_license: Kar Amaçsız Lisanslama (Creative Commons License)
|
1240
1252
|
decidim_logo: Decidim Logo
|
1241
1253
|
download_open_data: Açık Veri dosyalarını indir
|
1242
|
-
log_in: Giriş Yapın
|
1254
|
+
log_in: "Giriş \nGiriş Yapın "
|
1243
1255
|
made_with_open_source: Web sitesi <a target="_blank" href="https://github.com/decidim/decidim">ücretsiz yazılımla yapılmıştır</a>.
|
1244
1256
|
sign_up: Kaydol
|
1245
1257
|
header:
|
1246
|
-
log_in: Giriş Yapın
|
1258
|
+
log_in: "Giriş \nGiriş Yapın "
|
1247
1259
|
impersonation_warning:
|
1248
1260
|
close_session: Oturumu kapat
|
1249
1261
|
description_html: Kullanıcının kimliğine bürünüyorsunuz <b>%{user_name}</b>.
|
@@ -1253,6 +1265,9 @@ tr:
|
|
1253
1265
|
notifications_dashboard:
|
1254
1266
|
mark_all_as_read: Tümünü okundu olarak işaretle
|
1255
1267
|
mark_as_read: Okundu olarak işaretle
|
1268
|
+
shared:
|
1269
|
+
layout_item:
|
1270
|
+
prev: Önceki
|
1256
1271
|
social_media_links:
|
1257
1272
|
facebook: "Facebook'ta %{organization}"
|
1258
1273
|
github: "GitHub'da %{organization}"
|
@@ -1332,6 +1347,7 @@ tr:
|
|
1332
1347
|
long_dashed: "%Y-%m-%d %H:%M:%S"
|
1333
1348
|
short: "%d/%m/%Y %H:%M"
|
1334
1349
|
time_of_day: "%H:%M"
|
1350
|
+
tooltip: "%d-%m-%Y %H:%M %p %Z (GMT %:z)\n%Gün-%Ay-%Yıl %Saat:%Dakika %p %Zone (GMT %:z)"
|
1335
1351
|
versions:
|
1336
1352
|
directions:
|
1337
1353
|
left: Silme
|
@@ -1343,6 +1359,7 @@ tr:
|
|
1343
1359
|
option_split: Yan yana
|
1344
1360
|
option_unescaped: Yakalandı
|
1345
1361
|
option_unified: Birleşik
|
1362
|
+
toggle: Görünümü değiştir
|
1346
1363
|
views:
|
1347
1364
|
pagination:
|
1348
1365
|
next_title: Sonraki sayfaya git
|
data/config/locales/uk.yml
CHANGED
@@ -201,6 +201,7 @@ uk:
|
|
201
201
|
registrations:
|
202
202
|
new:
|
203
203
|
already_have_an_account?: Вже маєте обліковий запис?
|
204
|
+
log_in: Увійти
|
204
205
|
newsletter: Отримувати іноді розсилання зі свіжими новинами
|
205
206
|
newsletter_title: Дозвіл на зв'язок
|
206
207
|
sign_up: Зареєструватися
|
@@ -476,6 +477,12 @@ uk:
|
|
476
477
|
passwords:
|
477
478
|
edit:
|
478
479
|
new_password: Пароль
|
480
|
+
sessions:
|
481
|
+
new:
|
482
|
+
log_in: Увійти
|
483
|
+
shared:
|
484
|
+
links:
|
485
|
+
log_in: Увійти
|
479
486
|
doorkeeper:
|
480
487
|
scopes:
|
481
488
|
public: Оприлюднені відомості про вас.
|
@@ -493,8 +500,11 @@ uk:
|
|
493
500
|
edit_link:
|
494
501
|
edit: Редагувати
|
495
502
|
footer:
|
503
|
+
log_in: Увійти
|
496
504
|
made_with_open_source: Цей веб-сайт створено за допомогою <a target="_blank" href="https://github.com/decidim/decidim">безкоштовного програмного забезпечення</a>.
|
497
505
|
sign_up: Зареєструватися
|
506
|
+
header:
|
507
|
+
log_in: Увійти
|
498
508
|
impersonation_warning:
|
499
509
|
close_session: Завершити сеанс
|
500
510
|
description_html: Ви виступаєте в ролі учасника <b>%{user_name}</b>.
|
data/config/locales/zh-CN.yml
CHANGED
data/config/locales/zh-TW.yml
CHANGED
@@ -315,7 +315,6 @@ zh-TW:
|
|
315
315
|
'1': 創建您的修正案
|
316
316
|
'2': 比較您的修正案
|
317
317
|
'3': 完成您的修正案
|
318
|
-
'4': 發佈您的修正案
|
319
318
|
anonymous_user: 匿名
|
320
319
|
application:
|
321
320
|
document:
|
@@ -514,6 +513,7 @@ zh-TW:
|
|
514
513
|
registrations:
|
515
514
|
new:
|
516
515
|
already_have_an_account?: 已經有帳號了嗎?
|
516
|
+
log_in: 登入
|
517
517
|
newsletter: 偶爾收到包含相關信息的時事通訊。
|
518
518
|
newsletter_title: 聯絡人權限
|
519
519
|
sign_up: 註冊登記
|
@@ -819,6 +819,7 @@ zh-TW:
|
|
819
819
|
filename: 檔案名稱
|
820
820
|
remove: 移除
|
821
821
|
replace: 替換
|
822
|
+
save: 儲存
|
822
823
|
title: 標題
|
823
824
|
title_required: 標題為必填欄位!
|
824
825
|
uploaded: 已上傳
|
@@ -1565,12 +1566,16 @@ zh-TW:
|
|
1565
1566
|
signed_up_but_unconfirmed: 確認信件已送至您的 Email 信箱,請點擊信件內連結以啓動您的帳號。
|
1566
1567
|
update_needs_confirmation: 您已經成功的更新帳號資訊,但我們仍需確認您的電子信箱,請至新信箱收信並點擊連結以確認您的新電子郵件帳號。
|
1567
1568
|
updated: 您的帳號已成功升級。
|
1569
|
+
sessions:
|
1570
|
+
new:
|
1571
|
+
log_in: 登入
|
1568
1572
|
shared:
|
1569
1573
|
links:
|
1570
1574
|
back: 返回
|
1571
1575
|
didn_t_receive_confirmation_instructions: 沒有收到確認的說明嗎?
|
1572
1576
|
didn_t_receive_unlock_instructions: 沒有收到解鎖說明?
|
1573
1577
|
forgot_your_password: 忘記密碼了嗎?
|
1578
|
+
log_in: 登入
|
1574
1579
|
sign_up: 註冊登記
|
1575
1580
|
minimum_password_length:
|
1576
1581
|
other: "One\n(最少%{count} 個字符)\n\nOther\n(最少%{count} 個字符)"
|
@@ -1695,9 +1700,11 @@ zh-TW:
|
|
1695
1700
|
data_consent_settings: Cookie 設定
|
1696
1701
|
decidim_logo: Decidim 商標
|
1697
1702
|
download_open_data: 下載開放數據檔案
|
1703
|
+
log_in: 登入
|
1698
1704
|
made_with_open_source: 使用<a target="_blank" href="https://github.com/decidim/decidim">自由軟體</a>建立的網站。
|
1699
1705
|
sign_up: 註冊
|
1700
1706
|
header:
|
1707
|
+
log_in: 登入
|
1701
1708
|
main_menu: 主選單
|
1702
1709
|
user_menu: 使用者選單
|
1703
1710
|
impersonation_warning:
|
@@ -1,10 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class AddTimestampsToComponents < ActiveRecord::Migration[5.2]
|
4
|
+
class Component < ApplicationRecord
|
5
|
+
self.table_name = :decidim_components
|
6
|
+
end
|
7
|
+
|
4
8
|
def change
|
5
9
|
add_timestamps :decidim_components, null: true
|
6
10
|
# rubocop:disable Rails/SkipsModelValidations
|
7
|
-
|
11
|
+
Component.update_all(created_at: Time.current, updated_at: Time.current)
|
8
12
|
# rubocop:enable Rails/SkipsModelValidations
|
9
13
|
change_column_null :decidim_components, :created_at, false
|
10
14
|
change_column_null :decidim_components, :updated_at, false
|
data/decidim-core.gemspec
CHANGED
@@ -79,7 +79,6 @@ Gem::Specification.new do |s|
|
|
79
79
|
s.add_dependency "request_store", "~> 1.5.0"
|
80
80
|
s.add_dependency "rubyXL", "~> 3.4"
|
81
81
|
s.add_dependency "rubyzip", "~> 2.0"
|
82
|
-
s.add_dependency "seven_zip_ruby", "~> 1.3"
|
83
82
|
s.add_dependency "shakapacker", "~> 7.1.0"
|
84
83
|
s.add_dependency "valid_email2", "~> 4.0"
|
85
84
|
s.add_dependency "web-push", "~> 3.0"
|
@@ -6,6 +6,23 @@ module Decidim
|
|
6
6
|
# saved through ActiveStorage. This handles the different cases for routing
|
7
7
|
# to the remote routes when using an assets CDN or to local routes when
|
8
8
|
# using the local disk storage driver.
|
9
|
+
#
|
10
|
+
# Note that when the assets are stored in a remote storage service, such as
|
11
|
+
# Amazon S3, Google Cloud Storage or Azure Storage, this generates the asset
|
12
|
+
# URL directly to the storage service itself bypassing the Rails server and
|
13
|
+
# saving CPU time from serving the asset redirect requests. This causes a
|
14
|
+
# significant performance improvement on pages that display a lot of images.
|
15
|
+
# It will also produce a less significant performance improvement when using
|
16
|
+
# the local disk storage because in this situation, the images are served
|
17
|
+
# using one request instead of two when served directly from the storage
|
18
|
+
# service rather than through the asset redirect URL.
|
19
|
+
#
|
20
|
+
# When implementing changes to the logic, please keep the remote storage
|
21
|
+
# options and performance implications in mind because the specs for this
|
22
|
+
# utility do not cover the remote storage options because the extra
|
23
|
+
# configuration needed to test, the service itself needed for testing and
|
24
|
+
# the extra dependency overhead for adding these remote storage gems when
|
25
|
+
# they are not needed.
|
9
26
|
class Storage
|
10
27
|
# Initializes the router.
|
11
28
|
#
|
@@ -13,25 +30,36 @@ module Decidim
|
|
13
30
|
# to
|
14
31
|
def initialize(asset)
|
15
32
|
@asset = asset
|
33
|
+
@blob =
|
34
|
+
case asset
|
35
|
+
when ActiveStorage::Blob
|
36
|
+
asset
|
37
|
+
else
|
38
|
+
asset&.blob
|
39
|
+
end
|
16
40
|
end
|
17
41
|
|
18
42
|
# Generates the correct URL to the asset with the provided options.
|
19
43
|
#
|
20
44
|
# @param options The options for the URL that are the normal route options
|
21
45
|
# Rails route helpers accept
|
46
|
+
# @return [String] The URL of the asset
|
22
47
|
def url(**options)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
48
|
+
case asset
|
49
|
+
when ActiveStorage::Attached
|
50
|
+
ensure_current_host(asset.record, **options)
|
51
|
+
blob_url(**options)
|
52
|
+
when ActiveStorage::Blob
|
53
|
+
blob_url(**options)
|
54
|
+
else # ActiveStorage::VariantWithRecord, ActiveStorage::Variant
|
55
|
+
ensure_current_host(nil, **options)
|
28
56
|
representation_url(**options)
|
29
57
|
end
|
30
58
|
end
|
31
59
|
|
32
60
|
private
|
33
61
|
|
34
|
-
attr_reader :asset
|
62
|
+
attr_reader :asset, :blob
|
35
63
|
|
36
64
|
# Provides the route helpers depending on whether the URL is generated to
|
37
65
|
# the local host or an external CDN (remote).
|
@@ -80,24 +108,199 @@ module Decidim
|
|
80
108
|
}.compact
|
81
109
|
end
|
82
110
|
|
83
|
-
#
|
84
|
-
#
|
111
|
+
# Most of the times the current host should be set through the controller
|
112
|
+
# already when the logic below is unnecessary. This logic is needed e.g.
|
113
|
+
# for serializers where the request context is not available.
|
114
|
+
#
|
115
|
+
# @param record The record for which to check the organization
|
116
|
+
# @param opts Options for building the URL
|
117
|
+
# @return [void]
|
118
|
+
def ensure_current_host(record, **opts)
|
119
|
+
return if asset_url_available?
|
120
|
+
|
121
|
+
options = remote? ? remote_storage_options : routes.default_url_options
|
122
|
+
options = options.merge(opts)
|
123
|
+
|
124
|
+
if opts[:host].blank? && record.present?
|
125
|
+
organization = organization_for(record)
|
126
|
+
options[:host] = organization.host if organization
|
127
|
+
end
|
128
|
+
|
129
|
+
uri =
|
130
|
+
if options[:protocol] == "https" || options[:scheme] == "https"
|
131
|
+
URI::HTTPS.build(options)
|
132
|
+
else
|
133
|
+
URI::HTTP.build(options)
|
134
|
+
end
|
135
|
+
|
136
|
+
ActiveStorage::Current.host = uri.to_s
|
137
|
+
end
|
138
|
+
|
139
|
+
# Determines the organization for the passed record.
|
85
140
|
#
|
86
|
-
# @
|
141
|
+
# @param record The record for which to fetch the organization
|
142
|
+
# @return [Decidim::Organization, nil] The organization for the record or
|
143
|
+
# `nil` if the organization cannot be determined
|
144
|
+
def organization_for(record)
|
145
|
+
if record.is_a?(Decidim::Organization)
|
146
|
+
record
|
147
|
+
elsif record.respond_to?(:organization)
|
148
|
+
record.organization
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Returns the URL for the given blob object.
|
153
|
+
#
|
154
|
+
# @param blob The blob object
|
155
|
+
# @param options Options for building the URL
|
156
|
+
# @return [String, nil] The URL to the blob object or `nil` if the blob is
|
157
|
+
# not defined.
|
158
|
+
def blob_url(**options)
|
159
|
+
return unless blob
|
160
|
+
|
161
|
+
if options[:only_path] || remote? || !asset_url_available?
|
162
|
+
routes.rails_blob_url(blob, **default_options.merge(options))
|
163
|
+
else
|
164
|
+
blob.url(**options)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# Returns a representation URL for the asset either directly through the
|
169
|
+
# storage service or through the Rails representation URL in case the
|
170
|
+
# path URL is requested or if the asset variant has not been processed yet
|
171
|
+
# and is not therefore yet stored at the storage service.
|
172
|
+
#
|
173
|
+
# @return [String] The representation URL for the image variant
|
87
174
|
def representation_url(**options)
|
175
|
+
return rails_representation_url(**options) if options[:only_path] || remote?
|
176
|
+
|
177
|
+
representation_url = variant_url(**options)
|
178
|
+
return representation_url if representation_url.present?
|
179
|
+
|
180
|
+
# In case the representation has not been processed yet, it may not have
|
181
|
+
# a representation URL yet and it therefore needs to be served through
|
182
|
+
# the local representation URL for the first time (or until it has been
|
183
|
+
# processed).
|
184
|
+
if options[:host]
|
185
|
+
rails_representation_url(**options)
|
186
|
+
else
|
187
|
+
representation_url(**options.merge(only_path: true))
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Returns the local Rails representation URL meaning that the asset will
|
192
|
+
# be served through the service itself. This may be necessary if the asset
|
193
|
+
# variant (e.g. a thumbnail) has not been processed yet because the
|
194
|
+
# variant representation has not been requested before.
|
195
|
+
#
|
196
|
+
# Due to performance reasons it is advised to avoid requesting the assets
|
197
|
+
# through the Rails representation URLs when possible because that causes
|
198
|
+
# a lot of requests to the Rails backend and slowness to the service under
|
199
|
+
# heavy loads.
|
200
|
+
#
|
201
|
+
# Converts the variation URLs last part to the correct file extension in
|
202
|
+
# case the variation has a different format than the original image. The
|
203
|
+
# conversion needs to be only done for the Rails representation URLs
|
204
|
+
# because once the image is stored at the storage service, it already has
|
205
|
+
# the correct file extension.
|
206
|
+
#
|
207
|
+
# @param options The options for building the URL
|
208
|
+
# @return [String, nil] The converted representation URL or `nil` if the
|
209
|
+
# asset is not defined.
|
210
|
+
def rails_representation_url(**options)
|
211
|
+
return unless asset
|
212
|
+
|
88
213
|
representation_url = routes.rails_representation_url(asset, **default_options.merge(options))
|
214
|
+
|
89
215
|
variation = asset.try(:variation)
|
90
216
|
return representation_url unless variation
|
91
217
|
|
92
218
|
format = variation.try(:format)
|
93
219
|
return representation_url unless format
|
220
|
+
return unless blob
|
94
221
|
|
95
|
-
original_ext = File.extname(
|
222
|
+
original_ext = File.extname(blob.filename.to_s)
|
96
223
|
return representation_url if original_ext == ".#{format}"
|
97
224
|
|
98
|
-
basename = File.basename(
|
225
|
+
basename = File.basename(blob.filename.to_s, original_ext)
|
99
226
|
representation_url.sub(/#{basename}\.#{original_ext.tr(".", "")}$/, "#{basename}.#{format}")
|
100
227
|
end
|
228
|
+
|
229
|
+
# Fetches the image variant's URL at the storage service if the variant
|
230
|
+
# has already been processed and is stored at the storage service. If the
|
231
|
+
# variant has not been processed yet, returns `nil` in which case the
|
232
|
+
# variant has to be served through the service's own representation URL
|
233
|
+
# causing it to be processed and stored at the storage service.
|
234
|
+
#
|
235
|
+
# @param options The options for building the URL
|
236
|
+
# @return [String, nil] The variant URL at the storage service or `nil` if
|
237
|
+
# the variant has not been processed yet and does not yet exist at the
|
238
|
+
# storage service or `nil` when the asset is not defined
|
239
|
+
def variant_url(**options)
|
240
|
+
return unless asset
|
241
|
+
return unless asset_url_available?
|
242
|
+
return unless asset_exist?
|
243
|
+
|
244
|
+
case asset
|
245
|
+
when ActiveStorage::VariantWithRecord
|
246
|
+
# This is used when `ActiveStorage.track_variants` is enabled through
|
247
|
+
# `config.active_storage.track_variants`. In case the variant has not
|
248
|
+
# been processed yet, the `#url` method would return nil.
|
249
|
+
#
|
250
|
+
# Note that if the `asset.processed?` returns `true`, the variant
|
251
|
+
# record has been created in the database but it does not mean that
|
252
|
+
# it has been uploaded to the storage service yet. Likely a bug in
|
253
|
+
# ActiveStorage but to be sure that the asset is uploaded to the
|
254
|
+
# storage service, we also check that.
|
255
|
+
asset.url(**options) if asset.processed?
|
256
|
+
else # ActiveStorage::Variant
|
257
|
+
# Check whether the variant exists at the storage service before
|
258
|
+
# returning its URL. Otherwise the URL would be returned even when the
|
259
|
+
# variant is not yet processed causing 404 errors for the images on
|
260
|
+
# the page.
|
261
|
+
#
|
262
|
+
# Note that the `ActiveStorage::Variant#url` method only accepts
|
263
|
+
# certain keyword arguments where as the other objects allow any
|
264
|
+
# keyword arguments.
|
265
|
+
possible_kwargs = asset.method(:url).parameters.select { |p| p[0] == :key }.map { |p| p[1] }
|
266
|
+
asset.url(**options.slice(*possible_kwargs))
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
# Determines if the asset exists at the storage service.
|
271
|
+
#
|
272
|
+
# @return [Boolean] A boolean answering the question "does this asset
|
273
|
+
# exist at the storage service?".
|
274
|
+
def asset_exist?
|
275
|
+
return false if asset.key.blank?
|
276
|
+
|
277
|
+
blob.service.exist?(asset.key)
|
278
|
+
end
|
279
|
+
|
280
|
+
# Determines if the current host is required to build the asset URL.
|
281
|
+
#
|
282
|
+
# @return [Boolean] A boolean indicating if the current host is required
|
283
|
+
# to build the asset URL.
|
284
|
+
def current_host_required?
|
285
|
+
return false unless blob
|
286
|
+
return false unless defined?(ActiveStorage::Service::DiskService)
|
287
|
+
|
288
|
+
blob.service.is_a?(ActiveStorage::Service::DiskService)
|
289
|
+
end
|
290
|
+
|
291
|
+
# Determines if the asset URL can be generated.
|
292
|
+
#
|
293
|
+
# @return [Boolean] A boolean indicating if the asset URL can be
|
294
|
+
# generated.
|
295
|
+
def asset_url_available?
|
296
|
+
# If the service is an external service, the URL can be generated
|
297
|
+
# regardless of the current host being set.
|
298
|
+
return true unless current_host_required?
|
299
|
+
|
300
|
+
# For the disk service, the URL can be only generated if the current
|
301
|
+
# host has been set.
|
302
|
+
ActiveStorage::Current.host.present?
|
303
|
+
end
|
101
304
|
end
|
102
305
|
end
|
103
306
|
end
|
data/lib/decidim/core/engine.rb
CHANGED
@@ -237,6 +237,14 @@ module Decidim
|
|
237
237
|
app.config.action_mailer.deliver_later_queue_name = :mailers
|
238
238
|
end
|
239
239
|
|
240
|
+
initializer "decidim_core.signed_global_id", after: "global_id" do |app|
|
241
|
+
next if app.config.global_id.fetch(:expires_in, nil).present?
|
242
|
+
|
243
|
+
config.after_initialize do
|
244
|
+
SignedGlobalID.expires_in = nil
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
240
248
|
initializer "decidim_core.middleware" do |app|
|
241
249
|
if app.config.public_file_server.enabled
|
242
250
|
headers = app.config.public_file_server.headers || {}
|
data/lib/decidim/core/seeds.rb
CHANGED
@@ -209,7 +209,7 @@ module Decidim
|
|
209
209
|
|
210
210
|
oauth_application.organization_logo.attach(io: File.open(File.join(seeds_root, "homepage_image.jpg")), filename: "organization_logo.jpg", content_type: "image/jpeg")
|
211
211
|
|
212
|
-
Decidim::
|
212
|
+
Decidim::ContentBlocksCreator.new(organization).create_default!
|
213
213
|
|
214
214
|
hero_content_block = Decidim::ContentBlock.find_by(organization:, manifest_name: :hero, scope_name: :homepage)
|
215
215
|
hero_content_block.images_container.background_image = create_blob!(seeds_file: "homepage_image.jpg", filename: "homepage_image.jpg", content_type: "image/jpeg")
|
@@ -10,7 +10,7 @@ shared_examples_for "attachable interface" do
|
|
10
10
|
|
11
11
|
it "includes the attachment urls" do
|
12
12
|
attachment_urls = response["attachments"].map { |attachment| attachment["url"] }
|
13
|
-
expect(attachment_urls).to
|
13
|
+
expect(attachment_urls).to include_blob_urls(*attachments.map(&:file).map(&:blob))
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|