trusty-cms 7.1.3 → 7.2

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +72 -68
  3. data/lib/string_extensions/string_extensions.rb +4 -2
  4. data/lib/trusty_cms/version.rb +1 -1
  5. data/spec/controllers/admin/assets_controller_spec.rb +124 -0
  6. data/spec/controllers/admin/changes_controller_spec.rb +72 -0
  7. data/spec/controllers/admin/configuration_controller_spec.rb +49 -0
  8. data/spec/controllers/admin/page_attachments_controller_spec.rb +54 -0
  9. data/spec/controllers/admin/pages_controller_spec.rb +162 -0
  10. data/spec/controllers/admin/preferences_controller_spec.rb +44 -0
  11. data/spec/controllers/admin/security_controller_spec.rb +85 -0
  12. data/spec/controllers/admin/sessions_controller_spec.rb +56 -0
  13. data/spec/controllers/admin/two_factor_controller_spec.rb +63 -0
  14. data/spec/controllers/admin/users_controller_spec.rb +132 -0
  15. data/spec/controllers/page_status_controller_spec.rb +66 -0
  16. data/spec/dummy/bin/rails +3 -3
  17. data/spec/dummy/bin/rake +2 -2
  18. data/spec/dummy/bin/setup +21 -13
  19. data/spec/dummy/config/boot.rb +1 -1
  20. data/spec/dummy/config/cable.yml +10 -0
  21. data/spec/dummy/config/initializers/content_security_policy.rb +25 -0
  22. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -2
  23. data/spec/dummy/config/initializers/inflections.rb +4 -4
  24. data/spec/dummy/config/initializers/new_framework_defaults_7_2.rb +70 -0
  25. data/spec/dummy/config/initializers/permissions_policy.rb +13 -0
  26. data/spec/dummy/config/puma.rb +34 -0
  27. data/spec/dummy/config/storage.yml +28 -1
  28. data/spec/dummy/db/migrate/20260729201444_add_service_name_to_active_storage_blobs.active_storage.rb +22 -0
  29. data/spec/dummy/db/migrate/20260729201445_create_active_storage_variant_records.active_storage.rb +27 -0
  30. data/spec/dummy/db/migrate/20260729201446_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb +8 -0
  31. data/spec/dummy/public/404.html +6 -6
  32. data/spec/dummy/public/406-unsupported-browser.html +66 -0
  33. data/spec/dummy/public/422.html +6 -6
  34. data/spec/dummy/public/500.html +6 -6
  35. data/spec/dummy/public/icon.png +0 -0
  36. data/spec/dummy/public/icon.svg +3 -0
  37. data/spec/dummy/public/robots.txt +1 -0
  38. data/spec/helpers/admin/configuration_helper_spec.rb +62 -0
  39. data/spec/helpers/admin/node_helper_spec.rb +132 -0
  40. data/spec/helpers/admin/pages_helper_spec.rb +84 -0
  41. data/spec/helpers/application_helper_spec.rb +115 -0
  42. data/spec/lib/string_extensions_spec.rb +41 -0
  43. data/spec/support/active_record_encryption.rb +10 -0
  44. data/spec/support/asset_type_registry.rb +29 -0
  45. data/trusty_cms.gemspec +1 -1
  46. metadata +68 -8
  47. data/spec/controllers/assets_controller.rb +0 -66
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f50633a419203ee6b0b6e35814de7af711b70dd362d5fe0f712543d31f1fc75
4
- data.tar.gz: f5ccf44bd927e9a392e9979388c9d6f65ace4c1f965516d64936ee1da5e50d53
3
+ metadata.gz: 2378bbe6b853e3290648de1a8a832b61a25303f3078f4903ac70581a031bb3a5
4
+ data.tar.gz: 3e704c6349a8bf385190cc70ee6cf0021aa8c0cc575d5e033a3c1423a32e5e20
5
5
  SHA512:
6
- metadata.gz: 8324822cde6d47651420dc28038f51e629e1b411c276a0ddded87dac9587a571de5218e36452f929d0e5c55c4106aa47a21cf72f14e06c78b545c849cfafed6a
7
- data.tar.gz: 4e4dc362cd53e8124eaba08331db95eb085fe28b8778776ceef121a7e3b993f379b26d2c56c17538962adca2e2b47eb0e834c16d6f67f4a45b4a6cbab9a33cb3
6
+ metadata.gz: b4c137e5c84e08a9fc8395282986fe8a7b8b0c7c28d6e3b888b60a4e8a0c19f30d1520bc92a5580c8a3472961470e57558215ff3965546626dbb934863cd9f07
7
+ data.tar.gz: 42f087dbc0e78b43ffb48ad804b891992eafafe7d8e3ee5589b2d983902eaef2590f5325bb03f1df568227e52ae4a391d7ca8000432e9be82f59710c332f34b4
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- trusty-cms (7.1.3)
4
+ trusty-cms (7.2)
5
5
  RedCloth (= 4.3.4)
6
6
  activestorage-validator
7
7
  acts_as_list (>= 0.9.5, < 1.3.0)
@@ -29,7 +29,7 @@ PATH
29
29
  rack (>= 2.0.1, < 3.2.0)
30
30
  rack-cache (~> 1.7)
31
31
  radius (~> 0.8)
32
- rails (~> 7.2.2.1)
32
+ rails (>= 7.2, < 8.0)
33
33
  rake (< 14.0)
34
34
  ransack (~> 4.2.1)
35
35
  rdoc (>= 5.1, < 9.0)
@@ -46,68 +46,70 @@ GEM
46
46
  remote: https://rubygems.org/
47
47
  specs:
48
48
  RedCloth (4.3.4)
49
- actioncable (7.2.2.1)
50
- actionpack (= 7.2.2.1)
51
- activesupport (= 7.2.2.1)
49
+ actioncable (7.2.3.2)
50
+ actionpack (= 7.2.3.2)
51
+ activesupport (= 7.2.3.2)
52
52
  nio4r (~> 2.0)
53
53
  websocket-driver (>= 0.6.1)
54
54
  zeitwerk (~> 2.6)
55
- actionmailbox (7.2.2.1)
56
- actionpack (= 7.2.2.1)
57
- activejob (= 7.2.2.1)
58
- activerecord (= 7.2.2.1)
59
- activestorage (= 7.2.2.1)
60
- activesupport (= 7.2.2.1)
55
+ actionmailbox (7.2.3.2)
56
+ actionpack (= 7.2.3.2)
57
+ activejob (= 7.2.3.2)
58
+ activerecord (= 7.2.3.2)
59
+ activestorage (= 7.2.3.2)
60
+ activesupport (= 7.2.3.2)
61
61
  mail (>= 2.8.0)
62
- actionmailer (7.2.2.1)
63
- actionpack (= 7.2.2.1)
64
- actionview (= 7.2.2.1)
65
- activejob (= 7.2.2.1)
66
- activesupport (= 7.2.2.1)
62
+ actionmailer (7.2.3.2)
63
+ actionpack (= 7.2.3.2)
64
+ actionview (= 7.2.3.2)
65
+ activejob (= 7.2.3.2)
66
+ activesupport (= 7.2.3.2)
67
67
  mail (>= 2.8.0)
68
68
  rails-dom-testing (~> 2.2)
69
- actionpack (7.2.2.1)
70
- actionview (= 7.2.2.1)
71
- activesupport (= 7.2.2.1)
69
+ actionpack (7.2.3.2)
70
+ actionview (= 7.2.3.2)
71
+ activesupport (= 7.2.3.2)
72
+ cgi
72
73
  nokogiri (>= 1.8.5)
73
74
  racc
74
- rack (>= 2.2.4, < 3.2)
75
+ rack (>= 2.2.4, < 3.3)
75
76
  rack-session (>= 1.0.1)
76
77
  rack-test (>= 0.6.3)
77
78
  rails-dom-testing (~> 2.2)
78
79
  rails-html-sanitizer (~> 1.6)
79
80
  useragent (~> 0.16)
80
- actiontext (7.2.2.1)
81
- actionpack (= 7.2.2.1)
82
- activerecord (= 7.2.2.1)
83
- activestorage (= 7.2.2.1)
84
- activesupport (= 7.2.2.1)
81
+ actiontext (7.2.3.2)
82
+ actionpack (= 7.2.3.2)
83
+ activerecord (= 7.2.3.2)
84
+ activestorage (= 7.2.3.2)
85
+ activesupport (= 7.2.3.2)
85
86
  globalid (>= 0.6.0)
86
87
  nokogiri (>= 1.8.5)
