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.
- checksums.yaml +4 -4
- data/Gemfile.lock +72 -68
- data/lib/string_extensions/string_extensions.rb +4 -2
- data/lib/trusty_cms/version.rb +1 -1
- data/spec/controllers/admin/assets_controller_spec.rb +124 -0
- data/spec/controllers/admin/changes_controller_spec.rb +72 -0
- data/spec/controllers/admin/configuration_controller_spec.rb +49 -0
- data/spec/controllers/admin/page_attachments_controller_spec.rb +54 -0
- data/spec/controllers/admin/pages_controller_spec.rb +162 -0
- data/spec/controllers/admin/preferences_controller_spec.rb +44 -0
- data/spec/controllers/admin/security_controller_spec.rb +85 -0
- data/spec/controllers/admin/sessions_controller_spec.rb +56 -0
- data/spec/controllers/admin/two_factor_controller_spec.rb +63 -0
- data/spec/controllers/admin/users_controller_spec.rb +132 -0
- data/spec/controllers/page_status_controller_spec.rb +66 -0
- data/spec/dummy/bin/rails +3 -3
- data/spec/dummy/bin/rake +2 -2
- data/spec/dummy/bin/setup +21 -13
- data/spec/dummy/config/boot.rb +1 -1
- data/spec/dummy/config/cable.yml +10 -0
- data/spec/dummy/config/initializers/content_security_policy.rb +25 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -2
- data/spec/dummy/config/initializers/inflections.rb +4 -4
- data/spec/dummy/config/initializers/new_framework_defaults_7_2.rb +70 -0
- data/spec/dummy/config/initializers/permissions_policy.rb +13 -0
- data/spec/dummy/config/puma.rb +34 -0
- data/spec/dummy/config/storage.yml +28 -1
- data/spec/dummy/db/migrate/20260729201444_add_service_name_to_active_storage_blobs.active_storage.rb +22 -0
- data/spec/dummy/db/migrate/20260729201445_create_active_storage_variant_records.active_storage.rb +27 -0
- data/spec/dummy/db/migrate/20260729201446_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb +8 -0
- data/spec/dummy/public/404.html +6 -6
- data/spec/dummy/public/406-unsupported-browser.html +66 -0
- data/spec/dummy/public/422.html +6 -6
- data/spec/dummy/public/500.html +6 -6
- data/spec/dummy/public/icon.png +0 -0
- data/spec/dummy/public/icon.svg +3 -0
- data/spec/dummy/public/robots.txt +1 -0
- data/spec/helpers/admin/configuration_helper_spec.rb +62 -0
- data/spec/helpers/admin/node_helper_spec.rb +132 -0
- data/spec/helpers/admin/pages_helper_spec.rb +84 -0
- data/spec/helpers/application_helper_spec.rb +115 -0
- data/spec/lib/string_extensions_spec.rb +41 -0
- data/spec/support/active_record_encryption.rb +10 -0
- data/spec/support/asset_type_registry.rb +29 -0
- data/trusty_cms.gemspec +1 -1
- metadata +68 -8
- data/spec/controllers/assets_controller.rb +0 -66
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
# Exercises Admin::NodeHelper, which renders the admin page-tree nodes. The
|
|
4
|
+
# partial-rendering entry points are driven with `render` stubbed (the real
|
|
5
|
+
# partials need the full admin layout), while the node-presentation helpers
|
|
6
|
+
# (title, icon, expander, expansion state) are exercised directly.
|
|
7
|
+
describe Admin::NodeHelper, type: :helper do
|
|
8
|
+
let!(:home) { FactoryBot.create(:home, title: 'Home') }
|
|
9
|
+
let(:page) { FactoryBot.create(:page, title: 'Child', slug: 'child', parent: home) }
|
|
10
|
+
|
|
11
|
+
before do
|
|
12
|
+
# image() lives in ApplicationHelper (not mixed into this helper) and returns
|
|
13
|
+
# an <img> tag; stub it so the presentation helpers can be tested in isolation.
|
|
14
|
+
allow(helper).to receive(:image) { |name, *| "<img data-name='#{name}'/>".html_safe }
|
|
15
|
+
allow(helper).to receive(:cookies).and_return({})
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe '#prepare_page' do
|
|
19
|
+
it 'extends the page with MenuRenderer and wires up the view' do
|
|
20
|
+
result = helper.prepare_page(page)
|
|
21
|
+
expect(result).to be(page)
|
|
22
|
+
expect(result.view).to be(helper)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe '#homepage' do
|
|
27
|
+
it 'returns the page with no parent' do
|
|
28
|
+
expect(helper.homepage).to eq(home)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe '#show_all?' do
|
|
33
|
+
it 'is true only on the remove action' do
|
|
34
|
+
allow(helper.controller).to receive(:action_name).and_return('remove')
|
|
35
|
+
expect(helper.show_all?).to be(true)
|
|
36
|
+
|
|
37
|
+
allow(helper.controller).to receive(:action_name).and_return('index')
|
|
38
|
+
expect(helper.show_all?).to be(false)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe '#expanded_rows' do
|
|
43
|
+
it 'parses the expanded_rows cookie and always includes the homepage' do
|
|
44
|
+
allow(helper).to receive(:cookies).and_return(expanded_rows: "#{page.id},not-a-number")
|
|
45
|
+
|
|
46
|
+
rows = helper.expanded_rows
|
|
47
|
+
|
|
48
|
+
expect(rows).to include(page.id)
|
|
49
|
+
expect(rows).to include(home.id) # homepage is always expanded
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'defaults to just the homepage when no cookie is set' do
|
|
53
|
+
expect(helper.expanded_rows).to eq([home.id])
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @current_node is normally set by render_node; set it directly so the
|
|
58
|
+
# presentation helpers (which read it) can be exercised in isolation.
|
|
59
|
+
def make_current(a_page)
|
|
60
|
+
helper.instance_variable_set(:@current_node, helper.prepare_page(a_page))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe 'node presentation' do
|
|
64
|
+
before { make_current(page) }
|
|
65
|
+
|
|
66
|
+
describe '#expanded' do
|
|
67
|
+
it 'is true on the remove action regardless of cookie state' do
|
|
68
|
+
allow(helper).to receive(:show_all?).and_return(true)
|
|
69
|
+
expect(helper.expanded).to be(true)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe '#expander' do
|
|
74
|
+
it 'is blank at the top level' do
|
|
75
|
+
expect(helper.expander(0)).to eq('')
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'is blank for a childless node' do
|
|
79
|
+
make_current(page) # child has no children
|
|
80
|
+
expect(helper.expander(1)).to eq('')
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'renders a toggle image for a node with children at a nested level' do
|
|
84
|
+
make_current(home) # home has the child page
|
|
85
|
+
expect(helper.expander(1)).to include('<img')
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
describe '#icon' do
|
|
90
|
+
it 'renders an icon image' do
|
|
91
|
+
expect(helper.icon).to include('<img')
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
describe '#node_title' do
|
|
96
|
+
it 'wraps the escaped title in a span' do
|
|
97
|
+
expect(helper.node_title).to eq(%{<span class="title">Child</span>})
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
describe '#page_type' do
|
|
102
|
+
it 'is blank for a plain Page' do
|
|
103
|
+
expect(helper.page_type).to eq('')
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
describe '#spinner' do
|
|
108
|
+
it 'renders a hidden spinner image' do
|
|
109
|
+
expect(helper.spinner).to include('<img')
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe 'rendering entry points' do
|
|
115
|
+
before { allow(helper).to receive(:render).and_return('<node/>'.html_safe) }
|
|
116
|
+
|
|
117
|
+
it '#render_node accumulates rendered HTML and returns the index' do
|
|
118
|
+
helper.instance_variable_set(:@rendered_html, '') # normally done by render_nodes
|
|
119
|
+
expect(helper.render_node(page, 2)).to eq(2)
|
|
120
|
+
expect(helper.instance_variable_get(:@rendered_html)).to eq('<node/>')
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it '#render_nodes resets and returns the accumulated HTML' do
|
|
124
|
+
expect(helper.render_nodes(page, 0)).to eq('<node/>')
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it '#render_search_node renders the search partial' do
|
|
128
|
+
helper.render_search_node(page)
|
|
129
|
+
expect(helper.instance_variable_get(:@rendered_html)).to eq('<node/>')
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
# Exercises Admin::PagesHelper — small presentation helpers used by the page
|
|
4
|
+
# editor (class/filter lookups, meta-error detection, description cleanup,
|
|
5
|
+
# parent-page select options, and the revert confirmation copy).
|
|
6
|
+
describe Admin::PagesHelper, type: :helper do
|
|
7
|
+
describe '#class_of_page' do
|
|
8
|
+
it 'returns the assigned page class' do
|
|
9
|
+
helper.instance_variable_set(:@page, Page.new)
|
|
10
|
+
expect(helper.class_of_page).to eq(Page)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe '#filter' do
|
|
15
|
+
it "returns the first part's filter when parts are present" do
|
|
16
|
+
part = double('PagePart', filter: 'markdown')
|
|
17
|
+
helper.instance_variable_set(:@page, double('Page', parts: [part]))
|
|
18
|
+
expect(helper.filter).to eq('markdown')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'returns nil when there are no parts' do
|
|
22
|
+
helper.instance_variable_set(:@page, double('Page', parts: []))
|
|
23
|
+
expect(helper.filter).to be_nil
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe '#meta_errors?' do
|
|
28
|
+
# Admin::PagesHelper#meta_errors? is shadowed by ApplicationHelper#meta_errors?
|
|
29
|
+
# in the view ancestry, so `helper.meta_errors?` would call the wrong one.
|
|
30
|
+
# Bind this module's implementation to the helper to exercise it directly.
|
|
31
|
+
def meta_errors?
|
|
32
|
+
Admin::PagesHelper.instance_method(:meta_errors?).bind(helper).call
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'is true when slug has an error' do
|
|
36
|
+
page = Page.new
|
|
37
|
+
page.errors.add(:slug, 'is invalid')
|
|
38
|
+
helper.instance_variable_set(:@page, page)
|
|
39
|
+
expect(meta_errors?).to be(true)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# NOTE: latent bug — errors[:attr] returns an array, and an empty array is
|
|
43
|
+
# truthy, so `!!(errors[:slug] or errors[:breadcrumb])` is true even with no
|
|
44
|
+
# meta errors. This implementation always returns true; characterizing it.
|
|
45
|
+
it 'also (incorrectly) returns true when there are no meta errors' do
|
|
46
|
+
helper.instance_variable_set(:@page, Page.new)
|
|
47
|
+
expect(meta_errors?).to be(true)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe '#clean_page_description' do
|
|
52
|
+
it 'strips leading/trailing whitespace and collapses internal runs' do
|
|
53
|
+
page = double('Page', description: ' hello world ')
|
|
54
|
+
expect(helper.clean_page_description(page)).to eq('hello world')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'removes tab characters entirely' do
|
|
58
|
+
page = double('Page', description: "tab\there")
|
|
59
|
+
expect(helper.clean_page_description(page)).to eq('tabhere')
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe '#parent_page_options' do
|
|
64
|
+
it 'builds options_for_select from the available parent pages' do
|
|
65
|
+
home = FactoryBot.create(:home, title: 'Home')
|
|
66
|
+
child = FactoryBot.create(:page, title: 'Child', slug: 'child', parent: home)
|
|
67
|
+
current_site = double('Site', homepage_id: home.id)
|
|
68
|
+
allow(Page).to receive(:parent_pages).with(home.id).and_return([home])
|
|
69
|
+
|
|
70
|
+
html = helper.parent_page_options(current_site, child)
|
|
71
|
+
|
|
72
|
+
expect(html).to include('Home')
|
|
73
|
+
expect(html).to include("value=\"#{home.id}\"")
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe '#revert_confirmation_message' do
|
|
78
|
+
it 'includes the version date and time' do
|
|
79
|
+
message = helper.revert_confirmation_message(update_date: 'July 29, 2026', update_time: '10:00 AM')
|
|
80
|
+
expect(message).to include('July 29, 2026')
|
|
81
|
+
expect(message).to include('10:00 AM')
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -99,4 +99,119 @@ describe ApplicationHelper, type: :helper do
|
|
|
99
99
|
expect(helper.body_classes).to eq(['reversed'])
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
|
+
|
|
103
|
+
describe '#onsubmit_status' do
|
|
104
|
+
it 'reports a creating status for a new record' do
|
|
105
|
+
expect(helper.onsubmit_status(Snippet.new)).to match(/creat/i)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'reports a saving status for a persisted record' do
|
|
109
|
+
snippet = FactoryBot.create(:snippet, name: 'saved')
|
|
110
|
+
expect(helper.onsubmit_status(snippet)).to match(/saving/i)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe '#save_model_button' do
|
|
115
|
+
it 'labels the button Create for a new record' do
|
|
116
|
+
html = helper.save_model_button(Snippet.new)
|
|
117
|
+
expect(html).to include('type="submit"')
|
|
118
|
+
expect(html).to match(/Create/)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'labels the button Save Changes for a persisted record' do
|
|
122
|
+
snippet = FactoryBot.create(:snippet, name: 'persisted')
|
|
123
|
+
expect(helper.save_model_button(snippet)).to match(/Save Changes/)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
describe '#save_model_and_continue_editing_button' do
|
|
128
|
+
it 'renders a continue submit button' do
|
|
129
|
+
html = helper.save_model_and_continue_editing_button(Snippet.new)
|
|
130
|
+
expect(html).to include('name="continue"')
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe '#image' do
|
|
135
|
+
# Stub image_tag so the test exercises the path-building logic without doing
|
|
136
|
+
# a real asset-pipeline lookup (which warns for assets not in the pipeline).
|
|
137
|
+
before { allow(helper).to receive(:image_tag) { |path, _opts| path } }
|
|
138
|
+
|
|
139
|
+
it 'builds an admin image path, defaulting the extension to .png' do
|
|
140
|
+
helper.image('foo', alt: 'Foo')
|
|
141
|
+
expect(helper).to have_received(:image_tag).with('admin/foo.png', { alt: 'Foo' })
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it 'keeps an explicit extension' do
|
|
145
|
+
helper.image('bar.gif')
|
|
146
|
+
expect(helper).to have_received(:image_tag).with('admin/bar.gif', {})
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
describe '#timestamp' do
|
|
151
|
+
it 'localizes the time with the :timestamp format' do
|
|
152
|
+
time = Time.zone.local(2026, 7, 29, 10, 0, 0)
|
|
153
|
+
expect(helper.timestamp(time)).to eq(I18n.localize(time, format: :timestamp))
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
describe '#updated_stamp' do
|
|
158
|
+
it 'returns nil for a new record' do
|
|
159
|
+
expect(helper.updated_stamp(Snippet.new)).to be_nil
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it 'renders an updated line for a persisted record' do
|
|
163
|
+
snippet = FactoryBot.create(:snippet, name: 'stamped')
|
|
164
|
+
html = helper.updated_stamp(snippet)
|
|
165
|
+
expect(html).to include('updated_line')
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
describe 'asset overrides' do
|
|
170
|
+
it 'returns no stylesheet overrides when the override files are absent' do
|
|
171
|
+
expect(helper.stylesheet_overrides).to eq([])
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it 'returns no javascript overrides when the override file is absent' do
|
|
175
|
+
expect(helper.javascript_overrides).to eq([])
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it 'includes the stylesheet override when the file exists' do
|
|
179
|
+
allow(File).to receive(:exist?).and_return(true)
|
|
180
|
+
expect(helper.stylesheet_overrides).to eq(['admin/overrides'])
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it 'includes the javascript override when the file exists' do
|
|
184
|
+
allow(File).to receive(:exist?).and_return(true)
|
|
185
|
+
expect(helper.javascript_overrides).to eq(['admin/overrides'])
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
describe '#current_url?' do
|
|
190
|
+
it 'matches the current request path' do
|
|
191
|
+
allow(helper.request).to receive(:original_fullpath).and_return('/admin/pages/1/edit')
|
|
192
|
+
expect(helper.current_url?('/admin/pages')).to be_truthy
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it 'does not match an unrelated path' do
|
|
196
|
+
allow(helper.request).to receive(:original_fullpath).and_return('/admin/snippets')
|
|
197
|
+
expect(helper.current_url?('/admin/pages')).to be_falsey
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
describe '#current_tab?' do
|
|
202
|
+
it 'is true for a tab containing the current url and memoizes it' do
|
|
203
|
+
item = double('NavItem', relative_url: '/admin/pages')
|
|
204
|
+
tab = [item]
|
|
205
|
+
allow(helper).to receive(:current_url?).with('/admin/pages').and_return(true)
|
|
206
|
+
|
|
207
|
+
expect(helper.current_tab?(tab)).to be(true)
|
|
208
|
+
expect(helper.instance_variable_get(:@current_tab)).to eq(tab)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
describe '#pagination_for' do
|
|
213
|
+
it 'returns nil for a collection that is not paginatable' do
|
|
214
|
+
expect(helper.pagination_for(%w[a b c])).to be_nil
|
|
215
|
+
end
|
|
216
|
+
end
|
|
102
217
|
end
|
|
@@ -44,5 +44,46 @@ describe 'String extensions' do
|
|
|
44
44
|
expect('Hello World'.slugify).to eq('hello-world')
|
|
45
45
|
expect('Hello World'.slugerize).to eq('hello-world')
|
|
46
46
|
end
|
|
47
|
+
|
|
48
|
+
it 'downcases by default' do
|
|
49
|
+
expect('Hello World'.parameterize).to eq('hello-world')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'preserves case when preserve_case: true' do
|
|
53
|
+
expect('Hello World'.parameterize(preserve_case: true)).to eq('Hello-World')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'uses a custom string separator' do
|
|
57
|
+
expect('Hello World'.parameterize('_')).to eq('hello_world')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'honours the separator and preserve_case together' do
|
|
61
|
+
expect('Hello World'.parameterize('_', preserve_case: true)).to eq('Hello_World')
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# The upgrade added the guard `separator = '-' unless separator.is_a?(String)`
|
|
65
|
+
# so that Rails internals passing a non-String (e.g. a Symbol or nil)
|
|
66
|
+
# fall back to the default rather than blowing up.
|
|
67
|
+
it 'falls back to a dash when the separator is not a String' do
|
|
68
|
+
expect('Hello World'.parameterize(:_)).to eq('hello-world')
|
|
69
|
+
expect('Hello World'.parameterize(nil)).to eq('hello-world')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# `locale:` is part of the ActiveSupport-compatible signature; accepted and ignored.
|
|
73
|
+
it 'accepts a locale keyword without raising' do
|
|
74
|
+
expect('Hello World'.parameterize(locale: :en)).to eq('hello-world')
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'transliterates accented characters before downcasing' do
|
|
78
|
+
expect('Café Déjà Vu'.parameterize).to eq('cafe-deja-vu')
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'collapses repeated whitespace into a single separator' do
|
|
82
|
+
expect('Hello World'.parameterize).to eq('hello-world')
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'returns an empty string for an empty string' do
|
|
86
|
+
expect(''.parameterize).to eq('')
|
|
87
|
+
end
|
|
47
88
|
end
|
|
48
89
|
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# The app configures ActiveRecord::Encryption from ENV vars (see
|
|
2
|
+
# config/initializers/active_record_encryption.rb), which are unset in the test
|
|
3
|
+
# environment. Without keys, writing an encrypted attribute (e.g. User#otp_secret
|
|
4
|
+
# from devise-two-factor) raises a Configuration error. Configure deterministic
|
|
5
|
+
# test keys here so specs can exercise encrypted attributes.
|
|
6
|
+
ActiveRecord::Encryption.configure(
|
|
7
|
+
primary_key: 'test_primary_key_for_specs_only_0001',
|
|
8
|
+
deterministic_key: 'test_deterministic_key_for_specs_0001',
|
|
9
|
+
key_derivation_salt: 'test_key_derivation_salt_for_specs_0001'
|
|
10
|
+
)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# AssetType keeps its registry in class variables (@@types, @@type_lookup,
|
|
2
|
+
# @@default_type memoized by .catchall) with no reset hook, so registrations
|
|
3
|
+
# persist for the whole suite. Rather than snapshot/restore around individual
|
|
4
|
+
# specs — which desyncs the memoized catchall when a type is removed and later
|
|
5
|
+
# re-registered as a fresh object — every spec that needs asset types registers
|
|
6
|
+
# the SAME canonical definitions, guarded by `.known?`. Whichever spec runs
|
|
7
|
+
# first wins; the rest are no-ops. Definitions here mirror spec/models/asset_spec.rb
|
|
8
|
+
# so nothing gets shadowed by a thinner definition.
|
|
9
|
+
module AssetTypeRegistry
|
|
10
|
+
def register_standard_asset_types
|
|
11
|
+
unless AssetType.known?(:image)
|
|
12
|
+
AssetType.new(:image, icon: 'image', styles: :standard,
|
|
13
|
+
extensions: %w[jpg jpeg png gif],
|
|
14
|
+
mime_types: %w[image/png image/x-png image/jpeg image/pjpeg image/jpg image/gif])
|
|
15
|
+
end
|
|
16
|
+
unless AssetType.known?(:video)
|
|
17
|
+
AssetType.new(:video, icon: 'video',
|
|
18
|
+
mime_types: %w[video/mp4 video/mpeg video/quicktime video/webm])
|
|
19
|
+
end
|
|
20
|
+
unless AssetType.known?(:document)
|
|
21
|
+
AssetType.new(:document, icon: 'document',
|
|
22
|
+
mime_types: %w[application/msword application/rtf text/plain text/html])
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
RSpec.configure do |config|
|
|
28
|
+
config.include AssetTypeRegistry
|
|
29
|
+
end
|
data/trusty_cms.gemspec
CHANGED
|
@@ -51,7 +51,7 @@ a general purpose content management system--not merely a blogging engine.'
|
|
|
51
51
|
s.add_dependency 'rack', '>= 2.0.1', '< 3.2.0'
|
|
52
52
|
s.add_dependency 'rack-cache', '~> 1.7'
|
|
53
53
|
s.add_dependency 'radius', '~> 0.8'
|
|
54
|
-
s.add_dependency 'rails', '
|
|
54
|
+
s.add_dependency 'rails', '>= 7.2', '< 8.0'
|
|
55
55
|
s.add_dependency 'rake', '< 14.0'
|
|
56
56
|
s.add_dependency 'ransack', '~> 4.2.1'
|
|
57
57
|
s.add_dependency 'rdoc', '>= 5.1', '< 9.0'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trusty-cms
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 7.
|
|
4
|
+
version: '7.2'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- TrustyCms CMS dev team
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-08-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activestorage-validator
|
|
@@ -408,16 +408,22 @@ dependencies:
|
|
|
408
408
|
name: rails
|
|
409
409
|
requirement: !ruby/object:Gem::Requirement
|
|
410
410
|
requirements:
|
|
411
|
-
- - "
|
|
411
|
+
- - ">="
|
|
412
|
+
- !ruby/object:Gem::Version
|
|
413
|
+
version: '7.2'
|
|
414
|
+
- - "<"
|
|
412
415
|
- !ruby/object:Gem::Version
|
|
413
|
-
version:
|
|
416
|
+
version: '8.0'
|
|
414
417
|
type: :runtime
|
|
415
418
|
prerelease: false
|
|
416
419
|
version_requirements: !ruby/object:Gem::Requirement
|
|
417
420
|
requirements:
|
|
418
|
-
- - "
|
|
421
|
+
- - ">="
|
|
422
|
+
- !ruby/object:Gem::Version
|
|
423
|
+
version: '7.2'
|
|
424
|
+
- - "<"
|
|
419
425
|
- !ruby/object:Gem::Version
|
|
420
|
-
version:
|
|
426
|
+
version: '8.0'
|
|
421
427
|
- !ruby/object:Gem::Dependency
|
|
422
428
|
name: rake
|
|
423
429
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -1169,9 +1175,19 @@ files:
|
|
|
1169
1175
|
- script/extension
|
|
1170
1176
|
- script/rails
|
|
1171
1177
|
- spec/ci/database.mysql.yml
|
|
1178
|
+
- spec/controllers/admin/assets_controller_spec.rb
|
|
1179
|
+
- spec/controllers/admin/changes_controller_spec.rb
|
|
1180
|
+
- spec/controllers/admin/configuration_controller_spec.rb
|
|
1181
|
+
- spec/controllers/admin/page_attachments_controller_spec.rb
|
|
1182
|
+
- spec/controllers/admin/pages_controller_spec.rb
|
|
1183
|
+
- spec/controllers/admin/preferences_controller_spec.rb
|
|
1184
|
+
- spec/controllers/admin/security_controller_spec.rb
|
|
1185
|
+
- spec/controllers/admin/sessions_controller_spec.rb
|
|
1172
1186
|
- spec/controllers/admin/snippets_controller_spec.rb
|
|
1187
|
+
- spec/controllers/admin/two_factor_controller_spec.rb
|
|
1188
|
+
- spec/controllers/admin/users_controller_spec.rb
|
|
1173
1189
|
- spec/controllers/application_controller_spec.rb
|
|
1174
|
-
- spec/controllers/
|
|
1190
|
+
- spec/controllers/page_status_controller_spec.rb
|
|
1175
1191
|
- spec/controllers/site_controller_spec.rb
|
|
1176
1192
|
- spec/controllers/users_controller_spec.rb
|
|
1177
1193
|
- spec/dummy/README.rdoc
|
|
@@ -1184,6 +1200,7 @@ files:
|
|
|
1184
1200
|
- spec/dummy/config.ru
|
|
1185
1201
|
- spec/dummy/config/application.rb
|
|
1186
1202
|
- spec/dummy/config/boot.rb
|
|
1203
|
+
- spec/dummy/config/cable.yml
|
|
1187
1204
|
- spec/dummy/config/database.yml
|
|
1188
1205
|
- spec/dummy/config/environment.rb
|
|
1189
1206
|
- spec/dummy/config/environments/development.rb
|
|
@@ -1191,24 +1208,35 @@ files:
|
|
|
1191
1208
|
- spec/dummy/config/environments/test.rb
|
|
1192
1209
|
- spec/dummy/config/initializers/assets.rb
|
|
1193
1210
|
- spec/dummy/config/initializers/backtrace_silencers.rb
|
|
1211
|
+
- spec/dummy/config/initializers/content_security_policy.rb
|
|
1194
1212
|
- spec/dummy/config/initializers/cookies_serializer.rb
|
|
1195
1213
|
- spec/dummy/config/initializers/filter_parameter_logging.rb
|
|
1196
1214
|
- spec/dummy/config/initializers/inflections.rb
|
|
1197
1215
|
- spec/dummy/config/initializers/mime_types.rb
|
|
1216
|
+
- spec/dummy/config/initializers/new_framework_defaults_7_2.rb
|
|
1217
|
+
- spec/dummy/config/initializers/permissions_policy.rb
|
|
1198
1218
|
- spec/dummy/config/initializers/session_store.rb
|
|
1199
1219
|
- spec/dummy/config/initializers/trusty_cms_config.rb
|
|
1200
1220
|
- spec/dummy/config/initializers/wrap_parameters.rb
|
|
1201
1221
|
- spec/dummy/config/initializers/zeitwerk.rb
|
|
1202
1222
|
- spec/dummy/config/locales/en.yml
|
|
1223
|
+
- spec/dummy/config/puma.rb
|
|
1203
1224
|
- spec/dummy/config/routes.rb
|
|
1204
1225
|
- spec/dummy/config/secrets.yml
|
|
1205
1226
|
- spec/dummy/config/storage.yml
|
|
1227
|
+
- spec/dummy/db/migrate/20260729201444_add_service_name_to_active_storage_blobs.active_storage.rb
|
|
1228
|
+
- spec/dummy/db/migrate/20260729201445_create_active_storage_variant_records.active_storage.rb
|
|
1229
|
+
- spec/dummy/db/migrate/20260729201446_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb
|
|
1206
1230
|
- spec/dummy/db/schema.rb
|
|
1207
1231
|
- spec/dummy/package.json
|
|
1208
1232
|
- spec/dummy/public/404.html
|
|
1233
|
+
- spec/dummy/public/406-unsupported-browser.html
|
|
1209
1234
|
- spec/dummy/public/422.html
|
|
1210
1235
|
- spec/dummy/public/500.html
|
|
1211
1236
|
- spec/dummy/public/favicon.ico
|
|
1237
|
+
- spec/dummy/public/icon.png
|
|
1238
|
+
- spec/dummy/public/icon.svg
|
|
1239
|
+
- spec/dummy/public/robots.txt
|
|
1212
1240
|
- spec/dummy/yarn.lock
|
|
1213
1241
|
- spec/factories/layout.rb
|
|
1214
1242
|
- spec/factories/page.rb
|
|
@@ -1222,6 +1250,9 @@ files:
|
|
|
1222
1250
|
- spec/fixtures/files/sample.ics
|
|
1223
1251
|
- spec/fixtures/files/sample.txt
|
|
1224
1252
|
- spec/fixtures/users.yml
|
|
1253
|
+
- spec/helpers/admin/configuration_helper_spec.rb
|
|
1254
|
+
- spec/helpers/admin/node_helper_spec.rb
|
|
1255
|
+
- spec/helpers/admin/pages_helper_spec.rb
|
|
1225
1256
|
- spec/helpers/admin/references_helper_spec.rb
|
|
1226
1257
|
- spec/helpers/admin/url_helper_spec.rb
|
|
1227
1258
|
- spec/helpers/application_helper_spec.rb
|
|
@@ -1264,6 +1295,8 @@ files:
|
|
|
1264
1295
|
- spec/rails_helper.rb
|
|
1265
1296
|
- spec/requests/admin/snippets_spec.rb
|
|
1266
1297
|
- spec/spec_helper.rb
|
|
1298
|
+
- spec/support/active_record_encryption.rb
|
|
1299
|
+
- spec/support/asset_type_registry.rb
|
|
1267
1300
|
- spec/support/custom_actions.rb
|
|
1268
1301
|
- trusty_cms.gemspec
|
|
1269
1302
|
- vendor/extensions/clipped-extension/clipped_extension.rb
|
|
@@ -1364,9 +1397,19 @@ specification_version: 4
|
|
|
1364
1397
|
summary: A no-fluff content management system designed for small teams.
|
|
1365
1398
|
test_files:
|
|
1366
1399
|
- spec/ci/database.mysql.yml
|
|
1400
|
+
- spec/controllers/admin/assets_controller_spec.rb
|
|
1401
|
+
- spec/controllers/admin/changes_controller_spec.rb
|
|
1402
|
+
- spec/controllers/admin/configuration_controller_spec.rb
|
|
1403
|
+
- spec/controllers/admin/page_attachments_controller_spec.rb
|
|
1404
|
+
- spec/controllers/admin/pages_controller_spec.rb
|
|
1405
|
+
- spec/controllers/admin/preferences_controller_spec.rb
|
|
1406
|
+
- spec/controllers/admin/security_controller_spec.rb
|
|
1407
|
+
- spec/controllers/admin/sessions_controller_spec.rb
|
|
1367
1408
|
- spec/controllers/admin/snippets_controller_spec.rb
|
|
1409
|
+
- spec/controllers/admin/two_factor_controller_spec.rb
|
|
1410
|
+
- spec/controllers/admin/users_controller_spec.rb
|
|
1368
1411
|
- spec/controllers/application_controller_spec.rb
|
|
1369
|
-
- spec/controllers/
|
|
1412
|
+
- spec/controllers/page_status_controller_spec.rb
|
|
1370
1413
|
- spec/controllers/site_controller_spec.rb
|
|
1371
1414
|
- spec/controllers/users_controller_spec.rb
|
|
1372
1415
|
- spec/dummy/README.rdoc
|
|
@@ -1378,6 +1421,7 @@ test_files:
|
|
|
1378
1421
|
- spec/dummy/bin/setup
|
|
1379
1422
|
- spec/dummy/config/application.rb
|
|
1380
1423
|
- spec/dummy/config/boot.rb
|
|
1424
|
+
- spec/dummy/config/cable.yml
|
|
1381
1425
|
- spec/dummy/config/database.yml
|
|
1382
1426
|
- spec/dummy/config/environment.rb
|
|
1383
1427
|
- spec/dummy/config/environments/development.rb
|
|
@@ -1385,25 +1429,36 @@ test_files:
|
|
|
1385
1429
|
- spec/dummy/config/environments/test.rb
|
|
1386
1430
|
- spec/dummy/config/initializers/assets.rb
|
|
1387
1431
|
- spec/dummy/config/initializers/backtrace_silencers.rb
|
|
1432
|
+
- spec/dummy/config/initializers/content_security_policy.rb
|
|
1388
1433
|
- spec/dummy/config/initializers/cookies_serializer.rb
|
|
1389
1434
|
- spec/dummy/config/initializers/filter_parameter_logging.rb
|
|
1390
1435
|
- spec/dummy/config/initializers/inflections.rb
|
|
1391
1436
|
- spec/dummy/config/initializers/mime_types.rb
|
|
1437
|
+
- spec/dummy/config/initializers/new_framework_defaults_7_2.rb
|
|
1438
|
+
- spec/dummy/config/initializers/permissions_policy.rb
|
|
1392
1439
|
- spec/dummy/config/initializers/session_store.rb
|
|
1393
1440
|
- spec/dummy/config/initializers/trusty_cms_config.rb
|
|
1394
1441
|
- spec/dummy/config/initializers/wrap_parameters.rb
|
|
1395
1442
|
- spec/dummy/config/initializers/zeitwerk.rb
|
|
1396
1443
|
- spec/dummy/config/locales/en.yml
|
|
1444
|
+
- spec/dummy/config/puma.rb
|
|
1397
1445
|
- spec/dummy/config/routes.rb
|
|
1398
1446
|
- spec/dummy/config/secrets.yml
|
|
1399
1447
|
- spec/dummy/config/storage.yml
|
|
1400
1448
|
- spec/dummy/config.ru
|
|
1449
|
+
- spec/dummy/db/migrate/20260729201444_add_service_name_to_active_storage_blobs.active_storage.rb
|
|
1450
|
+
- spec/dummy/db/migrate/20260729201445_create_active_storage_variant_records.active_storage.rb
|
|
1451
|
+
- spec/dummy/db/migrate/20260729201446_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb
|
|
1401
1452
|
- spec/dummy/db/schema.rb
|
|
1402
1453
|
- spec/dummy/package.json
|
|
1403
1454
|
- spec/dummy/public/404.html
|
|
1455
|
+
- spec/dummy/public/406-unsupported-browser.html
|
|
1404
1456
|
- spec/dummy/public/422.html
|
|
1405
1457
|
- spec/dummy/public/500.html
|
|
1406
1458
|
- spec/dummy/public/favicon.ico
|
|
1459
|
+
- spec/dummy/public/icon.png
|
|
1460
|
+
- spec/dummy/public/icon.svg
|
|
1461
|
+
- spec/dummy/public/robots.txt
|
|
1407
1462
|
- spec/dummy/yarn.lock
|
|
1408
1463
|
- spec/factories/layout.rb
|
|
1409
1464
|
- spec/factories/page.rb
|
|
@@ -1417,6 +1472,9 @@ test_files:
|
|
|
1417
1472
|
- spec/fixtures/files/sample.ics
|
|
1418
1473
|
- spec/fixtures/files/sample.txt
|
|
1419
1474
|
- spec/fixtures/users.yml
|
|
1475
|
+
- spec/helpers/admin/configuration_helper_spec.rb
|
|
1476
|
+
- spec/helpers/admin/node_helper_spec.rb
|
|
1477
|
+
- spec/helpers/admin/pages_helper_spec.rb
|
|
1420
1478
|
- spec/helpers/admin/references_helper_spec.rb
|
|
1421
1479
|
- spec/helpers/admin/url_helper_spec.rb
|
|
1422
1480
|
- spec/helpers/application_helper_spec.rb
|
|
@@ -1459,4 +1517,6 @@ test_files:
|
|
|
1459
1517
|
- spec/rails_helper.rb
|
|
1460
1518
|
- spec/requests/admin/snippets_spec.rb
|
|
1461
1519
|
- spec/spec_helper.rb
|
|
1520
|
+
- spec/support/active_record_encryption.rb
|
|
1521
|
+
- spec/support/asset_type_registry.rb
|
|
1462
1522
|
- spec/support/custom_actions.rb
|