releaf-content 1.1.20 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +5 -5
  2. data/app/assets/config/releaf_content_manifest.js +2 -0
  3. data/app/assets/javascripts/controllers/releaf/content/nodes.js +6 -9
  4. data/app/controllers/releaf/content/nodes_controller.rb +1 -1
  5. data/lib/releaf/content/engine.rb +2 -2
  6. data/lib/releaf/content/node.rb +3 -3
  7. data/lib/releaf/content/route.rb +0 -1
  8. metadata +12 -58
  9. data/spec/builders/content/nodes/action_dialog_spec.rb +0 -39
  10. data/spec/builders/content/nodes/content_form_builder_spec.rb +0 -24
  11. data/spec/builders/content/nodes/form_builder_spec.rb +0 -262
  12. data/spec/builders/content/nodes/toolbox_builder_spec.rb +0 -77
  13. data/spec/controllers/releaf/content/nodes_controller_spec.rb +0 -52
  14. data/spec/features/nodes_services_spec.rb +0 -437
  15. data/spec/features/nodes_spec.rb +0 -572
  16. data/spec/fixtures/dummy.png +0 -0
  17. data/spec/lib/releaf/content/acts_as_node_spec.rb +0 -90
  18. data/spec/lib/releaf/content/configuration_spec.rb +0 -159
  19. data/spec/lib/releaf/content/engine_spec.rb +0 -149
  20. data/spec/lib/releaf/content/node_spec.rb +0 -591
  21. data/spec/lib/releaf/content/route_spec.rb +0 -229
  22. data/spec/middleware/routes_reloader_spec.rb +0 -96
  23. data/spec/routing/node_mapper_spec.rb +0 -310
  24. data/spec/services/releaf/content/build_route_objects_spec.rb +0 -72
  25. data/spec/services/releaf/content/node/copy_spec.rb +0 -338
  26. data/spec/services/releaf/content/node/move_spec.rb +0 -20
  27. data/spec/services/releaf/content/node/save_under_parent_spec.rb +0 -49
  28. data/spec/services/releaf/content/node/service_spec.rb +0 -19
  29. data/spec/validators/content/node/parent_validator_spec.rb +0 -56
  30. data/spec/validators/content/node/root_validator_spec.rb +0 -69
  31. data/spec/validators/content/node/singleness_validator_spec.rb +0 -145
