kt-paperclip 7.2.2 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7308352f1d792e5e861ba828d1eb3994b5956fc51df06a4cbfedfe134ce105d
4
- data.tar.gz: be4d4161c411a18edaf2a92b5a48d746d87d01f3d5a6e4fe5fecc20f87ad42a4
3
+ metadata.gz: 213cd04cf7f631853227e9c3fc6d6a38733f3c278907497e1f8e3c2e7a98bac8
4
+ data.tar.gz: 01aec044e7eff086cef50fab323730f617fd455e4ba70ffb99a58d099a4ffde5
5
5
  SHA512:
6
- metadata.gz: e202f7d5a1a9466f69118e485c5c747f10942644337940b6141ffb41904118353cab09858fbdabf4e68ba87d9e5199109a1a1525d7eaeea4a1601ba9e384459f
7
- data.tar.gz: 20fb1d6bd39a2d21a5b2f627d5ab92aba95ae88d523319de7b06e5e0983c281e76ae218a6bccf64fdc16362652cb1cc1251eab7fdacc14b6428b8dbafd2bdc81
6
+ metadata.gz: a7e922d52efbde590030651a7cbdca2087aa3c163d6cc498273e9ca57ce5c2b371b44601ccb9e825ee196f1197689438cb91cfca240b6361f259650ea63e5d03
7
+ data.tar.gz: 412ef55d0817f23247e52859d1b39cb1358f55bfd8c8d67cb16df376b42cc2926611b938004d6cec95d7a211895702cb279721322c1ac16e235af954a6f1f40e
data/LICENSE CHANGED
@@ -1,9 +1,9 @@
1
-
2
1
  LICENSE
3
2
 
4
3
  The MIT License
5
4
 
6
5
  Copyright (c) 2008-2016 Jon Yurek and thoughtbot, inc.
6
+ Copyright (c) 2019-2025 Kreeti Technologies Pvt Ltd.
7
7
 
8
8
  Permission is hereby granted, free of charge, to any person obtaining a copy
9
9
  of this software and associated documentation files (the "Software"), to deal
data/{NEWS → OLD_NEWS} RENAMED
@@ -1,5 +1,7 @@
1
1
  [UNRELEASED]
2
2
 
3
+ * Improvement: Support aws-sdk-s3 >= 1.196.1 and multipart file downloads
4
+
3
5
  7.2.1 (2023-09-09)
4
6
  * Improvement: Support file extension names both as symbols and strings for :content_type_mappings
5
7
 
@@ -10,30 +10,31 @@ module Paperclip
10
10
  class Attachment
11
11
  def self.default_options
12
12
  @default_options ||= {
13
- convert_options: {},
14
- default_style: :original,
15
- default_url: "/:attachment/:style/missing.png",
16
- escape_url: true,
17
- restricted_characters: /[&$+,\/:;=?@<>\[\]\{\}\|\\\^~%# ]/,
18
- filename_cleaner: nil,
19
- hash_data: ":class/:attachment/:id/:style/:updated_at",
20
- hash_digest: "SHA1",
21
- interpolator: Paperclip::Interpolations,
22
- only_process: [],
23
- path: ":rails_root/public:url",
24
- preserve_files: false,
25
- processors: [:thumbnail],
26
- source_file_options: {},
27
- storage: :filesystem,
28
- styles: {},
29
- url: "/system/:class/:attachment/:id_partition/:style/:filename",
30
- url_generator: Paperclip::UrlGenerator,
31
- use_default_time_zone: true,
32
- use_timestamp: true,
33
- whiny: Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails],
34
- validate_media_type: true,
35
- adapter_options: { hash_digest: Digest::MD5 },
36
- check_validity_before_processing: true
13
+ convert_options: {},
14
+ default_style: :original,
15
+ default_url: "/:attachment/:style/missing.png",
16
+ escape_url: true,
17
+ restricted_characters: /[&$+,\/:;=?@<>\[\]\{\}\|\\\^~%# ]/,
18
+ filename_cleaner: nil,
19
+ hash_data: ":class/:attachment/:id/:style/:updated_at",
20
+ hash_digest: "SHA1",
21
+ interpolator: Paperclip::Interpolations,
22
+ only_process: [],
23
+ path: ":rails_root/public:url",
24
+ preserve_files: false,
25
+ processors: [:thumbnail],
26
+ source_file_options: {},
27
+ storage: :filesystem,
28
+ styles: {},
29
+ url: "/system/:class/:attachment/:id_partition/:style/:filename",
30
+ url_generator: Paperclip::UrlGenerator,
31
+ use_default_time_zone: true,
32
+ use_timestamp: true,
33
+ whiny: Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails],
34
+ validate_media_type: true,
35
+ adapter_options: { hash_digest: Digest::MD5 },
36
+ check_validity_before_processing: true,
37
+ return_file_attributes_on_destroy: false
37
38
  }
