decidim-core 0.25.2 → 0.26.0.rc1

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 (146) 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/last_activity_cell.rb +1 -1
  12. data/app/cells/decidim/content_blocks/stats_cell.rb +12 -0
  13. data/app/cells/decidim/endorsers_list_cell.rb +3 -1
  14. data/app/cells/decidim/flag_modal/flag_user.erb +2 -2
  15. data/app/cells/decidim/flag_modal/show.erb +2 -2
  16. data/app/cells/decidim/flag_modal_cell.rb +10 -0
  17. data/app/cells/decidim/notification/show.erb +31 -0
  18. data/app/cells/decidim/notification_cell.rb +20 -0
  19. data/app/cells/decidim/notifications/show.erb +1 -24
  20. data/app/cells/decidim/notifications_cell.rb +0 -1
  21. data/app/cells/decidim/user_conversation/conversation_header.erb +1 -1
  22. data/app/cells/decidim/user_conversation/show.erb +4 -2
  23. data/app/cells/decidim/user_conversations/conversation_item.erb +1 -1
  24. data/app/commands/decidim/create_editor_image.rb +41 -0
  25. data/app/controllers/decidim/cookie_policy_controller.rb +2 -0
  26. data/app/controllers/decidim/editor_images_controller.rb +47 -0
  27. data/app/controllers/decidim/user_activities_controller.rb +2 -1
  28. data/app/forms/decidim/editor_image_form.rb +16 -0
  29. data/app/helpers/decidim/amendments_helper.rb +1 -1
  30. data/app/helpers/decidim/application_helper.rb +2 -2
  31. data/app/helpers/decidim/messaging/conversation_helper.rb +32 -3
  32. data/app/helpers/decidim/resource_versions_helper.rb +1 -1
  33. data/app/helpers/decidim/sanitize_helper.rb +65 -0
  34. data/app/models/decidim/editor_image.rb +14 -0
  35. data/app/models/decidim/messaging/conversation.rb +9 -0
  36. data/app/models/decidim/participatory_space_private_user.rb +16 -0
  37. data/app/models/decidim/user.rb +3 -3
  38. data/app/models/decidim/user_group.rb +40 -0
  39. data/app/packs/entrypoints/decidim_core.js +1 -0
  40. data/app/packs/src/decidim/dialog_mode.js +143 -0
  41. data/app/packs/src/decidim/dialog_mode.test.js +168 -0
  42. data/app/packs/src/decidim/editor.js +56 -14
  43. data/app/packs/src/decidim/form_attachments.js +5 -0
  44. data/app/packs/src/decidim/index.js +4 -0
  45. data/app/packs/src/decidim/vendor/image-resize.min.js +3 -0
  46. data/app/packs/src/decidim/vendor/image-upload.min.js +8 -0
  47. data/app/packs/stylesheets/decidim/extras/_extras.scss +0 -1
  48. data/app/packs/stylesheets/decidim/extras/_quill.scss +7 -0
  49. data/app/packs/stylesheets/decidim/modules/_buttons.scss +11 -4
  50. data/app/packs/stylesheets/decidim/modules/_cards.scss +4 -0
  51. data/app/packs/stylesheets/decidim/modules/_layout.scss +1 -1
  52. data/app/presenters/decidim/nil_presenter.rb +2 -2
  53. data/app/presenters/decidim/notification_presenter.rb +25 -0
  54. data/app/presenters/decidim/official_author_presenter.rb +1 -1
  55. data/app/presenters/decidim/validation_errors_presenter.rb +27 -0
  56. data/app/queries/decidim/similar_emendations.rb +1 -1
  57. data/app/resolvers/decidim/core/metric_resolver.rb +1 -1
  58. data/app/services/decidim/activity_search.rb +2 -2
  59. data/app/services/decidim/email_notification_generator.rb +4 -1
  60. data/app/services/decidim/html_truncation.rb +130 -0
  61. data/app/services/decidim/open_data_exporter.rb +29 -5
  62. data/app/services/decidim/resource_search.rb +1 -1
  63. data/app/uploaders/decidim/editor_image_uploader.rb +6 -0
  64. data/app/validators/password_validator.rb +123 -0
  65. data/app/views/decidim/account/_password_fields.html.erb +1 -1
  66. data/app/views/decidim/devise/passwords/edit.html.erb +1 -1
  67. data/app/views/decidim/devise/registrations/new.html.erb +1 -1
  68. data/app/views/decidim/devise/shared/_omniauth_buttons_mini.html.erb +6 -4
  69. data/app/views/decidim/messaging/conversations/_conversation.html.erb +3 -3
  70. data/app/views/decidim/messaging/conversations/_messages.html.erb +8 -2
  71. data/app/views/decidim/messaging/conversations/_show.html.erb +10 -12
  72. data/app/views/decidim/messaging/conversations/show.html.erb +4 -2
  73. data/app/views/decidim/newsletters/show.html.erb +1 -1
  74. data/app/views/decidim/notification_mailer/event_received.html.erb +17 -0
  75. data/app/views/decidim/pages/_tabbed.html.erb +1 -1
  76. data/app/views/decidim/searches/_filters_small_view.html.erb +3 -3
  77. data/app/views/decidim/shared/_login_modal.html.erb +5 -5
  78. data/app/views/decidim/shared/_orders.html.erb +1 -1
  79. data/app/views/decidim/shared/_results_per_page.html.erb +1 -1
  80. data/app/views/decidim/shared/participatory_space_filters/_filters_small_view.html.erb +3 -3
  81. data/app/views/layouts/decidim/_application.html.erb +1 -12
  82. data/app/views/layouts/decidim/_head.html.erb +4 -0
  83. data/app/views/layouts/decidim/_language_chooser.html.erb +1 -1
  84. data/app/views/layouts/decidim/_meta_tags_config.html.erb +11 -0
  85. data/app/views/layouts/decidim/_wrapper.html.erb +1 -1
  86. data/config/brakeman.ignore +149 -0
  87. data/config/initializers/devise.rb +1 -1
  88. data/config/initializers/rack_attack.rb +23 -21
  89. data/config/locales/ca.yml +2 -0
  90. data/config/locales/cs.yml +60 -0
  91. data/config/locales/en.yml +45 -0
  92. data/config/locales/es.yml +45 -0
  93. data/config/locales/eu.yml +5 -0
  94. data/config/locales/fi-plain.yml +6 -0
  95. data/config/locales/fi.yml +45 -0
  96. data/config/locales/fr-CA.yml +38 -0
  97. data/config/locales/fr.yml +44 -6
  98. data/config/locales/gl.yml +5 -0
  99. data/config/locales/it.yml +11 -0
  100. data/config/locales/ja.yml +72 -36
  101. data/config/locales/lb-LU.yml +1354 -0
  102. data/config/locales/lb.yml +1 -1
  103. data/config/locales/nl.yml +54 -0
  104. data/config/locales/pl.yml +5 -5
  105. data/config/locales/pt-BR.yml +1 -1
  106. data/config/locales/ro-RO.yml +8 -0
  107. data/config/locales/sv.yml +5 -0
  108. data/config/locales/val-ES.yml +1 -0
  109. data/config/routes.rb +2 -0
  110. data/db/migrate/20210730112319_create_decidim_editor_images.rb +12 -0
  111. data/db/migrate/20211126183540_add_timestamps_to_content_blocks.rb +14 -0
  112. data/db/seeds.rb +16 -14
  113. data/lib/decidim/api/functions/user_entity_list.rb +1 -0
  114. data/lib/decidim/api/input_sorts/component_input_sort.rb +1 -1
  115. data/lib/decidim/common_passwords.rb +56 -0
  116. data/lib/decidim/content_parsers/inline_images_parser.rb +68 -0
  117. data/lib/decidim/content_parsers.rb +1 -0
  118. data/lib/decidim/content_renderers/link_renderer.rb +85 -1
  119. data/lib/decidim/content_renderers/user_group_renderer.rb +1 -1
  120. data/lib/decidim/content_renderers/user_renderer.rb +1 -1
  121. data/lib/decidim/core/engine.rb +3 -12
  122. data/lib/decidim/core/test/factories.rb +7 -1
  123. data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +131 -0
  124. data/lib/decidim/core/test.rb +1 -0
  125. data/lib/decidim/core/version.rb +1 -1
  126. data/lib/decidim/core.rb +22 -5
  127. data/lib/decidim/db/common-passwords.txt +128420 -0
  128. data/lib/decidim/etherpad/pad.rb +48 -0
  129. data/lib/decidim/etherpad.rb +7 -0
  130. data/lib/decidim/events/base_event.rb +18 -0
  131. data/lib/decidim/events/machine_translated_event.rb +36 -0
  132. data/lib/decidim/events/user_group_event.rb +1 -3
  133. data/lib/decidim/events.rb +1 -0
  134. data/lib/decidim/exporters/csv.rb +7 -7
  135. data/lib/decidim/faker/localized.rb +15 -6
  136. data/lib/decidim/form_builder.rb +14 -4
  137. data/lib/decidim/has_attachments.rb +11 -4
  138. data/lib/decidim/importers/import_manifest.rb +103 -3
  139. data/lib/decidim/paddable.rb +1 -9
  140. data/lib/decidim/searchable.rb +2 -2
  141. data/lib/decidim/settings_manifest.rb +2 -0
  142. data/lib/decidim/translatable_attributes.rb +6 -6
  143. data/lib/decidim/view_model.rb +10 -0
  144. data/lib/tasks/decidim_active_storage_migration_tasks.rake +68 -0
  145. metadata +56 -65
  146. data/app/packs/stylesheets/decidim/extras/_social_icons_mini.scss +0 -11