87
- actionview (7.2.2.1)
88
- activesupport (= 7.2.2.1)
88
+ actionview (7.2.3.2)
89
+ activesupport (= 7.2.3.2)
89
90
  builder (~> 3.1)
91
+ cgi
90
92
  erubi (~> 1.11)
91
93
  rails-dom-testing (~> 2.2)
92
94
  rails-html-sanitizer (~> 1.6)
93
- activejob (7.2.2.1)
94
- activesupport (= 7.2.2.1)
95
+ activejob (7.2.3.2)
96
+ activesupport (= 7.2.3.2)
95
97
  globalid (>= 0.3.6)
96
- activemodel (7.2.2.1)
97
- activesupport (= 7.2.2.1)
98
- activerecord (7.2.2.1)
99
- activemodel (= 7.2.2.1)
100
- activesupport (= 7.2.2.1)
98
+ activemodel (7.2.3.2)
99
+ activesupport (= 7.2.3.2)
100
+ activerecord (7.2.3.2)
101
+ activemodel (= 7.2.3.2)
102
+ activesupport (= 7.2.3.2)
101
103
  timeout (>= 0.4.0)
102
- activestorage (7.2.2.1)
103
- actionpack (= 7.2.2.1)
104
- activejob (= 7.2.2.1)
105
- activerecord (= 7.2.2.1)
106
- activesupport (= 7.2.2.1)
104
+ activestorage (7.2.3.2)
105
+ actionpack (= 7.2.3.2)
106
+ activejob (= 7.2.3.2)
107
+ activerecord (= 7.2.3.2)
108
+ activesupport (= 7.2.3.2)
107
109
  marcel (~> 1.0)
108
110
  activestorage-validator (0.4.0)
109
111
  rails (>= 6.1.0)
110
- activesupport (7.2.2.1)
112
+ activesupport (7.2.3.2)
111
113
  base64
112
114
  benchmark (>= 0.3)
113
115
  bigdecimal
@@ -116,7 +118,7 @@ GEM
116
118
  drb
117
119
  i18n (>= 1.6, < 2)
118
120
  logger (>= 1.4.2)
119
- minitest (>= 5.1)
121
+ minitest (>= 5.1, < 6)
120
122
  securerandom (>= 0.3)
121
123
  tzinfo (~> 2.0, >= 2.0.5)
122
124
  acts_as_list (1.2.6)
@@ -142,12 +144,13 @@ GEM
142
144
  rack-test (>= 0.6.3)
143
145
  regexp_parser (>= 1.5, < 3.0)
144
146
  xpath (~> 3.2)
147
+ cgi (0.5.2)
145
148
  childprocess (5.1.0)
146
149
  logger (~> 1.5)
147
150
  chunky_png (1.4.0)
148
151
  cliver (0.3.2)
149
152
  coderay (1.1.3)
150
- concurrent-ruby (1.3.7)
153
+ concurrent-ruby (1.3.8)
151
154
  connection_pool (3.0.2)
152
155
  crass (1.0.7)
153
156
  css_parser (3.0.0)
@@ -180,7 +183,7 @@ GEM
180
183
  diffy (3.4.4)
181
184
  docile (1.4.1)
182
185
  drb (2.2.3)
183
- erb (6.0.4)
186
+ erb (6.0.6)
184
187
  erubi (1.13.1)
185
188
  execjs (2.10.0)
186
189
  factory_bot (6.6.0)
@@ -201,7 +204,7 @@ GEM
201
204
  file_validators (3.0.0)
202
205
  activemodel (>= 3.2)
203
206
  mime-types (>= 1.0)
204
- globalid (1.2.1)
207
+ globalid (1.4.0)
205
208
  activesupport (>= 6.1)
206
209
  haml (6.3.0)
207
210
  temple (>= 0.8.2)
@@ -251,12 +254,13 @@ GEM
251
254
  loofah (2.25.2)
252
255
  crass (~> 1.0.2)
253
256
  nokogiri (>= 1.12.0)
254
- mail (2.8.1)
257
+ mail (2.9.1)
258
+ logger
255
259
  mini_mime (>= 0.1.1)
256
260
  net-imap
257
261
  net-pop
258
262
  net-smtp
259
- marcel (1.0.4)
263
+ marcel (1.2.1)
260
264
  matrix (0.4.2)
261
265
  method_source (1.1.0)
