diff --git a/decidim-admin/app/controllers/decidim/admin/application_controller.rb b/decidim-admin/app/controllers/decidim/admin/application_controller.rb index 4694a34d2e48..49e4e064f3f9 100644 --- a/decidim-admin/app/controllers/decidim/admin/application_controller.rb +++ b/decidim-admin/app/controllers/decidim/admin/application_controller.rb @@ -18,6 +18,7 @@ class ApplicationController < ::DecidimController include Headers::ContentSecurityPolicy include DisableRedirectionToExternalHost include Decidim::Admin::Concerns::HasBreadcrumbItems + include ActiveStorage::SetCurrent helper Decidim::Admin::ApplicationHelper helper Decidim::Admin::AttributesDisplayHelper diff --git a/decidim-admin/app/views/decidim/admin/organization_appearance/form/_minimap.html.erb b/decidim-admin/app/views/decidim/admin/organization_appearance/form/_minimap.html.erb index e36b7877de1d..a0b35c71fce3 100644 --- a/decidim-admin/app/views/decidim/admin/organization_appearance/form/_minimap.html.erb +++ b/decidim-admin/app/views/decidim/admin/organization_appearance/form/_minimap.html.erb @@ -3,7 +3,7 @@
<% if current_organization.favicon.attached? %> - <%= image_tag current_organization.attached_uploader(:favicon).path, class: "minimap-favicon" %> + <%= image_tag current_organization.attached_uploader(:favicon).url, class: "minimap-favicon" %> <% else %> <%= content_tag :div, nil, { class: "minimap-favicon placeholder", style: "width: #{image_width(current_organization, :favicon) * size_factor}px; height: #{image_height(current_organization, :favicon) * size_factor}px;" } do %> <%= t("favicon", scope: "activemodel.attributes.organization") %> @@ -13,7 +13,7 @@
<% if current_organization.logo.present? %> - <%= image_tag current_organization.attached_uploader(:logo).path, class: "minimap-logo" %> + <%= image_tag current_organization.attached_uploader(:logo).url, class: "minimap-logo" %> <% else %> <%= content_tag :div, nil, { class: "minimap-logo placeholder", style: "width: #{image_width(current_organization, :logo) * size_factor}px; height: #{image_height(current_organization, :logo) * size_factor}px;" } do %> <%= t("logo", scope: "activemodel.attributes.organization") %> @@ -26,7 +26,7 @@
HTML diff --git a/decidim-assemblies/app/cells/decidim/assemblies/assembly_g_cell.rb b/decidim-assemblies/app/cells/decidim/assemblies/assembly_g_cell.rb index 40ee8f7a0569..8965f815a549 100644 --- a/decidim-assemblies/app/cells/decidim/assemblies/assembly_g_cell.rb +++ b/decidim-assemblies/app/cells/decidim/assemblies/assembly_g_cell.rb @@ -11,8 +11,8 @@ def resource_path Decidim::Assemblies::Engine.routes.url_helpers.assembly_path(model) end - def resource_image_path - model.attached_uploader(:hero_image).path + def resource_image_url + model.attached_uploader(:hero_image).url end def metadata_cell diff --git a/decidim-assemblies/app/views/decidim/assemblies/assemblies/show.html.erb b/decidim-assemblies/app/views/decidim/assemblies/assemblies/show.html.erb index 0165750c653f..8bd07e54feec 100644 --- a/decidim-assemblies/app/views/decidim/assemblies/assemblies/show.html.erb +++ b/decidim-assemblies/app/views/decidim/assemblies/assemblies/show.html.erb @@ -1,6 +1,6 @@ <% add_decidim_meta_tags({ title: translated_attribute(current_participatory_space.title), - image_url: current_participatory_space.attached_uploader(:hero_image).path, + image_url: current_participatory_space.attached_uploader(:hero_image).url, description: translated_attribute(current_participatory_space.short_description), url: assembly_url(current_participatory_space) }) %> diff --git a/decidim-assemblies/lib/decidim/api/assembly_type.rb b/decidim-assemblies/lib/decidim/api/assembly_type.rb index 46fd805acf96..23c7a5b71336 100644 --- a/decidim-assemblies/lib/decidim/api/assembly_type.rb +++ b/decidim-assemblies/lib/decidim/api/assembly_type.rb @@ -62,11 +62,11 @@ class AssemblyType < Decidim::Api::Types::BaseObject field :children, [Decidim::Assemblies::AssemblyType, { null: true }], "Children of this assembly", null: false def hero_image - object.attached_uploader(:hero_image).path + object.attached_uploader(:hero_image).url end def banner_image - object.attached_uploader(:banner_image).path + object.attached_uploader(:banner_image).url end end end diff --git a/decidim-assemblies/spec/presenters/decidim/assemblies/assembly_presenter_spec.rb b/decidim-assemblies/spec/presenters/decidim/assemblies/assembly_presenter_spec.rb index 0004a7807393..e4e50af28d4a 100644 --- a/decidim-assemblies/spec/presenters/decidim/assemblies/assembly_presenter_spec.rb +++ b/decidim-assemblies/spec/presenters/decidim/assemblies/assembly_presenter_spec.rb @@ -26,11 +26,11 @@ module Decidim describe "when images are attached" do it "resolves hero_image_url" do - expect(subject.hero_image_url).to eq("http://#{organization_host}:#{Capybara.server_port}#{assembly.attached_uploader(:hero_image).path}") + expect(subject.hero_image_url).to be_blob_url(assembly.hero_image.blob) end it "resolves banner_image_url" do - expect(subject.banner_image_url).to eq("http://#{organization_host}:#{Capybara.server_port}#{assembly.attached_uploader(:banner_image).path}") + expect(subject.banner_image_url).to be_blob_url(assembly.banner_image.blob) end end end diff --git a/decidim-assemblies/spec/presenters/decidim/assembly_member_presenter_spec.rb b/decidim-assemblies/spec/presenters/decidim/assembly_member_presenter_spec.rb index cad7a6fa50d6..94e99a5ee231 100644 --- a/decidim-assemblies/spec/presenters/decidim/assembly_member_presenter_spec.rb +++ b/decidim-assemblies/spec/presenters/decidim/assembly_member_presenter_spec.rb @@ -116,10 +116,10 @@ module Decidim subject { described_class.new(assembly_member).avatar_url } context "when user is present" do - let(:user) { build(:user, name: "Julia G.", nickname: "julia_g") } + let(:user) { create(:user, name: "Julia G.", nickname: "julia_g") } let(:assembly_member) { build(:assembly_member, full_name: "Full name", user:) } - it { is_expected.to eq user.attached_uploader(:avatar).path } + it { is_expected.to be_blob_url(user.avatar.blob) } end context "when no user is present" do diff --git a/decidim-assemblies/spec/serializers/decidim/assemblies/assembly_serializer_spec.rb b/decidim-assemblies/spec/serializers/decidim/assemblies/assembly_serializer_spec.rb index cd11397937c4..0b4979bce79f 100644 --- a/decidim-assemblies/spec/serializers/decidim/assemblies/assembly_serializer_spec.rb +++ b/decidim-assemblies/spec/serializers/decidim/assemblies/assembly_serializer_spec.rb @@ -23,8 +23,8 @@ module Decidim::Assemblies expect(serialized).to include(weight: resource.weight) expect(serialized).to include(short_description: resource.short_description) expect(serialized).to include(description: resource.description) - expect(serialized).to include(remote_hero_image_url: Decidim::Assemblies::AssemblyPresenter.new(resource).hero_image_url) - expect(serialized).to include(remote_banner_image_url: Decidim::Assemblies::AssemblyPresenter.new(resource).banner_image_url) + expect(serialized[:remote_hero_image_url]).to be_blob_url(resource.hero_image.blob) + expect(serialized[:remote_banner_image_url]).to be_blob_url(resource.banner_image.blob) expect(serialized).to include(promoted: resource.promoted) expect(serialized).to include(developer_group: resource.developer_group) expect(serialized).to include(meta_scope: resource.meta_scope) @@ -137,7 +137,7 @@ module Decidim::Assemblies expect(serialized_assembly_attachment).to include(title: attachment.title) expect(serialized_assembly_attachment).to include(weight: attachment.weight) expect(serialized_assembly_attachment).to include(description: attachment.description) - expect(serialized_assembly_attachment).to include(remote_file_url: Decidim::AttachmentPresenter.new(resource.attachments.first).attachment_file_url) + expect(serialized_assembly_attachment[:remote_file_url]).to be_blob_url(resource.attachments.first.file.blob) end end end diff --git a/decidim-assemblies/spec/shared/manage_assemblies_examples.rb b/decidim-assemblies/spec/shared/manage_assemblies_examples.rb index d0ce27112b77..c68893ab0688 100644 --- a/decidim-assemblies/spec/shared/manage_assemblies_examples.rb +++ b/decidim-assemblies/spec/shared/manage_assemblies_examples.rb @@ -76,8 +76,17 @@ expect(page).to have_admin_callout("successfully") - expect(page).to have_css("img[src*='#{assembly.attached_uploader(:hero_image).path}']") - expect(page).to have_css("img[src*='#{assembly.attached_uploader(:banner_image).path}']") + hero_blob = assembly.hero_image.blob + within %([data-active-uploads] [data-filename="#{hero_blob.filename}"]) do + src = page.find("img")["src"] + expect(src).to be_blob_url(hero_blob) + end + + banner_blob = assembly.hero_image.blob + within %([data-active-uploads] [data-filename="#{banner_blob.filename}"]) do + src = page.find("img")["src"] + expect(src).to be_blob_url(banner_blob) + end end end diff --git a/decidim-assemblies/spec/types/assembly_type_spec.rb b/decidim-assemblies/spec/types/assembly_type_spec.rb index b6f8c7da9d1c..3248a0a75b34 100644 --- a/decidim-assemblies/spec/types/assembly_type_spec.rb +++ b/decidim-assemblies/spec/types/assembly_type_spec.rb @@ -93,7 +93,7 @@ module Assemblies let(:query) { "{ heroImage }" } it "returns the hero image field" do - expect(response["heroImage"]).to eq(model.attached_uploader(:hero_image).path) + expect(response["heroImage"]).to be_blob_url(model.hero_image.blob) end end @@ -101,7 +101,7 @@ module Assemblies let(:query) { "{ bannerImage }" } it "returns the banner image field" do - expect(response["bannerImage"]).to eq(model.attached_uploader(:banner_image).path) + expect(response["bannerImage"]).to be_blob_url(model.banner_image.blob) end end diff --git a/decidim-assemblies/spec/types/integration_schema_spec.rb b/decidim-assemblies/spec/types/integration_schema_spec.rb index d179ef8afd65..4aee46ccc12a 100644 --- a/decidim-assemblies/spec/types/integration_schema_spec.rb +++ b/decidim-assemblies/spec/types/integration_schema_spec.rb @@ -22,7 +22,6 @@ "updatedAt" => assembly.assembly_type.updated_at.iso8601.to_s.gsub("Z", "+00:00") }, "attachments" => [], - "bannerImage" => assembly.attached_uploader(:banner_image).path, "categories" => [], "children" => [], "childrenCount" => 0, @@ -40,7 +39,6 @@ "facebookHandler" => assembly.facebook_handler, "githubHandler" => assembly.github_handler, "hashtag" => assembly.hashtag, - "heroImage" => assembly.attached_uploader(:hero_image).path, "id" => assembly.id.to_s, "includedAt" => assembly.included_at.to_date.to_s, "instagramHandler" => assembly.instagram_handler, @@ -218,7 +216,10 @@ end it "returns the correct response" do - expect(response["assemblies"].first).to eq(assembly_data) + data = response["assemblies"].first + expect(data).to include(assembly_data) + expect(data["bannerImage"]).to be_blob_url(assembly.banner_image.blob) + expect(data["heroImage"]).to be_blob_url(assembly.hero_image.blob) end it_behaves_like "implements stats type" do @@ -372,7 +373,10 @@ end it "returns the correct response" do - expect(response["assembly"]).to eq(assembly_data) + data = response["assembly"] + expect(data).to include(assembly_data) + expect(data["bannerImage"]).to be_blob_url(assembly.banner_image.blob) + expect(data["heroImage"]).to be_blob_url(assembly.hero_image.blob) end it_behaves_like "implements stats type" do diff --git a/decidim-blogs/app/cells/decidim/blogs/post_g_cell.rb b/decidim-blogs/app/cells/decidim/blogs/post_g_cell.rb index 389d968edeab..147ed72ff94e 100644 --- a/decidim-blogs/app/cells/decidim/blogs/post_g_cell.rb +++ b/decidim-blogs/app/cells/decidim/blogs/post_g_cell.rb @@ -9,10 +9,6 @@ class PostGCell < Decidim::CardGCell private - def has_image? - resource_image_path.present? - end - def show_description? true end @@ -21,7 +17,7 @@ def metadata_cell "decidim/blogs/post_metadata_g" end - def resource_image_path + def resource_image_url return if photo.blank? photo.url diff --git a/decidim-blogs/app/cells/decidim/blogs/post_l_cell.rb b/decidim-blogs/app/cells/decidim/blogs/post_l_cell.rb index 3ed071edd9e5..6bdeced994e7 100644 --- a/decidim-blogs/app/cells/decidim/blogs/post_l_cell.rb +++ b/decidim-blogs/app/cells/decidim/blogs/post_l_cell.rb @@ -9,10 +9,6 @@ class PostLCell < Decidim::CardLCell private - def has_image? - true - end - def has_description? true end @@ -25,7 +21,7 @@ def metadata_cell "decidim/blogs/post_metadata" end - def resource_image_path + def resource_image_url return if photo.blank? photo.url diff --git a/decidim-blogs/spec/types/integration_schema_spec.rb b/decidim-blogs/spec/types/integration_schema_spec.rb index 6f8f0e83a89d..81c389b08d0c 100644 --- a/decidim-blogs/spec/types/integration_schema_spec.rb +++ b/decidim-blogs/spec/types/integration_schema_spec.rb @@ -23,7 +23,7 @@ "endorsements" => post.endorsements.map do |endo| { "__typename" => "User", - "avatarUrl" => endo.author.attached_uploader(:avatar).path(variant: :thumb), + "avatarUrl" => endo.author.attached_uploader(:avatar).variant_url(:thumb), "badge" => "", "deleted" => false, "id" => endo.author.id.to_s, diff --git a/decidim-conferences/app/cells/decidim/conferences/conference_g_cell.rb b/decidim-conferences/app/cells/decidim/conferences/conference_g_cell.rb index 0b474e642fff..1602f35a6bd0 100644 --- a/decidim-conferences/app/cells/decidim/conferences/conference_g_cell.rb +++ b/decidim-conferences/app/cells/decidim/conferences/conference_g_cell.rb @@ -11,8 +11,8 @@ def resource_path Decidim::Conferences::Engine.routes.url_helpers.conference_path(model) end - def resource_image_path - model.attached_uploader(:hero_image).path + def resource_image_url + model.attached_uploader(:hero_image).url end def metadata_cell diff --git a/decidim-conferences/app/cells/decidim/conferences/partner/image.erb b/decidim-conferences/app/cells/decidim/conferences/partner/image.erb index 59bd2361cc9c..f604a25a53ea 100644 --- a/decidim-conferences/app/cells/decidim/conferences/partner/image.erb +++ b/decidim-conferences/app/cells/decidim/conferences/partner/image.erb @@ -1,3 +1,3 @@
- <%= image_tag model.attached_uploader(:logo).path(variant: :medium), alt: "logo" %> + <%= image_tag model.attached_uploader(:logo).variant_url(:medium), alt: "logo" %>
diff --git a/decidim-conferences/app/cells/decidim/conferences/partner_cell.rb b/decidim-conferences/app/cells/decidim/conferences/partner_cell.rb index e73198a88256..74cb596b69bb 100644 --- a/decidim-conferences/app/cells/decidim/conferences/partner_cell.rb +++ b/decidim-conferences/app/cells/decidim/conferences/partner_cell.rb @@ -21,7 +21,7 @@ def name def logo return unless model.logo.attached? - "
#{image_tag model.attached_uploader(:logo).path(variant: :medium), alt: "logo"}
" + "
#{image_tag model.attached_uploader(:logo).variant_url(:medium), alt: "logo"}
" end end end diff --git a/decidim-conferences/app/views/decidim/conferences/admin/partners/index.html.erb b/decidim-conferences/app/views/decidim/conferences/admin/partners/index.html.erb index 2633c5098f80..6c67b76050a9 100644 --- a/decidim-conferences/app/views/decidim/conferences/admin/partners/index.html.erb +++ b/decidim-conferences/app/views/decidim/conferences/admin/partners/index.html.erb @@ -35,8 +35,8 @@ <% end %> - <% if partner.attached_uploader(:logo).path %> - <%= image_tag(partner.attached_uploader(:logo).path(variant: :thumb)) %> + <% if partner.logo.attached? %> + <%= image_tag(partner.attached_uploader(:logo).variant_url(:thumb)) %> <% end %> diff --git a/decidim-conferences/app/views/decidim/conferences/admin/send_conference_diploma_mailer/diploma_user.html.erb b/decidim-conferences/app/views/decidim/conferences/admin/send_conference_diploma_mailer/diploma_user.html.erb index 678b057ae932..3c3e4ac4c6f7 100644 --- a/decidim-conferences/app/views/decidim/conferences/admin/send_conference_diploma_mailer/diploma_user.html.erb +++ b/decidim-conferences/app/views/decidim/conferences/admin/send_conference_diploma_mailer/diploma_user.html.erb @@ -3,7 +3,7 @@

<%= translated_attribute(@conference.title) %>

@@ -14,7 +14,7 @@
<%= t("decidim.conferences.admin.send_conference_diploma_mailer.diploma_user.attendance_verified_by") %>
- <%= wicked_pdf_image_tag @conference.attached_uploader(:signature).url(variant: :thumb, host: @conference.organization.host) %> + <%= wicked_pdf_image_tag @conference.attached_uploader(:signature).variant_url(:thumb) %>
<%= l(@conference.sign_date, format: :decidim_short) %>, <%= @conference.signature_name %>
diff --git a/decidim-conferences/app/views/decidim/conferences/conferences/_conference_hero.html.erb b/decidim-conferences/app/views/decidim/conferences/conferences/_conference_hero.html.erb index a974d508e2ee..5a1ad37a9566 100644 --- a/decidim-conferences/app/views/decidim/conferences/conferences/_conference_hero.html.erb +++ b/decidim-conferences/app/views/decidim/conferences/conferences/_conference_hero.html.erb @@ -1,4 +1,4 @@ -
+

diff --git a/decidim-conferences/app/views/decidim/conferences/conferences/show.html.erb b/decidim-conferences/app/views/decidim/conferences/conferences/show.html.erb index 0ab884729db0..a13f3feb3e0f 100644 --- a/decidim-conferences/app/views/decidim/conferences/conferences/show.html.erb +++ b/decidim-conferences/app/views/decidim/conferences/conferences/show.html.erb @@ -1,6 +1,6 @@ <% add_decidim_meta_tags({ title: translated_attribute(current_participatory_space.title), - image_url: current_participatory_space.attached_uploader(:hero_image).path, + image_url: current_participatory_space.attached_uploader(:hero_image).url, description: translated_attribute(current_participatory_space.short_description), url: conference_url(current_participatory_space) }) %> diff --git a/decidim-conferences/lib/decidim/api/conference_partner_type.rb b/decidim-conferences/lib/decidim/api/conference_partner_type.rb index 5f4d9d503826..792d026a1853 100644 --- a/decidim-conferences/lib/decidim/api/conference_partner_type.rb +++ b/decidim-conferences/lib/decidim/api/conference_partner_type.rb @@ -16,7 +16,7 @@ class ConferencePartnerType < Decidim::Api::Types::BaseObject field :updated_at, Decidim::Core::DateTimeType, "The time this partner was updated", null: true def logo - object.attached_uploader(:logo).path + object.attached_uploader(:logo).url end end end diff --git a/decidim-conferences/lib/decidim/api/conference_speaker_type.rb b/decidim-conferences/lib/decidim/api/conference_speaker_type.rb index 1ca87bd7b782..8fb7878972db 100644 --- a/decidim-conferences/lib/decidim/api/conference_speaker_type.rb +++ b/decidim-conferences/lib/decidim/api/conference_speaker_type.rb @@ -20,7 +20,7 @@ class ConferenceSpeakerType < Decidim::Api::Types::BaseObject field :updated_at, Decidim::Core::DateTimeType, "The time this member was updated", null: true def avatar - object.attached_uploader(:avatar).path + object.attached_uploader(:avatar).url end end end diff --git a/decidim-conferences/lib/decidim/api/conference_type.rb b/decidim-conferences/lib/decidim/api/conference_type.rb index 60a5e1b4ee9e..6d3dc894d16d 100644 --- a/decidim-conferences/lib/decidim/api/conference_type.rb +++ b/decidim-conferences/lib/decidim/api/conference_type.rb @@ -39,11 +39,11 @@ class ConferenceType < Decidim::Api::Types::BaseObject field :media_links, [Decidim::Conferences::ConferenceMediaLinkType, { null: true }], "List of media links in this conference", null: true def hero_image - object.attached_uploader(:hero_image).path + object.attached_uploader(:hero_image).url end def banner_image - object.attached_uploader(:banner_image).path + object.attached_uploader(:banner_image).url end def speakers diff --git a/decidim-conferences/spec/shared/manage_conferences_examples.rb b/decidim-conferences/spec/shared/manage_conferences_examples.rb index 27d30fea66a1..89bc128a0822 100644 --- a/decidim-conferences/spec/shared/manage_conferences_examples.rb +++ b/decidim-conferences/spec/shared/manage_conferences_examples.rb @@ -108,8 +108,17 @@ expect(page).to have_admin_callout("successfully") - expect(page).to have_css("img[src*='#{conference.attached_uploader(:hero_image).path}']") - expect(page).to have_css("img[src*='#{conference.attached_uploader(:banner_image).path}']") + hero_blob = conference.hero_image.blob + within %([data-active-uploads] [data-filename="#{hero_blob.filename}"]) do + src = page.find("img")["src"] + expect(src).to be_blob_url(hero_blob) + end + + banner_blob = conference.banner_image.blob + within %([data-active-uploads] [data-filename="#{banner_blob.filename}"]) do + src = page.find("img")["src"] + expect(src).to be_blob_url(banner_blob) + end end end diff --git a/decidim-conferences/spec/types/conference_partner_type_spec.rb b/decidim-conferences/spec/types/conference_partner_type_spec.rb index ed520780a390..e6eaf761c5ca 100644 --- a/decidim-conferences/spec/types/conference_partner_type_spec.rb +++ b/decidim-conferences/spec/types/conference_partner_type_spec.rb @@ -54,7 +54,7 @@ module Conferences let(:query) { "{ logo }" } it "returns the logo for this partner" do - expect(response["logo"]).to eq(model.attached_uploader(:logo).path) + expect(response["logo"]).to be_blob_url(model.logo.blob) end end diff --git a/decidim-conferences/spec/types/conference_speaker_type_spec.rb b/decidim-conferences/spec/types/conference_speaker_type_spec.rb index 8a211cfb3d3d..90dcd4ada946 100644 --- a/decidim-conferences/spec/types/conference_speaker_type_spec.rb +++ b/decidim-conferences/spec/types/conference_speaker_type_spec.rb @@ -70,7 +70,7 @@ module Conferences let(:query) { "{ avatar }" } it "returns the conference speaker avatar field" do - expect(response["avatar"]).to eq(model.attached_uploader(:avatar).path) + expect(response["avatar"]).to eq(model.attached_uploader(:avatar).url) end end diff --git a/decidim-conferences/spec/types/conference_type_spec.rb b/decidim-conferences/spec/types/conference_type_spec.rb index c4fa20fe80e0..e67eb77191b6 100644 --- a/decidim-conferences/spec/types/conference_type_spec.rb +++ b/decidim-conferences/spec/types/conference_type_spec.rb @@ -117,7 +117,7 @@ module Conferences let(:query) { "{ heroImage }" } it "returns the hero image field" do - expect(response["heroImage"]).to eq(model.attached_uploader(:hero_image).path) + expect(response["heroImage"]).to be_blob_url(model.hero_image.blob) end end @@ -125,7 +125,7 @@ module Conferences let(:query) { "{ bannerImage }" } it "returns the banner image field" do - expect(response["bannerImage"]).to eq(model.attached_uploader(:banner_image).path) + expect(response["bannerImage"]).to be_blob_url(model.banner_image.blob) end end diff --git a/decidim-conferences/spec/types/integration_schema_spec.rb b/decidim-conferences/spec/types/integration_schema_spec.rb index a67afde1a956..61a11184c2e8 100644 --- a/decidim-conferences/spec/types/integration_schema_spec.rb +++ b/decidim-conferences/spec/types/integration_schema_spec.rb @@ -15,14 +15,12 @@ { "attachments" => [], "availableSlots" => conference.available_slots, - "bannerImage" => conference.attached_uploader(:banner_image).path, "categories" => [], "components" => [], "createdAt" => conference.created_at.iso8601.to_s.gsub("Z", "+00:00"), "description" => { "translation" => conference.description[locale] }, "endDate" => conference.end_date.to_s, "hashtag" => conference.hashtag, - "heroImage" => conference.attached_uploader(:hero_image).path, "id" => conference.id.to_s, "location" => conference.location, "mediaLinks" => [], @@ -129,7 +127,10 @@ end it "returns the correct response" do - expect(response["conferences"].first).to eq(conference_data) + data = response["conferences"].first + expect(data).to include(conference_data) + expect(data["bannerImage"]).to be_blob_url(conference.banner_image.blob) + expect(data["heroImage"]).to be_blob_url(conference.hero_image.blob) end it_behaves_like "implements stats type" do @@ -222,7 +223,10 @@ end it "returns the correct response" do - expect(response["conference"]).to eq(conference_data) + data = response["conference"] + expect(data).to include(conference_data) + expect(data["bannerImage"]).to be_blob_url(conference.banner_image.blob) + expect(data["heroImage"]).to be_blob_url(conference.hero_image.blob) end it_behaves_like "implements stats type" do diff --git a/decidim-core/app/cells/decidim/card_g/show.erb b/decidim-core/app/cells/decidim/card_g/show.erb index 61e6cb05d3fa..a588b5276ff3 100644 --- a/decidim-core/app/cells/decidim/card_g/show.erb +++ b/decidim-core/app/cells/decidim/card_g/show.erb @@ -1,7 +1,7 @@ <%= link_to resource_path, class: classes[:default], id: resource_id do %>
<% if has_image? %> - <%= image_tag resource_image_path, alt: alt_title %> + <%= image_tag resource_image_url, alt: alt_title %> <% else %> <%= external_icon "media/images/placeholder-card-g.svg", class: "card__placeholder-g" %> <% end %> diff --git a/decidim-core/app/cells/decidim/card_g_cell.rb b/decidim-core/app/cells/decidim/card_g_cell.rb index e17ad11bc21a..b76d825bfc94 100644 --- a/decidim-core/app/cells/decidim/card_g_cell.rb +++ b/decidim-core/app/cells/decidim/card_g_cell.rb @@ -52,12 +52,15 @@ def id_base_name @id_base_name ||= resource.class.name.gsub(/\ADecidim::/, "").underscore.split("/").join("__") end - def resource_image_path + def resource_image_url + # Backwards compatibility. + return resource_image_path if respond_to?(:resource_image_path) + nil end def has_image? - resource_image_path.present? + resource_image_url.present? end def show_description? diff --git a/decidim-core/app/cells/decidim/card_l/image.erb b/decidim-core/app/cells/decidim/card_l/image.erb index 2ad37ecc8c9f..8408af8c0ccd 100644 --- a/decidim-core/app/cells/decidim/card_l/image.erb +++ b/decidim-core/app/cells/decidim/card_l/image.erb @@ -1,6 +1,6 @@
- <% if resource_image_path.present? %> - <%= image_tag resource_image_path, class: "w-full h-full object-cover" %> + <% if has_image? %> + <%= image_tag resource_image_url, class: "w-full h-full object-cover" %> <% else %>
diff --git a/decidim-core/app/cells/decidim/card_l_cell.rb b/decidim-core/app/cells/decidim/card_l_cell.rb index 601a01c6b4a3..9ad9d25076ea 100644 --- a/decidim-core/app/cells/decidim/card_l_cell.rb +++ b/decidim-core/app/cells/decidim/card_l_cell.rb @@ -66,12 +66,15 @@ def prefix_class(class_name = nil) "#{class_base_name}__#{class_name}" end - def resource_image_path + def resource_image_url + # Backwards compatibility. + return resource_image_path if respond_to?(:resource_image_path) + nil end def has_image? - resource_image_path.present? + resource_image_url.present? end def has_link_to_resource? diff --git a/decidim-core/app/cells/decidim/content_blocks/cta_cell.rb b/decidim-core/app/cells/decidim/content_blocks/cta_cell.rb index b37cd5384d99..20dff0ef3cac 100644 --- a/decidim-core/app/cells/decidim/content_blocks/cta_cell.rb +++ b/decidim-core/app/cells/decidim/content_blocks/cta_cell.rb @@ -22,7 +22,7 @@ def button_url end def background_image - model.images_container.attached_uploader(:background_image).path(variant: :big) + model.images_container.attached_uploader(:background_image).variant_url(:big) end end end diff --git a/decidim-core/app/cells/decidim/content_blocks/hero_cell.rb b/decidim-core/app/cells/decidim/content_blocks/hero_cell.rb index e1db2874a182..d01a626d41ee 100644 --- a/decidim-core/app/cells/decidim/content_blocks/hero_cell.rb +++ b/decidim-core/app/cells/decidim/content_blocks/hero_cell.rb @@ -15,7 +15,7 @@ def translated_welcome_text end def background_image - model.images_container.attached_uploader(:background_image).path(variant: :big) + model.images_container.attached_uploader(:background_image).variant_url(:big) end private diff --git a/decidim-core/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb b/decidim-core/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb index 8cad261177f6..20d6e10c4b5e 100644 --- a/decidim-core/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +++ b/decidim-core/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb @@ -1,4 +1,4 @@ -
+

diff --git a/decidim-core/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb b/decidim-core/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb index c5bb72dbe002..8847a73940f7 100644 --- a/decidim-core/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb +++ b/decidim-core/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb @@ -32,9 +32,9 @@ def subtitle_text # If it is called from the landing page content block, use the background image defined there # Else, use the banner image defined in the space (for assemblies) def image_path - return model.images_container.attached_uploader(:background_image).path if model.respond_to?(:images_container) + return model.images_container.attached_uploader(:background_image).url if model.respond_to?(:images_container) - attached_uploader(:banner_image).path + attached_uploader(:banner_image).url end def has_hashtag? diff --git a/decidim-core/app/controllers/concerns/decidim/devise_controllers.rb b/decidim-core/app/controllers/concerns/decidim/devise_controllers.rb index 15ba751a8cc1..afa1bc71cbf2 100644 --- a/decidim-core/app/controllers/concerns/decidim/devise_controllers.rb +++ b/decidim-core/app/controllers/concerns/decidim/devise_controllers.rb @@ -21,6 +21,7 @@ module DeviseControllers include Decidim::SafeRedirect include NeedsSnippets include UserBlockedChecker + include ActiveStorage::SetCurrent helper Decidim::TranslationsHelper helper Decidim::MetaTagsHelper diff --git a/decidim-core/app/controllers/decidim/application_controller.rb b/decidim-core/app/controllers/decidim/application_controller.rb index 67e0a3856c65..40bd3c53423e 100644 --- a/decidim-core/app/controllers/decidim/application_controller.rb +++ b/decidim-core/app/controllers/decidim/application_controller.rb @@ -24,6 +24,7 @@ class ApplicationController < ::DecidimController include DisableRedirectionToExternalHost include NeedsPasswordChange include LinkedResourceReference + include ActiveStorage::SetCurrent helper Decidim::MetaTagsHelper helper Decidim::DecidimFormHelper diff --git a/decidim-core/app/models/decidim/attachment.rb b/decidim-core/app/models/decidim/attachment.rb index 4d4c58d6ef0b..9352dcac4be9 100644 --- a/decidim-core/app/models/decidim/attachment.rb +++ b/decidim-core/app/models/decidim/attachment.rb @@ -84,11 +84,12 @@ def file_type # # Returns String. def url - if file? - attached_uploader(:file).path - elsif link? - link - end + @url ||= + if file? + attached_uploader(:file).url + elsif link? + link + end end # The URL to download the thumbnail of the file. Only works with images. @@ -97,7 +98,7 @@ def url def thumbnail_url return unless photo? - attached_uploader(:file).path(variant: :thumbnail) + @thumbnail_url ||= attached_uploader(:file).variant_url(:thumbnail) end # The URL to download the a big version of the file. Only works with images. @@ -106,7 +107,7 @@ def thumbnail_url def big_url return unless photo? - attached_uploader(:file).path(variant: :big) + @big_url ||= attached_uploader(:file).variant_url(:big) end def set_content_type_and_size diff --git a/decidim-core/app/models/decidim/content_block.rb b/decidim-core/app/models/decidim/content_block.rb index 1673310835c7..260358f09372 100644 --- a/decidim-core/app/models/decidim/content_block.rb +++ b/decidim-core/app/models/decidim/content_block.rb @@ -60,8 +60,8 @@ def reload(*) # # # This is how you can access the image data, just like with any other # # uploader field. You can use the uploader variants too. - # content_block.images_container.attached_uploader(:my_image).path - # content_block.images_container.attached_uploader(:my_image).path(variant: :big) + # content_block.images_container.attached_uploader(:my_image).url + # content_block.images_container.attached_uploader(:my_image).variant_url(:big) # # # This will delete the attached image # content_block.images_container.my_image = nil diff --git a/decidim-core/app/views/decidim/manifests/show.json.erb b/decidim-core/app/views/decidim/manifests/show.json.erb index e68ef8d9a52c..b8fd32b199fa 100644 --- a/decidim-core/app/views/decidim/manifests/show.json.erb +++ b/decidim-core/app/views/decidim/manifests/show.json.erb @@ -8,22 +8,22 @@ "background_color": "<%= organization_params.colors["primary"] %>", "icons": [ { - "src": "<%= current_organization.attached_uploader(:favicon).variant_path :small %>", + "src": "<%= current_organization.attached_uploader(:favicon).variant_url :small %>", "sizes": "32x32", "type": "image/png" }, { - "src": "<%= current_organization.attached_uploader(:favicon).variant_path :medium %>", + "src": "<%= current_organization.attached_uploader(:favicon).variant_url :medium %>", "sizes": "180x180", "type": "image/png" }, { - "src": "<%= current_organization.attached_uploader(:favicon).variant_path :big %>", + "src": "<%= current_organization.attached_uploader(:favicon).variant_url :big %>", "sizes": "192x192", "type": "image/png" }, { - "src": "<%= current_organization.attached_uploader(:favicon).variant_path :huge %>", + "src": "<%= current_organization.attached_uploader(:favicon).variant_url :huge %>", "sizes": "512x512", "type": "image/png" } diff --git a/decidim-core/app/views/layouts/decidim/_logo.html.erb b/decidim-core/app/views/layouts/decidim/_logo.html.erb index e1b0ccaa1c86..8968b210c5a6 100644 --- a/decidim-core/app/views/layouts/decidim/_logo.html.erb +++ b/decidim-core/app/views/layouts/decidim/_logo.html.erb @@ -1,7 +1,7 @@ <% if organization %> <%= link_to decidim.root_url(host: organization.host), "aria-label": t("front_page_link", scope: "decidim.accessibility") do %> <% if organization.logo.attached? %> - <%= image_tag organization.attached_uploader(:logo).variant_path(:medium), alt: t("logo", scope: "decidim.accessibility", organization: current_organization_name) %> + <%= image_tag organization.attached_uploader(:logo).variant_url(:medium), alt: t("logo", scope: "decidim.accessibility", organization: current_organization_name) %> <% else %> <%= current_organization_name %> <% end %> diff --git a/decidim-core/app/views/layouts/decidim/footer/_main_intro.html.erb b/decidim-core/app/views/layouts/decidim/footer/_main_intro.html.erb index 1bd2fada7cd7..e5860e20edef 100644 --- a/decidim-core/app/views/layouts/decidim/footer/_main_intro.html.erb +++ b/decidim-core/app/views/layouts/decidim/footer/_main_intro.html.erb @@ -1,6 +1,6 @@ <% if current_organization.official_img_footer.attached? %> <%= link_to current_organization.official_url, class: "block mb-6" do %> - <%= image_tag current_organization.attached_uploader(:official_img_footer).path, alt: current_organization_name, class: "max-h-16" %> + <%= image_tag current_organization.attached_uploader(:official_img_footer).url, alt: current_organization_name, class: "max-h-16" %> <% end %> <% end %>
diff --git a/decidim-core/app/views/layouts/decidim/header/_main_links_desktop.html.erb b/decidim-core/app/views/layouts/decidim/header/_main_links_desktop.html.erb index d863b7d017a3..c84471655604 100644 --- a/decidim-core/app/views/layouts/decidim/header/_main_links_desktop.html.erb +++ b/decidim-core/app/views/layouts/decidim/header/_main_links_desktop.html.erb @@ -33,7 +33,7 @@ <%= image_tag( - current_user.attached_uploader(:avatar).path(variant: :thumb), + current_user.attached_uploader(:avatar).variant_url(:thumb), alt: t("decidim.author.avatar", name: decidim_sanitize(current_user.avatar.name)) ) %> diff --git a/decidim-core/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb b/decidim-core/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb index aef9de54ab05..9d30660f460a 100644 --- a/decidim-core/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb +++ b/decidim-core/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb @@ -20,7 +20,7 @@ <% if current_user.avatar.attached? %>
<%= image_tag( - current_user.attached_uploader(:avatar).path(variant: :thumb), + current_user.attached_uploader(:avatar).variant_url(:thumb), alt: t("decidim.author.avatar", name: decidim_sanitize(current_user.avatar.name)) ) %>
diff --git a/decidim-core/app/views/layouts/decidim/header/_main_links_mobile_item_account.html.erb b/decidim-core/app/views/layouts/decidim/header/_main_links_mobile_item_account.html.erb index b8c8fd6aad03..77229e7c8725 100644 --- a/decidim-core/app/views/layouts/decidim/header/_main_links_mobile_item_account.html.erb +++ b/decidim-core/app/views/layouts/decidim/header/_main_links_mobile_item_account.html.erb @@ -6,7 +6,7 @@ <% if current_user.avatar.attached? %> <%= image_tag( - current_user.attached_uploader(:avatar).path(variant: :thumb), + current_user.attached_uploader(:avatar).variant_url(:thumb), alt: t("decidim.author.avatar", name: decidim_sanitize(current_user.avatar.name)) ) %> diff --git a/decidim-core/lib/decidim/asset_router/storage.rb b/decidim-core/lib/decidim/asset_router/storage.rb index e7d2fb0b67ee..c8f9adf843ec 100644 --- a/decidim-core/lib/decidim/asset_router/storage.rb +++ b/decidim-core/lib/decidim/asset_router/storage.rb @@ -6,6 +6,23 @@ module AssetRouter # saved through ActiveStorage. This handles the different cases for routing # to the remote routes when using an assets CDN or to local routes when # using the local disk storage driver. + # + # Note that when the assets are stored in a remote storage service, such as + # Amazon S3, Google Cloud Storage or Azure Storage, this generates the asset + # URL directly to the storage service itself bypassing the Rails server and + # saving CPU time from serving the asset redirect requests. This causes a + # significant performance improvement on pages that display a lot of images. + # It will also produce a less significant performance improvement when using + # the local disk storage because in this situation, the images are served + # using one request instead of two when served directly from the storage + # service rather than through the asset redirect URL. + # + # When implementing changes to the logic, please keep the remote storage + # options and performance implications in mind because the specs for this + # utility do not cover the remote storage options because the extra + # configuration needed to test, the service itself needed for testing and + # the extra dependency overhead for adding these remote storage gems when + # they are not needed. class Storage # Initializes the router. # @@ -13,25 +30,36 @@ class Storage # to def initialize(asset) @asset = asset + @blob = + case asset + when ActiveStorage::Blob + asset + else + asset&.blob + end end # Generates the correct URL to the asset with the provided options. # # @param options The options for the URL that are the normal route options # Rails route helpers accept - def url(**options) - if asset.is_a? ActiveStorage::Attached - routes.rails_blob_url(asset.blob, **default_options.merge(options)) - elsif asset.is_a? ActiveStorage::Blob - routes.rails_blob_url(asset, **default_options.merge(options)) - else - representation_url(**options) + # @return [String] The URL of the asset + def url(**) + case asset + when ActiveStorage::Attached + ensure_current_host(asset.record, **) + blob_url(**) + when ActiveStorage::Blob + blob_url(**) + else # ActiveStorage::VariantWithRecord, ActiveStorage::Variant + ensure_current_host(nil, **) + representation_url(**) end end private - attr_reader :asset + attr_reader :asset, :blob # Provides the route helpers depending on whether the URL is generated to # the local host or an external CDN (remote). @@ -80,24 +108,198 @@ def remote_storage_options }.compact end - # Converts the variation URLs last part to the correct file extension in - # case the variation has a different format than the original image. + # Most of the times the current host should be set through the controller + # already when the logic below is unnecessary. This logic is needed e.g. + # for serializers where the request context is not available. + # + # @param record The record for which to check the organization + # @param opts Options for building the URL + # @return [void] + def ensure_current_host(record, **opts) + return if asset_url_available? + + options = remote? ? remote_storage_options : routes.default_url_options + options = options.merge(opts) + + if opts[:host].blank? && record.present? + organization = organization_for(record) + options[:host] = organization.host if organization + end + + uri = + if options[:protocol] == "https" || options[:scheme] == "https" + URI::HTTPS.build(options) + else + URI::HTTP.build(options) + end + + ActiveStorage::Current.url_options = { host: uri.to_s } + end + + # Determines the organization for the passed record. # - # @return [String] The converted representation URL + # @param record The record for which to fetch the organization + # @return [Decidim::Organization, nil] The organization for the record or + # `nil` if the organization cannot be determined + def organization_for(record) + if record.is_a?(Decidim::Organization) + record + elsif record.respond_to?(:organization) + record.organization + end + end + + # Returns the URL for the given blob object. + # + # @param blob The blob object + # @param options Options for building the URL + # @return [String, nil] The URL to the blob object or `nil` if the blob is + # not defined. + def blob_url(**options) + return unless blob + + if options[:only_path] || remote? || !asset_url_available? + routes.rails_blob_url(blob, **default_options.merge(options)) + else + blob.url(**options) + end + end + + # Returns a representation URL for the asset either directly through the + # storage service or through the Rails representation URL in case the + # path URL is requested or if the asset variant has not been processed yet + # and is not therefore yet stored at the storage service. + # + # @return [String] The representation URL for the image variant def representation_url(**options) + return rails_representation_url(**options) if options[:only_path] || remote? + + representation_url = variant_url(**options) + return representation_url if representation_url.present? + + # In case the representation has not been processed yet, it may not have + # a representation URL yet and it therefore needs to be served through + # the local representation URL for the first time (or until it has been + # processed). + if options[:host] + rails_representation_url(**options) + else + representation_url(**options.merge(only_path: true)) + end + end + + # Returns the local Rails representation URL meaning that the asset will + # be served through the service itself. This may be necessary if the asset + # variant (e.g. a thumbnail) has not been processed yet because the + # variant representation has not been requested before. + # + # Due to performance reasons it is advised to avoid requesting the assets + # through the Rails representation URLs when possible because that causes + # a lot of requests to the Rails backend and slowness to the service under + # heavy loads. + # + # Converts the variation URLs last part to the correct file extension in + # case the variation has a different format than the original image. The + # conversion needs to be only done for the Rails representation URLs + # because once the image is stored at the storage service, it already has + # the correct file extension. + # + # @param options The options for building the URL + # @return [String, nil] The converted representation URL or `nil` if the + # asset is not defined. + def rails_representation_url(**options) + return unless asset + representation_url = routes.rails_representation_url(asset, **default_options.merge(options)) + variation = asset.try(:variation) return representation_url unless variation format = variation.try(:format) return representation_url unless format + return unless blob - original_ext = File.extname(asset.blob.filename.to_s) + original_ext = File.extname(blob.filename.to_s) return representation_url if original_ext == ".#{format}" - basename = File.basename(asset.blob.filename.to_s, original_ext) + basename = File.basename(blob.filename.to_s, original_ext) representation_url.sub(/#{basename}\.#{original_ext.tr(".", "")}$/, "#{basename}.#{format}") end + + # Fetches the image variant's URL at the storage service if the variant + # has already been processed and is stored at the storage service. If the + # variant has not been processed yet, returns `nil` in which case the + # variant has to be served through the service's own representation URL + # causing it to be processed and stored at the storage service. + # + # @param options The options for building the URL + # @return [String, nil] The variant URL at the storage service or `nil` if + # the variant has not been processed yet and does not yet exist at the + # storage service or `nil` when the asset is not defined + def variant_url(**options) + return unless asset + return unless asset_url_available? + return unless asset_exist? + + case asset + when ActiveStorage::VariantWithRecord + # This is used when `ActiveStorage.track_variants` is enabled through + # `config.active_storage.track_variants`. In case the variant has not + # been processed yet, the `#url` method would return nil. + # + # Note that if the `asset.processed?` returns `true`, the variant + # record has been created in the database but it does not mean that + # it has been uploaded to the storage service yet. Likely a bug in + # ActiveStorage but to be sure that the asset is uploaded to the + # storage service, we also check that. + asset.url(**options) if asset.processed? + else # ActiveStorage::Variant + # Check whether the variant exists at the storage service before + # returning its URL. Otherwise the URL would be returned even when the + # variant is not yet processed causing 404 errors for the images on + # the page. + # + # Note that the `ActiveStorage::Variant#url` method only accepts + # certain keyword arguments where as the other objects allow any + # keyword arguments. + possible_kwargs = asset.method(:url).parameters.select { |p| p[0] == :key }.map { |p| p[1] } + asset.url(**options.slice(*possible_kwargs)) + end + end + + # Determines if the asset exists at the storage service. + # + # @return [Boolean] A boolean answering the question "does this asset + # exist at the storage service?". + def asset_exist? + return false if asset.key.blank? + + blob.service.exist?(asset.key) + end + + # Determines if the current host is required to build the asset URL. + # + # @return [Boolean] A boolean indicating if the current host is required + # to build the asset URL. + def current_host_required? + return false unless blob + + blob.service.is_a?(ActiveStorage::Service::DiskService) + end + + # Determines if the asset URL can be generated. + # + # @return [Boolean] A boolean indicating if the asset URL can be + # generated. + def asset_url_available? + # If the service is an external service, the URL can be generated + # regardless of the current host being set. + return true unless current_host_required? + + # For the disk service, the URL can be only generated if the current + # host has been set. + ActiveStorage::Current.url_options&.dig(:host).present? + end end end end diff --git a/decidim-core/lib/decidim/core/test/shared_examples/attachable_interface_examples.rb b/decidim-core/lib/decidim/core/test/shared_examples/attachable_interface_examples.rb index 0269f7ef4194..527c30d8b23e 100644 --- a/decidim-core/lib/decidim/core/test/shared_examples/attachable_interface_examples.rb +++ b/decidim-core/lib/decidim/core/test/shared_examples/attachable_interface_examples.rb @@ -10,7 +10,7 @@ it "includes the attachment urls" do attachment_urls = response["attachments"].map { |attachment| attachment["url"] } - expect(attachment_urls).to include(*attachments.map(&:url)) + expect(attachment_urls).to include_blob_urls(*attachments.map(&:file).map(&:blob)) end end end diff --git a/decidim-core/spec/cells/decidim/content_blocks/hero_cell_spec.rb b/decidim-core/spec/cells/decidim/content_blocks/hero_cell_spec.rb index 69dbe2da4a49..fbaa84fc601b 100644 --- a/decidim-core/spec/cells/decidim/content_blocks/hero_cell_spec.rb +++ b/decidim-core/spec/cells/decidim/content_blocks/hero_cell_spec.rb @@ -44,7 +44,7 @@ end it "uses that image's big version as background" do - expect(subject.to_s).to include(content_block.images_container.attached_uploader(:background_image).path(variant: :big)) + expect(subject.to_s).to include(content_block.images_container.attached_uploader(:background_image).variant_url(:big)) end end diff --git a/decidim-core/spec/cells/decidim/content_blocks/participatory_space_hero_cell_spec.rb b/decidim-core/spec/cells/decidim/content_blocks/participatory_space_hero_cell_spec.rb index 8bef65ac6116..e03a269c0b1e 100644 --- a/decidim-core/spec/cells/decidim/content_blocks/participatory_space_hero_cell_spec.rb +++ b/decidim-core/spec/cells/decidim/content_blocks/participatory_space_hero_cell_spec.rb @@ -78,7 +78,9 @@ end it "uses that image's big version as background" do - expect(subject.to_s).to include(content_block.images_container.attached_uploader(:background_image).path(variant: :big)) + style = subject.find("section")["style"] + background_url = style.match(/background-image:url\('([^']+)'\)/)[1] + expect(background_url).to be_blob_url(content_block.images_container.background_image.blob) end end end diff --git a/decidim-core/spec/lib/asset_router/storage_spec.rb b/decidim-core/spec/lib/asset_router/storage_spec.rb index 0599affee5b4..7c006394f810 100644 --- a/decidim-core/spec/lib/asset_router/storage_spec.rb +++ b/decidim-core/spec/lib/asset_router/storage_spec.rb @@ -17,15 +17,30 @@ module Decidim::AssetRouter let(:default_port) { Capybara.server_port } context "with an ActiveStorage::Attached" do - it "creates the route to the blob" do - expect(subject).to match(%r{^http://localhost:#{default_port}/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + it "creates the disk service route to the blob" do + ActiveStorage::Current.url_options = { host: "http://localhost:#{default_port}" } + expect(subject).to match(%r{^http://localhost:#{default_port}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) end - context "with extra URL options" do - let(:options) { { port: nil, host: "custom.host", utm_source: "website", utm_medium: "email", utm_campaign: "testing" } } + context "when the host is not set" do + it "sets the host based on the asset" do + expect(subject).to match(%r{^http://#{organization.host}:#{default_port}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) + end + end - it "handles the extra URL options correctly" do - expect(subject).to match(%r{^http://custom.host/rails/active_storage/blobs/redirect/.*/avatar.jpg\?utm_campaign=testing&utm_medium=email&utm_source=website$}) + context "when requesting the local redirect path to the asset" do + let(:options) { { only_path: true } } + + it "creates the redirect route to the blob" do + expect(subject).to match(%r{^/rails/active_storage/blobs/redirect/[^/]+/avatar\.jpg$}) + end + + context "with extra URL options" do + let(:options) { { only_path: true, utm_source: "website", utm_medium: "email", utm_campaign: "testing" } } + + it "handles the extra URL options correctly" do + expect(subject).to match(%r{^/rails/active_storage/blobs/redirect/[^/]+/avatar\.jpg\?utm_campaign=testing&utm_medium=email&utm_source=website$}) + end end end end @@ -33,25 +48,143 @@ module Decidim::AssetRouter context "with an ActiveStorage::Blob" do let(:asset) { organization.official_img_footer.blob } - it "creates the route to the blob" do - expect(subject).to match(%r{^http://localhost:#{default_port}/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + it "creates the disk service route to the blob" do + ActiveStorage::Current.url_options = { host: "http://localhost:#{default_port}" } + expect(subject).to match(%r{^http://localhost:#{default_port}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) end - context "with extra URL options" do - let(:options) { { port: nil, host: "custom.host", utm_source: "website", utm_medium: "email", utm_campaign: "testing" } } + context "when the host is not set" do + it "creates the redirect route to the blob" do + expect(subject).to match(%r{^http://localhost:#{default_port}/rails/active_storage/blobs/redirect/[^/]+/avatar\.jpg$}) + end + end - it "handles the extra URL options correctly" do - expect(subject).to match(%r{^http://custom.host/rails/active_storage/blobs/redirect/.*/avatar.jpg\?utm_campaign=testing&utm_medium=email&utm_source=website$}) + context "when requesting the local redirect path to the asset" do + let(:options) { { only_path: true } } + + it "creates the redirect route to the blob" do + expect(subject).to match(%r{^/rails/active_storage/blobs/redirect/[^/]+/avatar\.jpg$}) + end + + context "with extra URL options" do + let(:options) { { only_path: true, utm_source: "website", utm_medium: "email", utm_campaign: "testing" } } + + it "handles the extra URL options correctly" do + expect(subject).to match(%r{^/rails/active_storage/blobs/redirect/[^/]+/avatar\.jpg\?utm_campaign=testing&utm_medium=email&utm_source=website$}) + end end end end context "with a variant" do let(:asset) { organization.official_img_footer.variant(resize_to_fit: [160, 160]) } + let(:track_variants) { true } + + before do + # This is typically set through `config.active_storage.track_variants` + # and for test environment it seems to be enabled by default at the + # time of writing these specs. This config is overridden for these + # specs because the default configurations may be changed through + # other changes or gem updates. + allow(ActiveStorage).to receive(:track_variants).and_return(track_variants) + end it "creates the route to the variant" do - expect(subject).to match(%r{^http://localhost:#{default_port}/rails/active_storage/representations/redirect/.*/avatar.jpg$}) + expect(subject).to match(%r{^/rails/active_storage/representations/redirect/[^/]+/[^/]+/avatar\.jpg$}) + end + + context "when the asset has been processed" do + before { asset.processed } + + it "creates the route to the variant through the storage service" do + expect(subject).to match(%r{^http://localhost:#{default_port}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) + end + + # Note that this situation should not normally happen but it is + # possible e.g. if the backend has created the variant record in the + # database but has not yet uploaded the asset to the storage service. + context "and does not exist at the storage service" do + before do + path = asset.blob.service.path_for(asset.key) + File.delete(path) + end + + it "creates the redirect route to the variant" do + expect(asset.processed?).to be(true) + expect(asset.key).to be_present + expect(asset.blob.service.exist?(asset.key)).to be(false) + expect(subject).to match(%r{^/rails/active_storage/representations/redirect/[^/]+/[^/]+/avatar\.jpg$}) + end + end end + + context "when track_variants is disabled" do + let(:track_variants) { false } + + it "creates the route to the variant" do + expect(subject).to match(%r{^/rails/active_storage/representations/redirect/[^/]+/[^/]+/avatar\.jpg$}) + end + + context "and the asset has been processed" do + before { asset.processed } + + it "creates the route to the variant through the storage service" do + expect(subject).to match(%r{^http://localhost:#{default_port}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) + end + + context "and when passing incompatible URL options" do + # The `:host` option is passed e.g. in many mailers. + # `ActiveStorage::Variant#url` method does not allow this argument + # which is why this test is testing that it does not lead to an + # error. + let(:options) { { host: "example.lvh.me" } } + + it "creates the route to the variant" do + expect(subject).to match(%r{^http://example\.lvh\.me:#{default_port}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) + end + end + end + end + + context "when the variant has a different file extension" do + let(:asset) { organization.official_img_footer.variant(resize_to_fit: [160, 160], format: "png") } + + it "creates the route to the variant with converted file extension" do + expect(subject).to match(%r{^/rails/active_storage/representations/redirect/[^/]+/[^/]+/avatar\.png$}) + end + + context "when the asset has been processed" do + before { asset.processed } + + it "creates the route to the variant through the storage service" do + expect(subject).to match(%r{^http://localhost:#{default_port}/rails/active_storage/disk/[^/]+/avatar\.png$}) + end + end + + context "when track_variants is disabled" do + let(:track_variants) { false } + + it "creates the route to the variant with converted file extension" do + expect(subject).to match(%r{^/rails/active_storage/representations/redirect/[^/]+/[^/]+/avatar\.png$}) + end + + context "and the asset has been processed" do + before { asset.processed } + + it "creates the route to the variant through the storage service" do + expect(subject).to match(%r{^http://localhost:#{default_port}/rails/active_storage/disk/[^/]+/avatar\.png$}) + end + end + end + end + end + + # This is used by the generator specs to check that some default + # configurations are set correctly. + context "with nil" do + let(:asset) { nil } + + it { is_expected.to be_nil } end context "when the CDN host is defined" do @@ -61,14 +194,14 @@ module Decidim::AssetRouter end it "creates the route to the CDN blob" do - expect(subject).to match(%r{^https://cdn.example.org/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + expect(subject).to match(%r{^https://cdn\.example\.org/rails/active_storage/blobs/redirect/[^/]+/avatar\.jpg$}) end context "with extra URL options" do let(:options) { { utm_source: "website", utm_medium: "email", utm_campaign: "testing" } } it "handles the extra URL options correctly" do - expect(subject).to match(%r{^https://cdn.example.org/rails/active_storage/blobs/redirect/.*/avatar.jpg\?utm_campaign=testing&utm_medium=email&utm_source=website$}) + expect(subject).to match(%r{^https://cdn\.example\.org/rails/active_storage/blobs/redirect/[^/]+/avatar\.jpg\?utm_campaign=testing&utm_medium=email&utm_source=website$}) end end end diff --git a/decidim-core/spec/lib/upgrade/wysiwyg_migrator_spec.rb b/decidim-core/spec/lib/upgrade/wysiwyg_migrator_spec.rb index b6f240dbdf4a..30168bbc1fe4 100644 --- a/decidim-core/spec/lib/upgrade/wysiwyg_migrator_spec.rb +++ b/decidim-core/spec/lib/upgrade/wysiwyg_migrator_spec.rb @@ -9,6 +9,7 @@ module Decidim let(:organization) { create(:organization) } let(:component) { create(:component, organization:) } let(:image) { create(:attachment, attached_to: organization) } + let(:image_path) { image.attached_uploader(:file).path } let(:content) { original_content } let(:original_content) do @@ -46,10 +47,10 @@ module Decidim

Paragraph content with an inline image. - + And some text after that.

-

This image had an alternative text

+

This image had an alternative text

Here we had some unrecognized node.
Blockquote element content
should be wrapped inside a paragraph.
@@ -151,11 +152,11 @@ module Decidim

Paragraph content with an inline image.

- +

And some text after that.

- This image had an alternative text + This image had an alternative text
diff --git a/decidim-core/spec/models/decidim/content_block_spec.rb b/decidim-core/spec/models/decidim/content_block_spec.rb index 21bb18966694..8e3ee29f677a 100644 --- a/decidim-core/spec/models/decidim/content_block_spec.rb +++ b/decidim-core/spec/models/decidim/content_block_spec.rb @@ -25,7 +25,7 @@ module Decidim context "when the image has not been uploaded" do it "returns nil" do - expect(subject.images_container.attached_uploader(:background_image).path).to be_nil + expect(subject.images_container.attached_uploader(:background_image).url).to be_nil end end @@ -46,7 +46,7 @@ module Decidim it "returns the image" do expect(subject.images_container.background_image.attached?).to be true - expect(subject.images_container.attached_uploader(:background_image).path).not_to be_nil + expect(subject.images_container.attached_uploader(:background_image).url).not_to be_nil end end diff --git a/decidim-core/spec/types/user_group_type_spec.rb b/decidim-core/spec/types/user_group_type_spec.rb index a54a4f61972d..e753c09b5228 100644 --- a/decidim-core/spec/types/user_group_type_spec.rb +++ b/decidim-core/spec/types/user_group_type_spec.rb @@ -38,7 +38,7 @@ module Core let(:query) { "{ avatarUrl }" } it "returns the user avatar url" do - expect(response).to include("avatarUrl" => model.attached_uploader(:avatar).path) + expect(response["avatarUrl"]).to be_blob_url(model.avatar.blob) end end diff --git a/decidim-core/spec/types/user_type_spec.rb b/decidim-core/spec/types/user_type_spec.rb index 79613a22a8c2..bf734001ce4b 100644 --- a/decidim-core/spec/types/user_type_spec.rb +++ b/decidim-core/spec/types/user_type_spec.rb @@ -50,7 +50,7 @@ module Core let(:query) { "{ avatarUrl }" } it "returns the user avatar url (small version)" do - expect(response).to include("avatarUrl" => model.attached_uploader(:avatar).path(variant: :thumb)) + expect(response).to include("avatarUrl" => model.attached_uploader(:avatar).variant_url(:thumb)) end end diff --git a/decidim-core/spec/uploaders/application_uploader_spec.rb b/decidim-core/spec/uploaders/application_uploader_spec.rb index 7a9a9c8b2830..8e8e8596425a 100644 --- a/decidim-core/spec/uploaders/application_uploader_spec.rb +++ b/decidim-core/spec/uploaders/application_uploader_spec.rb @@ -7,6 +7,7 @@ module Decidim subject { described_class.new(model, mounted_as) } let(:model) { create(:organization) } + let(:hostname) { model.host } let(:mounted_as) { :official_img_footer } before do @@ -48,21 +49,21 @@ module Decidim let(:default_port) { Rails.env.development? ? 3000 : Capybara.server_port } it "returns a URL containing the port only" do - expect(subject.variant_url(:testing)).to match(%r{^http://localhost:#{default_port}/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + expect(subject.variant_url(:testing)).to match(%r{^http://#{Regexp.escape(hostname)}:#{default_port}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) end context "when force_ssl is enabled" do include_context "with force_ssl enabled" it "returns a URL containing the port and protocol" do - expect(subject.variant_url(:testing)).to match(%r{^https://localhost:#{default_port}/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + expect(subject.variant_url(:testing)).to match(%r{^https://#{Regexp.escape(hostname)}:#{default_port}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) end context "and the PORT environment variable is defined as 3001" do let(:local_port) { 3001 } it "returns a URL containing the port and protocol" do - expect(subject.variant_url(:testing)).to match(%r{^https://localhost:3001/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + expect(subject.variant_url(:testing)).to match(%r{^https://#{Regexp.escape(hostname)}:3001/rails/active_storage/disk/[^/]+/avatar\.jpg$}) end end @@ -70,7 +71,7 @@ module Decidim let(:local_port) { 443 } it "returns a URL containing the protocol only" do - expect(subject.variant_url(:testing)).to match(%r{^https://localhost/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + expect(subject.variant_url(:testing)).to match(%r{^https://#{Regexp.escape(hostname)}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) end end end @@ -87,7 +88,7 @@ module Decidim end it "returns a URL to the variant" do - expect(subject.variant_url(:testing)).to match(%r{^http://localhost:#{default_port}/rails/active_storage/representations/redirect/.*/avatar.jpg$}) + expect(subject.variant_url(:testing)).to match(%r{^/rails/active_storage/representations/redirect/[^/]+/[^/]+/avatar\.jpg$}) end context "when the provided file is invariable" do @@ -96,7 +97,7 @@ module Decidim end it "returns the original URL" do - expect(subject.variant_url(:testing)).to match(%r{^http://localhost:#{default_port}/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + expect(subject.variant_url(:testing)).to match(%r{^http://#{Regexp.escape(hostname)}:#{default_port}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) end end end @@ -113,7 +114,15 @@ module Decidim end it "returns a URL to the variant with the correct extension" do - expect(subject.variant_url(:testing)).to match(%r{^http://localhost:#{default_port}/rails/active_storage/representations/redirect/.*/avatar.png$}) + expect(subject.variant_url(:testing)).to match(%r{^/rails/active_storage/representations/redirect/[^/]+/[^/]+/avatar\.png$}) + end + + context "and the variant has been processed" do + before { subject.variant(:testing).process } + + it "returns a URL to the variant with the correct extension" do + expect(subject.variant_url(:testing)).to match(%r{^http://localhost:#{default_port}/rails/active_storage/disk/[^/]+/avatar\.png$}) + end end end end @@ -132,6 +141,7 @@ module Decidim context "with production environment" do let(:hostname) { "production.decidim.test" } + let(:options) { { host: hostname } } before do allow(Rails.env).to receive(:development?).and_return(false) @@ -139,14 +149,14 @@ module Decidim end it "returns a default URL" do - expect(subject.variant_url(:testing)).to match(%r{^http://production.decidim.test/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + expect(subject.variant_url(:testing, options)).to match(%r{^http://#{Regexp.escape(hostname)}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) end context "and the PORT environment variable is defined as 443" do let(:local_port) { 443 } it "returns a URL containing the protocol only" do - expect(subject.variant_url(:testing)).to match(%r{^https://production.decidim.test/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + expect(subject.variant_url(:testing, options)).to match(%r{^https://#{Regexp.escape(hostname)}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) end end @@ -154,7 +164,7 @@ module Decidim let(:local_port) { 8080 } it "returns a URL containing the port" do - expect(subject.variant_url(:testing)).to match(%r{^http://production.decidim.test:8080/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + expect(subject.variant_url(:testing, options)).to match(%r{^http://#{Regexp.escape(hostname)}:8080/rails/active_storage/disk/[^/]+/avatar\.jpg$}) end end @@ -162,14 +172,14 @@ module Decidim include_context "with force_ssl enabled" it "returns a URL containing the protocol only" do - expect(subject.variant_url(:testing)).to match(%r{^https://production.decidim.test/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + expect(subject.variant_url(:testing, options)).to match(%r{^https://#{Regexp.escape(hostname)}/rails/active_storage/disk/[^/]+/avatar\.jpg$}) end context "and the PORT environment variable is defined as 8080" do let(:local_port) { 8080 } it "returns a URL containing the port and protocol" do - expect(subject.variant_url(:testing)).to match(%r{^https://production.decidim.test:8080/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + expect(subject.variant_url(:testing, options)).to match(%r{^https://#{Regexp.escape(hostname)}:8080/rails/active_storage/disk/[^/]+/avatar\.jpg$}) end end end @@ -190,7 +200,7 @@ module Decidim end it "returns a URL containing the CDN configurations" do - expect(subject.variant_url(:testing)).to match(%r{^https://cdn.example.org/rails/active_storage/blobs/redirect/.*/avatar.jpg$}) + expect(subject.variant_url(:testing)).to match(%r{^#{Regexp.escape(cdn_host)}/rails/active_storage/blobs/redirect/[^/]+/avatar\.jpg$}) end end end diff --git a/decidim-dev/lib/decidim/dev/test/rspec_support/activestorage_matchers.rb b/decidim-dev/lib/decidim/dev/test/rspec_support/activestorage_matchers.rb new file mode 100644 index 000000000000..170f43dea3f7 --- /dev/null +++ b/decidim-dev/lib/decidim/dev/test/rspec_support/activestorage_matchers.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +module ActiveStorageMatchers + def be_blob_url(expected) + BeBlobUrl.new(expected) + end + + def include_blob_urls(*expected) + IncludeBlobUrls.new(expected) + end + + class BlobMatch + BLOB_URL_MATCHERS = { + redirect: %r{/rails/active_storage/blobs/redirect/([^/]+)/([^/]+)$}, + representation: %r{/rails/active_storage/representations/redirect/([^/]+)/([^/]+)/([^/]+)$}, + disk: %r{/rails/active_storage/disk/([^/]+)/([^/]+)$} + }.freeze + + def initialize(url) + @url = url + end + + def blob + return unless key_match + + @blob ||= + case url_type + when :redirect, :representation + ActiveStorage::Blob.find_signed(key_match) + when :disk + decoded = ActiveStorage.verifier.verified(key_match, purpose: :blob_key) + ActiveStorage::Blob.find_by(key: decoded[:key]) if decoded + end + end + + def variation + return unless variation_match + + blob.representation(variation_match) + end + + def key_match + return unless match + + match[1] + end + + def variation_match + return unless match + + match[2] if url_type == :representation + end + + def filename_match + return unless match + + case url_type + when :representation + match[3] + else + match[2] + end + end + + private + + attr_reader :url, :url_type + + def match + return @match if @url_type + + @url_type = :none + @match = nil + BLOB_URL_MATCHERS.each do |type, matcher| + @match = url.match(matcher) + if @match + @url_type = type + break + end + end + + @match + end + end + + class BeBlobUrl + def initialize(expected) + @expected = expected + end + + def description + "be a blob URL" + end + + def matches?(actual) + @actual = actual + match = BlobMatch.new(actual) + match.blob == expected + end + + def failure_message + "expected #{actual} to match blob with ID #{expected.id}" + end + + def failure_message_when_negated + "expected #{actual} not to match blob with ID #{expected.id}" + end + + private + + attr_reader :expected, :actual + end + + class IncludeBlobUrls + def initialize(expected) + @expected = expected + end + + def description + "include blob URLs" + end + + def matches?(actual) + @actual = actual + + actual.all? do |url| + match = BlobMatch.new(url) + expected.include?(match.blob) + end + end + + def failure_message + "expected #{actual.inspect} to match blobs with ID #{expected.map(&:id).join(", ")}" + end + + def failure_message_when_negated + "expected #{actual.inspect} not to match blobs with ID #{expected.map(&:id).join(", ")}" + end + + private + + attr_reader :expected, :actual + end +end + +RSpec.configure do |config| + config.include ActiveStorageMatchers +end diff --git a/decidim-dev/lib/decidim/dev/test/spec_helper.rb b/decidim-dev/lib/decidim/dev/test/spec_helper.rb index d22822c11cc6..3a371add381a 100644 --- a/decidim-dev/lib/decidim/dev/test/spec_helper.rb +++ b/decidim-dev/lib/decidim/dev/test/spec_helper.rb @@ -45,4 +45,11 @@ "connect-src": %W(#{Decidim::Dev::Test::MapServer.host}) } end + + config.before do + # Ensure that the current host is not set for any spec in order to test that + # the automatic current host definition is working correctly in all + # situations. + ActiveStorage::Current.url_options = {} + end end diff --git a/decidim-forms/spec/presenters/decidim/admin/questionnaire_answer_presenter_spec.rb b/decidim-forms/spec/presenters/decidim/admin/questionnaire_answer_presenter_spec.rb index d17a91a260be..bc3d057f5292 100644 --- a/decidim-forms/spec/presenters/decidim/admin/questionnaire_answer_presenter_spec.rb +++ b/decidim-forms/spec/presenters/decidim/admin/questionnaire_answer_presenter_spec.rb @@ -79,14 +79,28 @@ module Decidim let!(:attachment) { create(:attachment, :with_image, attached_to: answer) } it "returns the download attachment link" do - expect(subject.body).to eq(%()) + regexp = %r{^} + expect(subject.body).to match(regexp) + + match = subject.body.match(regexp) + href = match[2] + inner = match[3] + + expect(inner).to eq(%(#{decidim_escape_translated(attachment.title)} jpeg 105 KB)) + expect(href).to be_blob_url(attachment.file.blob) end context "when the attachment does not have a title" do let!(:attachment) { create(:attachment, :with_image, attached_to: answer, title: {}, description: {}) } it "returns the download attachment link" do - expect(subject.body).to eq(%()) + regexp = %r{^$} + expect(subject.body).to match(regexp) + + match = subject.body.match(regexp) + href = match[1] + + expect(href).to be_blob_url(attachment.file.blob) end end end diff --git a/decidim-forms/spec/serializers/decidim/forms/user_answers_serializer_spec.rb b/decidim-forms/spec/serializers/decidim/forms/user_answers_serializer_spec.rb index 1bd0cdeeef34..cc3b00849e21 100644 --- a/decidim-forms/spec/serializers/decidim/forms/user_answers_serializer_spec.rb +++ b/decidim-forms/spec/serializers/decidim/forms/user_answers_serializer_spec.rb @@ -85,7 +85,7 @@ module Forms [key, choices.map { |choice| choice&.body }] end - serialized_files_answer = files_answer.attachments.map(&:url) + serialized_files_blobs = files_answer.attachments.map(&:file).map(&:blob) expect(serialized).to include( "#{multichoice_question.position + 1}. #{translated(multichoice_question.body, locale: I18n.locale)}" => [multichoice_answer_choices.first.body, multichoice_answer_choices.last.body] @@ -99,8 +99,8 @@ module Forms "#{matrixmultiple_question.position + 1}. #{translated(matrixmultiple_question.body, locale: I18n.locale)}" => serialized_matrix_answer ) - expect(serialized).to include( - "#{files_question.position + 1}. #{translated(files_question.body, locale: I18n.locale)}" => serialized_files_answer + expect(serialized["#{files_question.position + 1}. #{translated(files_question.body, locale: I18n.locale)}"]).to include_blob_urls( + *serialized_files_blobs ) end diff --git a/decidim-forms/spec/services/decidim/forms/download_your_data_user_answer_serializer_spec.rb b/decidim-forms/spec/services/decidim/forms/download_your_data_user_answer_serializer_spec.rb index 3ed4412bf070..0635a2a381be 100644 --- a/decidim-forms/spec/services/decidim/forms/download_your_data_user_answer_serializer_spec.rb +++ b/decidim-forms/spec/services/decidim/forms/download_your_data_user_answer_serializer_spec.rb @@ -62,7 +62,7 @@ module Forms end it "includes the answer" do - expect(serialized).to include(answer: answer.attachments.map(&:url)) + expect(serialized[:answer]).to include_blob_urls(*answer.attachments.map(&:file).map(&:blob)) end end diff --git a/decidim-initiatives/app/cells/decidim/initiatives/initiative_g_cell.rb b/decidim-initiatives/app/cells/decidim/initiatives/initiative_g_cell.rb index 49000ab12be7..21ee8fbfc88f 100644 --- a/decidim-initiatives/app/cells/decidim/initiatives/initiative_g_cell.rb +++ b/decidim-initiatives/app/cells/decidim/initiatives/initiative_g_cell.rb @@ -11,16 +11,14 @@ def resource_path Decidim::Initiatives::Engine.routes.url_helpers.initiative_path(model) end - def has_image? - image.present? - end - def image @image ||= model.attachments.find(&:image?) end - def resource_image_path - image.url if has_image? + def resource_image_url + return if image.blank? + + image.url end def metadata_cell diff --git a/decidim-initiatives/app/views/decidim/initiatives/committee_requests/new.html.erb b/decidim-initiatives/app/views/decidim/initiatives/committee_requests/new.html.erb index d46ef8ada56d..c57c329da669 100644 --- a/decidim-initiatives/app/views/decidim/initiatives/committee_requests/new.html.erb +++ b/decidim-initiatives/app/views/decidim/initiatives/committee_requests/new.html.erb @@ -1,12 +1,12 @@ <% add_decidim_meta_tags({ - image_url: current_initiative.type.attached_uploader(:banner_image).path, + image_url: current_initiative.type.attached_uploader(:banner_image).url, description: translated_attribute(current_initiative.description), title: translated_attribute(current_initiative.title), url: initiative_url(current_initiative.id) }) %> <% add_decidim_page_title(translated_attribute(current_initiative.title)) %> -<% provide :meta_image_url, current_initiative.type.attached_uploader(:banner_image).path %> +<% provide :meta_image_url, current_initiative.type.attached_uploader(:banner_image).url %> <%= render layout: "layouts/decidim/shared/layout_center" do %>
diff --git a/decidim-initiatives/app/views/decidim/initiatives/initiatives/print.html.erb b/decidim-initiatives/app/views/decidim/initiatives/initiatives/print.html.erb index 324813412987..0e17fa89030b 100644 --- a/decidim-initiatives/app/views/decidim/initiatives/initiatives/print.html.erb +++ b/decidim-initiatives/app/views/decidim/initiatives/initiatives/print.html.erb @@ -2,7 +2,7 @@
<% if current_organization.logo.present? %> - <%= image_tag current_organization.attached_uploader(:logo).path(variant: :medium), title: current_organization_name %> + <%= image_tag current_organization.attached_uploader(:logo).variant_url(:medium), title: current_organization_name %> <% end %> <%= current_organization_name %> diff --git a/decidim-initiatives/app/views/decidim/initiatives/initiatives/show.html.erb b/decidim-initiatives/app/views/decidim/initiatives/initiatives/show.html.erb index e1f5d5ee1119..46b35d2c57a4 100644 --- a/decidim-initiatives/app/views/decidim/initiatives/initiatives/show.html.erb +++ b/decidim-initiatives/app/views/decidim/initiatives/initiatives/show.html.erb @@ -1,5 +1,5 @@ <% add_decidim_meta_tags({ - image_url: current_initiative.type.attached_uploader(:banner_image).path, + image_url: current_initiative.type.attached_uploader(:banner_image).url, description: translated_attribute(current_initiative.description), title: translated_attribute(current_initiative.title), url: initiative_url(current_initiative.id) diff --git a/decidim-initiatives/app/views/layouts/decidim/_initiative_header.html.erb b/decidim-initiatives/app/views/layouts/decidim/_initiative_header.html.erb index f098bce3296d..c91068db1bbb 100644 --- a/decidim-initiatives/app/views/layouts/decidim/_initiative_header.html.erb +++ b/decidim-initiatives/app/views/layouts/decidim/_initiative_header.html.erb @@ -1,7 +1,7 @@
+ style="background-image:url('<%= current_participatory_space.type.attached_uploader(:banner_image).url %>');">
diff --git a/decidim-initiatives/app/views/layouts/decidim/initiative.html.erb b/decidim-initiatives/app/views/layouts/decidim/initiative.html.erb index 16c36ff60024..a49d60de5d8a 100644 --- a/decidim-initiatives/app/views/layouts/decidim/initiative.html.erb +++ b/decidim-initiatives/app/views/layouts/decidim/initiative.html.erb @@ -1,7 +1,7 @@ <%= append_javascript_pack_tag "decidim_initiatives" %> <%= append_stylesheet_pack_tag "decidim_initiatives", media: "all" %> -<% provide :meta_image_url, current_participatory_space.type.attached_uploader(:banner_image).path %> +<% provide :meta_image_url, current_participatory_space.type.attached_uploader(:banner_image).url %> <%= render "layouts/decidim/application" do %> <%= render layout: "layouts/decidim/shared/layout_center" do %> diff --git a/decidim-initiatives/app/views/layouts/decidim/initiative_head.html.erb b/decidim-initiatives/app/views/layouts/decidim/initiative_head.html.erb index 0a59ea4ea6e3..2a644271e767 100644 --- a/decidim-initiatives/app/views/layouts/decidim/initiative_head.html.erb +++ b/decidim-initiatives/app/views/layouts/decidim/initiative_head.html.erb @@ -1,7 +1,7 @@ <%= append_javascript_pack_tag "decidim_initiatives" %> <%= append_stylesheet_pack_tag "decidim_initiatives", media: "all" %> -<% provide :meta_image_url, current_initiative.type.attached_uploader(:banner_image).path %> +<% provide :meta_image_url, current_initiative.type.attached_uploader(:banner_image).url %> <%= render partial: "layouts/decidim/header/follow_space_menu_bar_button", locals: { participatory_space: current_participatory_space } %> diff --git a/decidim-initiatives/lib/decidim/api/initiative_api_type.rb b/decidim-initiatives/lib/decidim/api/initiative_api_type.rb index 05cacdbecbd5..63cb06cd8274 100644 --- a/decidim-initiatives/lib/decidim/api/initiative_api_type.rb +++ b/decidim-initiatives/lib/decidim/api/initiative_api_type.rb @@ -23,7 +23,7 @@ class InitiativeApiType < Decidim::Api::Types::BaseObject field :initiatives, [Decidim::Initiatives::InitiativeType, { null: true }], "The initiatives that have this type", null: false def banner_image - object.attached_uploader(:banner_image).path + object.attached_uploader(:banner_image).url end end end diff --git a/decidim-initiatives/spec/types/initiative_api_type_spec.rb b/decidim-initiatives/spec/types/initiative_api_type_spec.rb index e60e8b67d6e9..b735f1bcc43a 100644 --- a/decidim-initiatives/spec/types/initiative_api_type_spec.rb +++ b/decidim-initiatives/spec/types/initiative_api_type_spec.rb @@ -54,7 +54,7 @@ module Initiatives let(:query) { "{ bannerImage }" } it "returns the banner image field" do - expect(response["bannerImage"]).to eq(model.attached_uploader(:banner_image).path) + expect(response["bannerImage"]).to be_blob_url(model.banner_image.blob) end end diff --git a/decidim-initiatives/spec/types/integration_schema_spec.rb b/decidim-initiatives/spec/types/integration_schema_spec.rb index 8a19a8c24edd..7e1f227087ab 100644 --- a/decidim-initiatives/spec/types/integration_schema_spec.rb +++ b/decidim-initiatives/spec/types/integration_schema_spec.rb @@ -29,22 +29,6 @@ "description" => { "translation" => initiative.description[locale] }, "hashtag" => initiative.hashtag, "id" => initiative.id.to_s, - "initiativeType" => { - "bannerImage" => initiative.type.attached_uploader(:banner_image).path, - "collectUserExtraFields" => initiative.type.collect_user_extra_fields?, - "createdAt" => initiative.type.created_at.iso8601.to_s.gsub("Z", "+00:00"), - "description" => { "translation" => initiative.type.description[locale] }, - "extraFieldsLegalInformation" => initiative.type.extra_fields_legal_information, - "id" => initiative.type.id.to_s, - "initiatives" => initiative.type.initiatives.map { |i| { "id" => i.id.to_s } }, - "minimumCommitteeMembers" => initiative.type.minimum_committee_members, - "promotingCommitteeEnabled" => initiative.type.promoting_committee_enabled, - "signatureType" => initiative.type.signature_type, - "title" => { "translation" => initiative.type.title[locale] }, - "undoOnlineSignaturesEnabled" => initiative.type.undo_online_signatures_enabled, - "updatedAt" => initiative.type.updated_at.iso8601.to_s.gsub("Z", "+00:00"), - "validateSmsCodeOnVotes" => initiative.type.validate_sms_code_on_votes - }, "offlineVotes" => initiative.offline_votes_count, "onlineVotes" => initiative.online_votes_count, "publishedAt" => initiative.published_at.iso8601.to_s.gsub("Z", "+00:00"), @@ -61,6 +45,23 @@ } end + let(:initiative_type_data) do + { + "collectUserExtraFields" => initiative.type.collect_user_extra_fields?, + "createdAt" => initiative.type.created_at.iso8601.to_s.gsub("Z", "+00:00"), + "description" => { "translation" => initiative.type.description[locale] }, + "extraFieldsLegalInformation" => initiative.type.extra_fields_legal_information, + "id" => initiative.type.id.to_s, + "initiatives" => initiative.type.initiatives.map { |i| { "id" => i.id.to_s } }, + "minimumCommitteeMembers" => initiative.type.minimum_committee_members, + "promotingCommitteeEnabled" => initiative.type.promoting_committee_enabled, + "signatureType" => initiative.type.signature_type, + "title" => { "translation" => initiative.type.title[locale] }, + "undoOnlineSignaturesEnabled" => initiative.type.undo_online_signatures_enabled, + "updatedAt" => initiative.type.updated_at.iso8601.to_s.gsub("Z", "+00:00"), + "validateSmsCodeOnVotes" => initiative.type.validate_sms_code_on_votes + } + end let(:initiatives) do %( @@ -143,7 +144,10 @@ end it "returns the correct response" do - expect(response["initiatives"].first).to eq(initiative_data) + data = response["initiatives"].first + expect(data).to include(initiative_data) + expect(data["initiativeType"]).to include(initiative_type_data) + expect(data["initiativeType"]["bannerImage"]).to be_blob_url(initiative.type.banner_image.blob) end it_behaves_like "implements stats type" do @@ -161,7 +165,7 @@ end end - describe "single assembly" do + describe "single initiative" do let(:initiatives) do %( initiative(id: #{initiative.id}){ @@ -234,7 +238,10 @@ end it "returns the correct response" do - expect(response["initiative"]).to eq(initiative_data) + data = response["initiative"] + expect(data).to include(initiative_data) + expect(data["initiativeType"]).to include(initiative_type_data) + expect(data["initiativeType"]["bannerImage"]).to be_blob_url(initiative.type.banner_image.blob) end it_behaves_like "implements stats type" do diff --git a/decidim-meetings/app/cells/decidim/meetings/meeting_l_cell.rb b/decidim-meetings/app/cells/decidim/meetings/meeting_l_cell.rb index fea8f0a2a9b0..ac48249eb1e8 100644 --- a/decidim-meetings/app/cells/decidim/meetings/meeting_l_cell.rb +++ b/decidim-meetings/app/cells/decidim/meetings/meeting_l_cell.rb @@ -9,10 +9,6 @@ module Meetings class MeetingLCell < Decidim::CardLCell alias meeting model - def has_image? - true - end - def extra_class "card__calendar-list__reset" end diff --git a/decidim-participatory_processes/app/cells/decidim/participatory_processes/process_g_cell.rb b/decidim-participatory_processes/app/cells/decidim/participatory_processes/process_g_cell.rb index 1431a9464375..49481561005f 100644 --- a/decidim-participatory_processes/app/cells/decidim/participatory_processes/process_g_cell.rb +++ b/decidim-participatory_processes/app/cells/decidim/participatory_processes/process_g_cell.rb @@ -11,8 +11,8 @@ def resource_path Decidim::ParticipatoryProcesses::Engine.routes.url_helpers.participatory_process_path(model) end - def resource_image_path - model.attached_uploader(:hero_image).path + def resource_image_url + model.attached_uploader(:hero_image).url end def start_date diff --git a/decidim-participatory_processes/app/cells/decidim/participatory_processes/process_group_g_cell.rb b/decidim-participatory_processes/app/cells/decidim/participatory_processes/process_group_g_cell.rb index 9c1101a8d901..e75ab09bbef2 100644 --- a/decidim-participatory_processes/app/cells/decidim/participatory_processes/process_group_g_cell.rb +++ b/decidim-participatory_processes/app/cells/decidim/participatory_processes/process_group_g_cell.rb @@ -11,8 +11,8 @@ def resource_path Decidim::ParticipatoryProcesses::Engine.routes.url_helpers.participatory_process_group_path(model) end - def resource_image_path - model.attached_uploader(:hero_image).path + def resource_image_url + model.attached_uploader(:hero_image).url end def metadata_cell diff --git a/decidim-participatory_processes/app/helpers/decidim/participatory_processes/participatory_process_helper.rb b/decidim-participatory_processes/app/helpers/decidim/participatory_processes/participatory_process_helper.rb index 32b39a236c29..9f28625cb597 100644 --- a/decidim-participatory_processes/app/helpers/decidim/participatory_processes/participatory_process_helper.rb +++ b/decidim-participatory_processes/app/helpers/decidim/participatory_processes/participatory_process_helper.rb @@ -53,7 +53,7 @@ def participatory_process_group_cta_settings(process_group) OpenStruct.new( text: translated_attribute(cta_settings.button_text), path: cta_settings.button_url, - image_url: block.images_container.attached_uploader(:background_image).path(variant: :big) + image_url: block.images_container.attached_uploader(:background_image).variant_url(:big) ) end diff --git a/decidim-participatory_processes/app/views/decidim/participatory_processes/participatory_processes/show.html.erb b/decidim-participatory_processes/app/views/decidim/participatory_processes/participatory_processes/show.html.erb index 44ccefcc2185..7d33d425a6db 100644 --- a/decidim-participatory_processes/app/views/decidim/participatory_processes/participatory_processes/show.html.erb +++ b/decidim-participatory_processes/app/views/decidim/participatory_processes/participatory_processes/show.html.erb @@ -1,6 +1,6 @@ <% add_decidim_meta_tags({ title: translated_attribute(current_participatory_space.title), - image_url: current_participatory_space.attached_uploader(:hero_image).path, + image_url: current_participatory_space.attached_uploader(:hero_image).url, description: translated_attribute(current_participatory_space.short_description), url: participatory_process_url(current_participatory_space) }) %> diff --git a/decidim-participatory_processes/app/views/layouts/decidim/_process_header.html.erb b/decidim-participatory_processes/app/views/layouts/decidim/_process_header.html.erb index 31ac78eb82f1..3eeb377e44fa 100644 --- a/decidim-participatory_processes/app/views/layouts/decidim/_process_header.html.erb +++ b/decidim-participatory_processes/app/views/layouts/decidim/_process_header.html.erb @@ -1,4 +1,4 @@ -
+

diff --git a/decidim-participatory_processes/lib/decidim/api/participatory_process_group_type.rb b/decidim-participatory_processes/lib/decidim/api/participatory_process_group_type.rb index 3c7fdc2f3a84..5bb35ea9f490 100644 --- a/decidim-participatory_processes/lib/decidim/api/participatory_process_group_type.rb +++ b/decidim-participatory_processes/lib/decidim/api/participatory_process_group_type.rb @@ -14,7 +14,7 @@ class ParticipatoryProcessGroupType < Decidim::Api::Types::BaseObject field :hero_image, GraphQL::Types::String, "The hero image for this participatory process group", null: true def hero_image - object.attached_uploader(:hero_image).path + object.attached_uploader(:hero_image).url end end end diff --git a/decidim-participatory_processes/lib/decidim/api/participatory_process_type.rb b/decidim-participatory_processes/lib/decidim/api/participatory_process_type.rb index db6f068652bb..00f31d79559a 100644 --- a/decidim-participatory_processes/lib/decidim/api/participatory_process_type.rb +++ b/decidim-participatory_processes/lib/decidim/api/participatory_process_type.rb @@ -47,11 +47,11 @@ class ParticipatoryProcessType < Decidim::Api::Types::BaseObject description: "The participatory process group in which this process belong to" def banner_image - object.attached_uploader(:banner_image).path + object.attached_uploader(:banner_image).url end def hero_image - object.attached_uploader(:hero_image).path + object.attached_uploader(:hero_image).url end end end diff --git a/decidim-participatory_processes/spec/cells/decidim/participatory_processes/participatory_process_g_cell_spec.rb b/decidim-participatory_processes/spec/cells/decidim/participatory_processes/participatory_process_g_cell_spec.rb index b0baced444f4..fda26ea52aa5 100644 --- a/decidim-participatory_processes/spec/cells/decidim/participatory_processes/participatory_process_g_cell_spec.rb +++ b/decidim-participatory_processes/spec/cells/decidim/participatory_processes/participatory_process_g_cell_spec.rb @@ -22,7 +22,8 @@ module Decidim::ParticipatoryProcesses end it "displays the process hero image" do - expect(subject).to have_css("img[src='#{model.attached_uploader(:hero_image).path}']") + img = subject.find("img") + expect(img["src"]).to be_blob_url(model.hero_image.blob) end it_behaves_like "process card with metadata", metadata_class: "card__grid-metadata" diff --git a/decidim-participatory_processes/spec/presenters/decidim/participatory_processes/participatory_process_presenter_spec.rb b/decidim-participatory_processes/spec/presenters/decidim/participatory_processes/participatory_process_presenter_spec.rb index aad80b079dbd..3582ecd1557f 100644 --- a/decidim-participatory_processes/spec/presenters/decidim/participatory_processes/participatory_process_presenter_spec.rb +++ b/decidim-participatory_processes/spec/presenters/decidim/participatory_processes/participatory_process_presenter_spec.rb @@ -22,7 +22,7 @@ module Decidim context "when image is attached" do it "returns an URL including the organization domain" do expect(subject.hero_image_url).to include(process.organization.host) - expect(subject.hero_image_url).to include(process.attached_uploader(:hero_image).path) + expect(subject.hero_image_url).to be_blob_url(process.hero_image.blob) end end end @@ -41,7 +41,7 @@ module Decidim context "when image is attached" do it "returns an URL including the organization domain" do expect(subject.banner_image_url).to include(process.organization.host) - expect(subject.banner_image_url).to include(process.attached_uploader(:banner_image).path) + expect(subject.banner_image_url).to be_blob_url(process.banner_image.blob) end end end diff --git a/decidim-participatory_processes/spec/serializers/decidim/participatory_processes/participatory_process_serializer_spec.rb b/decidim-participatory_processes/spec/serializers/decidim/participatory_processes/participatory_process_serializer_spec.rb index f327aa53b896..ab7545c5c279 100644 --- a/decidim-participatory_processes/spec/serializers/decidim/participatory_processes/participatory_process_serializer_spec.rb +++ b/decidim-participatory_processes/spec/serializers/decidim/participatory_processes/participatory_process_serializer_spec.rb @@ -14,29 +14,29 @@ module Decidim::ParticipatoryProcesses expect(serialized).to be_a(Hash) - expect(subject.serialize).to include(id: resource.id) - expect(subject.serialize).to include(title: resource.title) - expect(subject.serialize).to include(subtitle: resource.subtitle) - expect(subject.serialize).to include(slug: resource.slug) - expect(subject.serialize).to include(hashtag: resource.hashtag) - expect(subject.serialize).to include(short_description: resource.short_description) - expect(subject.serialize).to include(description: resource.description) - expect(subject.serialize).to include(announcement: resource.announcement) - expect(subject.serialize).to include(start_date: resource.start_date) - expect(subject.serialize).to include(end_date: resource.end_date) - expect(subject.serialize).to include(remote_hero_image_url: Decidim::ParticipatoryProcesses::ParticipatoryProcessPresenter.new(resource).hero_image_url) - expect(subject.serialize).to include(remote_banner_image_url: Decidim::ParticipatoryProcesses::ParticipatoryProcessPresenter.new(resource).banner_image_url) - expect(subject.serialize).to include(developer_group: resource.developer_group) - expect(subject.serialize).to include(local_area: resource.local_area) - expect(subject.serialize).to include(meta_scope: resource.meta_scope) - expect(subject.serialize).to include(participatory_scope: resource.participatory_scope) - expect(subject.serialize).to include(participatory_structure: resource.participatory_structure) - expect(subject.serialize).to include(target: resource.target) - expect(subject.serialize).to include(private_space: resource.private_space) - expect(subject.serialize).to include(promoted: resource.promoted) - expect(subject.serialize).to include(scopes_enabled: resource.scopes_enabled) - expect(subject.serialize).to include(show_metrics: resource.show_metrics) - expect(subject.serialize).to include(show_statistics: resource.show_statistics) + expect(serialized).to include(id: resource.id) + expect(serialized).to include(title: resource.title) + expect(serialized).to include(subtitle: resource.subtitle) + expect(serialized).to include(slug: resource.slug) + expect(serialized).to include(hashtag: resource.hashtag) + expect(serialized).to include(short_description: resource.short_description) + expect(serialized).to include(description: resource.description) + expect(serialized).to include(announcement: resource.announcement) + expect(serialized).to include(start_date: resource.start_date) + expect(serialized).to include(end_date: resource.end_date) + expect(serialized[:remote_hero_image_url]).to be_blob_url(resource.hero_image.blob) + expect(serialized[:remote_banner_image_url]).to be_blob_url(resource.banner_image.blob) + expect(serialized).to include(developer_group: resource.developer_group) + expect(serialized).to include(local_area: resource.local_area) + expect(serialized).to include(meta_scope: resource.meta_scope) + expect(serialized).to include(participatory_scope: resource.participatory_scope) + expect(serialized).to include(participatory_structure: resource.participatory_structure) + expect(serialized).to include(target: resource.target) + expect(serialized).to include(private_space: resource.private_space) + expect(serialized).to include(promoted: resource.promoted) + expect(serialized).to include(scopes_enabled: resource.scopes_enabled) + expect(serialized).to include(show_metrics: resource.show_metrics) + expect(serialized).to include(show_statistics: resource.show_statistics) end context "when process has area" do @@ -109,7 +109,7 @@ module Decidim::ParticipatoryProcesses expect(serialized_participatory_process_group).to include(id: resource.participatory_process_group.id) expect(serialized_participatory_process_group).to include(title: resource.participatory_process_group.title) expect(serialized_participatory_process_group).to include(description: resource.participatory_process_group.description) - expect(serialized_participatory_process_group).to include(remote_hero_image_url: Decidim::ParticipatoryProcesses::ParticipatoryProcessGroupPresenter.new(resource.participatory_process_group).hero_image_url) + expect(serialized_participatory_process_group[:remote_hero_image_url]).to be_blob_url(resource.participatory_process_group.hero_image.blob) end end @@ -180,7 +180,7 @@ module Decidim::ParticipatoryProcesses expect(serialized_participatory_process_attachment).to include(title: attachment.title) expect(serialized_participatory_process_attachment).to include(weight: attachment.weight) expect(serialized_participatory_process_attachment).to include(description: attachment.description) - expect(serialized_participatory_process_attachment).to include(remote_file_url: Decidim::AttachmentPresenter.new(resource.attachments.first).attachment_file_url) + expect(serialized_participatory_process_attachment[:remote_file_url]).to be_blob_url(resource.attachments.first.file.blob) end end end diff --git a/decidim-participatory_processes/spec/shared/invite_process_users_shared_context.rb b/decidim-participatory_processes/spec/shared/invite_process_users_shared_context.rb index 411c996ad5e4..2339a34fefd5 100644 --- a/decidim-participatory_processes/spec/shared/invite_process_users_shared_context.rb +++ b/decidim-participatory_processes/spec/shared/invite_process_users_shared_context.rb @@ -19,6 +19,9 @@ def invite_user fill_in "Email", with: email select role, from: "Role" click_on "Create" + expect(page).to have_content("successfully added to this participatory process") logout :user + visit decidim.root_path + expect(page).to have_content(organization.name) end end diff --git a/decidim-participatory_processes/spec/system/admin/admin_manages_participatory_processes_spec.rb b/decidim-participatory_processes/spec/system/admin/admin_manages_participatory_processes_spec.rb index 72f13d67ffe6..9b9bb3f5e509 100644 --- a/decidim-participatory_processes/spec/system/admin/admin_manages_participatory_processes_spec.rb +++ b/decidim-participatory_processes/spec/system/admin/admin_manages_participatory_processes_spec.rb @@ -127,8 +127,18 @@ click_on "Update" expect(page).to have_admin_callout("successfully") - expect(page).to have_css("img[src*='#{participatory_process3.attached_uploader(:hero_image).path}']") - expect(page).to have_css("img[src*='#{participatory_process3.attached_uploader(:banner_image).path}']") + + hero_blob = participatory_process3.hero_image.blob + within %([data-active-uploads] [data-filename="#{hero_blob.filename}"]) do + src = page.find("img")["src"] + expect(src).to be_blob_url(hero_blob) + end + + banner_blob = participatory_process3.banner_image.blob + within %([data-active-uploads] [data-filename="#{banner_blob.filename}"]) do + src = page.find("img")["src"] + expect(src).to be_blob_url(banner_blob) + end end end end diff --git a/decidim-participatory_processes/spec/types/integration_schema_spec.rb b/decidim-participatory_processes/spec/types/integration_schema_spec.rb index 16592513b5dc..7960800ca67a 100644 --- a/decidim-participatory_processes/spec/types/integration_schema_spec.rb +++ b/decidim-participatory_processes/spec/types/integration_schema_spec.rb @@ -159,7 +159,6 @@ "translation" => participatory_process.announcement[locale] }, "attachments" => [], - "bannerImage" => participatory_process.attached_uploader(:banner_image).path.sub(Rails.public_path.to_s, ""), "categories" => [], "components" => components, "createdAt" => participatory_process.created_at.iso8601.to_s.gsub("Z", "+00:00"), @@ -167,7 +166,6 @@ "developerGroup" => { "translation" => participatory_process.developer_group[locale] }, "endDate" => participatory_process.end_date.to_s, "hashtag" => "", - "heroImage" => participatory_process.attached_uploader(:hero_image).path.sub(Rails.public_path.to_s, ""), "id" => participatory_process.id.to_s, "linkedParticipatorySpaces" => [], "localArea" => { "translation" => participatory_process.local_area[locale] }, @@ -203,10 +201,15 @@ describe "valid query" do it "executes successfully" do - expect { response }.not_to raise_error(StandardError) + expect { response }.not_to raise_error end - it { expect(response["participatoryProcess"]).to eq(participatory_process_response) } + it "returns the correct response" do + data = response["participatoryProcess"] + expect(data).to include(participatory_process_response) + expect(data["heroImage"]).to be_blob_url(participatory_process.hero_image.blob) + expect(data["bannerImage"]).to be_blob_url(participatory_process.banner_image.blob) + end it_behaves_like "implements stats type" do let(:participatory_process_query) do diff --git a/decidim-participatory_processes/spec/types/participatory_process_group_type_spec.rb b/decidim-participatory_processes/spec/types/participatory_process_group_type_spec.rb index edebf3f4c80c..88645ddfdcbf 100644 --- a/decidim-participatory_processes/spec/types/participatory_process_group_type_spec.rb +++ b/decidim-participatory_processes/spec/types/participatory_process_group_type_spec.rb @@ -38,7 +38,7 @@ module ParticipatoryProcesses let(:query) { "{ heroImage }" } it "returns the hero image of the process" do - expect(response["heroImage"]).to eq(model.attached_uploader(:hero_image).path) + expect(response["heroImage"]).to be_blob_url(model.hero_image.blob) end end diff --git a/decidim-participatory_processes/spec/types/participatory_process_type_spec.rb b/decidim-participatory_processes/spec/types/participatory_process_type_spec.rb index c83ae3c278d7..8f07aee31837 100644 --- a/decidim-participatory_processes/spec/types/participatory_process_type_spec.rb +++ b/decidim-participatory_processes/spec/types/participatory_process_type_spec.rb @@ -115,7 +115,7 @@ module ParticipatoryProcesses let(:query) { "{ bannerImage }" } it "returns the banner image of the process" do - expect(response["bannerImage"]).to eq(model.attached_uploader(:banner_image).path) + expect(response["bannerImage"]).to be_blob_url(model.banner_image.blob) end end @@ -123,7 +123,7 @@ module ParticipatoryProcesses let(:query) { "{ heroImage }" } it "returns the hero image of the process" do - expect(response["heroImage"]).to eq(model.attached_uploader(:hero_image).path) + expect(response["heroImage"]).to be_blob_url(model.hero_image.blob) end end diff --git a/decidim-proposals/app/cells/decidim/proposals/proposal_l_cell.rb b/decidim-proposals/app/cells/decidim/proposals/proposal_l_cell.rb index 00d093807862..ca06e9ed8f9e 100644 --- a/decidim-proposals/app/cells/decidim/proposals/proposal_l_cell.rb +++ b/decidim-proposals/app/cells/decidim/proposals/proposal_l_cell.rb @@ -27,7 +27,7 @@ def cache_hash hash << model.endorsements_count hash << model.comments_count hash << Digest::MD5.hexdigest(model.component.cache_key_with_version) - hash << Digest::MD5.hexdigest(resource_image_path) if resource_image_path + hash << Digest::MD5.hexdigest(resource_image_url) if resource_image_url hash << render_space? ? 1 : 0 if current_user hash << current_user.cache_key_with_version diff --git a/decidim-proposals/spec/system/admin/view_proposal_details_from_admin_spec.rb b/decidim-proposals/spec/system/admin/view_proposal_details_from_admin_spec.rb index ee86dd209801..3fcd3a4afe22 100644 --- a/decidim-proposals/spec/system/admin/view_proposal_details_from_admin_spec.rb +++ b/decidim-proposals/spec/system/admin/view_proposal_details_from_admin_spec.rb @@ -257,7 +257,8 @@ go_to_admin_proposal_page(proposal) within "#photos" do - expect(page).to have_xpath("//img[@src=\"#{image.thumbnail_url}\"]") + img = page.find("img") + expect(img["src"]).to be_blob_url(image.file.blob) end end end diff --git a/decidim-system/app/controllers/decidim/system/application_controller.rb b/decidim-system/app/controllers/decidim/system/application_controller.rb index e9de268ecbae..1bfc0f1e9da8 100644 --- a/decidim-system/app/controllers/decidim/system/application_controller.rb +++ b/decidim-system/app/controllers/decidim/system/application_controller.rb @@ -8,6 +8,7 @@ class ApplicationController < ActionController::Base include PayloadInfo include Headers::HttpCachingDisabler include DisableRedirectionToExternalHost + include ActiveStorage::SetCurrent protect_from_forgery with: :exception, prepend: true diff --git a/decidim-system/app/views/decidim/system/oauth_applications/index.html.erb b/decidim-system/app/views/decidim/system/oauth_applications/index.html.erb index 11ff5007504a..c8c33329a7ae 100644 --- a/decidim-system/app/views/decidim/system/oauth_applications/index.html.erb +++ b/decidim-system/app/views/decidim/system/oauth_applications/index.html.erb @@ -20,7 +20,7 @@ <% @oauth_applications.each do |oauth_application| %> - <%= image_tag oauth_application.attached_uploader(:organization_logo).path, class: "max-w-md" %> + <%= image_tag oauth_application.attached_uploader(:organization_logo).url, class: "max-w-md" %> <%= link_to oauth_application.name, oauth_application %>
diff --git a/decidim-verifications/app/views/decidim/verifications/id_documents/admin/confirmations/new.html.erb b/decidim-verifications/app/views/decidim/verifications/id_documents/admin/confirmations/new.html.erb index 45e39771848d..a3f2cccd6979 100644 --- a/decidim-verifications/app/views/decidim/verifications/id_documents/admin/confirmations/new.html.erb +++ b/decidim-verifications/app/views/decidim/verifications/id_documents/admin/confirmations/new.html.erb @@ -17,7 +17,7 @@
- <%= image_tag @pending_authorization.attached_uploader(:verification_attachment).variant_path(:big), class: "thumbnail" %> + <%= image_tag @pending_authorization.attached_uploader(:verification_attachment).variant_url(:big), class: "thumbnail" %>
diff --git a/decidim-verifications/app/views/decidim/verifications/id_documents/admin/pending_authorizations/index.html.erb b/decidim-verifications/app/views/decidim/verifications/id_documents/admin/pending_authorizations/index.html.erb index 98841178a1c3..4249ddd24747 100644 --- a/decidim-verifications/app/views/decidim/verifications/id_documents/admin/pending_authorizations/index.html.erb +++ b/decidim-verifications/app/views/decidim/verifications/id_documents/admin/pending_authorizations/index.html.erb @@ -24,7 +24,7 @@ <%= link_to new_pending_authorization_confirmation_path(authorization.id) do %> - <%= image_tag authorization.attached_uploader(:verification_attachment).variant_path(:thumbnail), class: "thumbnail-list" %> + <%= image_tag authorization.attached_uploader(:verification_attachment).variant_url(:thumbnail), class: "thumbnail-list" %> <% end %> diff --git a/decidim-verifications/spec/system/id_documents/id_document_online_review_spec.rb b/decidim-verifications/spec/system/id_documents/id_document_online_review_spec.rb index ce7ae2556d4b..1c8a8dc81fb5 100644 --- a/decidim-verifications/spec/system/id_documents/id_document_online_review_spec.rb +++ b/decidim-verifications/spec/system/id_documents/id_document_online_review_spec.rb @@ -58,6 +58,7 @@ context "and the user logs back in" do before do + expect(page).to have_content("Verification rejected. Participant will be prompted to amend their documents") relogin_as user, scope: :user visit decidim_verifications.authorizations_path click_on "Identity documents"