@@ -1,72 +0,0 @@
1
- require "rails_helper"
2
-
3
- describe Releaf::Content::BuildRouteObjects do
4
- let(:home_page_node) { create(:home_page_node, id: 23, locale: "lv", slug: "llvv") }
5
- let(:node) { create(:text_page_node, id: 27, parent: home_page_node, slug: "some-text") }
6
- let(:controller) { Releaf::Content::Route.default_controller( node.class ) }
7
- let(:subject) { described_class.new(node_class: node.class, node_content_class: TextPage, default_controller: controller) }
8
-
9
- describe "#call" do
10
- it "returns an array" do
11
- expect(subject.call).to be_a Array
12
- end
13
-
14
- it "returns an array of Node::Route objects" do
15
- result = subject.call
16
- expect(result.count).to eq(1)
17
- expect(result.first.class).to eq(Releaf::Content::Route)
18
- end
19
- end
20
-
21
- describe "#nodes" do
22
- it "returns all nodes" do
23
- expect(subject.nodes).to match_array([home_page_node, node])
24
- end
25
- end
26
-
27
- describe "#content_nodes" do
28
- it "returns nodes with a specified content class" do
29
- expect(subject.content_nodes).to eq([node])
30
- end
31
- end
32
-
33
- describe "#build_route_object" do
34
- let(:route) { subject.build_route_object(node) }
35
-
36
- context "when node is not available" do
37
- it "does not include it in return" do
38
- allow_any_instance_of(Node).to receive(:available?).and_return(false)
39
- expect(route).to be_nil
40
- end
41
- end
42
-
43
- it "returns a route instance" do
44
- expect(route).to be_a Releaf::Content::Route
45
- end
46
-
47
- it "assigns node_class from given node" do
48
- expect(route.node_class).to be Node
49
- end
50
-
51
- it "assigns node_id from given node" do
52
- expect(route.node_id).to eq "27"
53
- end
54
-
55
- it "assigns path from given node" do
56
- expect(route.path).to eq "/llvv/some-text"
57
- end
58
-
59
- it "assigns locale from given node" do
60
- expect(route.locale).to eq "lv"
61
- end
62
-
63
- it "assigns default_controller from given argument" do
64
- expect(route.default_controller).to be controller
65
- end
66
-
67
- it "assigns site from content routing configuration" do
68
- allow( Releaf::Content).to receive(:routing).and_return('Node' => {site: 'some_site'})
69
- expect(route.site).to eq 'some_site'
70
- end
71
- end
72
- end
@@ -1,338 +0,0 @@
1
- require "rails_helper"
2
-
3
- describe Releaf::Content::Node::Copy do
4
-
5
- let(:root_node) { create(:home_page_node) }
6
-
7
- let(:node) { create(node_factory, parent: root_node) }
8
- let(:node_factory) { :text_page_node }
9
-
10
- let(:content_factory) { :text_page }
11
- let(:content_attributes) { { } }
12
-
13
- let(:complex_node_factory) { :banner_page_node }
14
- let(:complex_content_factory) { :banner_page }
15
- let(:complex_content_duplicatable_associations) {
16
- [
17
- {
18
- banner_groups: [
19
- { banners: [] }
20
- ]
21
- }
22
- ] }
23
-
24
- let(:file) { File.new(File.expand_path('../../../../fixtures/dummy.png', __dir__)) }
25
-
26
- let(:original) { create(content_factory, content_attributes) }
27
-
28
- describe "#call" do
29
- subject { described_class.new(node: node, parent_id: root_node.id ) }
30
-
31
- it "returns node" do
32
- expect(subject.call.class).to eq(node.class)
33
- end
34
- end
35
-
36
- describe "#make_copy" do
37
- # this is a double check to verify file duplication by doing the full copying process.
38
- # #duplicate_dragonfly_attachments is tested separately in more detail below
39
- subject { described_class.new(node: node, parent_id: root_node.id ) }
40
-
41
- context "when node content has dragonfly file fields" do
42
- let(:node_factory) { complex_node_factory }
43
-
44
- it "duplicates dragonfly attachments, storing them as separate files that are no longer linked" do
45
- node.content.top_banner = file
46
- node.save!
47
- copy = subject.make_copy
48
-
49
- # make sure the uids are non-empty and different
50
- expect(node.content.top_banner_uid).to be_present
51
- expect(copy.content.top_banner_uid).to be_present
52
- expect(copy.content.top_banner_uid).to_not eq node.content.top_banner_uid
53
-
54
- # make sure the files are stored and exist
55
- expect(copy.content.top_banner.path).to start_with Dragonfly.app.datastore.root_path
56
- expect(node.content.top_banner.path).to start_with Dragonfly.app.datastore.root_path
57
- expect(copy.content.top_banner.path).to_not eq node.content.top_banner.path
58
- end
59
- end
60
-
61
- end
62
-
63
-
64
- describe "#duplicate_under" do
65
- let!(:source_node) { create(:node, locale: "lv") }
66
- let!(:target_node) { create(:node, locale: "en") }
67
-
68
- before do
69
- allow_any_instance_of(Releaf::Content::Node::RootValidator).to receive(:validate)
70
- subject.node = source_node
71
- subject.parent_id = target_node.id
72
- end
73
-
74
- it "creates duplicated node under target node" do
75
- new_node = Node.new
76
- duplicated_content = double('content', id: 1234)
77
- expect( Node ).to receive(:new).ordered.and_return(new_node)
78
- expect( new_node ).to receive(:assign_attributes_from).with(source_node).ordered.and_call_original
79
- expect( subject ).to receive(:duplicate_content).ordered.and_return(duplicated_content)
80
- expect( new_node ).to receive(:content_id=).with(1234).ordered
81
- expect( Releaf::Content::Node::SaveUnderParent ).to receive(:call).with(node: new_node, parent_id: target_node.id)
82
- .ordered.and_call_original
83
- expect(subject.duplicate_under).to eq(new_node)
84
- end
85
-
86
- it "doesn't update settings timestamp" do
87
- expect( Node ).to_not receive(:updated)
88
- subject.duplicate_under
89
- end
90
- end
91
-
92
-
93
- describe "#duplicate_content" do
94
-
95
- let(:content) { node.content }
96
-
97
- before do
98
- allow(subject).to receive(:node).and_return(node)
99
- end
100
-
101
- context "when node has a content object" do
102
-
103
- it "calls #duplicate_object with current content" do
104
- expect(subject).to receive(:duplicate_object).with(content).and_return(content)
105
- subject.duplicate_content
106
- end
107
-
108
- it "saves the duplicated result" do
109
- new_content = subject.duplicate_content
110
- expect(new_content.new_record?).to be false
111
- end
112
-
113
- it "returns the newly saved content" do
114
- new_content = subject.duplicate_content
115
- expect(new_content.id).to_not eq content.id
116
- end
117
- end
118
-
119
- context "when node does not have a content object" do
120
- before do
121
- node.content = nil
122
- end
123
-
124
- it "does nothing" do
125
- expect(subject).to_not receive(:duplicate_object)
126
- expect(node).to_not receive(:save!)
127
- subject.duplicate_content
128
- end
129
- it "returns nil" do
130
- expect(subject.duplicate_content).to be_nil
131
- end
132
- end
133
-
134
- end
135
-
136
-
137
- describe "#duplicate_object" do
138
-
139
- context "when object has no duplicatable associations" do
140
- let(:content_factory) { :text_page }
141
- let(:content_attributes) { { text_html: "html" } }
142
-
143
- it "builds an unsaved copy of the object" do
144
- copy = subject.duplicate_object(original)
145
- expect(copy.class).to be original.class
146
- expect(copy.new_record?).to be true
147
-
148
- expect(copy.text_html).to eq original.text_html
149
- end
150
-
151
- it "uses #deep_clone for copying" do
152
- expect(subject).to receive(:duplicatable_associations).with(original.class).and_call_original
153
- expect(original).to receive(:deep_clone).with( include: [] ).and_call_original
154
- subject.duplicate_object(original)
155
- end
156
-
157
- it "calls #supplement_object_duplication with the original object and its new copy" do
158
- copy = original.dup
159
-
160
- # stub #dup (which is called by deep_clone internally) so that it returns a known instance
161
- allow(original).to receive(:dup).and_return(copy)
162
-
163
- expect(subject).to receive(:supplement_object_duplication).with(original, copy)
164
- subject.duplicate_object(original)
165
- end
166
-
167
- end
168
-
169
- context "when object has duplicatable associations" do
170
- let(:content_factory) { complex_content_factory }
171
-
172
- let(:content_attributes) do
173
- {
174
- intro_text_html: "Intro html",
175
- banner_groups_attributes: [
176
- {
177
- title: "Group title",
178
- banners_attributes: [
179
- url: "Banner url"
180
- ]
181
- },
182
- ]
183
- }
184
- end
185
-
186
- it "passes duplicatable associations to #deep_clone" do
187
- expect(original).to receive(:deep_clone).with( include: complex_content_duplicatable_associations ).and_call_original
188
- subject.duplicate_object(original)
189
- end
190
-
191
- it "builds an unsaved copy with nested copies of associated objects" do
192
- copy = subject.duplicate_object(original)
193
- expect(copy.class).to be original.class
194
- expect(copy.new_record?).to be true
195
- expect(copy.intro_text_html).to eq original.intro_text_html
196
-
197
- original_item = original.banner_groups.first
198
- copied_item = copy.banner_groups.first
199
- expect(copied_item.class).to be original_item.class
200
- expect(copied_item.new_record?).to be true
201
- expect(copied_item.title).to eq original_item.title
202
-
203
- original_nested_item = original.banner_groups.first.banners.first
204
- copied_nested_item = copy.banner_groups.first.banners.first
205
- expect(copied_nested_item.class).to be original_nested_item.class
206
- expect(copied_nested_item.new_record?).to be true
207
- expect(copied_nested_item.url).to eq original_nested_item.url
208
- end
209
-
210
- it "calls #supplement_object_duplication on all cloned objects" do
211
- original_item = original.banner_groups.first
212
- original_nested_item = original_item.banners.first
213
-
214
- expect(subject).to receive(:supplement_object_duplication).with(original, kind_of(original.class))
215
- expect(subject).to receive(:supplement_object_duplication).with(original_item, kind_of(original_item.class))
216
- expect(subject).to receive(:supplement_object_duplication).with(original_nested_item, kind_of(original_nested_item.class))
217
- subject.duplicate_object(original)
218
- end
219
-
220
- end
221
-
222
- end
223
-
224
- describe "#supplement_object_duplication" do
225
- it "calls #duplicate_dragonfly_attachments with given original and copy" do
226
- expect(subject).to receive(:duplicate_dragonfly_attachments).with(:foo, :bar)
227
- subject.supplement_object_duplication(:foo, :bar)
228
- end
229
- end
230
-
231
- describe "#duplicatable_associations" do
232
- let(:content_class) { build(content_factory).class }
233
-
234
- it "uses Releaf::ResourceBase to detect duplicatable associations" do
235
- expect(Releaf::ResourceBase).to receive(:new).with(content_class).and_call_original
236
- subject.duplicatable_associations(content_class)
237
- end
238
-
239
- context "when given class has duplicatable associations" do
240
- it "returns duplicatable association names as nested arrays of hashes" do
241
- expect(subject.duplicatable_associations(content_class)).to eq []
242
- end
243
- end
244
-
245
- context "when given class has no duplicatable associations" do
246
- let(:content_factory) { complex_content_factory }
247
- it "returns an empty array" do
248
- expect(subject.duplicatable_associations(content_class)).to eq complex_content_duplicatable_associations
249
- end
250
- end
251
- end
252
-
253
-
254
- describe "#duplicate_dragonfly_attachments" do
255
- let(:content_factory) { complex_content_factory }
256
- let(:copy) { original.dup }
257
-
258
- context "when the original object's dragonfly attributes" do
259
-
260
- context "are blank" do
261
- it "sets the file attributes to nil on the given copy" do
262
- expect(copy).to receive(:top_banner_uid=).with(nil).ordered
263
- expect(copy).to receive(:top_banner=).with(nil).ordered
264
- subject.duplicate_dragonfly_attachments(original, copy)
265
- end
266
- end
267
-
268
- context "contain files" do
269
-
270
- it "separates the attachments so that dragonfly treats them as separate files" do
271
- # it is important that the owner class used in this test has at least two dragonfly attributes
272
- # and the test is not using the first one.
273
- # (an earlier implementation worked only with the first file
274
- # and would have passed the test if the test used the first file)
275
- expect(original.dragonfly_attachments.keys.find_index(:bottom_banner)).to be > 0
276
-
277
- original.bottom_banner = file
278
- original.save!
279
-
280
- subject.duplicate_dragonfly_attachments(original, copy)
281
- copy.save!
282
-
283
- # refetch the objects. calling #reload on them is not enough
284
- original_id = original.id
285
- copy_id = copy.id
286
- klass = original.class
287
-
288
- original = klass.find(original_id)
289
- copy = klass.find(copy_id)
290
-
291
- # make sure the uids are non-empty and different
292
- expect(original.bottom_banner_uid).to be_present
293
- expect(copy.bottom_banner_uid).to be_present
294
- expect(copy.bottom_banner_uid).to_not eq original.bottom_banner_uid
295
-
296
- # make sure the files are stored and exist
297
- expect(copy.bottom_banner.path).to start_with Dragonfly.app.datastore.root_path
298
- expect(original.bottom_banner.path).to start_with Dragonfly.app.datastore.root_path
299
- expect(copy.bottom_banner.path).to_not eq original.bottom_banner.path
300
-
301
- # make sure the metadata is readable as well
302
- expect(copy.bottom_banner.format).to eq original.bottom_banner.format
303
- end
304
-
305
- end
306
-
307
- context "contain files that are missing" do
308
-
309
- it "sets the file attributes to nil on the given copy" do
310
- original.top_banner = file
311
- original.save!
312
-
313
- original_id = original.id
314
-
315
- # simulate deletion from filesystem by setting the uid to an invalid path
316
- original.top_banner_uid = "xxx" + original.top_banner_uid
317
- original.save!
318
-
319
- klass = original.class
320
- original = klass.find(original_id)
321
-
322
- subject.duplicate_dragonfly_attachments(original, copy)
323
- copy.save!
324
- copy_id = copy.id
325
- copy = klass.find(copy_id)
326
-
327
- expect(copy.top_banner_uid).to be_nil
328
- expect(copy.top_banner).to be_nil
329
- end
330
-
331
- end
332
-
333
- end
334
- end
335
-
336
-
337
-
338
- end
@@ -1,20 +0,0 @@
1
- require "rails_helper"
2
-
3
- describe Releaf::Content::Node::Move do
4
- class DummyNodeServiceIncluder
5
- include Releaf::Content::Node::Service
6
- end
7
-
8
- let(:node){ Node.new }
9
- subject{ described_class.new(node: node, parent_id: 12) }
10
-
11
- describe "#call" do
12
- context "when parent is same" do
13
- it "does nothing and returns self" do
14
- node.parent_id = 12
15
- expect(node.class).to_not receive(:transaction)
16
- expect(subject.call).to eq(node)
17
- end
18
- end
19
- end
20
- end
@@ -1,49 +0,0 @@
1
- require "rails_helper"
2
-
3
- describe Releaf::Content::Node::SaveUnderParent do
4
- class DummyNodeServiceIncluder
5
- include Releaf::Content::Node::Service
6
- end
7
-
8
- let(:root_node){ create(:node, locale: "lv") }
9
- let(:node){ build(:text_page_node) }
10
- subject{ described_class.new(node: node, parent_id: root_node.id) }
11
-
12
- describe "#call" do
13
- it "saves node nuder node with given node_id" do
14
- node2 = create(:text_page_node, parent: root_node)
15
-
16
- subject.parent_id = node2.id
17
- subject.call
18
- expect( node ).to_not be_new_record
19
- expect( node.parent ).to eq node2
20
- end
21
-
22
- it "maintains node name and slug, then saves record" do
23
- expect( node ).to receive(:maintain_name).ordered.and_call_original
24
- expect( node ).to receive(:maintain_slug).ordered.and_call_original
25
- expect( node ).to receive(:save!).ordered.and_call_original
26
- subject.call
27
- end
28
-
29
- context "when #validate_root_locale_uniqueness? returns true" do
30
- let(:node){ root_node }
31
-
32
- it "sets locale to nil" do
33
- allow(node).to receive(:validate_root_locale_uniqueness?).and_return(true)
34
- subject.parent_id = nil
35
- expect { subject.call }.to change{ node.locale }.from("lv").to(nil)
36
- end
37
- end
38
-
39
- context "when #validate_root_locale_uniqueness? returns false" do
40
- let(:node){ root_node }
41
-
42
- it "doesn't set locale to nil" do
43
- allow(node).to receive(:validate_root_locale_uniqueness?).and_return(false)
44
- subject.parent_id = nil
45
- expect { subject.call }.to_not change{ node.locale }
46
- end
47
- end
48
- end
49
- end