262
266
  mime-types (3.6.0)
@@ -268,15 +272,13 @@ GEM
268
272
  mini_portile2 (2.8.9)
269
273
  mini_racer (0.16.0)
270
274
  libv8-node (~> 18.19.0.0)
271
- minitest (6.0.6)
272
- drb (~> 2.0)
273
- prism (~> 1.5)
275
+ minitest (5.27.0)
274
276
  multi_xml (0.9.1)
275
277
  bigdecimal (>= 3.1, < 5)
276
278
  multipart-post (2.4.1)
277
279
  mutex_m (0.3.0)
278
280
  mysql2 (0.5.6)
279
- net-imap (0.5.15)
281
+ net-imap (0.6.6)
280
282
  date
281
283
  net-protocol
282
284
  net-pop (0.1.2)
@@ -285,7 +287,7 @@ GEM
285
287
  timeout
286
288
  net-smtp (0.5.1)
287
289
  net-protocol
288
- nio4r (2.7.4)
290
+ nio4r (2.7.5)
289
291
  nokogiri (1.19.4)
290
292
  mini_portile2 (~> 2.8.2)
291
293
  racc (~> 1.4)
@@ -342,20 +344,20 @@ GEM
342
344
  rackup (2.3.1)
343
345
  rack (>= 3)
344
346
  radius (0.8.0)
345
- rails (7.2.2.1)
346
- actioncable (= 7.2.2.1)
347
- actionmailbox (= 7.2.2.1)
348
- actionmailer (= 7.2.2.1)
349
- actionpack (= 7.2.2.1)
350
- actiontext (= 7.2.2.1)
351
- actionview (= 7.2.2.1)
352
- activejob (= 7.2.2.1)
353
- activemodel (= 7.2.2.1)
354
- activerecord (= 7.2.2.1)
355
- activestorage (= 7.2.2.1)
356
- activesupport (= 7.2.2.1)
347
+ rails (7.2.3.2)
348
+ actioncable (= 7.2.3.2)
349
+ actionmailbox (= 7.2.3.2)
350
+ actionmailer (= 7.2.3.2)
351
+ actionpack (= 7.2.3.2)
352
+ actiontext (= 7.2.3.2)
353
+ actionview (= 7.2.3.2)
354
+ activejob (= 7.2.3.2)
355
+ activemodel (= 7.2.3.2)
356
+ activerecord (= 7.2.3.2)
357
+ activestorage (= 7.2.3.2)
358
+ activesupport (= 7.2.3.2)
357
359
  bundler (>= 1.15.0)
358
- railties (= 7.2.2.1)
360
+ railties (= 7.2.3.2)
359
361
  rails-dom-testing (2.3.0)
360
362
  activesupport (>= 5.0.0)
361
363
  minitest
@@ -365,20 +367,22 @@ GEM
365
367
  nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
366
368
  rails-observers (0.1.5)
367
369
  activemodel (>= 4.0)
368
- railties (7.2.2.1)
369
- actionpack (= 7.2.2.1)
370
- activesupport (= 7.2.2.1)
370
+ railties (7.2.3.2)
371
+ actionpack (= 7.2.3.2)
372
+ activesupport (= 7.2.3.2)
373
+ cgi
371
374
  irb (~> 1.13)
372
375
  rackup (>= 1.0.0)
373
376
  rake (>= 12.2)
374
377
  thor (~> 1.0, >= 1.2.2)
378
+ tsort (>= 0.2)
375
379
  zeitwerk (~> 2.6)
376
380
  rake (13.4.2)
377
381
  ransack (4.2.1)
378
382
  activerecord (>= 6.1.5)
379
383
  activesupport (>= 6.1.5)
380
384
  i18n
381
- rbs (4.0.3)
385
+ rbs (4.1.0)
382
386
  logger
383
387
  prism (>= 1.6.0)
384
388
  tsort
@@ -14,8 +14,10 @@ class String
14
14
  end
15
15
 
16
16
  unless methods.include?('parameterize')
17
- def parameterize(sep = '-')
18
- remove_formatting.downcase.replace_whitespace(sep).collapse(sep)
17
+ def parameterize(separator = '-', preserve_case: false, locale: nil)
18
+ separator = '-' unless separator.is_a?(String)
19
+ slug = remove_formatting.replace_whitespace(separator).collapse(separator)
20
+ preserve_case ? slug : slug.downcase
19
21
  end