38
39
  end
39
40
 
@@ -69,6 +70,8 @@ module Paperclip
69
70
  # +interpolator+ - the object used to interpolate filenames and URLs. Defaults to Paperclip::Interpolations
70
71
  # +url_generator+ - the object used to generate URLs, using the interpolator. Defaults to Paperclip::UrlGenerator
71
72
  # +escape_url+ - Perform URI escaping to URLs. Defaults to true
73
+ # +return_file_attributes_on_destroy+ - whether attachment-related attributes should be displayed when
74
+ # destroying a record. Defaults to false.
72
75
  def initialize(name, instance, options = {})
73
76
  @name = name.to_sym
74
77
  @name_string = name.to_s
@@ -563,12 +566,10 @@ module Paperclip
563
566
  path(style) if exists?(style)
564
567
  end.compact
565
568
  end
566
- instance_write(:file_name, nil)
567
- instance_write(:content_type, nil)
568
- instance_write(:file_size, nil)
569
- instance_write(:fingerprint, nil)
570
- instance_write(:created_at, nil) if has_enabled_but_unset_created_at?
571
- instance_write(:updated_at, nil)
569
+
570
+ return if show_attrs_and_destroy_callback_triggered?
571
+
572
+ clear_all_attachment_attributes
572
573
  end
573
574
 
574
575
  def flush_errors #:nodoc:
@@ -613,5 +614,21 @@ module Paperclip
613
614
  def has_enabled_but_unset_created_at?
614
615
  able_to_store_created_at? && !instance_read(:created_at)
615
616
  end
617
+
618
+ # Checks whether the option to show attributes to be destroyed is enabled and whether a destroy callback has been
619
+ # invoked when deleting the entire record.
620
+ def show_attrs_and_destroy_callback_triggered?
621
+ @options[:return_file_attributes_on_destroy] && instance.instance_variable_get(:@_destroy_callback_already_called)
622
+ end
623
+
624
+ # Sets attachment-related attributes to `nil`.
625
+ def clear_all_attachment_attributes
626
+ instance_write(:file_name, nil)
627
+ instance_write(:content_type, nil)
628
+ instance_write(:file_size, nil)
629
+ instance_write(:fingerprint, nil)
630
+ instance_write(:created_at, nil) if has_enabled_but_unset_created_at?
631
+ instance_write(:updated_at, nil)
632
+ end
616
633
  end
617
634
  end
@@ -72,7 +72,7 @@ module Paperclip
72
72
 
73
73
  # Returns the width and height in a format suitable to be passed to Geometry.parse
74
74
  def to_s
75
- s = ""
75
+ s = String.new
76
76
  s << width.to_i.to_s if width > 0
77
77
  s << "x#{height.to_i}" if height > 0
78
78
  s << modifier.to_s
@@ -17,7 +17,7 @@ module Paperclip
17
17
  @fingerprint ||= begin
18
18
  digest = @options.fetch(:hash_digest).new
19
19
  File.open(path, "rb") do |f|
20
- buf = ""
20
+ buf = String.new
21
21
  digest.update(buf) while f.read(16384, buf)
22
22
  end
23
23
  digest.hexdigest
@@ -33,6 +33,15 @@ module Paperclip
33
33
  else
34
34
  begin
35
35
  source.copy_to_local_file(@style, destination.path)
36
+
37
+ # Some sources (like S3) writes to a temporary file first for multi-part downloads then moves
38
+ # it to the final destination path. This means our destination Tempfile reference is stale
39
+ # and reads will return an empty string. For compatibility, we need to copy the contents
40
+ # of the destination file to our current Tempfile instance.
41
+ if destination.size.zero?
42
+ IO.copy_stream(destination.path, destination)
43
+ destination.rewind
44
+ end
36
45
  rescue Errno::EACCES
37
46
  # clean up lingering tempfile if we cannot access source file
38
47
  destination.close(true)
@@ -0,0 +1,18 @@
1
+ fr:
2
+ errors:
3
+ messages:
4
+ in_between: "doit être entre %{min} et %{max}"
5
+ spoofed_media_type: "à du contenu qui ne correspond pas au type déclaré"
6
+
7
+ number:
8
+ human:
9
+ storage_units:
10
+ format: "%n %u"
11
+ units:
12
+ byte:
13
+ one: "Octet"
14
+ other: "Octets"
15
+ kb: "ko"
16
+ mb: "Mo"
17
+ gb: "Go"
18
+ tb: "To"
@@ -1,4 +1,4 @@
1
- gd:
1
+ gd:
2
2
  errors:
3
3
  messages:
4
4
  in_between: "– feumaidh seo a bhith eadar %{min} ’s %{max}"
@@ -214,9 +214,9 @@ module Paperclip
214
214
  def find_credentials(creds)
215
215
  case creds
216
216
  when File
217
- YAML::safe_load(ERB.new(File.read(creds.path)).result)
217
+ load_credentials_from_file(creds.path)
218
218
  when String, Pathname
219
- YAML::safe_load(ERB.new(File.read(creds)).result)
219
+ load_credentials_from_file(creds.path)
220
220
  when Hash
221
221
  creds
222
222
  else
@@ -228,6 +228,14 @@ module Paperclip
228
228
  end
229
229
  end
230
230
 
231
+ def load_credentials_from_file(path)
232
+ if Gem::Version.new(Psych::VERSION) >= Gem::Version.new("3.1.0")
233
+ YAML::safe_load(ERB.new(File.read(path)).result, aliases: true)
234
+ else
235
+ YAML::safe_load(ERB.new(File.read(path)).result, [], [], true)
236
+ end
237
+ end
238
+
231
239
  def connection
232
240
  @connection ||= ::Fog::Storage.new(fog_credentials)
233
241
  end
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  module Paperclip
2
3
  module Storage
3
4
  # Amazon's S3 file hosting service is a scalable, easy place to store files for
@@ -280,6 +281,16 @@ module Paperclip
280
281
  s3_bucket.object style_name_as_path(style_name)
281
282
  end
282
283
 
284
+ def s3_transfer_manager
285
+ @s3_transfer_manager ||= begin
286
+ if ::Aws::S3.const_defined?(:TransferManager, false)
287
+ ::Aws::S3::TransferManager.new(client: s3_interface.client)
288
+ else
289
+ nil
290
+ end
291
+ end
292
+ end
293
+
283
294
  def use_accelerate_endpoint?
284
295
  !!@use_accelerate_endpoint
285
296
  end
@@ -386,7 +397,12 @@ module Paperclip
386
397
  write_options[:metadata] = @s3_metadata unless @s3_metadata.empty?
387
398
  write_options.merge!(@s3_headers)
388
399
 
389
- s3_object(style).upload_file(file.path, write_options)
400
+ if s3_transfer_manager
401
+ destination = style_name_as_path(style)
402
+ s3_transfer_manager.upload_file(file.path, **write_options, bucket: bucket_name, key: destination)
403
+ else
404
+ s3_object(style).upload_file(file.path, write_options)
405
+ end
390
406
  rescue ::Aws::S3::Errors::NoSuchBucket
391
407
  create_bucket
392
408
  retry
@@ -422,7 +438,13 @@ module Paperclip
422
438
 
423
439
  def copy_to_local_file(style, local_dest_path)
424
440
  log("copying #{path(style)} to local file #{local_dest_path}")
425
- s3_object(style).download_file(local_dest_path)
441
+
442
+ if s3_transfer_manager
443
+ source = style_name_as_path(style)
444
+ s3_transfer_manager.download_file(local_dest_path, bucket: bucket_name, key: source)
445
+ else
446
+ s3_object(style).download_file(local_dest_path)
447
+ end
426
448
  rescue Aws::Errors::ServiceError => e
427
449
  warn("#{e} - cannot copy #{path(style)} to local file #{local_dest_path}")
428
450
  false
@@ -433,7 +455,7 @@ module Paperclip
433
455
  def find_credentials(creds)
434
456
  case creds
435
457
  when File
436
- load_credentials_from_file(creds.path)
458
+ load_credentials_from_file(creds.path)
437
459
  when String, Pathname
438
460
  load_credentials_from_file(creds)
439
461
  when Hash
@@ -1,3 +1,3 @@
1
1
  module Paperclip
2
- VERSION = "7.2.2" unless defined?(Paperclip::VERSION)
2
+ VERSION = "7.3.0" unless defined?(Paperclip::VERSION)
3
3
  end
@@ -1267,7 +1267,7 @@ describe Paperclip::Attachment do
1267
1267
  @existing_names.each { |f| assert_file_not_exists(f) }
1268
1268
  end
1269
1269
 
1270
- it "deletes the files when you call #delete" do
1270
+ it "deletes the files when you call #destroy" do
1271
1271
  expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1272
1272
  expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1273
1273
  expect(@attachment).to receive(:instance_write).with(:file_size, nil)
@@ -1277,6 +1277,32 @@ describe Paperclip::Attachment do
1277
1277
  @existing_names.each { |f| assert_file_not_exists(f) }
1278
1278
  end
1279
1279
 
1280
+ it "deletes the files when you destroy the model" do
1281
+ expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1282
+ expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1283
+ expect(@attachment).to receive(:instance_write).with(:file_size, nil)
1284
+ expect(@attachment).to receive(:instance_write).with(:fingerprint, nil)
1285
+ expect(@attachment).to receive(:instance_write).with(:updated_at, nil)
1286
+ @attachment.instance.destroy
1287
+ @existing_names.each { |f| assert_file_not_exists(f) }
1288
+ end
1289
+
1290
+ context "when 'return_file_attributes_on_destroy' option is set to true" do
1291
+ before do
1292
+ @attachment.options[:return_file_attributes_on_destroy] = true
1293
+ end
1294
+
1295
+ it "does not override attachment-related attributes and deletes the files" do
1296
+ expect(@attachment).not_to receive(:instance_write)
1297
+ expect(@attachment).not_to receive(:instance_write)
1298
+ expect(@attachment).not_to receive(:instance_write)
1299
+ expect(@attachment).not_to receive(:instance_write)
1300
+ expect(@attachment).not_to receive(:instance_write)
1301
+ @attachment.instance.destroy
1302
+ @existing_names.each { |f| assert_file_not_exists(f) }
1303
+ end
1304
+ end
1305
+
1280
1306
  context "when keeping old files" do
1281
1307
  before do
1282
1308
  @attachment.options[:keep_old_files] = true
@@ -1304,7 +1330,7 @@ describe Paperclip::Attachment do
1304
1330
  @existing_names.each { |f| assert_file_exists(f) }
1305
1331
  end
1306
1332
 
1307
- it "keeps the files when you call #delete" do
1333
+ it "keeps the files when you call #destroy" do
1308
1334
  expect(@attachment).to receive(:instance_write).with(:file_name, nil)
1309
1335
  expect(@attachment).to receive(:instance_write).with(:content_type, nil)
1310
1336
  expect(@attachment).to receive(:instance_write).with(:file_size, nil)
@@ -6,6 +6,33 @@ describe Paperclip::AttachmentAdapter do
6
6
  @attachment = Dummy.new.avatar
7
7
  end
8
8
 
9
+ context "for an attachment that renames the source to the destination" do
10
+ before do
11
+ @file = File.new(fixture_file("5k.png"))
12
+ @file.binmode
13
+
14
+ @attachment.assign(@file)
15
+ @attachment.save
16
+
17
+ allow(@attachment).to receive(:copy_to_local_file) do |style, path|
18
+ FileUtils.cp(@file.path, "#{@file.path}.tmp")
19
+ FileUtils.mv("#{@file.path}.tmp", path)
20
+ end
21
+
22
+ @subject = Paperclip.io_adapters.for(@attachment,
23
+ hash_digest: Digest::MD5)
24
+ end
25
+
26
+ after do
27
+ @file.close
28
+ @subject.close
29
+ end
30
+
31
+ it "handles the case where the source is renamed to the destination" do
32
+ assert_equal @file.read, @subject.read
33
+ end
34
+ end
35
+
9
36
  context "for an attachment" do
10
37
  before do
11
38
  @file = File.new(fixture_file("5k.png"))
@@ -6,6 +6,10 @@ describe Paperclip::Storage::S3 do
6
6
  Aws.config[:stub_responses] = true
7
7
  end
8
8
 
9
+ def s3_uses_transfer_manager?
10
+ defined?(Aws::S3::TransferManager)
11
+ end
12
+
9
13
  def aws2_add_region
10
14
  { s3_region: "us-east-1" }
11
15
  end
@@ -389,27 +393,30 @@ describe Paperclip::Storage::S3 do
389
393
 
390
394
  @dummy = Dummy.new
391
395
  @dummy.avatar = @file
392
-
393
396
  object = double
394
- allow(@dummy.avatar).to receive(:s3_object).with(:original).and_return(object)
395
- allow(@dummy.avatar).to receive(:s3_object).with(:thumbnail).and_return(object)
396
397
 
398
+ if s3_uses_transfer_manager?
399
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
400
+ else
401
+ allow(@dummy.avatar).to receive(:s3_object).with(:original).and_return(object)
402
+ allow(@dummy.avatar).to receive(:s3_object).with(:thumbnail).and_return(object)
403
+ end
397
404
  expect(object).to receive(:upload_file).
398
405
  with(
399
406
  anything,
400
- {
407
+ hash_including(
401
408
  content_type: "image/png",
402
409
  acl: :"public-read",
403
- },
410
+ ),
404
411
  )
405
412
  expect(object).to receive(:upload_file).
406
413
  with(
407
414
  anything,
408
- {
415
+ hash_including(
409
416
  content_type: "image/png",
410
417
  acl: :"public-read",
411
418
  cache_control: "max-age=31557600",
412
- },
419
+ ),
413
420
  )
414
421
  @dummy.save
415
422
  end
@@ -417,7 +424,12 @@ describe Paperclip::Storage::S3 do
417
424
  after { @file.close }
418
425
 
419
426
  it "succeeds" do
420
- assert_equal @dummy.counter, 7
427
+ if s3_uses_transfer_manager?
428
+ count = 9
429
+ else
430
+ count = 7
431
+ end
432
+ assert_equal @dummy.counter, count
421
433
  end
422
434
  end
423
435
 
@@ -445,22 +457,27 @@ describe Paperclip::Storage::S3 do
445
457
  context "reprocess" do
446
458
  before do
447
459
  @object = double
448
- allow(@dummy.avatar).to receive(:s3_object).with(:original).and_return(@object)
449
- allow(@dummy.avatar).to receive(:s3_object).with(:thumb).and_return(@object)
450
- allow(@object).to receive(:get).and_yield(@file.read)
451
- allow(@object).to receive(:exists?).and_return(true)
452
- allow(@object).to receive(:download_file).with(anything)
460
+ if s3_uses_transfer_manager?
461
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(@object)
462
+ allow(@object).to receive(:download_file).with(any_args)
463
+ else
464
+ allow(@dummy.avatar).to receive(:s3_object).with(:original).and_return(@object)
465
+ allow(@dummy.avatar).to receive(:s3_object).with(:thumb).and_return(@object)
466
+ allow(@object).to receive(:get).and_yield(@file.read)
467
+ allow(@object).to receive(:exists?).and_return(true)
468
+ allow(@object).to receive(:download_file).with(anything)
469
+ end
453
470
  end
454
471
 
455
472
  it "uploads original" do
456
473
  expect(@object).to receive(:upload_file).with(
457
474
  anything,
458
- { content_type: "image/png" },
475
+ hash_including(content_type: "image/png"),
459
476
  ).and_return(true)
460
477
  @dummy.avatar.reprocess!
461
478
  expect(@object).to receive(:upload_file).with(
462
479
  anything,
463
- { content_type: "image/png" },
480
+ hash_including(content_type: "image/png"),
464
481
  ).and_return(true)
465
482
  @dummy.avatar.reprocess!
466
483
  end
@@ -468,7 +485,7 @@ describe Paperclip::Storage::S3 do
468
485
  it "doesn't upload original" do
469
486
  expect(@object).to receive(:upload_file).with(
470
487
  anything,
471
- { content_type: "image/png" },
488
+ hash_including(content_type: "image/png"),
472
489
  ).and_return(true)
473
490
  @dummy.avatar.reprocess!
474
491
  end
@@ -500,28 +517,33 @@ describe Paperclip::Storage::S3 do
500
517
  context "reprocess" do
501
518
  before do
502
519
  @object = double
503
- allow(@dummy.avatar).to receive(:s3_object).with(:original).and_return(@object)
504
- allow(@dummy.avatar).to receive(:s3_object).with(:thumb).and_return(@object)
505
- allow(@object).to receive(:get).and_yield(@file.read)
506
- allow(@object).to receive(:exists?).and_return(true)
507
- allow(@object).to receive(:download_file).with(anything)
520
+ if s3_uses_transfer_manager?
521
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(@object)
522
+ allow(@object).to receive(:download_file).with(any_args)
523
+ else
524
+ allow(@dummy.avatar).to receive(:s3_object).with(:original).and_return(@object)
525
+ allow(@dummy.avatar).to receive(:s3_object).with(:thumb).and_return(@object)
526
+ allow(@object).to receive(:get).and_yield(@file.read)
527
+ allow(@object).to receive(:exists?).and_return(true)
528
+ allow(@object).to receive(:download_file).with(anything)
529
+ end
508
530
  end
509
531
 
510
532
  it "uploads original" do
511
533
  expect(@object).to receive(:upload_file).with(
512
534
  anything,
513
- {
535
+ hash_including(
514
536
  content_type: "image/png",
515
537
  acl: :"public-read",
516
- },
538
+ ),
517
539
  ).and_return(true)
518
540
  @dummy.avatar.reprocess!
519
541
  expect(@object).to receive(:upload_file).with(
520
542
  anything,
521
- {
543
+ hash_including(
522
544
  content_type: "image/png",
523
545
  acl: :"public-read",
524
- },
546
+ ),
525
547
  ).and_return(true)
526
548
  @dummy.avatar.reprocess!