@@ -1283,7 +1283,7 @@ lb:
1283
1283
  share: Deelen
1284
1284
  share_link: Link deelen
1285
1285
  statistics:
1286
- comments_count: Kommentare
1286
+ comments_count: Kommentarer
1287
1287
  endorsements_count: Ënnerstëtzungen
1288
1288
  followers_count: Follower
1289
1289
  headline: Statistiken
@@ -75,6 +75,33 @@ nl:
75
75
  decidim_with_day_and_month_name: "%A %d %b %Y"
76
76
  decidim_with_month_name: "%d %B %Y"
77
77
  decidim_with_month_name_short: "%d %b"
78
+ datetime:
79
+ distance_in_words:
80
+ about_x_hours:
81
+ one: ongeveer 1 uur
82
+ other: ongeveer %{count} uren
83
+ about_x_months:
84
+ one: ongeveer 1 maand
85
+ other: ongeveer %{count} maanden
86
+ half_a_minute: een halve minuut
87
+ less_than_x_minutes:
88
+ one: minder dan een minuut
89
+ other: minder dan %{count} minuten
90
+ less_than_x_seconds:
91
+ one: nu meteen
92
+ other: minder dan %{count} seconden
93
+ x_days:
94
+ one: 1 dag geleden
95
+ other: "%{count} dagen geleden"
96
+ x_hours:
97
+ one: 1 uur geleden
98
+ other: "%{count} uren geleden"
99
+ x_minutes:
100
+ one: 1 minuut geleden
101
+ other: "%{count} minuten geleden"
102
+ x_seconds:
103
+ one: 1 seconde geleden
104
+ other: "%{count} seconden geleden"
78
105
  decidim:
79
106
  accessibility:
80
107
  external_link: Externe link
@@ -495,6 +522,11 @@ nl:
495
522
  this_application_will_not_be_able_to: 'Deze applicatie krijgt geen toegang tot:'
496
523
  update_profile: update je profiel
497
524
  wants_to_use_your_account_html: "<strong>%{application_name}</strong> wil toegang tot je account"
525
+ editor_images:
526
+ create:
527
+ error: Fout bij het uploaden van een afbeelding
528
+ success: Afbeelding met succes geüploaded
529
+ drag_and_drop_help: Voeg afbeeldingen toe door ze te slepen of te plakken.
498
530
  endorsable:
499
531
  endorsements: Aanbevelingen
500
532
  endorsements_count: Aantal suggesties
@@ -677,6 +709,7 @@ nl:
677
709
  no_followers: Nog geen volgers.
678
710
  following:
679
711
  no_followings: Volgt nog niets of niemand.
712
+ non_public_followings: Sommige van de gevolgde bronnen zijn niet openbaar.
680
713
  follows:
681
714
  create:
682
715
  button: Volgen
@@ -837,6 +870,15 @@ nl:
837
870
  index:
838
871
  last_activity: Laatste Activiteit
839
872
  resource_type: Type
873
+ links:
874
+ invalid_url: Ongeldige URL
875
+ warning:
876
+ body_1: Je staat op het punt om een externe link te bezoeken, wees voorzichtig met de inhoud van de externe site.
877
+ body_2: Controleer de link, zorg ervoor dat je deze herkent als een veilige site voor je verdergaat.
878
+ cancel: Annuleer
879
+ close_modal: Sluit venster
880
+ proceed: Doorgaan
881
+ title: Externe link openen
840
882
  log:
841
883
  base_presenter:
842
884
  create: "%{user_name} gemaakt %{resource_name}"
@@ -939,6 +981,7 @@ nl:
939
981
  show:
940
982
  back: Terug naar alle gesprekken
941
983
  chat_with: Gesprek met
984
+ deleted_accounts: Je kunt geen gesprek voeren met verwijderde accounts.
942
985
  not_allowed: Deze deelnemer aanvaardt geen rechtstreekse berichten.
943
986
  title: Gesprek met %{usernames}
944
987
  start:
@@ -1006,6 +1049,12 @@ nl:
1006
1049
  greetings: Groeten,<br/>%{organization_name}<br/><a href="%{organization_url}">%{organization_url}</a>
1007
1050
  hello: Hallo,
1008
1051
  subject: Wilt u relevante informatie over %{organization_name}blijven ontvangen?
1052
+ notification_mailer:
1053
+ event_received:
1054
+ no_translation_available: Sorry, de geautomatiseerde vertaling kon niet worden opgehaald toen de e-mail is verzonden. Je kan de vertaling van de oorspronkelijke tekst controleren via de volgende link %{link}.
1055
+ original_text: 'Originele tekst:'
1056
+ same_language: De inhoud werd in je voorkeurstaal (%{language}) geplaatst. Dit is de reden waarom er geen automatische vertaling wordt weergegeven in deze e-mail.
1057
+ translated_text: 'Automatisch vertaalde tekst:'
1009
1058
  notifications:
1010
1059
  no_notifications: Nog geen meldingen.
1011
1060
  notifications_settings:
@@ -1289,6 +1338,7 @@ nl:
1289
1338
  title_reply: Beantwoorden
1290
1339
  show:
1291
1340
  back: Toon alle gesprekken
1341
+ deleted_accounts: Je kunt geen gesprek voeren met verwijderde accounts.
1292
1342
  not_allowed: Deze gebruiker accepteert geen directe berichten meer.
1293
1343
  title: Gesprek met %{usernames}
1294
1344
  update:
@@ -1573,10 +1623,12 @@ nl:
1573
1623
  name: Nederlands
1574
1624
  name_with_error: Engels (fout!)
1575
1625
  password_validator:
1626
+ blacklisted: staat op de zwarte lijst
1576
1627
  domain_included_in_password: lijkt te veel op deze domeinnaam
1577
1628
  email_included_in_password: lijkt te veel op uw e-mail
1578
1629
  fallback: is niet geldig
1579
1630
  name_included_in_password: lijkt te veel op uw naam
1631
+ nickname_included_in_password: lijkt te veel op jouw bijnaam
1580
1632
  not_enough_unique_characters: heeft niet genoeg unieke tekens
1581
1633
  password_not_allowed: is niet toegestaan
1582
1634
  password_too_common: te algemeen
@@ -1611,6 +1663,8 @@ nl:
1611
1663
  day_of_week: "%a"
1612
1664
  day_of_week_long: "%a %e"
1613
1665
  day_of_year: "%d.%m.%y"
1666
+ ddmm: "%d.%m"
1667
+ ddmmyyyy: "%d.%m.%Y"
1614
1668
  decidim_day_of_year: "%d %B %Y"
1615
1669
  decidim_short: "%d/%m/%Y %H:%M"
1616
1670
  default: "%a, %d %b %Y %H:%M:%S %z"
@@ -412,7 +412,7 @@ pl:
412
412
  button_url: Adres url przycisku CTA
413
413
  description: Opis
414
414
  footer_sub_hero:
415
- name: Banner podrzędny stopki
415
+ name: Baner podrzędny stopki
416
416
  hero:
417
417
  name: Obraz główny
418
418
  hero_settings_form:
@@ -439,7 +439,7 @@ pl:
439
439
  stats:
440
440
  name: Statystyki organizacji
441
441
  sub_hero:
442
- name: Banner podrzędny
442
+ name: Baner podrzędny
443
443
  core:
444
444
  actions:
445
445
  login_before_access: Zaloguj się na swoje konto, żeby mieć dostęp
@@ -469,7 +469,7 @@ pl:
469
469
  newsletter: Chcę otrzymywać okazjonalne newslettery z istotnymi informacjami
470
470
  newsletter_title: Zgoda na subskrybcję
471
471
  nickname_help: Twój pseudonim w %{organization}. Może zawierać tylko litery, cyfry, '-' i '_'.
472
- password_help: "Minimalna liczba znaków: %{minimun_characters}; nie może być zbyt powszechny (np. 123456) i musi różnić się od Twojego pseudonimu i adresu e-mail."
472
+ password_help: "Minimalna liczba znaków: %{minimun_characters}; nie może być zbyt powszechne (np. 123456) i musi różnić się od Twojego pseudonimu i adresu e-mail."
473
473
  sign_in: Zaloguj się
474
474
  sign_up: Zarejestruj się
475
475
  sign_up_as:
@@ -682,7 +682,7 @@ pl:
682
682
  click_button: 'Kliknij poniższy przycisk, aby pobrać swoje dane. <br/>Plik będzie dostępny do %{date}. <br/>Będziesz potrzebował <a href=''''https://www.7-zip.org/''''>7-Zip</a> (Windows), <a href="https://www.keka.io/en/">Keka</a> (MacOS) lub <a href="https://peazip.github.io">PeaZip</a> (Linux) do otwarcia pliku. Hasło: %{password}'
683
683
  download: Pobieranie
684
684
  export:
685
- ready: Znajdź załączoną wersję eksportowanego pliku.
685
+ ready: Mail zawiera załączony plik eksportu.
686
686
  subject: Twój eksport "%{name}" jest gotowy
687
687
  filters:
688
688
  linked_classes:
@@ -1487,7 +1487,7 @@ pl:
1487
1487
  change_your_password: Zmień swoje hasło
1488
1488
  confirm_new_password: Potwierdź nowe hasło
1489
1489
  new_password: Nowe hasło
