kithe 1.1.2 → 2.0.0.pre.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/jobs/kithe/asset_delete_job.rb +5 -2
- data/app/jobs/kithe/asset_promote_job.rb +12 -2
- data/app/models/kithe/asset.rb +14 -6
- data/app/models/kithe/asset/derivative_updater.rb +2 -3
- data/app/uploaders/kithe/asset_uploader.rb +24 -21
- data/app/uploaders/kithe/derivative_uploader.rb +7 -3
- data/lib/kithe/version.rb +1 -1
- data/lib/shrine/plugins/kithe_accept_remote_url.rb +36 -9
- data/lib/shrine/plugins/kithe_multi_cache.rb +3 -6
- data/lib/shrine/plugins/kithe_promotion_callbacks.rb +82 -0
- data/lib/shrine/plugins/kithe_promotion_directives.rb +111 -0
- data/spec/dummy/log/development.log +1 -0
- data/spec/dummy/log/test.log +51669 -0
- data/spec/models/kithe/asset/asset_create_derivatives_spec.rb +7 -3
- data/spec/models/kithe/asset/asset_promotion_hooks_spec.rb +179 -12
- data/spec/models/kithe/asset_spec.rb +3 -2
- data/spec/models/kithe/derivative_spec.rb +4 -4
- data/spec/shrine/kithe_multi_cache_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/test_support/shrine_spec_support.rb +2 -1
- metadata +9 -8
- data/lib/shrine/plugins/kithe_promotion_hooks.rb +0 -138
@@ -27,8 +27,12 @@ describe "Kithe::Asset derivative definitions", queue_adapter: :test do
|
|
27
27
|
).tap do |a|
|
28
28
|
# We want to promote without create_derivatives being automatically called
|
29
29
|
# as usual, so we can test create_derivatives manually.
|
30
|
-
a.file_attacher.set_promotion_directives(
|
30
|
+
a.file_attacher.set_promotion_directives(create_derivatives: false)
|
31
31
|
a.promote
|
32
|
+
|
33
|
+
# Precondition assumptions for our test setup to be valid
|
34
|
+
expect(a.file_attacher.stored?).to be(true)
|
35
|
+
expect(a.derivatives).to be_empty
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
@@ -101,7 +105,7 @@ describe "Kithe::Asset derivative definitions", queue_adapter: :test do
|
|
101
105
|
asset.create_derivatives
|
102
106
|
|
103
107
|
jpg_deriv = asset.derivatives.find {|d| d.key == "a_jpg"}
|
104
|
-
expect(jpg_deriv.file.storage_key).to eq(
|
108
|
+
expect(jpg_deriv.file.storage_key).to eq(:kithe_derivatives)
|
105
109
|
end
|
106
110
|
|
107
111
|
|
@@ -147,7 +151,7 @@ describe "Kithe::Asset derivative definitions", queue_adapter: :test do
|
|
147
151
|
deriv = asset.derivatives.first
|
148
152
|
|
149
153
|
expect(deriv).to be_present
|
150
|
-
expect(deriv.file.storage_key).to eq(
|
154
|
+
expect(deriv.file.storage_key).to eq(:store)
|
151
155
|
end
|
152
156
|
end
|
153
157
|
|
@@ -15,6 +15,28 @@ describe "Kithe::Asset promotion hooks", queue_adapter: :inline do
|
|
15
15
|
)
|
16
16
|
}
|
17
17
|
|
18
|
+
describe "before_promotion" do
|
19
|
+
temporary_class("TestAsset") do
|
20
|
+
Class.new(Kithe::Asset) do
|
21
|
+
before_promotion do
|
22
|
+
$metadata_in_before_promotion = self.file.metadata
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
before do
|
27
|
+
$metadata_in_before_promotion = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# we have a built-in before_promotion for metadata extraction,
|
31
|
+
# make sure it happens before any additional before_promotions,
|
32
|
+
# so they can eg use it to cancel
|
33
|
+
it "has access to automatic metadata extraction" do
|
34
|
+
unsaved_asset.save!
|
35
|
+
expect($metadata_in_before_promotion).to be_present
|
36
|
+
expect($metadata_in_before_promotion['sha512']).to be_present
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
18
40
|
describe "before_promotion cancellation" do
|
19
41
|
temporary_class("TestAsset") do
|
20
42
|
Class.new(Kithe::Asset) do
|
@@ -28,23 +50,138 @@ describe "Kithe::Asset promotion hooks", queue_adapter: :inline do
|
|
28
50
|
end
|
29
51
|
end
|
30
52
|
|
31
|
-
|
32
|
-
|
53
|
+
describe "with inline promotion", queue_adapter: :test do
|
54
|
+
before do
|
55
|
+
unsaved_asset.file_attacher.set_promotion_directives(promote: :inline)
|
56
|
+
end
|
33
57
|
|
34
|
-
|
35
|
-
|
36
|
-
|
58
|
+
it "cancels" do
|
59
|
+
expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:promote)
|
60
|
+
|
61
|
+
unsaved_asset.save!
|
62
|
+
unsaved_asset.reload
|
63
|
+
expect(unsaved_asset.reload.stored?).to be(false)
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "with promotion_directives[:skip_callbacks]" do
|
67
|
+
it "doesn't cancel" do
|
68
|
+
expect_any_instance_of(Kithe::AssetUploader::Attacher).to receive(:promote).and_call_original
|
69
|
+
|
70
|
+
unsaved_asset.file_attacher.set_promotion_directives(skip_callbacks: true)
|
71
|
+
unsaved_asset.save!
|
72
|
+
unsaved_asset.reload
|
73
|
+
|
74
|
+
expect(unsaved_asset.stored?).to be(true)
|
75
|
+
end
|
76
|
+
end
|
37
77
|
end
|
38
78
|
|
39
|
-
describe "with
|
40
|
-
it "
|
41
|
-
expect_any_instance_of(Kithe::AssetUploader::Attacher).
|
79
|
+
describe "with backgrounding promotion", queue_adapter: :inline do
|
80
|
+
it "cancels" do
|
81
|
+
expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:promote)
|
42
82
|
|
43
|
-
unsaved_asset.file_attacher.set_promotion_directives(skip_callbacks: true)
|
44
83
|
unsaved_asset.save!
|
45
84
|
unsaved_asset.reload
|
85
|
+
expect(unsaved_asset.stored?).to be(false)
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "with promotion_directives[:skip_callbacks]" do
|
89
|
+
it "doesn't cancel" do
|
90
|
+
expect_any_instance_of(Kithe::AssetUploader::Attacher).to receive(:promote).and_call_original
|
91
|
+
|
92
|
+
unsaved_asset.file_attacher.set_promotion_directives(skip_callbacks: true)
|
93
|
+
unsaved_asset.save!
|
94
|
+
unsaved_asset.reload
|
95
|
+
|
96
|
+
expect(unsaved_asset.stored?).to be(true)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
describe "assigning directly to store" do
|
103
|
+
temporary_class("TestAsset") do
|
104
|
+
Class.new(Kithe::Asset) do
|
105
|
+
before_promotion do
|
106
|
+
raise "Should not call before_promotion"
|
107
|
+
end
|
108
|
+
|
109
|
+
after_promotion do
|
110
|
+
raise "Should not call after_promotion"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
let(:asset) {
|
116
|
+
TestAsset.create(title: "test")
|
117
|
+
}
|
118
|
+
|
119
|
+
let(:filepath) { Kithe::Engine.root.join("spec/test_support/images/1x1_pixel.jpg") }
|
120
|
+
|
121
|
+
describe "with inline promoting" do
|
122
|
+
before do
|
123
|
+
asset.file_attacher.set_promotion_directives(promote: :inline)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should not call callbacks" do
|
127
|
+
expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:promote)
|
128
|
+
|
129
|
+
asset.file_attacher.attach(File.open(filepath))
|
130
|
+
asset.save!
|
131
|
+
|
132
|
+
expect(asset.changed?).to be(false)
|
133
|
+
asset.reload
|
134
|
+
expect(asset.file).to be_present
|
135
|
+
expect(asset.stored?).to be(true)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "with background promoting", queue_adapter: :inline do
|
140
|
+
before do
|
141
|
+
asset.file_attacher.set_promotion_directives(promote: :background)
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should not call callbacks" do
|
145
|
+
expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:promote)
|
146
|
+
|
147
|
+
asset.file_attacher.attach(File.open(filepath))
|
148
|
+
asset.save!
|
149
|
+
|
150
|
+
expect(asset.changed?).to be(false)
|
151
|
+
asset.reload
|
152
|
+
expect(asset.file).to be_present
|
153
|
+
expect(asset.stored?).to be(true)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
describe "calling Asset#promote directly", queue_adapter: :inline do
|
160
|
+
before do
|
161
|
+
unsaved_asset.file_attacher.set_promotion_directives(promote: false)
|
162
|
+
unsaved_asset.save!
|
163
|
+
# precondition
|
164
|
+
expect(unsaved_asset.reload.file_attacher.cached?).to be(true)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "cancels" do
|
168
|
+
expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:promote)
|
169
|
+
|
170
|
+
unsaved_asset.promote
|
171
|
+
unsaved_asset.reload
|
172
|
+
expect(unsaved_asset.stored?).to be(false)
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "with promotion_directives[:skip_callbacks]" do
|
176
|
+
it "doesn't cancel" do
|
177
|
+
expect_any_instance_of(Kithe::AssetUploader::Attacher).to receive(:promote).and_call_original
|
46
178
|
|
47
|
-
|
179
|
+
unsaved_asset.file_attacher.set_promotion_directives(skip_callbacks: true)
|
180
|
+
unsaved_asset.promote
|
181
|
+
unsaved_asset.reload
|
182
|
+
|
183
|
+
expect(unsaved_asset.stored?).to be(true)
|
184
|
+
end
|
48
185
|
end
|
49
186
|
end
|
50
187
|
end
|
@@ -56,7 +193,7 @@ describe "Kithe::Asset promotion hooks", queue_adapter: :inline do
|
|
56
193
|
receiver = after_promotion_receiver
|
57
194
|
Class.new(Kithe::Asset) do
|
58
195
|
after_promotion do
|
59
|
-
receiver.call
|
196
|
+
receiver.call(self)
|
60
197
|
end
|
61
198
|
end
|
62
199
|
end
|
@@ -66,6 +203,29 @@ describe "Kithe::Asset promotion hooks", queue_adapter: :inline do
|
|
66
203
|
unsaved_asset.save!
|
67
204
|
end
|
68
205
|
|
206
|
+
describe "with inline promotion" do
|
207
|
+
before do
|
208
|
+
unsaved_asset.file_attacher.set_promotion_directives(promote: :inline)
|
209
|
+
end
|
210
|
+
|
211
|
+
# this is actually what's checking for following example...
|
212
|
+
let(:after_promotion_receiver) do
|
213
|
+
proc do |asset|
|
214
|
+
expect(asset.changed?).to be(false)
|
215
|
+
|
216
|
+
asset.reload
|
217
|
+
|
218
|
+
expect(asset.stored?).to be(true)
|
219
|
+
expect(asset.sha512).to be_present
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
it "asset has metadata and is finalized" do
|
224
|
+
expect(after_promotion_receiver).to receive(:call).and_call_original
|
225
|
+
unsaved_asset.save!
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
69
229
|
describe "with promotion_directives[:skip_callbacks]" do
|
70
230
|
it "doesn't call" do
|
71
231
|
expect(after_promotion_receiver).not_to receive(:call)
|
@@ -178,7 +338,7 @@ describe "Kithe::Asset promotion hooks", queue_adapter: :inline do
|
|
178
338
|
let!(:existing_file) { saved_asset.file }
|
179
339
|
|
180
340
|
it "can cancel deletion" do
|
181
|
-
|
341
|
+
expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:destroy)
|
182
342
|
|
183
343
|
|
184
344
|
saved_asset.set_promotion_directives(delete: false)
|
@@ -224,5 +384,12 @@ describe "Kithe::Asset promotion hooks", queue_adapter: :inline do
|
|
224
384
|
asset.set_promotion_directives(promote: :inline)
|
225
385
|
expect(asset.file_attacher.promotion_directives).to eq("promote" => "inline")
|
226
386
|
end
|
387
|
+
|
388
|
+
it "setting from instance writer is aggregative" do
|
389
|
+
Kithe::Asset.promotion_directives = { promote: :inline }
|
390
|
+
asset = Kithe::Asset.new
|
391
|
+
asset.set_promotion_directives(create_derivatives: false)
|
392
|
+
expect(asset.file_attacher.promotion_directives).to eq("promote" => "inline", "create_derivatives" => "false")
|
393
|
+
end
|
227
394
|
end
|
228
395
|
end
|
@@ -107,7 +107,7 @@ RSpec.describe Kithe::Asset, type: :model do
|
|
107
107
|
asset.save!
|
108
108
|
asset.reload
|
109
109
|
|
110
|
-
expect(asset.file.storage_key).to eq(asset.file_attacher.store.storage_key.
|
110
|
+
expect(asset.file.storage_key).to eq(asset.file_attacher.store.storage_key.to_sym)
|
111
111
|
expect(asset.stored?).to be true
|
112
112
|
expect(asset.file.read).to include("Example Response")
|
113
113
|
expect(asset.file.id).to end_with(".html") # no query params
|
@@ -120,6 +120,7 @@ RSpec.describe Kithe::Asset, type: :model do
|
|
120
120
|
asset.file = {"id" => "http://www.example.com/bar.html?foo=bar",
|
121
121
|
"storage" => "remote_url",
|
122
122
|
"headers" => {"Authorization" => "Bearer TestToken"}}
|
123
|
+
|
123
124
|
asset.save!
|
124
125
|
|
125
126
|
expect(
|
@@ -172,7 +173,7 @@ RSpec.describe Kithe::Asset, type: :model do
|
|
172
173
|
file: File.open(Kithe::Engine.root.join("spec/test_support/images/1x1_pixel.jpg"))
|
173
174
|
).tap do |a|
|
174
175
|
a.file_attacher.set_promotion_directives(skip_callbacks: true)
|
175
|
-
a.promote
|
176
|
+
#a.promote
|
176
177
|
a.reload
|
177
178
|
a.update_derivative(:existing, StringIO.new("content"))
|
178
179
|
end
|
@@ -52,7 +52,7 @@ RSpec.describe Kithe::Derivative, type: :model, queue_adapter: :test do
|
|
52
52
|
# file is stored
|
53
53
|
expect(derivative.key).to eq(key)
|
54
54
|
expect(derivative.file).to be_present
|
55
|
-
expect(derivative.file.storage_key).to eq(
|
55
|
+
expect(derivative.file.storage_key).to eq(:kithe_derivatives)
|
56
56
|
expect(derivative.file.read).to eq(dummy_content)
|
57
57
|
|
58
58
|
# some metadata we got
|
@@ -63,7 +63,7 @@ RSpec.describe Kithe::Derivative, type: :model, queue_adapter: :test do
|
|
63
63
|
expect(derivative.file.metadata["filename"]).to eq("#{asset.friendlier_id}_some_derivative.jpeg")
|
64
64
|
|
65
65
|
# path on storage is nice and pretty
|
66
|
-
expect(derivative.file.id).to match %r{\A#{asset.id}/#{key}/[a-f0-9]+\.
|
66
|
+
expect(derivative.file.id).to match %r{\A#{asset.id}/#{key}/[a-f0-9]+\.jpeg\Z}
|
67
67
|
end
|
68
68
|
|
69
69
|
it "can add a derivative with custom storage location" do
|
@@ -72,11 +72,11 @@ RSpec.describe Kithe::Derivative, type: :model, queue_adapter: :test do
|
|
72
72
|
expect(derivative).to be_present
|
73
73
|
derivative.reload
|
74
74
|
expect(derivative.file).to be_present
|
75
|
-
expect(derivative.file.storage_key).to eq(
|
75
|
+
expect(derivative.file.storage_key).to eq(:store)
|
76
76
|
end
|
77
77
|
|
78
78
|
it "can add a derivative with custom metadata" do
|
79
|
-
derivative = asset.update_derivative(key, dummy_io, metadata: { foo
|
79
|
+
derivative = asset.update_derivative(key, dummy_io, metadata: { "foo" => "bar" })
|
80
80
|
expect(derivative).to be_present
|
81
81
|
expect(derivative.file.metadata["size"]).to eq(dummy_content.length)
|
82
82
|
expect(derivative.file.metadata["foo"]).to eq("bar")
|
@@ -22,7 +22,7 @@ describe Shrine::Plugins::KitheMultiCache do
|
|
22
22
|
it "can promote from additional cache" do
|
23
23
|
extra_storage.upload(fakeio("test_content"), "test_id")
|
24
24
|
attacher.assign({"id" => "test_id", "storage" => "additional_one"}.to_json)
|
25
|
-
attacher.promote
|
25
|
+
attacher.promote
|
26
26
|
|
27
27
|
uploaded_file = attacher.get
|
28
28
|
expect(uploaded_file).not_to be_nil
|
data/spec/spec_helper.rb
CHANGED
@@ -130,7 +130,7 @@ end
|
|
130
130
|
# https://github.com/shrinerb/shrine/pull/443
|
131
131
|
#
|
132
132
|
require 'sane_patch'
|
133
|
-
SanePatch.patch("shrine", "< 3") do
|
133
|
+
SanePatch.patch("shrine", "< 3.2.2") do
|
134
134
|
require 'shrine/storage/memory'
|
135
135
|
class Shrine::Storage::Memory
|
136
136
|
def open(id, *)
|
@@ -3,6 +3,7 @@ module ShrineSpecSupport
|
|
3
3
|
# https://github.com/shrinerb/shrine/blob/203c2c9a0c83815c9ded1b09d5d006b2a523579c/test/support/generic_helper.rb#L6
|
4
4
|
def test_uploader(storage_key = :store, &block)
|
5
5
|
uploader_class = Class.new(Shrine)
|
6
|
+
uploader_class.plugin :model
|
6
7
|
uploader_class.storages[:cache] = Shrine::Storage::Test.new
|
7
8
|
uploader_class.storages[:store] = Shrine::Storage::Test.new
|
8
9
|
uploader_class.class_eval(&block) if block
|
@@ -13,7 +14,7 @@ module ShrineSpecSupport
|
|
13
14
|
uploader = test_uploader(*args, &block)
|
14
15
|
Object.send(:remove_const, "TestUser") if defined?(TestUser) # for warnings
|
15
16
|
user_class = Object.const_set("TestUser", Struct.new(:avatar_data, :id))
|
16
|
-
user_class.include uploader.class::Attachment
|
17
|
+
user_class.include uploader.class::Attachment(:avatar, **attachment_options)
|
17
18
|
user_class.new.avatar_attacher
|
18
19
|
end
|
19
20
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kithe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.pre.alpha1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Rochkind
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-04-
|
11
|
+
date: 2020-04-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -70,14 +70,14 @@ dependencies:
|
|
70
70
|
requirements:
|
71
71
|
- - "~>"
|
72
72
|
- !ruby/object:Gem::Version
|
73
|
-
version: '2
|
73
|
+
version: '3.2'
|
74
74
|
type: :runtime
|
75
75
|
prerelease: false
|
76
76
|
version_requirements: !ruby/object:Gem::Requirement
|
77
77
|
requirements:
|
78
78
|
- - "~>"
|
79
79
|
- !ruby/object:Gem::Version
|
80
|
-
version: '2
|
80
|
+
version: '3.2'
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
82
|
name: shrine-url
|
83
83
|
requirement: !ruby/object:Gem::Requirement
|
@@ -376,7 +376,8 @@ files:
|
|
376
376
|
- lib/kithe/version.rb
|
377
377
|
- lib/shrine/plugins/kithe_accept_remote_url.rb
|
378
378
|
- lib/shrine/plugins/kithe_multi_cache.rb
|
379
|
-
- lib/shrine/plugins/
|
379
|
+
- lib/shrine/plugins/kithe_promotion_callbacks.rb
|
380
|
+
- lib/shrine/plugins/kithe_promotion_directives.rb
|
380
381
|
- lib/shrine/plugins/kithe_storage_location.rb
|
381
382
|
- lib/tasks/kithe_tasks.rake
|
382
383
|
- lib/vendor/icc/sRGB2014.icc
|
@@ -483,12 +484,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
483
484
|
requirements:
|
484
485
|
- - ">="
|
485
486
|
- !ruby/object:Gem::Version
|
486
|
-
version: '
|
487
|
+
version: '2.5'
|
487
488
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
488
489
|
requirements:
|
489
|
-
- - "
|
490
|
+
- - ">"
|
490
491
|
- !ruby/object:Gem::Version
|
491
|
-
version:
|
492
|
+
version: 1.3.1
|
492
493
|
requirements: []
|
493
494
|
rubygems_version: 3.0.3
|
494
495
|
signing_key:
|
@@ -1,138 +0,0 @@
|
|
1
|
-
class Shrine
|
2
|
-
module Plugins
|
3
|
-
# This adds some features around shrine promotion that we found useful for dealing
|
4
|
-
# with backgrounding promotion.
|
5
|
-
#
|
6
|
-
# * It will run shrine uploader metadata extraction routines on _any promotion_,
|
7
|
-
# also adding a `promoting: true` key to the shrine context for that metadata
|
8
|
-
# extraction. (Using shrine refresh_metadata plugin)
|
9
|
-
#
|
10
|
-
# * We separately give our Kithe::Asset model class an activemodel callback
|
11
|
-
# "promotion" hook. This plugin will call those callbacks around promotion (whether background
|
12
|
-
# or foreground) -- before, after, or around.
|
13
|
-
#
|
14
|
-
# If a callback does a `throw :abort` before promotion, it can cancel promotion. This could
|
15
|
-
# be used to cancel promotion for a validation failure of some kind -- you'd want to somehow
|
16
|
-
# store or notify what happened, otherwise to the app and it's users it will just look like
|
17
|
-
# the thing was never promoted for unknown reasons.
|
18
|
-
#
|
19
|
-
# After promotion hooks can be used to hook into things you want to do only after a promotion;
|
20
|
-
# since promotion is backgrounded it would be otherwise inconvenient to execute something
|
21
|
-
# only after promotion completes.
|
22
|
-
#
|
23
|
-
# The default Kithe::Asset hooks into after_promotion to run derivatives creation
|
24
|
-
# routines.
|
25
|
-
#
|
26
|
-
# * A special :promotion_directives key in the shrine context, which will be serialized
|
27
|
-
# and restored to be preserved even accross background promotion. It is intended to hold
|
28
|
-
# a hash of arbitrary key/values. The special key :skip_callbacks, when set to a truthy
|
29
|
-
# value, will prevent the promotion callbacks discussed above from happening. So if you want
|
30
|
-
# to save a Kithe::Asset and have promotion happen as usual, but _not_ trigger any callbacks
|
31
|
-
# (including derivative creation):
|
32
|
-
#
|
33
|
-
# some_asset.file = some_assignable_file
|
34
|
-
# some_asset.file_attacher.set_promotion_directives(skip_callbacks: true)
|
35
|
-
# some_asset.save!
|
36
|
-
#
|
37
|
-
# You can add other arbitrary keys which your own code in an uploader or promotion
|
38
|
-
# callback may consult, with `set_promotion_directives` as above. To consult, check
|
39
|
-
# attacher.promotion_directives[:some_key]
|
40
|
-
#
|
41
|
-
# You can also set promotion directives globally for Kithe::Asset or a sub-class, in
|
42
|
-
# a class method. Especially useful for batch processing.
|
43
|
-
#
|
44
|
-
# Kithe::Asset.promotion_directives = { promote: :inline, create_derivatives: :inline }
|
45
|
-
#
|
46
|
-
class KithePromotionHooks
|
47
|
-
# whitelist of allowed promotion_directive keys, so we can raise on typos but still
|
48
|
-
# be extensible. Also serves as some documentation of what directives available.
|
49
|
-
class_attribute :allowed_promotion_directives,
|
50
|
-
instance_writer: false,
|
51
|
-
default: [:promote, :skip_callbacks, :create_derivatives, :delete]
|
52
|
-
|
53
|
-
def self.load_dependencies(uploader, *)
|
54
|
-
uploader.plugin :refresh_metadata
|
55
|
-
uploader.plugin :backgrounding
|
56
|
-
end
|
57
|
-
|
58
|
-
module AttacherClassMethods
|
59
|
-
# Overridden to restore any serialized promotion_directives to context[:promotion_directives],
|
60
|
-
# in backgrounding promotion.
|
61
|
-
def load(data)
|
62
|
-
super.tap do |attacher|
|
63
|
-
if data["promotion_directives"]
|
64
|
-
attacher.context[:promotion_directives] = data["promotion_directives"]
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
module AttacherMethods
|
71
|
-
|
72
|
-
# Set one or more promotion directives, in context[:promotion_directives], that
|
73
|
-
# will be serialized and restored to context for bg promotion. The values are intended
|
74
|
-
# to be simple strings or other json-serializable primitives.
|
75
|
-
#
|
76
|
-
# set_promotion_directives will merge it's results into existing promotion directives,
|
77
|
-
# existing keys will remain. So you can set multiple directives with multiple
|
78
|
-
# calls to set_promotion_directives, or pass multiple keys to one calls.
|
79
|
-
#
|
80
|
-
# @example
|
81
|
-
# some_model.file_attacher.set_promotion_directives(skip_callbacks: true)
|
82
|
-
# some_model.save!
|
83
|
-
def set_promotion_directives(hash)
|
84
|
-
# ActiveJob sometimes has trouble if there are symbols in there, somewhat
|
85
|
-
# unpredictably.
|
86
|
-
hash = hash.collect { |k, v| [k.to_s, v === Symbol ? v.to_s : v.to_s]}.to_h
|
87
|
-
|
88
|
-
unrecognized = hash.keys.collect(&:to_sym) - KithePromotionHooks.allowed_promotion_directives
|
89
|
-
unless unrecognized.length == 0
|
90
|
-
raise ArgumentError.new("Unrecognized promotion directive key: #{unrecognized.join('')}")
|
91
|
-
end
|
92
|
-
|
93
|
-
promotion_directives.merge!(hash)
|
94
|
-
end
|
95
|
-
|
96
|
-
# context[:promotion_directives], lazily initializing to hash for convenience.
|
97
|
-
def promotion_directives
|
98
|
-
context[:promotion_directives] ||= {}
|
99
|
-
end
|
100
|
-
|
101
|
-
# Overridden so our context[:promotion_directives] is serialized for
|
102
|
-
# backgrounding.
|
103
|
-
def dump
|
104
|
-
super.tap do |hash|
|
105
|
-
if context[:promotion_directives]
|
106
|
-
hash["promotion_directives"] = context[:promotion_directives]
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
# Overridden to:
|
112
|
-
# a) refresh metadata as part of promotion (adds `promoting: true` to context for such)
|
113
|
-
# b) call promotion callbacks on Asset model, unless `promotion_directives["skip_callbacks"]`
|
114
|
-
# has been set.
|
115
|
-
def promote(uploaded_file = get, **options)
|
116
|
-
# insist on a metadata extraction, add a new key `promoting: true` in case
|
117
|
-
# anyone is interested.
|
118
|
-
|
119
|
-
uploaded_file.refresh_metadata!(**context.merge(options).merge(promoting: true))
|
120
|
-
|
121
|
-
# Now run ordinary promotion with activemodel callbacks from
|
122
|
-
# the Asset, which will automatically allow them to cancel promotion using
|
123
|
-
# ordinary activemodel callbacck technique of `throw :abort`.
|
124
|
-
if ( !promotion_directives["skip_callbacks"] &&
|
125
|
-
context[:record] &&
|
126
|
-
context[:record].class.respond_to?(:_promotion_callbacks) )
|
127
|
-
context[:record].run_callbacks(:promotion) do
|
128
|
-
super(uploaded_file, **options)
|
129
|
-
end
|
130
|
-
else
|
131
|
-
super(uploaded_file, **options)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
register_plugin(:kithe_promotion_hooks, KithePromotionHooks)
|
137
|
-
end
|
138
|
-
end
|