527
549
  end
@@ -529,10 +551,10 @@ describe Paperclip::Storage::S3 do
529
551
  it "doesn't upload original" do
530
552
  expect(@object).to receive(:upload_file).with(
531
553
  anything,
532
- {
554
+ hash_including(
533
555
  content_type: "image/png",
534
556
  acl: :"public-read",
535
- },
557
+ ),
536
558
  ).and_return(true)
537
559
  @dummy.avatar.reprocess!
538
560
  end
@@ -973,9 +995,12 @@ describe Paperclip::Storage::S3 do
973
995
 
974
996
  it "will retry to save again but back off on SlowDown" do
975
997
  allow(@dummy.avatar).to receive(:sleep)
976
- allow_any_instance_of(Aws::S3::Object).to receive(:upload_file).
977
- and_raise(Aws::S3::Errors::SlowDown.new(spy,
978
- spy(status: 503, body: "")))
998
+ err = Aws::S3::Errors::SlowDown.new(spy, spy(status: 503, body: ""))
999
+ if s3_uses_transfer_manager?
1000
+ allow_any_instance_of(Aws::S3::TransferManager).to receive(:upload_file).and_raise(err)
1001
+ else
1002
+ allow_any_instance_of(Aws::S3::Object).to receive(:upload_file).and_raise(err)
1003
+ end
979
1004
  expect { @dummy.save }.to raise_error(Aws::S3::Errors::SlowDown)
980
1005
  expect(@dummy.avatar).to have_received(:sleep).with(1)
981
1006
  expect(@dummy.avatar).to have_received(:sleep).with(2)
@@ -987,9 +1012,13 @@ describe Paperclip::Storage::S3 do
987
1012
  context "and saved" do
988
1013
  before do
989
1014
  object = double
990
- allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1015
+ if s3_uses_transfer_manager?
1016
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
1017
+ else
1018
+ allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1019
+ end
991
1020
  expect(object).to receive(:upload_file).
992
- with(anything, { content_type: "image/png", acl: :"public-read" })
1021
+ with(anything, hash_including(content_type: "image/png", acl: :"public-read"))
993
1022
  @dummy.save
994
1023
  end
995
1024
 
@@ -1146,16 +1175,19 @@ describe Paperclip::Storage::S3 do
1146
1175
  context "and saved" do
1147
1176
  before do
1148
1177
  object = double
1149
- allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1150
-
1178
+ if s3_uses_transfer_manager?
1179
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
1180
+ else
1181
+ allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1182
+ end
1151
1183
  expect(object).to receive(:upload_file).
1152
1184
  with(
1153
1185
  anything,
1154
- {
1186
+ hash_including(
1155
1187
  content_type: "image/png",
1156
1188
  acl: :"public-read",
1157
1189
  cache_control: "max-age=31557600",
1158
- },
1190
+ ),
1159
1191
  )
1160
1192
  @dummy.save
1161
1193
  end
@@ -1191,16 +1223,20 @@ describe Paperclip::Storage::S3 do
1191
1223
  context "and saved" do
1192
1224
  before do
1193
1225
  object = double
1194
- allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1226
+ if s3_uses_transfer_manager?
1227
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
1228
+ else
1229
+ allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1230
+ end
1195
1231
 
1196
1232
  expect(object).to receive(:upload_file).
1197
1233
  with(
1198
1234
  anything,
1199
- {
1235
+ hash_including(
1200
1236
  content_type: "image/png",
1201
1237
  acl: :"public-read",
1202
1238
  metadata: { "color" => "red" },
1203
- },
1239
+ ),
1204
1240
  )
1205
1241
  @dummy.save
1206
1242
  end
@@ -1236,16 +1272,20 @@ describe Paperclip::Storage::S3 do
1236
1272
  context "and saved" do
1237
1273
  before do
1238
1274
  object = double
1239
- allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1275
+ if s3_uses_transfer_manager?
1276
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
1277
+ else
1278
+ allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1279
+ end
1240
1280
 
1241
1281
  expect(object).to receive(:upload_file).
1242
1282
  with(
1243
1283
  anything,
1244
- {
1284
+ hash_including(
1245
1285
  content_type: "image/png",
1246
1286
  acl: :"public-read",
1247
1287
  metadata: { "color" => "red" },
1248
- },
1288
+ ),
1249
1289
  )
1250
1290
  @dummy.save
1251
1291
  end
@@ -1282,16 +1322,20 @@ describe Paperclip::Storage::S3 do
1282
1322
  context "and saved" do
1283
1323
  before do
1284
1324
  object = double
1285
- allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1325
+ if s3_uses_transfer_manager?
1326
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
1327
+ else
1328
+ allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1329
+ end
1286
1330
 