1490
- password_help: "Minimalna liczba znaków: %{minimun_characters}; nie może być zbyt powszechny (np. 123456) i musi różnić się od Twojego pseudonimu i adresu e-mail."
1490
+ password_help: "Minimalna liczba znaków: %{minimun_characters}; nie może być zbyt powszechne (np. 123456) i musi różnić się od Twojego pseudonimu i adresu e-mail."
1491
1491
  new:
1492
1492
  forgot_your_password: Zapomniałeś hasła?
1493
1493
  send_me_reset_password_instructions: Wyślij mi instrukcje resetowania hasła
@@ -1,4 +1,4 @@
1
- pt:
1
+ pt-BR:
2
2
  activemodel:
3
3
  attributes:
4
4
  account:
@@ -80,6 +80,9 @@ ro:
80
80
  decidim_with_day_and_month_name: "%A %d %b %Y"
81
81
  decidim_with_month_name: "%d %B %Y"
82
82
  decidim_with_month_name_short: "%d %b"
83
+ datetime:
84
+ distance_in_words:
85
+ half_a_minute: jumătate de minut
83
86
  decidim:
84
87
  accessibility:
85
88
  external_link: Link extern
@@ -518,6 +521,11 @@ ro:
518
521
  this_application_will_not_be_able_to: 'Această aplicație nu va putea să:'
519
522
  update_profile: Actualizeză-ți profilul
520
523
  wants_to_use_your_account_html: "<strong>%{application_name}</strong> vrea să folosească contul tău"
524
+ editor_images:
525
+ create:
526
+ error: Eroare la încărcarea imaginii
527
+ success: Imaginea a fost încărcată cu succes
528
+ drag_and_drop_help: Adaugă imagini prin tragere & plasare sau lipirea lor.
521
529
  endorsable:
522
530
  endorsements: Susținători
523
531
  endorsements_count: Număr de susțineri
@@ -505,6 +505,11 @@ sv:
505
505
  this_application_will_not_be_able_to: 'Det här programmet kommer inte att kunna:'
506
506
  update_profile: Uppdatera din profil
507
507
  wants_to_use_your_account_html: "<strong>%{application_name}</strong> vill använda ditt konto"
508
+ editor_images:
509
+ create:
510
+ error: Fel vid uppladdning av bild
511
+ success: Bilden har laddats upp
512
+ drag_and_drop_help: Lägg till bilder genom att dra och släppa eller klistra in dem.
508
513
  endorsable:
509
514
  endorsements: Instämmanden
510
515
  endorsements_count: Antal Endorsements
@@ -0,0 +1 @@
1
+ val:
data/config/routes.rb CHANGED
@@ -156,6 +156,8 @@ Decidim::Core::Engine.routes.draw do
156
156
  end
157
157
  end
158
158
 
159
+ resources :editor_images, only: [:create]
160
+
159
161
  namespace :gamification do
160
162
  resources :badges, only: [:index]
161
163
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateDecidimEditorImages < ActiveRecord::Migration[6.0]
4
+ def change
5
+ create_table :decidim_editor_images do |t|
6
+ t.references :decidim_author, null: false, foreign_key: { to_table: :decidim_users }, index: { name: "decidim_editor_images_author" }
7
+ t.references :decidim_organization, null: false, foreign_key: true, index: { name: "decidim_editor_images_constraint_organization" }
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddTimestampsToContentBlocks < ActiveRecord::Migration[6.0]
4
+ def up
5
+ add_timestamps :decidim_content_blocks, default: Time.zone.now
6
+ change_column_default :decidim_content_blocks, :created_at, nil
7
+ change_column_default :decidim_content_blocks, :updated_at, nil
8
+ end
9
+
10
+ def down
11
+ remove_column :decidim_content_blocks, :updated_at
12
+ remove_column :decidim_content_blocks, :created_at
13
+ end
14
+ end
data/db/seeds.rb CHANGED
@@ -132,21 +132,23 @@ if !Rails.env.production? || ENV["SEED"]
132
132
  admin_terms_accepted_at: Time.current
133
133
  )
134
134
 
135
- regular_user = Decidim::User.find_or_initialize_by(email: "user@example.org")
135
+ ["user@example.org", "user2@example.org"].each do |email|
136
+ Decidim::User.find_or_initialize_by(email: email).update!(
137
+ name: Faker::Name.name,
138
+ nickname: Faker::Twitter.unique.screen_name,
139
+ password: "decidim123456",
140
+ password_confirmation: "decidim123456",
141
+ confirmed_at: Time.current,
142
+ locale: I18n.default_locale,
143
+ organization: organization,
144
+ tos_agreement: true,
145
+ personal_url: Faker::Internet.url,
146
+ about: Faker::Lorem.paragraph(sentence_count: 2),
147
+ accepted_tos_version: organization.tos_version
148
+ )
149
+ end
136
150
 