20
22
  end
21
23
 
@@ -1,3 +1,3 @@
1
1
  module TrustyCms
2
- VERSION = '7.1.3'.freeze
2
+ VERSION = '7.2'.freeze
3
3
  end
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+ require 'rack/test'
3
+
4
+ # Exercises Admin::AssetsController, which overrides the ResourceController CRUD
5
+ # with custom upload handling (process_uploaded_asset, maybe_compress,
6
+ # failure_response, set_owner_or_editor). Uses the JSON/partial endpoints so the
7
+ # specs don't depend on the asset-pipeline-heavy admin HTML layout. High-value
8
+ # regression net for a Rails/Ruby upgrade — file uploads and content-type
9
+ # negotiation are common breakage points.
10
+ RSpec.describe Admin::AssetsController, type: :controller do
11
+ routes { TrustyCms::Application.routes }
12
+
13
+ let(:user) { create(:admin) }
14
+ let(:fixtures_path) { TrustyCms::Engine.root.join('spec', 'fixtures', 'files') }
15
+
16
+ before do
17
+ # approved_content_types derives from the AssetType registry, which is empty
18
+ # by default; register the canonical set (shared with asset_spec) so uploads
19
+ # of text/plain, images, etc. can be approved. See AssetTypeRegistry.
20
+ register_standard_asset_types
21
+
22
+ # public_url generation needs a host; controller specs don't set one on the
23
+ # Disk service the way a real request would.
24
+ @previous_active_storage_url_options = ActiveStorage::Current.url_options
25
+ ActiveStorage::Current.url_options = { host: 'test.host', protocol: 'http' }
26
+
27
+ allow(controller).to receive(:authenticate_user!).and_return(true)
28
+ allow(controller).to receive(:current_user).and_return(user)
29
+ end
30
+
31
+ after do
32
+ ActiveStorage::Current.url_options = @previous_active_storage_url_options
33
+ end
34
+
35
+ # A plain stub (not an rspec double) so it can be assigned in an `around`
36
+ # hook, which runs outside the per-test double lifecycle. api_key: nil makes
37
+ # should_compress? false, so uploads skip Kraken compression.
38
+ around do |example|
39
+ original_kraken = defined?($kraken) ? $kraken : nil
40
+ $kraken = Struct.new(:api_key).new(nil)
41
+ example.run
42
+ $kraken = original_kraken
43
+ end
44
+
45
+ def upload(filename, content_type)
46
+ Rack::Test::UploadedFile.new(fixtures_path.join(filename), content_type)
47
+ end
48
+
49
+ describe 'POST #uploader' do
50
+ it 'returns the asset url when the upload succeeds' do
51
+ expect {
52
+ post :uploader, params: { upload: upload('sample.txt', 'text/plain') }, format: :json
53
+ }.to change(Asset, :count).by(1)
54
+
55
+ expect(response).to have_http_status(:ok)
56
+ expect(JSON.parse(response.body)).to have_key('url')
57
+ end
58
+
59
+ it 'records the uploading user as owner/editor' do
60
+ post :uploader, params: { upload: upload('sample.txt', 'text/plain') }, format: :json
61
+
62
+ asset = Asset.last
63
+ expect(asset.created_by_id).to eq(user.id)
64
+ expect(asset.updated_by_id).to eq(user.id)
65
+ end
66
+
67
+ it 'returns unsupported media type for disallowed content types' do
68
+ expect(Asset).not_to receive(:create)
69
+
70
+ post :uploader, params: { upload: upload('sample.txt', 'application/x-unsupported') }, format: :json
71
+
72
+ expect(response).to have_http_status(:unsupported_media_type)
73
+ expect(JSON.parse(response.body)['error']).to eq('Unsupported file type.')
74
+ expect(flash[:error]).to eq('Unsupported file type.')
75
+ end
76
+
77
+ it 'rejects the generic octet-stream content type with a notice' do
78
+ post :uploader, params: { upload: upload('sample.txt', 'application/octet-stream') }, format: :json
79
+
80
+ expect(response).to have_http_status(:unprocessable_entity)
81
+ expect(JSON.parse(response.body)['error']).to match(/valid extension/)
82
+ expect(flash[:notice]).to match(/valid extension/)
83
+ end
84
+
85
+ it 'returns unprocessable entity when no file is provided' do
86
+ post :uploader, params: {}, format: :json
87
+
88
+ expect(response).to have_http_status(:unprocessable_entity)
89
+ expect(JSON.parse(response.body)['error']).to eq('No file uploaded.')
90
+ expect(flash[:error]).to eq('No file uploaded.')
91
+ end
92
+ end
93
+
94
+ describe 'POST #create' do
95
+ it 'creates an asset from an uploaded file and redirects (HTML)' do
96
+ expect {
97
+ post :create, params: { asset: { asset: [upload('sample.txt', 'text/plain')] } }
98
+ }.to change(Asset, :count).by(1)
99
+
100
+ expect(response).to be_redirect
101
+ end
102
+
103
+ it 'redirects back to new with a flash error when the upload is unsupported' do
104
+ expect {
105
+ post :create, params: { asset: { asset: [upload('sample.txt', 'application/x-unsupported')] } }
106
+ }.not_to change(Asset, :count)
107
+
108
+ expect(response).to redirect_to(new_admin_asset_path)
109
+ expect(flash[:error]).to eq('Unsupported file type.')
110
+ end
111
+ end
112
+
113
+ describe 'DELETE #destroy' do
114
+ it 'destroys the asset and redirects' do
115
+ asset = Asset.create!(asset: upload('sample.txt', 'text/plain'), caption: '')
116
+
117
+ expect {
118
+ delete :destroy, params: { id: asset.id }
119
+ }.to change(Asset, :count).by(-1)
120
+
121
+ expect(response).to be_redirect
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ # Exercises Admin::ChangesController, which builds a PaperTrail-backed diff view
4
+ # of recent page changes. Controller specs (views not rendered) let us drive the
5
+ # action and its private diff-building helpers without the admin HTML layout.
6
+ # PaperTrail behaviour is a plausible upgrade casualty, so this pins it down.
7
+ RSpec.describe Admin::ChangesController, type: :controller do
8
+ routes { TrustyCms::Application.routes }
9
+
10
+ let(:user) { create(:admin) }
11
+ let!(:site) { create(:site) }
12
+
13
+ before do
14
+ allow(controller).to receive(:authenticate_user!).and_return(true)
15
+ allow(controller).to receive(:current_user).and_return(user)
16
+ # The multi-site extension (which provides #current_site) isn't loaded in the
17
+ # dummy app, so stub it to the site our fixtures are scoped to.
18
+ allow(controller).to receive(:current_site).and_return(site)
19
+ end
20
+
21
+ # Create a page scoped to the current site and give it a versioned change so
22
+ # the controller has something to diff.
23
+ def page_with_change
24
+ page = create(:home, title: 'Original', site_id: site.id)
25
+ PaperTrail.request(whodunnit: user.id.to_s) do
26
+ page.update!(title: 'Updated Title')
27
+ end
28
+ page
29
+ end
30
+
31
+ # rails-controller-testing (which provides `assigns`) isn't in the bundle, so
32
+ # read the controller's assigned ivars directly.
33
+ def changes
34
+ controller.instance_variable_get(:@changes)
35
+ end
36
+
37
+ describe 'GET #show' do
38
+ it 'succeeds and assigns recent changes' do
39
+ page_with_change
40
+
41
+ get :show
42
+
43
+ expect(response).to have_http_status(:ok)
44
+ expect(changes).to be_present
45
+ end
46
+
47
+ it 'loads a single change when a version_id is given' do
48
+ page = page_with_change
49
+ version = PaperTrail::Version.where(item_type: 'Page', item_id: page.id).last
50
+
51
+ get :show, params: { version_id: version.id }
52
+
53
+ expect(response).to have_http_status(:ok)
54
+ expect(changes.size).to eq(1)
55
+ expect(changes.first[:id]).to eq(version.id)
56
+ end
57
+
58
+ it 'reports an error when the version_id is unknown' do
59
+ get :show, params: { version_id: 0 }
60
+
61
+ expect(changes).to be_empty
62
+ expect(controller.instance_variable_get(:@change_error)).to eq('Version ID not found.')
63
+ end
64
+
65
+ it 'succeeds with no changes present' do
66
+ get :show
67
+
68
+ expect(response).to have_http_status(:ok)
69
+ expect(changes).to eq([])
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ # Exercises Admin::ConfigurationController, which batch-updates TrustyCms::Config
4
+ # entries inside a transaction and is admin-gated. Config plumbing is easy to
5
+ # break in a framework upgrade, so pin the happy path and the auth gate.
6
+ RSpec.describe Admin::ConfigurationController, type: :controller do
7
+ routes { TrustyCms::Application.routes }
8
+
9
+ let(:admin) { create(:admin) }
10
+
11
+ before do
12
+ allow(controller).to receive(:authenticate_user!).and_return(true)
13
+ allow(controller).to receive(:current_user).and_return(admin)
14
+ end
15
+
16
+ describe 'GET #show' do
17
+ it 'succeeds' do
18
+ get :show
19
+ expect(response).to have_http_status(:ok)
20
+ end
21
+ end
22
+
23
+ describe 'GET #edit' do
24
+ it 'succeeds for an admin' do
25
+ get :edit
26
+ expect(response).to have_http_status(:ok)
27
+ end
28
+ end
29
+
30
+ describe 'PUT #update' do
31
+ it 'persists the submitted config values and redirects to show' do
32
+ put :update, params: { trusty_config: { 'admin.title' => 'Renamed CMS' } }
33
+
34
+ expect(response).to redirect_to(action: :show)
35
+ expect(TrustyCms::Config['admin.title']).to eq('Renamed CMS')
36
+ end
37
+ end
38
+
39
+ describe 'authorization' do
40
+ it 'denies a non-admin access to edit' do
41
+ allow(controller).to receive(:current_user).and_return(create(:non_admin, email: 'plain@example.com'))
42
+
43
+ get :edit
44
+
45
+ expect(response).to be_redirect
46
+ expect(flash[:error]).to be_present
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'rack/test'
3
+
4
+ # Exercises Admin::PageAttachmentsController, whose custom #load_model builds a
5
+ # PageAttachment from an asset_id (+ optional page_id) and rescues a missing
6
+ # asset. Controller spec (views not rendered) drives the action and its
7
+ # before-action without needing the admin HTML layout.
8
+ RSpec.describe Admin::PageAttachmentsController, type: :controller do
9
+ routes { TrustyCms::Application.routes }
10
+
11
+ let(:user) { create(:admin) }
12
+ let(:fixtures_path) { TrustyCms::Engine.root.join('spec', 'fixtures', 'files') }
13
+ let(:asset) do
14
+ Asset.create!(asset: Rack::Test::UploadedFile.new(fixtures_path.join('sample.txt'), 'text/plain'), caption: '')
15
+ end
16
+
17
+ before do
18
+ register_standard_asset_types # shared canonical AssetTypes (see AssetTypeRegistry)
19
+ allow(controller).to receive(:authenticate_user!).and_return(true)
20
+ allow(controller).to receive(:current_user).and_return(user)
21
+ end
22
+
23
+ describe 'GET #new' do
24
+ it 'builds a PageAttachment for the asset with a new (unsaved) page' do
25
+ get :new, params: { asset_id: asset.id }
26
+
27
+ expect(response).to have_http_status(:ok)
28
+ model = controller.instance_variable_get(:@page_attachment)
29
+ expect(model).to be_a(PageAttachment)
30
+ expect(model.asset).to eq(asset)
31
+ expect(model.page).to be_a(Page).and be_new_record
32
+ end
33
+
34
+ it 'associates an existing page when a page_id is given' do
35
+ page = create(:home, title: 'Attach Target')
36
+
37
+ get :new, params: { asset_id: asset.id, page_id: page.id }
38
+
39
+ expect(controller.instance_variable_get(:@page)).to eq(page)
40
+ end
41
+
42
+ # NOTE: latent bug — load_model rescues a missing asset with
43
+ # `render nothing: true`, but the `nothing:` option was removed in Rails 5.1.
44
+ # It's now ignored, so Rails falls through to rendering the (nonexistent)
45
+ # `new` template and raises MissingTemplate instead of returning an empty
46
+ # body. Characterizing current behavior; the fix is `head :no_content`.
47
+ # This is exactly the kind of breakage a Rails 8 upgrade should clean up.
48
+ it 'raises MissingTemplate for a missing asset (broken rescue path)' do
49
+ expect {
50
+ get :new, params: { asset_id: 0 }
51
+ }.to raise_error(ActionView::MissingTemplate)
52
+ end
53
+ end
54
+ end