1287
1331
  expect(object).to receive(:upload_file).
1288
1332
  with(
1289
1333
  anything,
1290
- {
1334
+ hash_including(
1291
1335
  content_type: "image/png",
1292
1336
  acl: :"public-read",
1293
1337
  storage_class: "reduced_redundancy",
1294
- },
1338
+ ),
1295
1339
  )
1296
1340
  @dummy.save
1297
1341
  end
@@ -1333,7 +1377,11 @@ describe Paperclip::Storage::S3 do
1333
1377
  before do
1334
1378
  object = double
1335
1379
  [:thumb, :original].each do |style|
1336
- allow(@dummy.avatar).to receive(:s3_object).with(style).and_return(object)
1380
+ if s3_uses_transfer_manager?
1381
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
1382
+ else
1383
+ allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1384
+ end
1337
1385
 
1338
1386
  expected_options = {
1339
1387
  content_type: "image/png",
@@ -1342,7 +1390,7 @@ describe Paperclip::Storage::S3 do
1342
1390
  expected_options.merge!(storage_class: :reduced_redundancy) if style == :thumb
1343
1391
 
1344
1392
  expect(object).to receive(:upload_file).
1345
- with(anything, expected_options)
1393
+ with(anything, hash_including(expected_options))
1346
1394
  end
1347
1395
  @dummy.save
1348
1396
  end
@@ -1382,16 +1430,20 @@ describe Paperclip::Storage::S3 do
1382
1430
  before do
1383
1431
  object = double
1384
1432
  [:thumb, :original].each do |style|
1385
- allow(@dummy.avatar).to receive(:s3_object).with(style).and_return(object)
1433
+ if s3_uses_transfer_manager?
1434
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
1435
+ else
1436
+ allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1437
+ end
1386
1438
 
1387
1439
  expect(object).to receive(:upload_file).
1388
1440
  with(
1389
1441
  anything,
1390
- {
1442
+ hash_including(
1391
1443
  content_type: "image/png",
1392
1444
  acl: :"public-read",
1393
1445
  storage_class: :reduced_redundancy,
1394
- },
1446
+ ),
1395
1447
  )
1396
1448
  end
1397
1449
  @dummy.save
@@ -1432,10 +1484,14 @@ describe Paperclip::Storage::S3 do
1432
1484
  context "and saved" do
1433
1485
  before do
1434
1486
  object = double
1435
- allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1487
+ if s3_uses_transfer_manager?
1488
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
1489
+ else
1490
+ allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1491
+ end
1436
1492
 
1437
1493
  expect(object).to receive(:upload_file).
1438
- with(anything, { content_type: "image/png", acl: :"public-read" })
1494
+ with(anything, hash_including(content_type: "image/png", acl: :"public-read"))
1439
1495
  @dummy.save
1440
1496
  end
1441
1497
 
@@ -1471,16 +1527,20 @@ describe Paperclip::Storage::S3 do
1471
1527
  context "and saved" do
1472
1528
  before do
1473
1529
  object = double
1474
- allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1530
+ if s3_uses_transfer_manager?
1531
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
1532
+ else
1533
+ allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1534
+ end
1475
1535
 
1476
1536
  expect(object).to receive(:upload_file).
1477
1537
  with(
1478
1538
  anything,
1479
- {
1539
+ hash_including(
1480
1540
  content_type: "image/png",
1481
1541
  acl: :"public-read",
1482
1542
  server_side_encryption: "AES256",
1483
- },
1543
+ ),
1484
1544
  )
1485
1545
  @dummy.save
1486
1546
  end
@@ -1516,16 +1576,20 @@ describe Paperclip::Storage::S3 do
1516
1576
  context "and saved" do
1517
1577
  before do
1518
1578
  object = double
1519
- allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1579
+ if s3_uses_transfer_manager?
1580
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
1581
+ else
1582
+ allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1583
+ end
1520
1584
 
1521
1585
  expect(object).to receive(:upload_file).
1522
1586
  with(
1523
1587
  anything,
1524
- {
1588
+ hash_including(
1525
1589
  content_type: "image/png",
1526
1590
  acl: :"public-read",
1527
1591
  storage_class: :reduced_redundancy,
1528
- },
1592
+ ),
1529
1593
  )
1530
1594
  @dummy.save
1531
1595
  end
@@ -1667,10 +1731,14 @@ describe Paperclip::Storage::S3 do
1667
1731
  context "and saved" do
1668
1732
  before do
1669
1733
  object = double
1670
- allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1734
+ if s3_uses_transfer_manager?
1735
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
1736
+ else
1737
+ allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1738
+ end
1671
1739
 
1672
1740
  expect(object).to receive(:upload_file).
1673
- with(anything, { content_type: "image/png", acl: :"public-read" })
1741
+ with(anything, hash_including(content_type: "image/png", acl: :"public-read"))
1674
1742
  @dummy.save
1675
1743
  end
1676
1744
 
@@ -1705,10 +1773,14 @@ describe Paperclip::Storage::S3 do
1705
1773
  context "and saved" do
1706
1774
  before do
1707
1775
  object = double
1708
- allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1776
+ if s3_uses_transfer_manager?
1777
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object)
1778
+ else
1779
+ allow(@dummy.avatar).to receive(:s3_object).and_return(object)
1780
+ end
1709
1781
 