137
- regular_user.update!(
138
- name: Faker::Name.name,
139
- nickname: Faker::Twitter.unique.screen_name,
140
- password: "decidim123456",
141
- password_confirmation: "decidim123456",
142
- confirmed_at: Time.current,
143
- locale: I18n.default_locale,
144
- organization: organization,
145
- tos_agreement: true,
146
- personal_url: Faker::Internet.url,
147
- about: Faker::Lorem.paragraph(sentence_count: 2),
148
- accepted_tos_version: organization.tos_version
149
- )
151
+ regular_user = Decidim::User.find_or_initialize_by(email: "user@example.org")
150
152
 
151
153
  locked_user = Decidim::User.find_or_initialize_by(email: "locked_user@example.org")
152
154
 
@@ -20,6 +20,7 @@ module Decidim
20
20
  @query = Decidim::UserBaseEntity
21
21
  .where(organization: ctx[:current_organization])
22
22
  .where.not(confirmed_at: nil)
23
+ .includes(avatar_attachment: :blob)
23
24
  add_filter_keys(args[:filter])
24
25
  add_order_keys(args[:order].to_h)
25
26
  @query
@@ -23,7 +23,7 @@ module Decidim
23
23
  prepare: lambda { |direction, ctx|
24
24
  lambda { |locale|
25
25
  locale = ctx[:current_organization].default_locale if locale.blank?
26
- [Arel.sql("name->? #{direction.upcase}"), locale]
26
+ [Arel.sql("name->? #{direction.upcase}").to_s, locale]
27
27
  }
28
28
  }
29
29
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ class CommonPasswords
5
+ include Singleton
6
+
7
+ attr_reader :passwords
8
+
9
+ URLS = %w(
10
+ https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/xato-net-10-million-passwords-1000000.txt
11
+ https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/darkweb2017-top10000.txt
12
+ https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/Common-Credentials/10-million-password-list-top-1000000.txt
13
+ ).freeze
14
+
15
+ def initialize
16
+ raise FileNotFoundError unless File.exist?(self.class.common_passwords_path)
17
+
18
+ File.open(self.class.common_passwords_path, "r") do |file|
19
+ @passwords = file.read.split
20
+ end
21
+ end
22
+
23
+ def self.update_passwords!
24
+ File.open(common_passwords_path, "w") do |file|
25
+ common_password_list.each { |item| file.puts(item) }
26
+ end
27
+ end
28
+
29
+ def self.common_password_list
30
+ @common_password_list ||= begin
31
+ list = []
32
+ URLS.each do |url|
33
+ URI.open(url) do |data|
34
+ data.read.split.each do |line|
35
+ list << line if line.length >= min_length
36
+ end
37
+ end
38
+ end
39
+
40
+ list.uniq
41
+ end
42
+ end
43
+
44
+ def self.min_length
45
+ return ::PasswordValidator::MINIMUM_LENGTH if defined?(::PasswordValidator)
46
+
47
+ 10
48
+ end
49
+
50
+ def self.common_passwords_path
51
+ File.join(__dir__, "db", "common-passwords.txt")
52
+ end
53
+
54
+ class FileNotFoundError < StandardError; end
55
+ end
56
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ContentParsers
5
+ # A parser that searches for inline images in an html content and
6
+ # replaces them with EditorImage attachments. Note that rewrite method may
7
+ # create EditorImage instances
8
+ #
9
+ # @see BaseParser Examples of how to use a content parser
10
+ class InlineImagesParser < BaseParser
11
+ # @return [String] the content with the inline images replaced.
12
+ def rewrite
13
+ return content unless inline_images?
14
+
15
+ replace_inline_images
16
+ parsed_content.to_html
17
+ end
18
+
19
+ def inline_images?
20
+ parsed_content.search(:img).find do |image|
21
+ image.attr(:src).start_with?(%r{data:image/[a-z]{3,4};base64,})
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def parsed_content
28
+ @parsed_content ||= Nokogiri::HTML(content)
29
+ end
30
+
31
+ def replace_inline_images
32
+ parsed_content.search(:img).each do |image|
33
+ next unless image.attr(:src).start_with?(%r{data:image/[a-z]{3,4};base64,})
34
+
35
+ file = base64_tempfile(image.attr(:src))
36
+ editor_image = EditorImage.create!(
37
+ decidim_author_id: context[:user]&.id,
38
+ organization: context[:user].organization,
39
+ file: file
40
+ )
41
+
42
+ image.set_attribute(:src, editor_image.attached_uploader(:file).path)
43
+ end
44
+ end
45
+
46
+ def base64_tempfile(base64_data, filename = nil)
47
+ return base64_data unless base64_data.is_a? String
48
+
49
+ start_regex = %r{data:image/[a-z]{3,4};base64,}
50
+ filename ||= SecureRandom.hex
51
+
52
+ regex_result = start_regex.match(base64_data)
53
+
54
+ return unless base64_data && regex_result
55
+
56
+ start = regex_result.to_s
57
+ tempfile = Tempfile.new(filename)
58
+ tempfile.binmode
59
+ tempfile.write(Base64.decode64(base64_data[start.length..-1]))
60
+ ActionDispatch::Http::UploadedFile.new(
61
+ tempfile: tempfile,
62
+ filename: filename,
63
+ original_filename: filename
64
+ )
65
+ end
66
+ end
67
+ end
68
+ end
@@ -8,5 +8,6 @@ module Decidim
8
8
  autoload :HashtagParser, "decidim/content_parsers/hashtag_parser"
