trusty-cms 7.0.49 → 7.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/app/assets/builds/trusty_cms/ckeditor5.css +459 -81
- data/app/assets/builds/trusty_cms/ckeditor5.css.map +3 -3
- data/app/assets/builds/trusty_cms/ckeditor5.js +11247 -7722
- data/app/assets/builds/trusty_cms/ckeditor5.js.map +4 -4
- data/app/assets/stylesheets/admin/assets.scss +5 -0
- data/app/controllers/admin/assets_controller.rb +7 -14
- data/app/javascript/plugins/asset_tags/asset_tag_builder.js +7 -2
- data/app/models/asset.rb +144 -48
- data/app/models/asset_type.rb +29 -25
- data/app/views/admin/assets/_search_results.html.haml +2 -3
- data/app/views/admin/assets/edit.html.haml +2 -2
- data/app/views/admin/assets/remove.html.haml +1 -1
- data/app/views/admin/configuration/_clipped_edit.html.haml +1 -0
- data/app/views/admin/configuration/_clipped_show.html.haml +2 -0
- data/config/database.yml +30 -0
- data/config/initializers/trusty_cms_config.rb +3 -50
- data/config/locales/en.yml +6 -1
- data/config/routes.rb +0 -2
- data/db/migrate/20110606111250_update_configuration.rb +0 -16
- data/lib/trusty_cms/geometry.rb +117 -0
- data/lib/trusty_cms/version.rb +1 -1
- data/spec/dummy/log/development.log +345 -0
- data/spec/dummy/log/test.log +0 -0
- data/spec/dummy/tmp/cache/747/A70/TrustyCms%3A%3AConfig +0 -0
- data/spec/dummy/tmp/cache/85C/FA0/TrustyCms.cache_mtime +0 -0
- data/spec/dummy/tmp/local_secret.txt +1 -0
- data/spec/dummy/tmp/trusty_config_cache.txt +0 -0
- data/spec/lib/trusty_cms/geometry_spec.rb +28 -0
- data/spec/models/asset_spec.rb +235 -12
- data/trusty_cms.gemspec +1 -1
- data/vendor/extensions/clipped-extension/clipped_extension.rb +4 -9
- data/vendor/extensions/clipped-extension/lib/asset_tags.rb +10 -4
- data/vendor/extensions/clipped-extension/lib/generators/templates/clipped_config.rb +11 -35
- data/vendor/extensions/clipped-extension/lib/tasks/active_storage_tasks.rake +66 -0
- data/vendor/extensions/clipped-extension/lib/tasks/clipped_extension_tasks.rake +5 -2
- data/vendor/extensions/clipped-extension/lib/trusty_cms_clipped_extension/cloud.rb +32 -27
- data/yarn.lock +9 -9
- metadata +21 -8
- data/lib/trusty_cms/deprecation.rb +0 -15
- data/vendor/extensions/clipped-extension/lib/paperclip/frame_grab.rb +0 -73
- data/vendor/extensions/clipped-extension/lib/paperclip/geometry_transformation.rb +0 -80
- data/vendor/extensions/clipped-extension/lib/tasks/paperclip_tasks.rake +0 -79
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe TrustyCms::Geometry do
|
|
4
|
+
describe '.parse' do
|
|
5
|
+
it 'parses basic geometry strings' do
|
|
6
|
+
geom = described_class.parse('100x200')
|
|
7
|
+
expect(geom.width).to eq(100)
|
|
8
|
+
expect(geom.height).to eq(200)
|
|
9
|
+
expect(geom.modifier).to be_nil
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'parses geometry modifiers' do
|
|
13
|
+
geom = described_class.parse('640x480@')
|
|
14
|
+
expect(geom.width).to eq(640)
|
|
15
|
+
expect(geom.height).to eq(480)
|
|
16
|
+
expect(geom.modifier).to eq('@')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '#transformed_by' do
|
|
21
|
+
it 'scales to fit preserving aspect ratio' do
|
|
22
|
+
source = described_class.new(400, 200)
|
|
23
|
+
result = source.transformed_by('100x100')
|
|
24
|
+
expect(result.width).to eq(100)
|
|
25
|
+
expect(result.height).to eq(50)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
data/spec/models/asset_spec.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
require 'rack/test'
|
|
3
|
+
require 'base64'
|
|
4
|
+
require 'stringio'
|
|
3
5
|
|
|
4
6
|
RSpec.describe Asset, type: :model do
|
|
5
7
|
let(:fixtures_path) { TrustyCms::Engine.root.join('spec', 'fixtures', 'files') }
|
|
@@ -9,31 +11,252 @@ RSpec.describe Asset, type: :model do
|
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
describe 'validations' do
|
|
14
|
+
before do
|
|
15
|
+
AssetType.new :image, icon: 'image', styles: :standard, extensions: %w[jpg jpeg png gif], mime_types: %w[image/png image/x-png image/jpeg image/pjpeg image/jpg image/gif] unless AssetType.known?(:image)
|
|
16
|
+
AssetType.new :video, icon: 'video', mime_types: %w[video/mp4 video/mpeg video/quicktime video/webm] unless AssetType.known?(:video)
|
|
17
|
+
AssetType.new :document, icon: 'document', mime_types: %w[application/msword application/rtf text/plain text/html] unless AssetType.known?(:document)
|
|
18
|
+
end
|
|
19
|
+
|
|
12
20
|
it 'is valid when the content type is approved' do
|
|
13
|
-
asset = described_class.new(asset: upload_fixture('sample.
|
|
21
|
+
asset = described_class.new(asset: upload_fixture('sample.txt', 'text/plain'))
|
|
14
22
|
|
|
15
23
|
expect(asset).to be_valid
|
|
16
24
|
end
|
|
17
25
|
|
|
18
26
|
it 'is invalid when the content type is not approved' do
|
|
19
|
-
asset = described_class.new(asset: upload_fixture('sample.txt', '
|
|
27
|
+
asset = described_class.new(asset: upload_fixture('sample.txt', 'application/x-unsupported'))
|
|
20
28
|
|
|
21
29
|
expect(asset).not_to be_valid
|
|
22
|
-
expect(asset.errors[:asset]).to include(a_string_matching(/file
|
|
30
|
+
expect(asset.errors[:asset]).to include(a_string_matching(/file type/i))
|
|
23
31
|
end
|
|
24
32
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
context 'with stubbed size limits (1 MB asset / 2 MB video)' do
|
|
34
|
+
before do
|
|
35
|
+
allow(TrustyCms.config).to receive(:[]).and_call_original
|
|
36
|
+
allow(TrustyCms.config).to receive(:[]).with('assets.max_asset_size').and_return('1')
|
|
37
|
+
allow(TrustyCms.config).to receive(:[]).with('assets.max_video_size').and_return('2')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'is invalid when a non-video file exceeds the maximum asset size' do
|
|
41
|
+
Tempfile.open(['large', '.png']) do |tempfile|
|
|
42
|
+
tempfile.binmode
|
|
43
|
+
tempfile.write('0' * (1.megabyte + 1))
|
|
44
|
+
tempfile.rewind
|
|
45
|
+
|
|
46
|
+
uploaded = Rack::Test::UploadedFile.new(tempfile.path, 'image/png')
|
|
47
|
+
asset = described_class.new(asset: uploaded)
|
|
48
|
+
|
|
49
|
+
expect(asset).not_to be_valid
|
|
50
|
+
expect(asset.errors[:asset]).to include(a_string_matching(/1 MB/))
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'is invalid when a video file exceeds the maximum video size' do
|
|
55
|
+
Tempfile.open(['large', '.mp4']) do |tempfile|
|
|
56
|
+
tempfile.binmode
|
|
57
|
+
tempfile.write('0' * (2.megabytes + 1))
|
|
58
|
+
tempfile.rewind
|
|
30
59
|
|
|
31
|
-
|
|
32
|
-
|
|
60
|
+
uploaded = Rack::Test::UploadedFile.new(tempfile.path, 'video/mp4')
|
|
61
|
+
asset = described_class.new(asset: uploaded)
|
|
33
62
|
|
|
34
|
-
|
|
35
|
-
|
|
63
|
+
expect(asset).not_to be_valid
|
|
64
|
+
expect(asset.errors[:asset]).to include(a_string_matching(/2 MB/))
|
|
65
|
+
end
|
|
36
66
|
end
|
|
67
|
+
|
|
68
|
+
it 'allows a video file that exceeds the asset size limit but is within the video size limit' do
|
|
69
|
+
Tempfile.open(['video', '.mp4']) do |tempfile|
|
|
70
|
+
tempfile.binmode
|
|
71
|
+
tempfile.write('0' * (1.megabyte + 1.kilobyte))
|
|
72
|
+
tempfile.rewind
|
|
73
|
+
|
|
74
|
+
uploaded = Rack::Test::UploadedFile.new(tempfile.path, 'video/mp4')
|
|
75
|
+
asset = described_class.new(asset: uploaded)
|
|
76
|
+
|
|
77
|
+
expect(asset).to be_valid
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'allows a video file within the maximum video size' do
|
|
82
|
+
Tempfile.open(['video', '.mp4']) do |tempfile|
|
|
83
|
+
tempfile.binmode
|
|
84
|
+
tempfile.write('0' * 1.kilobyte)
|
|
85
|
+
tempfile.rewind
|
|
86
|
+
|
|
87
|
+
uploaded = Rack::Test::UploadedFile.new(tempfile.path, 'video/mp4')
|
|
88
|
+
asset = described_class.new(asset: uploaded)
|
|
89
|
+
|
|
90
|
+
expect(asset).to be_valid
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
describe 'active storage metadata' do
|
|
96
|
+
before do
|
|
97
|
+
AssetType.new :image, :styles => :standard, :extensions => %w[png], :mime_types => %w[image/png] unless AssetType.known?(:image)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
let(:png_data) do
|
|
101
|
+
Base64.decode64('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==')
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def png_io
|
|
105
|
+
io = StringIO.new(png_data)
|
|
106
|
+
io.set_encoding(Encoding::BINARY)
|
|
107
|
+
io.rewind
|
|
108
|
+
io
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'exposes filename, content type, and size from the attachment' do
|
|
112
|
+
asset = described_class.new(caption: '')
|
|
113
|
+
asset.asset.attach(io: png_io, filename: 'pixel.png', content_type: 'image/png')
|
|
114
|
+
asset.save!
|
|
115
|
+
|
|
116
|
+
expect(asset.filename).to eq('pixel.png')
|
|
117
|
+
expect(asset.content_type).to eq('image/png')
|
|
118
|
+
expect(asset.byte_size).to eq(png_data.bytesize)
|
|
119
|
+
expect(asset.original_extension).to eq('png')
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'reports styles and extensions from active storage styles' do
|
|
123
|
+
asset = described_class.new(caption: '')
|
|
124
|
+
asset.asset.attach(io: png_io, filename: 'pixel.png', content_type: 'image/png')
|
|
125
|
+
asset.save!
|
|
126
|
+
|
|
127
|
+
expect(asset.style?('thumbnail')).to be(true)
|
|
128
|
+
expect(asset.extension('thumbnail').to_s).to eq('png')
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
describe 'thumbnails' do
|
|
133
|
+
before do
|
|
134
|
+
AssetType.new :image, :styles => :standard, :extensions => %w[png], :mime_types => %w[image/png] unless AssetType.known?(:image)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
let(:png_data) do
|
|
138
|
+
Base64.decode64('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==')
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def png_io
|
|
142
|
+
io = StringIO.new(png_data)
|
|
143
|
+
io.set_encoding(Encoding::BINARY)
|
|
144
|
+
io.rewind
|
|
145
|
+
io
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it 'returns a variant url for known styles' do
|
|
149
|
+
asset = described_class.new(caption: '')
|
|
150
|
+
asset.asset.attach(io: png_io, filename: 'pixel.png', content_type: 'image/png')
|
|
151
|
+
asset.save!
|
|
152
|
+
|
|
153
|
+
variant = instance_double(ActiveStorage::Variant, processed: instance_double(ActiveStorage::Variant, url: '/rails/active_storage/variant/test'))
|
|
154
|
+
allow(asset).to receive(:asset_variant).with('thumbnail').and_return(variant)
|
|
155
|
+
|
|
156
|
+
expect(asset.thumbnail('thumbnail')).to eq('/rails/active_storage/variant/test')
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it 'returns the direct asset url for pdfs without variant processing' do
|
|
160
|
+
asset = described_class.new(caption: '')
|
|
161
|
+
allow(asset).to receive_message_chain(:asset, :attached?).and_return(true)
|
|
162
|
+
allow(asset).to receive(:content_type).and_return('application/pdf')
|
|
163
|
+
allow(asset).to receive_message_chain(:asset, :url).and_return('https://s3.amazonaws.com/bucket/myprefix/system/assets/20260501/doc-abc123.pdf')
|
|
164
|
+
allow(asset).to receive(:rewrite_cloud_url) { |url| url }
|
|
165
|
+
|
|
166
|
+
expect(asset).not_to receive(:asset_variant)
|
|
167
|
+
expect(asset.thumbnail('normal')).to eq('https://s3.amazonaws.com/bucket/myprefix/system/assets/20260501/doc-abc123.pdf')
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
it 'returns the asset type icon when nothing is attached' do
|
|
171
|
+
asset = described_class.new(caption: '')
|
|
172
|
+
allow(asset).to receive_message_chain(:asset, :attached?).and_return(false)
|
|
173
|
+
allow(asset).to receive(:asset_variant).and_return(nil)
|
|
174
|
+
allow(asset).to receive_message_chain(:asset_type, :icon).with('normal').and_return('/assets/admin/image_icon.png')
|
|
175
|
+
|
|
176
|
+
expect(asset.thumbnail('normal')).to eq('/assets/admin/image_icon.png')
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
describe '#render_original' do
|
|
181
|
+
it 'returns true for any style when the asset key starts with the configured prefix' do
|
|
182
|
+
asset = described_class.new
|
|
183
|
+
allow(TrustyCms::Config).to receive(:[]).with('assets.storage.prefix').and_return('myprefix')
|
|
184
|
+
allow(asset).to receive_message_chain(:asset, :attached?).and_return(true)
|
|
185
|
+
allow(asset).to receive_message_chain(:asset, :key).and_return('myprefix/system/assets/20260501/image-abc123.jpg')
|
|
186
|
+
|
|
187
|
+
expect(asset.render_original('normal')).to be(true)
|
|
188
|
+
expect(asset.render_original('thumbnail')).to be(true)
|
|
189
|
+
expect(asset.render_original('original')).to be(true)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it 'returns true when no prefix is configured but the key contains a path separator' do
|
|
193
|
+
asset = described_class.new
|
|
194
|
+
allow(TrustyCms::Config).to receive(:[]).with('assets.storage.prefix').and_return(nil)
|
|
195
|
+
allow(asset).to receive_message_chain(:asset, :attached?).and_return(true)
|
|
196
|
+
allow(asset).to receive_message_chain(:asset, :key).and_return('system/assets/20260501/image-abc123.jpg')
|
|
197
|
+
|
|
198
|
+
expect(asset.render_original('normal')).to be(true)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it 'returns false when the key does not start with the configured prefix' do
|
|
202
|
+
asset = described_class.new
|
|
203
|
+
allow(TrustyCms::Config).to receive(:[]).with('assets.storage.prefix').and_return('myprefix')
|
|
204
|
+
allow(asset).to receive_message_chain(:asset, :attached?).and_return(true)
|
|
205
|
+
allow(asset).to receive_message_chain(:asset, :key).and_return('randomlegacykey')
|
|
206
|
+
|
|
207
|
+
expect(asset.render_original('normal')).to be(false)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it 'returns false when no asset is attached' do
|
|
211
|
+
asset = described_class.new
|
|
212
|
+
allow(asset).to receive_message_chain(:asset, :attached?).and_return(false)
|
|
213
|
+
|
|
214
|
+
expect(asset.render_original('normal')).to be(false)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
describe '#public_url' do
|
|
219
|
+
let(:original_url) { 'https://s3.amazonaws.com/bucket/myprefix/system/assets/20260501/image-abc123.jpg' }
|
|
220
|
+
let(:variant_url) { 'https://s3.amazonaws.com/bucket/variants/abc/xyz.jpg' }
|
|
221
|
+
|
|
222
|
+
it 'returns the original url for new-style assets regardless of style' do
|
|
223
|
+
asset = described_class.new
|
|
224
|
+
allow(asset).to receive(:render_original).and_return(true)
|
|
225
|
+
allow(asset).to receive_message_chain(:asset, :url).and_return(original_url)
|
|
226
|
+
allow(asset).to receive(:rewrite_cloud_url) { |url| url }
|
|
227
|
+
|
|
228
|
+
expect(asset.public_url('normal')).to eq(original_url)
|
|
229
|
+
expect(asset.public_url('thumbnail')).to eq(original_url)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it 'returns the original url when style_name is original' do
|
|
233
|
+
asset = described_class.new
|
|
234
|
+
allow(asset).to receive(:render_original).and_return(false)
|
|
235
|
+
allow(asset).to receive_message_chain(:asset, :url).and_return(original_url)
|
|
236
|
+
allow(asset).to receive(:rewrite_cloud_url) { |url| url }
|
|
237
|
+
|
|
238
|
+
expect(asset.public_url('original')).to eq(original_url)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
it 'returns a variant url for old-style assets' do
|
|
242
|
+
asset = described_class.new
|
|
243
|
+
allow(asset).to receive(:render_original).and_return(false)
|
|
244
|
+
processed = instance_double(ActiveStorage::Variant, url: variant_url)
|
|
245
|
+
variant = instance_double(ActiveStorage::Variant, processed: processed)
|
|
246
|
+
allow(asset).to receive(:asset_variant).and_return(variant)
|
|
247
|
+
allow(asset).to receive(:rewrite_cloud_url) { |url| url }
|
|
248
|
+
|
|
249
|
+
expect(asset.public_url('normal')).to eq(variant_url)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it 'falls back to the asset url when no variant exists for an old-style asset' do
|
|
253
|
+
asset = described_class.new
|
|
254
|
+
allow(asset).to receive(:render_original).and_return(false)
|
|
255
|
+
allow(asset).to receive(:asset_variant).and_return(nil)
|
|
256
|
+
allow(asset).to receive_message_chain(:asset, :url).and_return('https://s3.amazonaws.com/bucket/randomlegacykey')
|
|
257
|
+
allow(asset).to receive(:rewrite_cloud_url) { |url| url }
|
|
258
|
+
|
|
259
|
+
expect(asset.public_url('normal')).to eq('https://s3.amazonaws.com/bucket/randomlegacykey')
|
|
37
260
|
end
|
|
38
261
|
end
|
|
39
262
|
end
|
data/trusty_cms.gemspec
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
require File.expand_path(__FILE__ + '/../lib/trusty_cms/version.rb')
|
|
5
5
|
Gem::Specification.new do |s|
|
|
6
|
-
s.required_ruby_version = '>= 3.
|
|
6
|
+
s.required_ruby_version = '>= 3.3.4'
|
|
7
7
|
s.name = 'trusty-cms'
|
|
8
8
|
s.version = TrustyCms::VERSION
|
|
9
9
|
s.platform = Gem::Platform::RUBY
|
|
@@ -9,11 +9,10 @@ class ClippedExtension < TrustyCms::Extension
|
|
|
9
9
|
TrustyCms::AdminUI.send :include, ClippedAdminUI unless defined? admin.asset # defines shards for extension of the asset-admin interface
|
|
10
10
|
Admin::PagesController.send :helper, Admin::AssetsHelper # currently only provides a description of asset sizes
|
|
11
11
|
Page.send :include, AssetTags # radius tags for selecting sets of assets and presenting each one
|
|
12
|
-
AssetType.new :image, :icon => 'image', :default_radius_tag => 'image', :
|
|
13
|
-
AssetType.new :video, :icon => 'video', :
|
|
14
|
-
AssetType.new :audio, :icon => 'audio', :mime_types => %w[audio/mpeg audio/mpg audio/ogg
|
|
15
|
-
AssetType.new :pdf, :icon => 'pdf', :
|
|
16
|
-
AssetType.new :document, :icon => 'document', :mime_types => %w[application/msword application/rtf application/vnd.ms-excel application/vnd.ms-powerpoint application/vnd.ms-project application/vnd.ms-works text/plain text/html]
|
|
12
|
+
AssetType.new :image, :icon => 'image', :default_radius_tag => 'image', :styles => :standard, :extensions => %w[jpg jpeg png gif webp avif], :mime_types => %w[image/png image/x-png image/jpeg image/pjpeg image/jpg image/gif image/webp image/avif]
|
|
13
|
+
AssetType.new :video, :icon => 'video', :styles => :standard, :mime_types => %w[video/mp4 video/webm video/quicktime video/mpeg video/ogg video/mp2t application/x-mp4]
|
|
14
|
+
AssetType.new :audio, :icon => 'audio', :mime_types => %w[audio/mpeg audio/mpg audio/ogg audio/mp4 audio/wav audio/x-wav application/ogg audio/flac]
|
|
15
|
+
AssetType.new :pdf, :icon => 'pdf', :extensions => %w{pdf}, :mime_types => %w[application/pdf application/x-pdf], :styles => :standard
|
|
17
16
|
AssetType.new :other, :icon => 'unknown'
|
|
18
17
|
|
|
19
18
|
admin.asset ||= TrustyCms::AdminUI.load_default_asset_regions # loads the shards defined in AssetsAdminUI
|
|
@@ -23,10 +22,6 @@ class ClippedExtension < TrustyCms::Extension
|
|
|
23
22
|
admin.configuration.show.add :trusty_config, 'admin/configuration/clipped_show', :after => 'defaults'
|
|
24
23
|
admin.configuration.edit.add :form, 'admin/configuration/clipped_edit', :after => 'edit_defaults'
|
|
25
24
|
|
|
26
|
-
if TrustyCms::Config.table_exists? && TrustyCms::config["paperclip.command_path"] # This is needed for testing if you are using mod_rails
|
|
27
|
-
Paperclip.options[:command_path] = TrustyCms::config["paperclip.command_path"]
|
|
28
|
-
end
|
|
29
|
-
|
|
30
25
|
tab "Assets", :after => "Content" do
|
|
31
26
|
add_item "All", "/admin/assets"
|
|
32
27
|
end
|
|
@@ -181,17 +181,24 @@ module AssetTags
|
|
|
181
181
|
options = tag.attr.dup
|
|
182
182
|
# XXX build_regexp_for comes from StandardTags
|
|
183
183
|
regexp = build_regexp_for(tag, options)
|
|
184
|
-
asset_content_type = tag.locals.asset.
|
|
184
|
+
asset_content_type = tag.locals.asset.content_type
|
|
185
185
|
tag.expand unless asset_content_type.match(regexp).nil?
|
|
186
186
|
end
|
|
187
187
|
|
|
188
|
+
attribute_mappings = {
|
|
189
|
+
asset_file_name: :filename,
|
|
190
|
+
asset_content_type: :content_type,
|
|
191
|
+
asset_file_size: :byte_size,
|
|
192
|
+
}
|
|
193
|
+
|
|
188
194
|
[:title, :caption, :asset_file_name, :extension, :asset_content_type, :asset_file_size, :id].each do |method|
|
|
189
195
|
desc %{
|
|
190
196
|
Renders the @#{method.to_s}@ attribute of the asset
|
|
191
197
|
}
|
|
192
198
|
tag "asset:#{method.to_s}" do |tag|
|
|
193
199
|
asset, options = asset_and_options(tag)
|
|
194
|
-
|
|
200
|
+
mapped = attribute_mappings.fetch(method, method)
|
|
201
|
+
asset.send(mapped) rescue nil
|
|
195
202
|
end
|
|
196
203
|
end
|
|
197
204
|
|
|
@@ -201,7 +208,7 @@ module AssetTags
|
|
|
201
208
|
|
|
202
209
|
tag 'asset:filename' do |tag|
|
|
203
210
|
asset, options = asset_and_options(tag)
|
|
204
|
-
asset.
|
|
211
|
+
asset.filename rescue nil
|
|
205
212
|
end
|
|
206
213
|
|
|
207
214
|
desc %{
|
|
@@ -308,4 +315,3 @@ module AssetTags
|
|
|
308
315
|
}
|
|
309
316
|
end
|
|
310
317
|
end
|
|
311
|
-
|
|
@@ -3,11 +3,8 @@ TrustyCms.config do |config|
|
|
|
3
3
|
# Uncomment and change the settings below to customize the Clipped extension
|
|
4
4
|
|
|
5
5
|
# The default settings
|
|
6
|
-
# config["
|
|
7
|
-
# config["
|
|
8
|
-
# config["paperclip.storage"] = "filesystem"
|
|
9
|
-
# config["paperclip.skip_filetype_validation"] = true
|
|
10
|
-
# config["assets.max_asset_size"] = 5 # megabytes
|
|
6
|
+
# config["assets.max_asset_size"] = 10 # megabytes
|
|
7
|
+
# config["assets.max_video_size"] = 50 # megabytes
|
|
11
8
|
# config["assets.display_size"] = "normal"
|
|
12
9
|
# config["assets.insertion_size"] = "normal"
|
|
13
10
|
# config["assets.create_image_thumbnails?"] = true
|
|
@@ -19,35 +16,14 @@ TrustyCms.config do |config|
|
|
|
19
16
|
# config["assets.thumbnails.video"] = "normal:size=640x640>,format=jpg|small:size=320x320>,format=jpg"
|
|
20
17
|
# config["assets.thumbnails.pdf"] = "normal:size=640x640>,format=jpg|small:size=320x320>,format=jpg"
|
|
21
18
|
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# config["
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
# config["paperclip.fog.host"] = "http://assets.example.com"
|
|
32
|
-
# optionally set the S3 region of your bucket; defaults to US East
|
|
33
|
-
# Asia North East => ap-northeast-1
|
|
34
|
-
# Asia South East => ap-southeast-1
|
|
35
|
-
# EU West => eu-west-1
|
|
36
|
-
# US East => us-east-1
|
|
37
|
-
# US West => us-west-1
|
|
38
|
-
# config["paperclip.s3.region"] = "us-east-1"
|
|
39
|
-
|
|
40
|
-
# An example of using Rackspace Cloud Files
|
|
41
|
-
# add `gem "fog", "~> 1.0"` to your Gemfile and run `bundle install`
|
|
42
|
-
# config["paperclip.storage"] = "fog"
|
|
43
|
-
# config["paperclip.path"] = ":attachment/:id/:style/:basename:no_original_style.:extension"
|
|
44
|
-
# config["paperclip.fog.provider"] = "Rackspace"
|
|
45
|
-
# config["paperclip.fog.directory"] = "container-name"
|
|
46
|
-
# config["paperclip.rackspace.username"] = "RACKSPACE_USERNAME"
|
|
47
|
-
# config["paperclip.rackspace.api_key"] = "RACKSPACE_API_KEY"
|
|
48
|
-
# paperclip.fog.host is your Cloud Files CDN URL
|
|
49
|
-
# config["paperclip.fog.host"] = "http://a.b.c.rackcdn.com"
|
|
50
|
-
# optionally use a custom domain name; requires a CNAME DNS record
|
|
51
|
-
# config["paperclip.fog.host"] = "http://assets.example.com"
|
|
19
|
+
# ActiveStorage configuration is handled in config/storage.yml and
|
|
20
|
+
# config.active_storage.service (per environment). For S3 or other
|
|
21
|
+
# cloud providers, configure the appropriate ActiveStorage service.
|
|
22
|
+
#
|
|
23
|
+
# Optional CDN host override for ActiveStorage URLs:
|
|
24
|
+
# config["assets.cdn.host"] = "https://assets.example.com"
|
|
25
|
+
#
|
|
26
|
+
# Or provide a dynamic host in an initializer:
|
|
27
|
+
# TrustyCmsClippedExtension::Cloud.host_provider = -> { AssetBucket.current&.asset_host }
|
|
52
28
|
|
|
53
29
|
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
def obtain_class
|
|
2
|
+
class_name = ENV['CLASS'] || ENV['class']
|
|
3
|
+
raise "Must specify CLASS" unless class_name
|
|
4
|
+
Object.const_get(class_name)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def obtain_attachments(klass)
|
|
8
|
+
name = ENV['ATTACHMENT'] || ENV['attachment']
|
|
9
|
+
attachment_names = if klass.respond_to?(:reflect_on_all_attachments)
|
|
10
|
+
klass.reflect_on_all_attachments.map(&:name)
|
|
11
|
+
else
|
|
12
|
+
[]
|
|
13
|
+
end
|
|
14
|
+
raise "Class #{klass.name} has no ActiveStorage attachments" if attachment_names.empty?
|
|
15
|
+
if name.present? && attachment_names.include?(name.to_sym)
|
|
16
|
+
[name.to_sym]
|
|
17
|
+
else
|
|
18
|
+
attachment_names
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def for_all_attachments
|
|
23
|
+
klass = obtain_class
|
|
24
|
+
names = obtain_attachments(klass)
|
|
25
|
+
|
|
26
|
+
klass.find_each do |instance|
|
|
27
|
+
names.each do |name|
|
|
28
|
+
attachment = instance.public_send(name)
|
|
29
|
+
result = if attachment.attached?
|
|
30
|
+
yield(instance, name, attachment)
|
|
31
|
+
else
|
|
32
|
+
true
|
|
33
|
+
end
|
|
34
|
+
print result ? "." : "x"; $stdout.flush
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
puts " Done."
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
namespace :active_storage do
|
|
41
|
+
desc "Refreshes both metadata and variants."
|
|
42
|
+
task :refresh => ["active_storage:refresh:metadata", "active_storage:refresh:variants"]
|
|
43
|
+
|
|
44
|
+
namespace :refresh do
|
|
45
|
+
desc "Regenerates variants for a given CLASS (and optional ATTACHMENT)."
|
|
46
|
+
task :variants => :environment do
|
|
47
|
+
for_all_attachments do |instance, name, attachment|
|
|
48
|
+
if instance.respond_to?(:refresh_variants!) && name == :asset
|
|
49
|
+
instance.refresh_variants!
|
|
50
|
+
else
|
|
51
|
+
attachment.preview if attachment.previewable?
|
|
52
|
+
end
|
|
53
|
+
true
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
desc "Re-analyzes metadata for a given CLASS (and optional ATTACHMENT)."
|
|
58
|
+
task :metadata => :environment do
|
|
59
|
+
for_all_attachments do |instance, name, attachment|
|
|
60
|
+
attachment.analyze unless attachment.analyzed?
|
|
61
|
+
instance.save(validate: false)
|
|
62
|
+
true
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -52,8 +52,11 @@ namespace :trusty do
|
|
|
52
52
|
asset_path = File.join(Rails.root, "assets")
|
|
53
53
|
mkdir_p asset_path
|
|
54
54
|
Asset.find(:all).each do |asset|
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
next unless asset.asset.attached?
|
|
56
|
+
puts "Exporting #{asset.filename}"
|
|
57
|
+
asset.asset.open do |file|
|
|
58
|
+
cp file.path, File.join(asset_path, asset.filename)
|
|
59
|
+
end
|
|
57
60
|
end
|
|
58
61
|
puts "Done."
|
|
59
62
|
end
|
|
@@ -1,41 +1,46 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
|
|
1
3
|
module TrustyCmsClippedExtension
|
|
2
4
|
|
|
3
5
|
module Cloud
|
|
6
|
+
mattr_accessor :host_provider
|
|
4
7
|
|
|
5
8
|
def self.credentials
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
:aws_access_key_id => TrustyCms.config["paperclip.s3.key"],
|
|
11
|
-
:aws_secret_access_key => TrustyCms.config["paperclip.s3.secret"],
|
|
12
|
-
:region => TrustyCms.config["paperclip.s3.region"],
|
|
13
|
-
}
|
|
14
|
-
when "Google"
|
|
15
|
-
{
|
|
16
|
-
:provider => "Google",
|
|
17
|
-
:rackspace_username => TrustyCms.config["paperclip.google_storage.access_key_id"],
|
|
18
|
-
:rackspace_api_key => TrustyCms.config["paperclip.google_storage.secret_access_key"]
|
|
19
|
-
}
|
|
20
|
-
when "Rackspace"
|
|
21
|
-
{
|
|
22
|
-
:provider => "Rackspace",
|
|
23
|
-
:rackspace_username => TrustyCms.config["paperclip.rackspace.username"],
|
|
24
|
-
:rackspace_api_key => TrustyCms.config["paperclip.rackspace.api_key"]
|
|
25
|
-
}
|
|
26
|
-
end
|
|
9
|
+
service = ActiveStorage::Blob.service
|
|
10
|
+
return {} unless service.respond_to?(:config)
|
|
11
|
+
|
|
12
|
+
service.config
|
|
27
13
|
end
|
|
28
14
|
|
|
29
15
|
def self.host
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
else
|
|
35
|
-
nil
|
|
16
|
+
if host_provider
|
|
17
|
+
host_provider.call
|
|
18
|
+
elsif defined?(TrustyCms::Config)
|
|
19
|
+
TrustyCms::Config['assets.cdn.host']
|
|
36
20
|
end
|
|
37
21
|
end
|
|
38
22
|
|
|
23
|
+
def self.rewrite_url(url)
|
|
24
|
+
return url unless url.present?
|
|
25
|
+
configured_host = host
|
|
26
|
+
return url if configured_host.blank?
|
|
27
|
+
|
|
28
|
+
uri = URI.parse(url)
|
|
29
|
+
return url unless uri.is_a?(URI::HTTP)
|
|
30
|
+
|
|
31
|
+
host_uri = URI.parse(configured_host.to_s.match?(/\Ahttps?:\/\//) ? configured_host.to_s : "https://#{configured_host}")
|
|
32
|
+
uri.scheme = host_uri.scheme if host_uri.scheme
|
|
33
|
+
uri.host = host_uri.host if host_uri.host
|
|
34
|
+
uri.port = host_uri.port if host_uri.port
|
|
35
|
+
|
|
36
|
+
if host_uri.path.present? && host_uri.path != '/'
|
|
37
|
+
uri.path = File.join(host_uri.path, uri.path.sub(%r{\A/}, ''))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
uri.to_s
|
|
41
|
+
rescue URI::InvalidURIError
|
|
42
|
+
url
|
|
43
|
+
end
|
|
39
44
|
end
|
|
40
45
|
|
|
41
46
|
end
|
data/yarn.lock
CHANGED
|
@@ -1735,9 +1735,9 @@ flat-cache@^3.0.4:
|
|
|
1735
1735
|
rimraf "^3.0.2"
|
|
1736
1736
|
|
|
1737
1737
|
flatted@^3.2.9:
|
|
1738
|
-
version "3.
|
|
1739
|
-
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.
|
|
1740
|
-
integrity sha512-
|
|
1738
|
+
version "3.4.2"
|
|
1739
|
+
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.4.2.tgz#f5c23c107f0f37de8dbdf24f13722b3b98d52726"
|
|
1740
|
+
integrity sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==
|
|
1741
1741
|
|
|
1742
1742
|
fs.realpath@^1.0.0:
|
|
1743
1743
|
version "1.0.0"
|
|
@@ -2262,9 +2262,9 @@ lodash.truncate@^4.4.2:
|
|
|
2262
2262
|
integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==
|
|
2263
2263
|
|
|
2264
2264
|
lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21:
|
|
2265
|
-
version "4.
|
|
2266
|
-
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.
|
|
2267
|
-
integrity sha512-
|
|
2265
|
+
version "4.18.1"
|
|
2266
|
+
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.18.1.tgz#ff2b66c1f6326d59513de2407bf881439812771c"
|
|
2267
|
+
integrity sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==
|
|
2268
2268
|
|
|
2269
2269
|
log-symbols@^4.1.0:
|
|
2270
2270
|
version "4.1.0"
|
|
@@ -2961,9 +2961,9 @@ picocolors@^1.1.1:
|
|
|
2961
2961
|
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
|
|
2962
2962
|
|
|
2963
2963
|
picomatch@^2.3.1:
|
|
2964
|
-
version "2.3.
|
|
2965
|
-
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.
|
|
2966
|
-
integrity sha512-
|
|
2964
|
+
version "2.3.2"
|
|
2965
|
+
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.2.tgz#5a942915e26b372dc0f0e6753149a16e6b1c5601"
|
|
2966
|
+
integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==
|
|
2967
2967
|
|
|
2968
2968
|
postcss-html@^0.36.0:
|
|
2969
2969
|
version "0.36.0"
|