1710
1782
  expect(object).to receive(:upload_file).
1711
- with(anything, { content_type: "image/png", acl: :private })
1783
+ with(anything, hash_including(content_type: "image/png", acl: :private))
1712
1784
  @dummy.save
1713
1785
  end
1714
1786
 
@@ -1748,16 +1820,21 @@ describe Paperclip::Storage::S3 do
1748
1820
 
1749
1821
  context "and saved" do
1750
1822
  before do
1751
- [:thumb, :original].each do |style|
1752
- object = double
1753
- allow(@dummy.avatar).to receive(:s3_object).with(style).and_return(object)
1823
+ object = double
1824
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object) if s3_uses_transfer_manager?
1754
1825
 
1826
+ [:thumb, :original].each do |style|
1827
+ expected_args = { content_type: "image/png", acl: style == :thumb ? :public_read : :private }
1828
+ if s3_uses_transfer_manager?
1829
+ expected_args = expected_args.merge({bucket: "testing", key: "avatars/#{style}/5k.png"})
1830
+ else
1831
+ allow(@dummy.avatar).to receive(:s3_object).with(style).and_return(object)
1832
+ end
1755
1833
  expect(object).to receive(:upload_file).
1756
- with(anything,
1757
- {
1758
- content_type: "image/png",
1759
- acl: style == :thumb ? :public_read : :private
1760
- })
1834
+ with(
1835
+ anything,
1836
+ hash_including(expected_args)
1837
+ )
1761
1838
  end
1762
1839
  @dummy.save
1763
1840
  end
@@ -1821,18 +1898,24 @@ describe Paperclip::Storage::S3 do
1821
1898
 
1822
1899
  context "and saved" do
1823
1900
  before do
1824
- [:thumb, :original].each do |style|
1825
- object = double
1826
- allow(@dummy.avatar).to receive(:s3_object).with(style).and_return(object)
1901
+ object = double
1902
+ allow(@dummy.avatar).to receive(:s3_transfer_manager).and_return(object) if s3_uses_transfer_manager?
1827
1903
 
1904
+ [:thumb, :original].each do |style|
1905
+ expected_args = {
1906
+ content_type: "image/png",
1907
+ acl: :"public-read",
1908
+ content_disposition: 'attachment; filename="Custom Avatar Name.png"'
1909
+ }
1910
+ if s3_uses_transfer_manager?
1911
+ expected_args = expected_args.merge({bucket: "testing", key: "avatars/#{style}/5k.png"})
1912
+ else
1913
+ allow(@dummy.avatar).to receive(:s3_object).with(style).and_return(object)
1914
+ end
1828
1915
  expect(object).to receive(:upload_file).
1829
1916
  with(
1830
1917
  anything,
1831
- {
1832
- content_type: "image/png",
1833
- acl: :"public-read",
1834
- content_disposition: 'attachment; filename="Custom Avatar Name.png"',
1835
- },
1918
+ hash_including(expected_args)
1836
1919
  )
1837
1920
  end
1838
1921
  @dummy.save
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kt-paperclip
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.2
4
+ version: 7.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Surendra Singhi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-19 00:00:00.000000000 Z
11
+ date: 2026-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -372,7 +372,7 @@ files:
372
372
  - CONTRIBUTING.md
373
373
  - Gemfile
374
374
  - LICENSE
375
- - NEWS
375
+ - OLD_NEWS
376
376
  - README.md
377
377
  - RELEASING.md
378
378
  - Rakefile
@@ -434,6 +434,7 @@ files:
434
434
  - lib/paperclip/io_adapters/uploaded_file_adapter.rb
435
435
  - lib/paperclip/io_adapters/uri_adapter.rb
436
436
  - lib/paperclip/locales/en.yml
437
+ - lib/paperclip/locales/fr.yml
437
438
  - lib/paperclip/locales/gd.yml
438
439
  - lib/paperclip/logger.rb
439
440
  - lib/paperclip/matchers.rb