Add Cloudflare to Images::Optimizer options (proof of concept) (#19574)
* Add cloudflare image option * Add tests for cloudflare * Update app/services/images/optimizer.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Avoid nested prefixes in cloudflare * Update spec/services/images/optimizer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update spec/services/images/optimizer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update spec/services/images/optimizer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update app/services/images/optimizer.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update spec/services/images/optimizer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Rebase * Refactor optimizer and finalize tests * Skips scheduled posts in featured post count (#19563) * Add image title for comment (#19586) * Add image title for comment * Break out boolean logic * Add organizations to onboarding follow suggestions (#19564) * Prepare: relocate user suggestions * Prepare: relocate users suggestion service -> query * Organization query for orgs with above-average scores * Rubocop * Limit to last 3 weeks * Tweak recent scope, limit to 5 orgs * Onboarding routes are also always JSON * Divide by zero makes NaN means * Add Orgs suggester into suggestions * Rubocop * select distinct orgs * Fix for weird edge-case with bad local data * Include type_identifier in JSON payload * Update follows API to allow org_ids as input * Update onboarding front-end to distinguish users/orgs * Fix: i18n issues * Fix: type_identifier in json output * Fix: distinct is weird * Fix: JS linter * Continue tweaking front-end * Audit import order * Cleanup @todo note * Try renaming controller action * Move Article average calculation to postgres and fix math * Refactor decorated type_identifier * Refactor SuggestProminent, return more orgs, fix spec math * Use FeatureFlag for organization suggestions * This might fix the jest * Sort organization members and tag moderators by badge count (#19582) * show tag moderators in descending badge count order * show organization users in descending badge count order * specs & docs for find_each_respecting_scope * Update spec/services/images/optimizer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update spec/services/images/optimizer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update spec/services/images/optimizer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update spec/services/images/optimizer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update spec/services/images/optimizer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update app/services/images/optimizer.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Remove cloudflare typo * Adjust cloudflare prefix line in tests * Clean up test logic * Update spec/services/images/optimizer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update app/services/images/optimizer.rb Co-authored-by: Mac Siri <mac@forem.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Joshua Wehner <joshua@forem.com> Co-authored-by: Dhurba baral <dhurba87@gmail.com> Co-authored-by: PJ <pj@forem.com> Co-authored-by: Mac Siri <mac@forem.com>
This commit is contained in:
parent
a4419a249a
commit
f0e99c6279
2 changed files with 89 additions and 0 deletions
|
|
@ -7,6 +7,8 @@ module Images
|
|||
imgproxy(img_src, **kwargs)
|
||||
elsif cloudinary_enabled?
|
||||
cloudinary(img_src, **kwargs)
|
||||
elsif cloudflare_enabled?
|
||||
cloudflare(img_src, **kwargs)
|
||||
else
|
||||
img_src
|
||||
end
|
||||
|
|
@ -23,6 +25,21 @@ module Images
|
|||
sign_url: true
|
||||
}.freeze
|
||||
|
||||
def self.cloudflare(img_src, **kwargs)
|
||||
template = Addressable::Template.new("https://{domain}/cdn-cgi/image/{options*}/{src}")
|
||||
template.expand(
|
||||
domain: ApplicationConfig["CLOUDFLARE_IMAGES_DOMAIN"],
|
||||
options: {
|
||||
width: kwargs[:width],
|
||||
height: kwargs[:height],
|
||||
fit: "cover",
|
||||
gravity: "auto",
|
||||
format: "auto"
|
||||
},
|
||||
src: extract_suffix_url(img_src),
|
||||
).to_s
|
||||
end
|
||||
|
||||
def self.cloudinary(img_src, **kwargs)
|
||||
options = DEFAULT_CL_OPTIONS.merge(kwargs).compact_blank
|
||||
|
||||
|
|
@ -68,6 +85,10 @@ module Images
|
|||
config.cloud_name.present? && config.api_key.present? && config.api_secret.present?
|
||||
end
|
||||
|
||||
def self.cloudflare_enabled?
|
||||
ApplicationConfig["CLOUDFLARE_IMAGES_DOMAIN"].present?
|
||||
end
|
||||
|
||||
def self.get_imgproxy_endpoint
|
||||
if Rails.env.production?
|
||||
# Use /images with the same domain on Production as
|
||||
|
|
@ -81,5 +102,14 @@ module Images
|
|||
ApplicationConfig["IMGPROXY_ENDPOINT"] || "http://localhost:8080"
|
||||
end
|
||||
end
|
||||
|
||||
def self.extract_suffix_url(full_url)
|
||||
prefix = "https://#{ApplicationConfig['CLOUDFLARE_IMAGES_DOMAIN']}/cdn-cgi/image"
|
||||
return full_url unless full_url&.starts_with?(prefix)
|
||||
|
||||
uri = URI.parse(full_url)
|
||||
match = uri.path.match(%r{https?.+})
|
||||
CGI.unescape(match[0]) if match
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ RSpec.describe Images::Optimizer, type: :service do
|
|||
describe "#call" do
|
||||
before do
|
||||
allow(described_class).to receive(:cloudinary)
|
||||
allow(described_class).to receive(:cloudflare)
|
||||
allow(described_class).to receive(:imgproxy)
|
||||
end
|
||||
|
||||
|
|
@ -85,6 +86,52 @@ RSpec.describe Images::Optimizer, type: :service do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#cloudflare" do
|
||||
before do
|
||||
allow(ApplicationConfig).to receive(:[]).with("CLOUDFLARE_IMAGES_DOMAIN").and_return("images.example.com")
|
||||
end
|
||||
|
||||
it "generates correct url based on h/w input" do
|
||||
cloudflare_url = described_class.cloudflare(image_url, width: 821, height: 420)
|
||||
expect(cloudflare_url).to match(%r{/width=821,height=420,fit=cover,gravity=auto,format=auto/#{CGI.escape(image_url)}})
|
||||
end
|
||||
|
||||
it "does not error if nil" do
|
||||
cloudflare_url = described_class.cloudflare(nil, width: 821, height: 420)
|
||||
expect(cloudflare_url).to match(%r{/width=821,height=420,fit=cover,gravity=auto,format=auto/})
|
||||
end
|
||||
|
||||
it "pulls suffix if nested cloudflare url is provided" do
|
||||
cloudflare_url = described_class.cloudflare(
|
||||
"https://#{ApplicationConfig['CLOUDFLARE_IMAGES_DOMAIN']}/cdn-cgi/image/width=821,height=900,fit=cover,gravity=auto,format=auto/#{CGI.escape(image_url)}", width: 821, height: 420
|
||||
)
|
||||
expect(cloudflare_url).to eq("https://#{ApplicationConfig['CLOUDFLARE_IMAGES_DOMAIN']}/cdn-cgi/image/width=821,height=420,fit=cover,gravity=auto,format=auto/#{CGI.escape(image_url)}")
|
||||
end
|
||||
|
||||
it "does not error out if image is empty" do
|
||||
cloudflare_url = described_class.cloudflare(
|
||||
"https://#{ApplicationConfig['CLOUDFLARE_IMAGES_DOMAIN']}/cdn-cgi/image/width=821,height=900,fit=cover,gravity=auto,format=auto/", width: 821, height: 420
|
||||
)
|
||||
expect(cloudflare_url).to eq("https://#{ApplicationConfig['CLOUDFLARE_IMAGES_DOMAIN']}/cdn-cgi/image/width=821,height=420,fit=cover,gravity=auto,format=auto/")
|
||||
end
|
||||
|
||||
it "does not error out if image is not proper url and has https" do
|
||||
image_url = "https:hello"
|
||||
cloudflare_url = described_class.cloudflare(
|
||||
"https://#{ApplicationConfig['CLOUDFLARE_IMAGES_DOMAIN']}/cdn-cgi/image/width=821,height=900,fit=cover,gravity=auto,format=auto/#{CGI.escape(image_url)}", width: 821, height: 420
|
||||
)
|
||||
expect(cloudflare_url).to eq("https://#{ApplicationConfig['CLOUDFLARE_IMAGES_DOMAIN']}/cdn-cgi/image/width=821,height=420,fit=cover,gravity=auto,format=auto/https%3Ahello")
|
||||
end
|
||||
|
||||
it "does not error out if image is not proper url and does not have https" do
|
||||
image_url = "hello"
|
||||
cloudflare_url = described_class.cloudflare(
|
||||
"https://#{ApplicationConfig['CLOUDFLARE_IMAGES_DOMAIN']}/cdn-cgi/image/width=821,height=900,fit=cover,gravity=auto,format=auto/#{CGI.escape(image_url)}", width: 821, height: 420
|
||||
)
|
||||
expect(cloudflare_url).to eq("https://#{ApplicationConfig['CLOUDFLARE_IMAGES_DOMAIN']}/cdn-cgi/image/width=821,height=420,fit=cover,gravity=auto,format=auto/")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#cloudinary_enabled?" do
|
||||
it "returns false if cloud_name, api_key or api_secret are missing", :aggregate_failures do
|
||||
allow(Cloudinary.config).to receive(:cloud_name).and_return("")
|
||||
|
|
@ -127,6 +174,18 @@ RSpec.describe Images::Optimizer, type: :service do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#cloudflare_enabled?" do
|
||||
it "returns false if config missing" do
|
||||
allow(ApplicationConfig).to receive(:[]).with("CLOUDFLARE_IMAGES_DOMAIN").and_return(nil)
|
||||
expect(described_class.cloudflare_enabled?).to be(false)
|
||||
end
|
||||
|
||||
it "returns true if config is present" do
|
||||
allow(ApplicationConfig).to receive(:[]).with("CLOUDFLARE_IMAGES_DOMAIN").and_return("images.com")
|
||||
expect(described_class.cloudflare_enabled?).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#translate_cloudinary_options" do
|
||||
it "sets resizing_type to fill if crop: fill is provided" do
|
||||
options = { width: 100, height: 100, crop: "fill" }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue