decidim-core 0.29.1 → 0.29.3
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.
- checksums.yaml +4 -4
- data/app/cells/decidim/activity_cell.rb +0 -3
- data/app/cells/decidim/author/show.erb +5 -4
- data/app/cells/decidim/author_cell.rb +26 -0
- data/app/cells/decidim/card_s/show.erb +5 -3
- data/app/cells/decidim/diff_cell.rb +4 -0
- data/app/cells/decidim/newsletter_templates/image_text_cta_cell.rb +1 -1
- data/app/cells/decidim/participatory_space_dropdown_metadata/show.erb +5 -3
- data/app/cells/decidim/profile_actions/show.erb +1 -1
- data/app/cells/decidim/report_button/already_reported_modal.erb +2 -2
- data/app/cells/decidim/report_button/flag_modal.erb +13 -27
- data/app/cells/decidim/report_button_cell.rb +2 -8
- data/app/cells/decidim/report_user_button/already_reported_modal.erb +11 -0
- data/app/cells/decidim/report_user_button/flag_modal.erb +46 -0
- data/app/cells/decidim/report_user_button/show.erb +2 -0
- data/app/cells/decidim/report_user_button_cell.rb +59 -0
- data/app/cells/decidim/resource_types_filter/show.erb +1 -1
- data/app/cells/decidim/resource_types_filter_cell.rb +6 -6
- data/app/cells/decidim/translation_bar/show.erb +2 -2
- data/app/cells/decidim/translation_bar_cell.rb +1 -1
- data/app/cells/decidim/user_activity/show.erb +1 -1
- data/app/commands/decidim/create_omniauth_registration.rb +14 -8
- data/app/commands/decidim/create_report.rb +1 -6
- data/app/commands/decidim/destroy_account.rb +3 -0
- data/app/commands/decidim/search.rb +14 -0
- data/app/controllers/decidim/doorkeeper/credentials_controller.rb +1 -1
- data/app/controllers/decidim/links_controller.rb +1 -1
- data/app/controllers/decidim/profiles_controller.rb +6 -2
- data/app/controllers/decidim/reports_controller.rb +1 -1
- data/app/controllers/decidim/user_activities_controller.rb +1 -1
- data/app/forms/decidim/account_form.rb +5 -2
- data/app/helpers/concerns/decidim/user_role_checker.rb +46 -0
- data/app/helpers/decidim/cta_button_helper.rb +1 -1
- data/app/helpers/decidim/map_helper.rb +6 -1
- data/app/helpers/decidim/orders_helper.rb +2 -1
- data/app/helpers/decidim/participatory_space_helpers.rb +1 -1
- data/app/helpers/decidim/sanitize_helper.rb +11 -2
- data/app/jobs/decidim/hide_child_resources_job.rb +24 -0
- data/app/mailers/decidim/reported_mailer.rb +1 -0
- data/app/models/decidim/action_log.rb +1 -9
- data/app/models/decidim/attachment.rb +1 -1
- data/app/models/decidim/report.rb +1 -1
- data/app/models/decidim/user.rb +0 -4
- data/app/models/decidim/user_base_entity.rb +4 -0
- data/app/packs/src/decidim/append_redirect_url_to_modals.js +14 -6
- data/app/packs/src/decidim/datepicker/datepicker_functions.js +3 -3
- data/app/packs/src/decidim/direct_uploads/upload_field.js +21 -8
- data/app/packs/src/decidim/index.js +5 -0
- data/app/packs/src/decidim/map/provider/here.js +1 -1
- data/app/packs/src/decidim/remote_tooltips.js +38 -0
- data/app/packs/src/decidim/toggle.js +1 -1
- data/app/packs/src/decidim/tooltips.js +42 -22
- data/app/packs/stylesheets/decidim/_content_blocks.scss +4 -0
- data/app/packs/stylesheets/decidim/_hashtags.scss +5 -0
- data/app/packs/stylesheets/decidim/_header.scss +11 -5
- data/app/packs/stylesheets/decidim/_labels.scss +1 -1
- data/app/packs/stylesheets/decidim/_profile.scss +1 -1
- data/app/packs/stylesheets/decidim/_progress-bar.scss +1 -1
- data/app/packs/stylesheets/decidim/application.scss +1 -0
- data/app/packs/stylesheets/decidim/legacy/conference-diploma.scss +2 -1
- data/app/presenters/decidim/attachment_presenter.rb +1 -1
- data/app/presenters/decidim/log/user_presenter.rb +1 -0
- data/app/presenters/decidim/user_presenter.rb +1 -1
- data/app/services/decidim/base_diff_renderer.rb +28 -2
- data/app/services/decidim/email_notification_generator.rb +14 -5
- data/app/services/decidim/static_map_generator.rb +1 -1
- data/app/views/decidim/last_activities/index.html.erb +1 -1
- data/app/views/decidim/pages/_tabbed.html.erb +2 -2
- data/app/views/decidim/reported_mailer/hide.html.erb +17 -1
- data/app/views/decidim/reported_mailer/report.html.erb +1 -1
- data/app/views/decidim/searches/_count.html.erb +1 -1
- data/app/views/decidim/searches/_filters.html.erb +40 -38
- data/app/views/decidim/shared/_orders.html.erb +2 -2
- data/app/views/layouts/decidim/footer/_main_legal.html.erb +1 -1
- data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile_tablet.html.erb +1 -1
- data/config/locales/ar.yml +56 -27
- data/config/locales/bg.yml +10 -24
- data/config/locales/bn-BD.yml +1 -0
- data/config/locales/bs-BA.yml +100 -0
- data/config/locales/ca-IT.yml +2111 -0
- data/config/locales/ca.yml +70 -38
- data/config/locales/cs.yml +60 -32
- data/config/locales/de.yml +66 -38
- data/config/locales/el.yml +17 -15
- data/config/locales/en.yml +48 -16
- data/config/locales/eo.yml +2 -0
- data/config/locales/es-MX.yml +61 -29
- data/config/locales/es-PY.yml +66 -34
- data/config/locales/es.yml +71 -39
- data/config/locales/eu.yml +303 -261
- data/config/locales/fi-plain.yml +48 -28
- data/config/locales/fi.yml +85 -65
- data/config/locales/fr-CA.yml +64 -27
- data/config/locales/fr.yml +62 -25
- data/config/locales/ga-IE.yml +13 -4
- data/config/locales/gl.yml +33 -15
- data/config/locales/hu.yml +12 -26
- data/config/locales/id-ID.yml +32 -16
- data/config/locales/is-IS.yml +18 -2
- data/config/locales/it.yml +54 -27
- data/config/locales/ja.yml +70 -38
- data/config/locales/lb.yml +33 -22
- data/config/locales/lt.yml +10 -18
- data/config/locales/lv.yml +26 -15
- data/config/locales/nl.yml +33 -19
- data/config/locales/no.yml +27 -16
- data/config/locales/pl.yml +8 -22
- data/config/locales/pt-BR.yml +13 -25
- data/config/locales/pt.yml +32 -16
- data/config/locales/ro-RO.yml +500 -220
- data/config/locales/ru.yml +31 -8
- data/config/locales/sk.yml +38 -19
- data/config/locales/sl.yml +4 -0
- data/config/locales/sr-CS.yml +2 -0
- data/config/locales/sv.yml +29 -33
- data/config/locales/tr-TR.yml +34 -24
- data/config/locales/uk.yml +20 -3
- data/config/locales/zh-CN.yml +27 -15
- data/config/locales/zh-TW.yml +16 -16
- data/config/routes.rb +1 -0
- data/decidim-core.gemspec +4 -1
- data/lib/decidim/api/functions/component_list.rb +1 -1
- data/lib/decidim/api/functions/participatory_space_finder_base.rb +11 -1
- data/lib/decidim/api/interfaces/participatory_space_interface.rb +1 -1
- data/lib/decidim/api/types/component_type.rb +7 -0
- data/lib/decidim/api/types/user_group_type.rb +4 -0
- data/lib/decidim/api/types/user_type.rb +4 -0
- data/lib/decidim/asset_router/storage.rb +7 -2
- data/lib/decidim/attributes/rich_text.rb +38 -0
- data/lib/decidim/attributes/time_with_zone.rb +16 -2
- data/lib/decidim/attributes.rb +2 -0
- data/lib/decidim/content_parsers/blob_parser.rb +95 -0
- data/lib/decidim/content_parsers/user_parser.rb +1 -1
- data/lib/decidim/content_parsers.rb +1 -0
- data/lib/decidim/content_renderers/blob_renderer.rb +90 -0
- data/lib/decidim/content_renderers.rb +1 -0
- data/lib/decidim/core/engine.rb +29 -1
- data/lib/decidim/core/test/factories.rb +28 -0
- data/lib/decidim/core/test/shared_examples/authorable_interface_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +15 -2
- data/lib/decidim/core/test/shared_examples/reports_examples.rb +48 -6
- data/lib/decidim/core/test/shared_examples/social_share_examples.rb +32 -0
- data/lib/decidim/core/test/shared_examples/uncommentable_component_examples.rb +26 -0
- data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +26 -0
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/diffy_extension.rb +18 -0
- data/lib/decidim/form_builder.rb +1 -1
- data/lib/decidim/map/autocomplete.rb +1 -0
- data/lib/decidim/map/provider/dynamic_map/here.rb +1 -40
- data/lib/decidim/map/provider/static_map/here.rb +34 -0
- data/lib/decidim/moderation_tools.rb +16 -2
- data/lib/decidim/nicknamizable.rb +1 -1
- data/lib/decidim/participatory_space_user.rb +4 -0
- data/lib/decidim/query_extensions.rb +0 -26
- data/lib/decidim/reportable.rb +6 -2
- data/lib/decidim/settings_manifest.rb +2 -0
- data/lib/decidim/translatable_attributes.rb +10 -1
- data/lib/tasks/upgrade/clean_hidden_resources.rake +33 -0
- data/lib/tasks/upgrade/decidim_fix_categorization.rake +34 -8
- data/lib/tasks/upgrade/decidim_fix_nickname_uniqueness.rake +23 -20
- metadata +37 -15
- data/app/cells/decidim/author/flag.erb +0 -6
- data/app/cells/decidim/author/flag_user.erb +0 -14
- data/app/cells/decidim/flag_modal/flag_user.erb +0 -34
- data/app/cells/decidim/flag_modal/show.erb +0 -52
- data/app/cells/decidim/flag_modal_cell.rb +0 -56
- data/app/cells/decidim/profile_sidebar/show.erb +0 -167
- data/app/cells/decidim/profile_sidebar_cell.rb +0 -68
- data/app/packs/src/decidim/vendor/leaflet-tilelayer-here.js +0 -212
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ContentRenderers
|
5
|
+
# A renderer that searches Global IDs representing blobs in content and
|
6
|
+
# replaces it with a URL to these blobs.
|
7
|
+
#
|
8
|
+
# e.g. gid://<APP_NAME>/ActiveStorage::Blob/1
|
9
|
+
#
|
10
|
+
# OR for representations
|
11
|
+
#
|
12
|
+
# e.g. gid://<APP_NAME>/ActiveStorage::Blob/1/<encoded variant transformations>
|
13
|
+
#
|
14
|
+
# The `<encoded variant transformations>` part of the URL is a Base64
|
15
|
+
# encoded string that contains an unencrypted JSON-encoded value about the
|
16
|
+
# blob transformations. This way the specific representations can be stored
|
17
|
+
# in the database without having these values expiring.
|
18
|
+
#
|
19
|
+
# @see BaseRenderer Examples of how to use a content renderer
|
20
|
+
class BlobRenderer < BaseRenderer
|
21
|
+
# Matches a global id representing a Decidim::User
|
22
|
+
GLOBAL_ID_REGEX = %r{(gid://[\w-]+/ActiveStorage::Blob/\d+)(/([\w=-]+))?}
|
23
|
+
|
24
|
+
# Replaces found Global IDs matching an existing blob with a URL to
|
25
|
+
# that blob. The Global IDs representing an invalid ActiveStorage::Blob
|
26
|
+
# are replaced with an empty string.
|
27
|
+
#
|
28
|
+
# @return [String] the content ready to display (contains HTML)
|
29
|
+
def render(_options = nil)
|
30
|
+
replace_pattern(content, GLOBAL_ID_REGEX)
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def replace_pattern(text, pattern)
|
36
|
+
return text unless text.respond_to?(:gsub)
|
37
|
+
|
38
|
+
text.gsub(pattern) do
|
39
|
+
blob_gid = Regexp.last_match(1)
|
40
|
+
variation_key = Regexp.last_match(3)
|
41
|
+
|
42
|
+
blob = GlobalID::Locator.locate(blob_gid)
|
43
|
+
if variation_key
|
44
|
+
variation = begin
|
45
|
+
ActiveSupport::JSON.decode(Base64.strict_decode64(variation_key))
|
46
|
+
rescue JSON::ParseError
|
47
|
+
variation_key
|
48
|
+
end
|
49
|
+
blob_url(blob, variation)
|
50
|
+
else
|
51
|
+
blob_url(blob)
|
52
|
+
end
|
53
|
+
rescue ActiveRecord::RecordNotFound => _e
|
54
|
+
""
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def blob_url(blob, variation = nil)
|
59
|
+
url = begin
|
60
|
+
if variation
|
61
|
+
blob.variant(variation).url
|
62
|
+
else
|
63
|
+
blob.url
|
64
|
+
end
|
65
|
+
rescue ArgumentError
|
66
|
+
# ArgumentError is raised in case the blob's service is set to
|
67
|
+
# ActiveStorage::Service::DiskService and
|
68
|
+
# `ActiveStorage::Current.url_options` is not set.
|
69
|
+
end
|
70
|
+
raise URI::InvalidURIError if url.blank?
|
71
|
+
|
72
|
+
url
|
73
|
+
rescue URI::InvalidURIError
|
74
|
+
local_blob_url(blob, variation)
|
75
|
+
end
|
76
|
+
|
77
|
+
def local_blob_url(blob, variation = nil)
|
78
|
+
if variation
|
79
|
+
routes.rails_representation_url(blob.variant(variation), only_path: true)
|
80
|
+
else
|
81
|
+
routes.rails_blob_url(blob, only_path: true)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def routes
|
86
|
+
@routes ||= Rails.application.routes.url_helpers
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module Decidim
|
4
4
|
module ContentRenderers
|
5
5
|
autoload :BaseRenderer, "decidim/content_renderers/base_renderer"
|
6
|
+
autoload :BlobRenderer, "decidim/content_renderers/blob_renderer"
|
6
7
|
autoload :UserRenderer, "decidim/content_renderers/user_renderer"
|
7
8
|
autoload :UserGroupRenderer, "decidim/content_renderers/user_group_renderer"
|
8
9
|
autoload :HashtagRenderer, "decidim/content_renderers/hashtag_renderer"
|
data/lib/decidim/core/engine.rb
CHANGED
@@ -239,6 +239,34 @@ module Decidim
|
|
239
239
|
app.config.action_mailer.deliver_later_queue_name = :mailers
|
240
240
|
end
|
241
241
|
|
242
|
+
initializer "decidim_core.active_storage", before: "active_storage.configs" do |app|
|
243
|
+
next if app.config.active_storage.service_urls_expire_in.present?
|
244
|
+
|
245
|
+
# Ensure that the ActiveStorage URLs are valid long enough because with
|
246
|
+
# the default configuration they would expire in 5 minutes which is a
|
247
|
+
# problem:
|
248
|
+
# a) for the backend blob URL replacement
|
249
|
+
# and
|
250
|
+
# b) for caching
|
251
|
+
#
|
252
|
+
# Note the limitations for each storage service regarding the signed URL
|
253
|
+
# expiration times. This limitation has to be also considered when
|
254
|
+
# defining a caching strategy, otherwise e.g. images or files may not
|
255
|
+
# display correctly when caching is enabled.
|
256
|
+
#
|
257
|
+
# ActiveStorage disk service (default): no limitation
|
258
|
+
#
|
259
|
+
# S3: maximum is 7 days from the creation of the URL
|
260
|
+
# https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html
|
261
|
+
#
|
262
|
+
# Google: maximum is 7 days (604800 seconds)
|
263
|
+
# https://cloud.google.com/storage/docs/access-control/signed-urls
|
264
|
+
#
|
265
|
+
# Azure: no limitation
|
266
|
+
# https://learn.microsoft.com/en-us/azure/storage/common/storage-sas-overview#best-practices-when-using-sas
|
267
|
+
app.config.active_storage.service_urls_expire_in = 7.days
|
268
|
+
end
|
269
|
+
|
242
270
|
initializer "decidim_core.signed_global_id", after: "global_id" do |app|
|
243
271
|
next if app.config.global_id.fetch(:expires_in, nil).present?
|
244
272
|
|
@@ -414,7 +442,7 @@ module Decidim
|
|
414
442
|
|
415
443
|
initializer "decidim_core.content_processors" do |_app|
|
416
444
|
Decidim.configure do |config|
|
417
|
-
config.content_processors += [:user, :user_group, :hashtag, :link]
|
445
|
+
config.content_processors += [:user, :user_group, :hashtag, :link, :blob]
|
418
446
|
end
|
419
447
|
end
|
420
448
|
|
@@ -218,8 +218,15 @@ FactoryBot.define do
|
|
218
218
|
end
|
219
219
|
|
220
220
|
trait :deleted do
|
221
|
+
name { "" }
|
222
|
+
nickname { "" }
|
221
223
|
email { "" }
|
224
|
+
delete_reason { "I want to delete my account" }
|
225
|
+
admin { false }
|
222
226
|
deleted_at { Time.current }
|
227
|
+
avatar { nil }
|
228
|
+
personal_url { "" }
|
229
|
+
about { "" }
|
223
230
|
end
|
224
231
|
|
225
232
|
trait :admin_terms_accepted do
|
@@ -1022,4 +1029,25 @@ FactoryBot.define do
|
|
1022
1029
|
end
|
1023
1030
|
end
|
1024
1031
|
end
|
1032
|
+
|
1033
|
+
factory :blob, class: "ActiveStorage::Blob" do
|
1034
|
+
transient do
|
1035
|
+
filepath { Decidim::Dev.asset("city.jpeg") }
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
filename { File.basename(filepath) }
|
1039
|
+
content_type { MiniMime.lookup_by_filename(filepath)&.content_type || "text/plain" }
|
1040
|
+
|
1041
|
+
before(:create) do |object, evaluator|
|
1042
|
+
object.upload(File.open(evaluator.filepath))
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
trait :image do
|
1046
|
+
filepath { Decidim::Dev.asset("city.jpeg") }
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
trait :document do
|
1050
|
+
filepath { Decidim::Dev.asset("Exampledocument.pdf") }
|
1051
|
+
end
|
1052
|
+
end
|
1025
1053
|
end
|
@@ -18,7 +18,7 @@ shared_examples_for "authorable interface" do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
describe "with a regular user" do
|
21
|
-
let(:author) { create(:user, organization: model.participatory_space.organization) }
|
21
|
+
let(:author) { create(:user, :confirmed, organization: model.participatory_space.organization) }
|
22
22
|
let(:query) { "{ author { name } }" }
|
23
23
|
|
24
24
|
before do
|
@@ -619,7 +619,7 @@ shared_examples "comments" do
|
|
619
619
|
end
|
620
620
|
|
621
621
|
context "when the user has verified organizations" do
|
622
|
-
let(:user_group) { create(:user_group, :verified) }
|
622
|
+
let(:user_group) { create(:user_group, :verified, organization:) }
|
623
623
|
let(:content) { "This is a new comment" }
|
624
624
|
|
625
625
|
before do
|
@@ -747,6 +747,20 @@ shared_examples "comments" do
|
|
747
747
|
expect(page).to have_content("Edited")
|
748
748
|
end
|
749
749
|
end
|
750
|
+
|
751
|
+
it "has only one edit modal" do
|
752
|
+
expect(page).to have_css("#editCommentModal#{comment.id}", visible: :hidden, count: 1)
|
753
|
+
3.times do |index|
|
754
|
+
sleep 2
|
755
|
+
within "#comment_#{comment.id}" do
|
756
|
+
page.find("[id^='dropdown-trigger']").click
|
757
|
+
click_on "Edit"
|
758
|
+
end
|
759
|
+
fill_in "edit_comment_#{comment.id}", with: " This comment has been edited #{1 + index} times"
|
760
|
+
click_on "Send"
|
761
|
+
end
|
762
|
+
expect(page).to have_css("#editCommentModal#{comment.id}", visible: :all, count: 1)
|
763
|
+
end
|
750
764
|
end
|
751
765
|
end
|
752
766
|
end
|
@@ -1031,7 +1045,6 @@ shared_examples "comments blocked" do
|
|
1031
1045
|
end
|
1032
1046
|
|
1033
1047
|
context "when authenticated" do
|
1034
|
-
let!(:organization) { create(:organization) }
|
1035
1048
|
let!(:user) { create(:user, :confirmed, organization:) }
|
1036
1049
|
let!(:comments) { create_list(:comment, 3, commentable:) }
|
1037
1050
|
|
@@ -33,17 +33,46 @@ shared_examples "higher user role hides" do
|
|
33
33
|
before do
|
34
34
|
login_as user, scope: :user
|
35
35
|
end
|
36
|
-
around do |example|
|
37
|
-
previous = Capybara.raise_server_errors
|
38
36
|
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
it "reports the resource" do
|
38
|
+
visit reportable_path
|
39
|
+
|
40
|
+
expect(page).to have_css(%(button[data-dialog-open="flagModal"]))
|
41
|
+
find(%(button[data-dialog-open="flagModal"])).click
|
42
|
+
expect(page).to have_css(".flag-modal", visible: :visible)
|
43
|
+
|
44
|
+
within ".flag-modal" do
|
45
|
+
find(:css, "input[name='report[hide]']").set(true)
|
46
|
+
click_on "Hide"
|
47
|
+
end
|
48
|
+
|
49
|
+
sleep(1)
|
50
|
+
|
51
|
+
expect(page).to have_current_path(reportable_index_path, ignore_query: true)
|
52
|
+
|
53
|
+
expect(reportable.reload).to be_hidden
|
42
54
|
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
shared_examples "higher user role hides resource with comments" do
|
59
|
+
context "and the admin hides a resource with comments" do
|
60
|
+
let!(:comments) { create_list(:comment, 2, body: "Dummy comment", commentable: reportable, author: user) }
|
61
|
+
|
62
|
+
before do
|
63
|
+
login_as user, scope: :user
|
64
|
+
end
|
65
|
+
|
66
|
+
it "hides the resource" do
|
67
|
+
visit decidim.search_path
|
68
|
+
expect(page).to have_content(translated(comments.first.body))
|
69
|
+
expect(page).to have_content(translated(comments.second.body))
|
43
70
|
|
44
|
-
it "reports the resource" do
|
45
71
|
visit reportable_path
|
46
72
|
|
73
|
+
expect(page).to have_content(translated(comments.first.body))
|
74
|
+
expect(page).to have_content(translated(comments.second.body))
|
75
|
+
|
47
76
|
expect(page).to have_css(%(button[data-dialog-open="flagModal"]))
|
48
77
|
find(%(button[data-dialog-open="flagModal"])).click
|
49
78
|
expect(page).to have_css(".flag-modal", visible: :visible)
|
@@ -53,7 +82,19 @@ shared_examples "higher user role hides" do
|
|
53
82
|
click_on "Hide"
|
54
83
|
end
|
55
84
|
|
85
|
+
sleep(1)
|
86
|
+
|
87
|
+
expect(page).to have_current_path(reportable_index_path, ignore_query: true)
|
88
|
+
|
89
|
+
perform_enqueued_jobs
|
90
|
+
|
56
91
|
expect(reportable.reload).to be_hidden
|
92
|
+
expect(comments.first.reload).to be_hidden
|
93
|
+
expect(comments.second.reload).to be_hidden
|
94
|
+
|
95
|
+
visit decidim.search_path
|
96
|
+
expect(page).to have_no_content(translated(comments.first.body))
|
97
|
+
expect(page).to have_no_content(translated(comments.second.body))
|
57
98
|
end
|
58
99
|
end
|
59
100
|
end
|
@@ -120,6 +161,7 @@ shared_examples "reports by user type" do
|
|
120
161
|
let!(:user) { create(:user, :admin, :confirmed, organization:) }
|
121
162
|
include_examples "higher user role reports"
|
122
163
|
include_examples "higher user role hides"
|
164
|
+
include_examples "higher user role hides resource with comments"
|
123
165
|
end
|
124
166
|
context "When reporting user is process admin" do
|
125
167
|
let!(:user) { create :process_admin, :confirmed, participatory_process: }
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
def visit_resource
|
6
|
+
return visit resource if resource.is_a?(String)
|
7
|
+
|
8
|
+
return visit decidim.root_path if resource.is_a?(Decidim::Organization)
|
9
|
+
|
10
|
+
visit resource_locator(resource).path
|
11
|
+
end
|
12
|
+
|
13
|
+
shared_examples "a social share widget" do
|
14
|
+
it "has the social share button" do
|
15
|
+
visit_resource
|
16
|
+
|
17
|
+
expect(page).to have_css('button[data-dialog-open="socialShare"]')
|
18
|
+
end
|
19
|
+
|
20
|
+
it "lists all the expected social share providers" do
|
21
|
+
visit_resource
|
22
|
+
click_on "Share"
|
23
|
+
|
24
|
+
within "#socialShare" do
|
25
|
+
expect(page).to have_css('a[title="Share to X"]')
|
26
|
+
expect(page).to have_css('a[title="Share to Facebook"]')
|
27
|
+
expect(page).to have_css('a[title="Share to WhatsApp"]')
|
28
|
+
expect(page).to have_css('a[title="Share to Telegram"]')
|
29
|
+
expect(page).to have_css(".share-modal__input")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -8,6 +8,7 @@ shared_examples "an uncommentable component" do
|
|
8
8
|
manifest:,
|
9
9
|
participatory_space:)
|
10
10
|
end
|
11
|
+
let!(:comment) { create(:comment, commentable: resources.first) }
|
11
12
|
|
12
13
|
it "does not displays comments count" do
|
13
14
|
component.update!(settings: { comments_enabled: false })
|
@@ -18,4 +19,29 @@ shared_examples "an uncommentable component" do
|
|
18
19
|
expect(page).to have_no_link(resource_locator(resource).path)
|
19
20
|
end
|
20
21
|
end
|
22
|
+
|
23
|
+
describe "when search a comment in the global search" do
|
24
|
+
it "does displays the comments" do
|
25
|
+
visit decidim.root_path
|
26
|
+
|
27
|
+
within ".main-bar__search" do
|
28
|
+
fill_in "term", with: comment.body["en"]
|
29
|
+
find("input#input-search").native.send_keys :enter
|
30
|
+
end
|
31
|
+
|
32
|
+
expect(page).to have_content("1 Results for the search")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "does not displays the comment when comments are disable" do
|
36
|
+
component.update!(settings: { comments_enabled: false })
|
37
|
+
visit decidim.root_path
|
38
|
+
|
39
|
+
within ".main-bar__search" do
|
40
|
+
fill_in "term", with: comment.body["en"]
|
41
|
+
find("input#input-search").native.send_keys :enter
|
42
|
+
end
|
43
|
+
|
44
|
+
expect(page).to have_content("0 Results for the search")
|
45
|
+
end
|
46
|
+
end
|
21
47
|
end
|
@@ -2,6 +2,32 @@
|
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
|
+
shared_examples "a version of a hidden object" do
|
6
|
+
before do
|
7
|
+
visit resource_path
|
8
|
+
click_on "see other versions"
|
9
|
+
click_on("Version 1 of #{hidden_object.reload.versions.size}")
|
10
|
+
end
|
11
|
+
|
12
|
+
around do |example|
|
13
|
+
previous = Capybara.raise_server_errors
|
14
|
+
|
15
|
+
Capybara.raise_server_errors = false
|
16
|
+
example.run
|
17
|
+
Capybara.raise_server_errors = previous
|
18
|
+
end
|
19
|
+
|
20
|
+
it "shows an error page" do
|
21
|
+
expect(page).to have_content("Changes at")
|
22
|
+
|
23
|
+
create(:moderation, reportable: hidden_object, hidden_at: 1.day.ago)
|
24
|
+
|
25
|
+
visit current_path
|
26
|
+
|
27
|
+
expect(page).to have_content(ActiveRecord::RecordNotFound)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
5
31
|
shared_examples "versions controller" do
|
6
32
|
let(:base_params) do
|
7
33
|
if resource.is_a?(Decidim::Participable)
|
data/lib/decidim/core/version.rb
CHANGED
@@ -13,6 +13,24 @@ module Decidim
|
|
13
13
|
str = wrap_lines(@diff.map { |line| wrap_line(line) })
|
14
14
|
ActionView::Base.new(ActionView::LookupContext.new(nil), {}, nil).sanitize(str, tags: TAGS)
|
15
15
|
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def wrap_line(line)
|
20
|
+
cleaned = clean_line(line)
|
21
|
+
case line
|
22
|
+
when /^(---|\+\+\+|\\\\)/
|
23
|
+
" <li class=\"diff-comment\"><div>#{line.chomp}</div></li>"
|
24
|
+
when /^\+/
|
25
|
+
" <li class=\"ins\"><ins>#{cleaned}</ins></li>"
|
26
|
+
when /^-/
|
27
|
+
" <li class=\"del\"><del>#{cleaned}</del></li>"
|
28
|
+
when /^ /
|
29
|
+
" <li class=\"unchanged\"><div>#{cleaned}</div></li>"
|
30
|
+
when /^@@/
|
31
|
+
" <li class=\"diff-block-info\"><div>#{line.chomp}</div></li>"
|
32
|
+
end
|
33
|
+
end
|
16
34
|
end
|
17
35
|
|
18
36
|
# Adding a new method to Diffy::Format so we can pass the
|
data/lib/decidim/form_builder.rb
CHANGED
@@ -390,7 +390,7 @@ module Decidim
|
|
390
390
|
# options - A Hash with options to build the field. See upload method for
|
391
391
|
# more detailed information.
|
392
392
|
def attachment(attribute, options = {})
|
393
|
-
object_attachment = object.attachment.present?
|
393
|
+
object_attachment = object.respond_to?(:attachment) && object.attachment.present?
|
394
394
|
record = object_attachment ? object.attachment : object
|
395
395
|
options = {
|
396
396
|
titled: options[:multiple],
|
@@ -49,46 +49,7 @@ module Decidim
|
|
49
49
|
private
|
50
50
|
|
51
51
|
def language_code
|
52
|
-
|
53
|
-
secondary = primary.split("-")[0]
|
54
|
-
available_language_codes[primary] || available_language_codes[secondary] || ""
|
55
|
-
end
|
56
|
-
|
57
|
-
def available_language_codes
|
58
|
-
@available_language_codes ||= {
|
59
|
-
"ar" => "ara", # Arabic
|
60
|
-
"eu" => "baq", # Basque
|
61
|
-
"ca" => "cat", # Catalan
|
62
|
-
"zh" => "chi", # Chinese (simplified)
|
63
|
-
# "" => "cht", # Chinese (traditional)
|
64
|
-
"cs" => "cze", # Czech
|
65
|
-
"da" => "dan", # Danish
|
66
|
-
"nl" => "dut", # Dutch
|
67
|
-
"en" => "eng", # English
|
68
|
-
"fi" => "fin", # Finnish
|
69
|
-
"fr" => "fre", # French
|
70
|
-
"de" => "ger", # German
|
71
|
-
"ga" => "gle", # Gaelic
|
72
|
-
"el" => "gre", # Greek
|
73
|
-
"he" => "heb", # Hebrew
|
74
|
-
"hi" => "hin", # Hindi
|
75
|
-
"id" => "ind", # Indonesian
|
76
|
-
"it" => "ita", # Italian
|
77
|
-
"no" => "nor", # Norwegian
|
78
|
-
"fa" => "per", # Persian
|
79
|
-
"pl" => "pol", # Polish
|
80
|
-
"pt" => "por", # Portuguese
|
81
|
-
"ru" => "rus", # Russian
|
82
|
-
"si" => "sin", # Sinhalese
|
83
|
-
"es" => "spa", # Spanish
|
84
|
-
"sv" => "swe", # Swedish
|
85
|
-
"th" => "tha", # Thai
|
86
|
-
"tr" => "tur", # Turkish
|
87
|
-
"uk" => "ukr", # Ukrainian
|
88
|
-
"ur" => "urd", # Urdu
|
89
|
-
"vi" => "vie", # Vietnamese
|
90
|
-
"cy" => "wel" # Welsh
|
91
|
-
}
|
52
|
+
I18n.locale.to_s
|
92
53
|
end
|
93
54
|
end
|
94
55
|
end
|
@@ -6,8 +6,42 @@ module Decidim
|
|
6
6
|
module StaticMap
|
7
7
|
# The static map utility class for the HERE maps service
|
8
8
|
class Here < ::Decidim::Map::StaticMap
|
9
|
+
def url(latitude:, longitude:, options: {})
|
10
|
+
map_url = configuration.fetch(:url, nil)
|
11
|
+
return super unless map_url
|
12
|
+
|
13
|
+
return super unless map_url.include?("mia/v3")
|
14
|
+
|
15
|
+
w = options[:width] || Decidim::Map::StaticMap::DEFAULT_SIZE
|
16
|
+
h = options[:height] || Decidim::Map::StaticMap::DEFAULT_SIZE
|
17
|
+
|
18
|
+
params = {
|
19
|
+
apiKey: configuration[:api_key],
|
20
|
+
overlay: "point:#{latitude},#{longitude};icon=cp;size=large|#{latitude},#{longitude};style=circle;width=50m;color=%231B9D2C60"
|
21
|
+
}
|
22
|
+
|
23
|
+
URI.parse("#{map_url}:radius=90/#{w}x#{h}/png8").tap do |uri|
|
24
|
+
uri.query = URI.encode_www_form(params)
|
25
|
+
end.to_s
|
26
|
+
end
|
27
|
+
|
9
28
|
# @See Decidim::Map::StaticMap#url_params
|
10
29
|
def url_params(latitude:, longitude:, options: {})
|
30
|
+
ActiveSupport::Deprecation.warn(
|
31
|
+
<<~DEPRECATION.strip
|
32
|
+
Please use a V3 version HERE maps.
|
33
|
+
For further information, see:
|
34
|
+
https://www.here.com/docs/bundle/map-image-migration-guide-v3/page/README.html
|
35
|
+
Also make sure your Decidim.maps configurations are using the
|
36
|
+
up to date format.
|
37
|
+
You need to change:
|
38
|
+
static_url = "https://image.maps.ls.hereapi.com/mia/1.6/mapview" if static_provider == "here" && static_url.blank?
|
39
|
+
to:
|
40
|
+
static_url = "https://image.maps.hereapi.com/mia/v3/base/mc/overlay" if static_provider == "here"
|
41
|
+
in your config/initializers/decidim.rb file.
|
42
|
+
DEPRECATION
|
43
|
+
)
|
44
|
+
|
11
45
|
params = {
|
12
46
|
c: "#{latitude}, #{longitude}",
|
13
47
|
z: options[:zoom] || Decidim::Map::StaticMap::DEFAULT_ZOOM,
|
@@ -59,9 +59,11 @@ module Decidim
|
|
59
59
|
event_class: Decidim::ResourceHiddenEvent,
|
60
60
|
resource: @reportable,
|
61
61
|
extra: {
|
62
|
-
report_reasons
|
62
|
+
report_reasons:,
|
63
|
+
force_email: true
|
63
64
|
},
|
64
|
-
affected_users
|
65
|
+
affected_users:,
|
66
|
+
force_send: true
|
65
67
|
}
|
66
68
|
|
67
69
|
Decidim::EventsManager.publish(**data)
|
@@ -80,10 +82,22 @@ module Decidim
|
|
80
82
|
@reportable.moderation.update!(hidden_at: Time.current)
|
81
83
|
@reportable.try(:touch)
|
82
84
|
end
|
85
|
+
|
86
|
+
if @reportable.is_a?(Decidim::Comments::Commentable)
|
87
|
+
@reportable.comment_threads.each do |comment|
|
88
|
+
Decidim::HideChildResourcesJob.perform_later(comment, @current_user.id)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
send_notification_to_author
|
83
93
|
end
|
84
94
|
|
85
95
|
private
|
86
96
|
|
97
|
+
def affected_users
|
98
|
+
@affected_users ||= (@reportable.try(:authors) || [@reportable.try(:author)]).select { |author| author.is_a?(Decidim::User) }
|
99
|
+
end
|
100
|
+
|
87
101
|
def report_reasons
|
88
102
|
@reportable.moderation.reports.pluck(:reason).uniq
|
89
103
|
end
|
@@ -52,7 +52,7 @@ module Decidim
|
|
52
52
|
candidate = name
|
53
53
|
|
54
54
|
2.step do |n|
|
55
|
-
return candidate if Decidim::UserBaseEntity.where(
|
55
|
+
return candidate if Decidim::UserBaseEntity.where(nickname: candidate.downcase).where(scope).empty?
|
56
56
|
|
57
57
|
candidate = numbered_variation_of(name, n)
|
58
58
|
end
|
@@ -10,22 +10,6 @@ module Decidim
|
|
10
10
|
#
|
11
11
|
# Returns nothing.
|
12
12
|
def self.included(type)
|
13
|
-
type.field :participatory_processes,
|
14
|
-
[Decidim::ParticipatoryProcesses::ParticipatoryProcessType],
|
15
|
-
null: true,
|
16
|
-
description: "Lists all participatory_processes" do
|
17
|
-
argument :filter, Decidim::ParticipatoryProcesses::ParticipatoryProcessInputFilter, "This argument lets you filter the results", required: false
|
18
|
-
argument :order, Decidim::ParticipatoryProcesses::ParticipatoryProcessInputSort, "This argument lets you order the results", required: false
|
19
|
-
end
|
20
|
-
|
21
|
-
type.field :participatory_process,
|
22
|
-
Decidim::ParticipatoryProcesses::ParticipatoryProcessType,
|
23
|
-
null: true,
|
24
|
-
description: "Finds a participatory_process" do
|
25
|
-
argument :id, GraphQL::Types::ID, "The ID of the participatory space", required: false
|
26
|
-
argument :slug, String, "The slug of the participatory process", required: false
|
27
|
-
end
|
28
|
-
|
29
13
|
type.field :component, Decidim::Core::ComponentInterface, null: true do
|
30
14
|
description "Lists the components this space contains."
|
31
15
|
argument :id, GraphQL::Types::ID, required: true, description: "The ID of the component to be found"
|
@@ -62,16 +46,6 @@ module Decidim
|
|
62
46
|
end
|
63
47
|
end
|
64
48
|
|
65
|
-
def participatory_processes(filter: {}, order: {})
|
66
|
-
manifest = Decidim.participatory_space_manifests.select { |m| m.name == :participatory_processes }.first
|
67
|
-
Decidim::Core::ParticipatorySpaceListBase.new(manifest:).call(object, { filter:, order: }, context)
|
68
|
-
end
|
69
|
-
|
70
|
-
def participatory_process(id: nil, slug: nil)
|
71
|
-
manifest = Decidim.participatory_space_manifests.select { |m| m.name == :participatory_processes }.first
|
72
|
-
Decidim::Core::ParticipatorySpaceFinderBase.new(manifest:).call(object, { id:, slug: }, context)
|
73
|
-
end
|
74
|
-
|
75
49
|
def component(id: {})
|
76
50
|
component = Decidim::Component.published.find_by(id:)
|
77
51
|
component&.organization == context[:current_organization] ? component : nil
|