9
9
  autoload :NewlineParser, "decidim/content_parsers/newline_parser"
10
10
  autoload :LinkParser, "decidim/content_parsers/link_parser"
11
+ autoload :InlineImagesParser, "decidim/content_parsers/inline_images_parser"
11
12
  end
12
13
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Decidim
4
4
  module ContentRenderers
5
+ # Original: https://github.com/neighborland/anchored/
5
6
  # A renderer that converts URLs to links and strips attributes in anchors.
6
7
  #
7
8
  # Examples:
@@ -20,7 +21,90 @@ module Decidim
20
21
  return content unless content.is_a?(String)
21
22
 
22
23
  options = { target: "_blank", rel: "nofollow noopener" }.merge(options)
23
- Anchored::Linker.auto_link(content, options)
24
+ auto_link(content, options)
25
+ end
26
+
27
+ def auto_link(text, options = {}, &block)
28
+ return "" if text.to_s.empty?
29
+
30
+ auto_link_urls(text, options, &block)
31
+ end
32
+
33
+ # remove_target_if_local("http://same.com/x", "same.com", target: "_blank")
34
+ # => <a href="http://same.com/x">http://same.com/x</a>
35
+ #
36
+ # remove_target_if_local("http://same.com/x", "different.com", target: "_blank")
37
+ # => <a href="http://same.com/x" target="_blank">http://same.com/x</a>
38
+ #
39
+ # modifies options in place
40
+ def remove_target_if_local(href, domain, options)
41
+ return unless options[:target]
42
+
43
+ options.delete(:target) if href.include?("//#{domain}")
44
+ end
45
+
46
+ private
47
+
48
+ AUTO_LINK_RE = %r{(?: ((?:ftp|http|https):)// | www\. )[^\s<\u00A0"]+}ix.freeze
49
+
50
+ # # regexps for determining context, used high-volume
51
+ AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, %r{</a>}i].freeze
52
+
53
+ PUNCTUATION_RE = %r{[^\p{Word}/=&]$}.freeze
54
+
55
+ BRACKETS = { "]" => "[", ")" => "(", "}" => "{" }.freeze
56
+
57
+ # Turns all urls into clickable links. If a block is given, each url
58
+ # is yielded and the result is used as the link text.
59
+ def auto_link_urls(text, options = {})
60
+ # to_str is for SafeBuffer objects (text marked html_safe)
61
+ text.to_str.gsub(AUTO_LINK_RE) do
62
+ match = Regexp.last_match
63
+ href = match[0]
64
+ scheme = match[1]
65
+ punctuation = []
66
+
67
+ if auto_linked?(match)
68
+ # do not change string; URL is already linked
69
+ href
70
+ else
71
+ # don't include trailing punctuation character as part of the URL
72
+ while href.sub!(PUNCTUATION_RE, "")
73
+ punctuation.push Regexp.last_match(0)
74
+ if (opening = BRACKETS[punctuation.last]) && href.scan(opening).size > href.scan(punctuation.last).size
75
+ href << punctuation.pop
76
+ break
77
+ end
78
+ end
79
+
80
+ link_text = block_given? ? yield(href) : href
81
+ href = "http://#{href}" unless scheme
82
+
83
+ # content_tag(:a, link_text, html.merge(href: href)) + punctuation.reverse.join('')
84
+ anchor_tag(href, link_text, options) + punctuation.reverse.join
85
+ end
86
+ end
87
+ end
88
+
89
+ # Detects already linked context or position in the middle of a tag
90
+ # Note: this changes the current Regexp
91
+ def auto_linked?(match)
92
+ left = match.pre_match
93
+ right = match.post_match
94
+ (left =~ AUTO_LINK_CRE[0] && right =~ AUTO_LINK_CRE[1]) ||
95
+ (left.rindex(AUTO_LINK_CRE[2]) && Regexp.last_match.post_match !~ AUTO_LINK_CRE[3])
96
+ end
97
+
98
+ def anchor_attrs(options)
99
+ options.map { |k, v| %(#{k}="#{v}") }.unshift("").join(" ")
100
+ end
101
+
102
+ def anchor_tag(href, text, options)
103
+ options = options.dup
104
+ if (domain = options.delete(:domain))
105
+ remove_target_if_local href, domain, options
106
+ end
107
+ %(<a href="#{href}"#{anchor_attrs(options)}>#{text}</a>)
24
108
  end
25
109
  end
26
110
  end
@@ -10,7 +10,7 @@ module Decidim
10
10
  # @see BaseRenderer Examples of how to use a content renderer
11
11
  class UserGroupRenderer < BaseRenderer
12
12
  # Matches a global id representing a Decidim::UserGroup
13
- GLOBAL_ID_REGEX = %r{gid://\S+/Decidim::UserGroup/\d+}.freeze
13
+ GLOBAL_ID_REGEX = %r{gid://[\w-]+/Decidim::UserGroup/\d+}.freeze
14
14
 
15
15
  # Replaces found Global IDs matching an existing user with
16
16
  # a link to their profile. The Global IDs representing an
@@ -10,7 +10,7 @@ module Decidim
10
10
  # @see BaseRenderer Examples of how to use a content renderer
11
11
  class UserRenderer < BaseRenderer
12
12
  # Matches a global id representing a Decidim::User
13
- GLOBAL_ID_REGEX = %r{gid://\S+/Decidim::User/\d+}.freeze
13
+ GLOBAL_ID_REGEX = %r{gid://[\w-]+/Decidim::User/\d+}.freeze
14
14
 
15
15
  # Replaces found Global IDs matching an existing user with
16
16
  # a link to their profile. The Global IDs representing an
@@ -17,7 +17,6 @@ require "rectify"
17
17
  require "carrierwave"
18
18
  require "rails-i18n"
19
19
  require "date_validator"
20
- require "truncato"
21
20
  require "file_validators"
22
21
  require "omniauth"
23
22
  require "omniauth-facebook"
@@ -34,11 +33,9 @@ require "cell/partial"
34
33
  require "kaminari"
35
34
  require "doorkeeper"
36
35
  require "doorkeeper-i18n"
37
- require "nobspw"
38
36
  require "batch-loader"
39
- require "etherpad-lite"
37
+ require "mime-types"
40
38
  require "diffy"
41
- require "anchored"
42
39
  require "social-share-button"
43
40
  require "ransack"
44
41
  require "searchlight"
@@ -85,8 +82,6 @@ module Decidim
85
82
  end
86
83
 
87
84
  initializer "decidim.graphql_api" do
88
- # Enable them method `!` everywhere for compatibility, this line will be removed when upgrading to GraphQL 2.0
89
- GraphQL::DeprecatedDSL.activate
90
85
  Decidim::Api::QueryType.include Decidim::QueryExtensions
91
86
 
92
87
  Decidim::Api.add_orphan_type Decidim::Core::UserType
@@ -304,7 +299,7 @@ module Decidim
304
299
 
305
300
  initializer "SSL and HSTS" do
306
301
  Rails.application.configure do
307
- config.force_ssl = Rails.env.production? && Decidim.config.force_ssl
302
+ config.force_ssl = Decidim.config.force_ssl
308
303
  end
309
304
  end
310
305
 
@@ -315,7 +310,7 @@ module Decidim
315
310
  end
316
311
 
317
312
  initializer "Expire sessions" do
318
- Rails.application.config.session_store :cookie_store, expire_after: Decidim.config.expire_session_after
313
+ Rails.application.config.session_store :cookie_store, secure: Decidim.config.force_ssl, expire_after: Decidim.config.expire_session_after
319
314
  end
320
315
 
321
316
  initializer "decidim.core.register_resources" do
@@ -542,10 +537,6 @@ module Decidim
542
537
  end
543
538
  end
544
539
 
545
- initializer "nbspw" do
546
- NOBSPW.configuration.use_ruby_grep = true
547
- end
548
-
549
540
  initializer "decidim.premailer" do
550
541
  Premailer::Adapter.use = :decidim
551
542
  end
@@ -248,7 +248,7 @@ FactoryBot.define do
248
248
  end
249
249
 
250
250
  factory :user_group_membership, class: "Decidim::UserGroupMembership" do
251
- user
251
+ user { create(:user, :confirmed, organization: user_group.organization) }
252
252
  role { :creator }
253
253
  user_group
254
254
  end
@@ -749,4 +749,10 @@ FactoryBot.define do
749
749
  last_used_at { 1.hour.ago }
750
750
  end
751
751
  end
752
+
753
+ factory :editor_image, class: "Decidim::EditorImage" do
754
+ organization
755
+ author { create(:user, :admin, :confirmed, organization: organization) }
756
+ file { Decidim::Dev.test_file("city.jpeg", "image/jpeg") }
757
+ end
752
758
  end