spontaneous 0.2.0.alpha7 → 0.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +10 -4
- data/Readme.markdown +1 -1
- data/application/css/definitions.css.scss +5 -0
- data/application/css/dialogue.css.scss +62 -0
- data/application/js/content.js +1 -1
- data/application/js/dom.js +1 -1
- data/application/js/event_source.js +3 -0
- data/application/js/{field_types/date_field.js → field/date.js} +2 -2
- data/application/js/{field_types/file_field.js → field/file.js} +2 -2
- data/application/js/{field_types/image_field.js → field/image.js} +54 -20
- data/application/js/{field_types/long_string_field.js → field/long_string.js} +2 -2
- data/application/js/{field_types/markdown_field.js → field/markdown.js} +2 -2
- data/application/js/{field_types/select_field.js → field/select.js} +2 -2
- data/application/js/{field_types/string_field.js → field/string.js} +21 -7
- data/application/js/{field_types/webvideo_field.js → field/webvideo.js} +2 -2
- data/application/js/field.js +2 -2
- data/application/js/publish.js +99 -19
- data/application/js/spontaneous.js +8 -8
- data/application/js/top_bar.js +6 -4
- data/db/migrations/20130109125023_add_page_publish_lock.rb +17 -0
- data/db/migrations/20130111161934_convert_bcrypt_passwords.rb +22 -0
- data/db/migrations/20130114120000_create_revision_tables.rb +106 -0
- data/db/migrations/20130116220423_add_index_to_archive.rb +9 -0
- data/lib/spontaneous/box.rb +53 -18
- data/lib/spontaneous/box_style.rb +2 -3
- data/lib/spontaneous/change.rb +39 -13
- data/lib/spontaneous/cli/fields.rb +29 -0
- data/lib/spontaneous/cli/init.rb +2 -2
- data/lib/spontaneous/cli/migrate.rb +0 -1
- data/lib/spontaneous/cli/server.rb +14 -10
- data/lib/spontaneous/cli/site.rb +20 -9
- data/lib/spontaneous/cli.rb +8 -6
- data/lib/spontaneous/collections/box_set.rb +11 -0
- data/lib/spontaneous/collections/field_set.rb +24 -1
- data/lib/spontaneous/concern.rb +37 -0
- data/lib/spontaneous/config.rb +3 -4
- data/lib/spontaneous/crypt/version.rb +130 -0
- data/lib/spontaneous/crypt.rb +84 -0
- data/lib/spontaneous/data_mapper/content_model/associations.rb +199 -0
- data/lib/spontaneous/data_mapper/content_model/column_accessors.rb +52 -0
- data/lib/spontaneous/data_mapper/content_model/instance_hooks.rb +34 -0
- data/lib/spontaneous/data_mapper/content_model/serialization.rb +54 -0
- data/lib/spontaneous/data_mapper/content_model/timestamps.rb +39 -0
- data/lib/spontaneous/data_mapper/content_model.rb +343 -0
- data/lib/spontaneous/data_mapper/content_table.rb +103 -0
- data/lib/spontaneous/data_mapper/dataset.rb +194 -0
- data/lib/spontaneous/data_mapper/scope.rb +195 -0
- data/lib/spontaneous/data_mapper.rb +161 -0
- data/lib/spontaneous/facet.rb +2 -2
- data/lib/spontaneous/field/base.rb +418 -0
- data/lib/spontaneous/field/date.rb +54 -0
- data/lib/spontaneous/{field_version.rb → field/field_version.rb} +1 -1
- data/lib/spontaneous/field/file.rb +100 -0
- data/lib/spontaneous/{field_types/image_field.rb → field/image.rb} +33 -33
- data/lib/spontaneous/{field_types/location_field.rb → field/location.rb} +2 -2
- data/lib/spontaneous/{field_types/long_string_field.rb → field/long_string.rb} +3 -3
- data/lib/spontaneous/field/markdown.rb +36 -0
- data/lib/spontaneous/{field_types/select_field.rb → field/select.rb} +4 -5
- data/lib/spontaneous/field/string.rb +17 -0
- data/lib/spontaneous/field/update.rb +156 -0
- data/lib/spontaneous/field/webvideo.rb +310 -0
- data/lib/spontaneous/field.rb +80 -0
- data/lib/spontaneous/generators/site/Gemfile.tt +2 -2
- data/lib/spontaneous/generators/site/config/environments/development.rb.tt +1 -1
- data/lib/spontaneous/generators/site/config/environments/production.rb.tt +1 -1
- data/lib/spontaneous/generators/site/lib/content.rb.tt +6 -0
- data/lib/spontaneous/generators/site/schema/box.rb.tt +3 -2
- data/lib/spontaneous/generators/site/schema/page.rb.tt +3 -1
- data/lib/spontaneous/generators/site/schema/piece.rb.tt +3 -1
- data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +3 -1
- data/lib/spontaneous/generators/site.rb +4 -3
- data/lib/spontaneous/image_size.rb +8 -1
- data/lib/spontaneous/layout.rb +5 -1
- data/lib/spontaneous/loader.rb +2 -5
- data/lib/spontaneous/media/file.rb +11 -2
- data/lib/spontaneous/media/temp_file.rb +23 -0
- data/lib/spontaneous/media.rb +20 -39
- data/lib/spontaneous/{plugins → model/box}/allowed_types.rb +38 -17
- data/lib/spontaneous/model/box.rb +18 -0
- data/lib/spontaneous/{plugins → model/core}/aliases.rb +10 -14
- data/lib/spontaneous/{plugins → model/core}/boxes.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/content_groups.rb +2 -2
- data/lib/spontaneous/model/core/editor_class.rb +4 -0
- data/lib/spontaneous/{plugins → model/core}/entries.rb +19 -7
- data/lib/spontaneous/{plugins → model/core}/entry.rb +3 -3
- data/lib/spontaneous/{plugins → model/core}/fields.rb +38 -5
- data/lib/spontaneous/{plugins → model/core}/instance_code.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/media.rb +2 -12
- data/lib/spontaneous/{plugins → model/core}/modifications.rb +7 -6
- data/lib/spontaneous/model/core/page_search.rb +36 -0
- data/lib/spontaneous/{plugins → model/core}/permissions.rb +4 -4
- data/lib/spontaneous/{plugins → model/core}/prototypes.rb +4 -4
- data/lib/spontaneous/{plugins → model/core}/publishing.rb +93 -115
- data/lib/spontaneous/{plugins → model/core}/render.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/schema_hierarchy.rb +7 -11
- data/lib/spontaneous/model/core/schema_id.rb +65 -0
- data/lib/spontaneous/{plugins → model/core}/schema_title.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/serialisation.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/styles.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/supertype.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/visibility.rb +7 -48
- data/lib/spontaneous/model/core.rb +143 -0
- data/lib/spontaneous/{plugins → model/page}/controllers.rb +3 -3
- data/lib/spontaneous/{plugins → model}/page/formats.rb +2 -2
- data/lib/spontaneous/{plugins → model/page}/layouts.rb +2 -2
- data/lib/spontaneous/model/page/locks.rb +14 -0
- data/lib/spontaneous/{plugins → model/page}/page_tree.rb +3 -3
- data/lib/spontaneous/{plugins → model/page}/paths.rb +30 -12
- data/lib/spontaneous/{plugins → model}/page/request.rb +2 -2
- data/lib/spontaneous/{plugins → model/page}/site_map.rb +2 -2
- data/lib/spontaneous/model/page/site_timestamps.rb +44 -0
- data/lib/spontaneous/{page.rb → model/page.rb} +49 -28
- data/lib/spontaneous/{piece.rb → model/piece.rb} +7 -6
- data/lib/spontaneous/model.rb +97 -0
- data/lib/spontaneous/output/context.rb +1 -1
- data/lib/spontaneous/output/format.rb +4 -0
- data/lib/spontaneous/output/template/renderer.rb +2 -2
- data/lib/spontaneous/output.rb +2 -2
- data/lib/spontaneous/page_lock.rb +62 -0
- data/lib/spontaneous/page_piece.rb +1 -1
- data/lib/spontaneous/permissions/access_key.rb +9 -4
- data/lib/spontaneous/permissions/user.rb +19 -9
- data/lib/spontaneous/permissions.rb +2 -5
- data/lib/spontaneous/plugins/application/facets.rb +1 -2
- data/lib/spontaneous/plugins/application/features.rb +1 -1
- data/lib/spontaneous/plugins/application/paths.rb +1 -1
- data/lib/spontaneous/plugins/application/render.rb +1 -1
- data/lib/spontaneous/plugins/application/serialisation.rb +1 -1
- data/lib/spontaneous/plugins/application/state.rb +30 -1
- data/lib/spontaneous/plugins/application/system.rb +12 -12
- data/lib/spontaneous/prototypes/box_prototype.rb +1 -1
- data/lib/spontaneous/prototypes/field_prototype.rb +3 -6
- data/lib/spontaneous/prototypes/style_prototype.rb +1 -1
- data/lib/spontaneous/publishing/immediate.rb +77 -49
- data/lib/spontaneous/publishing/revision.rb +355 -0
- data/lib/spontaneous/publishing/simultaneous.rb +10 -49
- data/lib/spontaneous/publishing.rb +1 -0
- data/lib/spontaneous/rack/around_back.rb +1 -1
- data/lib/spontaneous/rack/around_front.rb +2 -4
- data/lib/spontaneous/rack/around_preview.rb +1 -1
- data/lib/spontaneous/rack/back.rb +80 -63
- data/lib/spontaneous/rack/cacheable_file.rb +2 -2
- data/lib/spontaneous/rack/cookie_authentication.rb +1 -1
- data/lib/spontaneous/rack/front.rb +1 -1
- data/lib/spontaneous/rack/helpers.rb +8 -9
- data/lib/spontaneous/{page_controller.rb → rack/page_controller.rb} +1 -1
- data/lib/spontaneous/rack/public.rb +3 -3
- data/lib/spontaneous/rack.rb +15 -15
- data/lib/spontaneous/schema/uid.rb +4 -1
- data/lib/spontaneous/schema.rb +57 -24
- data/lib/spontaneous/search/database.rb +12 -1
- data/lib/spontaneous/search/index.rb +34 -6
- data/lib/spontaneous/search/results.rb +1 -1
- data/lib/spontaneous/server.rb +3 -3
- data/lib/spontaneous/simultaneous.rb +53 -0
- data/lib/spontaneous/{plugins/site → site}/features.rb +2 -2
- data/lib/spontaneous/{plugins/site → site}/helpers.rb +2 -3
- data/lib/spontaneous/{plugins/site → site}/hooks.rb +2 -2
- data/lib/spontaneous/{plugins/site → site}/instance.rb +4 -6
- data/lib/spontaneous/{plugins/site → site}/level.rb +2 -2
- data/lib/spontaneous/{plugins/site → site}/map.rb +4 -4
- data/lib/spontaneous/{plugins/site → site}/paths.rb +2 -2
- data/lib/spontaneous/site/publishing.rb +89 -0
- data/lib/spontaneous/{plugins/site → site}/schema.rb +4 -4
- data/lib/spontaneous/{plugins/site → site}/search.rb +2 -2
- data/lib/spontaneous/{plugins/site → site}/selectors.rb +15 -7
- data/lib/spontaneous/{plugins/site → site}/state.rb +2 -2
- data/lib/spontaneous/{plugins/site → site}/storage.rb +2 -2
- data/lib/spontaneous/{plugins/site → site}/url.rb +2 -2
- data/lib/spontaneous/site.rb +31 -14
- data/lib/spontaneous/state.rb +5 -6
- data/lib/spontaneous/style.rb +3 -2
- data/lib/spontaneous/utils/database/mysql_dumper.rb +13 -0
- data/lib/spontaneous/utils/database/postgres_dumper.rb +5 -0
- data/lib/spontaneous/version.rb +1 -1
- data/lib/spontaneous.rb +34 -89
- data/spontaneous.gemspec +112 -114
- data/test/experimental/test_crypt.rb +158 -0
- data/test/experimental/test_features.rb +3 -3
- data/test/fixtures/example_application/config/environments/development.rb +1 -1
- data/test/fixtures/example_application/lib/content.rb +5 -0
- data/test/fixtures/example_application/schema/page.rb +2 -1
- data/test/fixtures/example_application/schema/piece.rb +3 -2
- data/test/fixtures/serialisation/class_hash.yaml.erb +5 -5
- data/test/fixtures/serialisation/root_hash.yaml.erb +8 -0
- data/test/functional/test_application.rb +12 -1
- data/test/functional/test_back.rb +80 -48
- data/test/functional/test_front.rb +39 -46
- data/test/functional/test_user_manager.rb +3 -9
- data/test/javascript/test_markdown.rb +2 -2
- data/test/test_helper.rb +78 -23
- data/test/unit/test_alias.rb +21 -15
- data/test/unit/test_asset_bundler.rb +3 -3
- data/test/unit/test_assets.rb +2 -2
- data/test/unit/test_async.rb +7 -6
- data/test/unit/test_authentication.rb +43 -37
- data/test/unit/test_boxes.rb +46 -21
- data/test/unit/test_changesets.rb +65 -20
- data/test/unit/test_config.rb +9 -9
- data/test/unit/test_content.rb +50 -51
- data/test/unit/test_content_inheritance.rb +6 -20
- data/test/unit/test_datamapper.rb +1330 -0
- data/test/unit/test_datamapper_content.rb +214 -0
- data/test/unit/test_fields.rb +543 -54
- data/test/unit/test_formats.rb +2 -3
- data/test/unit/test_generators.rb +6 -6
- data/test/unit/test_helpers.rb +1 -1
- data/test/unit/test_image_size.rb +10 -5
- data/test/unit/test_images.rb +17 -18
- data/test/unit/test_layouts.rb +18 -3
- data/test/unit/test_media.rb +74 -49
- data/test/unit/test_modifications.rb +43 -43
- data/test/unit/test_page.rb +7 -10
- data/test/unit/test_permissions.rb +3 -10
- data/test/unit/test_piece.rb +5 -6
- data/test/unit/test_plugins.rb +7 -14
- data/test/unit/test_prototypes.rb +3 -3
- data/test/unit/test_publishing.rb +49 -27
- data/test/unit/test_render.rb +46 -15
- data/test/unit/test_revisions.rb +124 -127
- data/test/unit/test_schema.rb +53 -58
- data/test/unit/test_search.rb +64 -16
- data/test/unit/test_serialisation.rb +4 -11
- data/test/unit/test_site.rb +11 -12
- data/test/unit/test_structure.rb +2 -5
- data/test/unit/test_styles.rb +22 -24
- data/test/unit/test_type_hierarchy.rb +7 -5
- data/test/unit/test_visibility.rb +79 -55
- metadata +128 -102
- data/lib/sequel/plugins/content_table_inheritance.rb +0 -203
- data/lib/sequel/plugins/scoped_table_name.rb +0 -54
- data/lib/spontaneous/content.rb +0 -129
- data/lib/spontaneous/field_types/date_field.rb +0 -56
- data/lib/spontaneous/field_types/field.rb +0 -302
- data/lib/spontaneous/field_types/file_field.rb +0 -68
- data/lib/spontaneous/field_types/markdown_field.rb +0 -38
- data/lib/spontaneous/field_types/string_field.rb +0 -19
- data/lib/spontaneous/field_types/webvideo_field.rb +0 -313
- data/lib/spontaneous/field_types.rb +0 -38
- data/lib/spontaneous/generators/site/lib/site.rb.tt +0 -4
- data/lib/spontaneous/plugins/field/editor_class.rb +0 -13
- data/lib/spontaneous/plugins/page/site_timestamps.rb +0 -28
- data/lib/spontaneous/plugins/page_search.rb +0 -63
- data/lib/spontaneous/plugins/schema_id.rb +0 -68
- data/lib/spontaneous/plugins/site/publishing.rb +0 -75
- data/lib/spontaneous/rack/fiber_pool.rb +0 -26
- data/test/unit/test_table_scoping.rb +0 -80
data/test/unit/test_fields.rb
CHANGED
@@ -6,7 +6,10 @@ class FieldsTest < MiniTest::Spec
|
|
6
6
|
|
7
7
|
def setup
|
8
8
|
@site = setup_site
|
9
|
-
|
9
|
+
@now = Time.now
|
10
|
+
stub_time(@now)
|
11
|
+
Spontaneous::State.delete
|
12
|
+
Site.background_mode = :immediate
|
10
13
|
end
|
11
14
|
|
12
15
|
def teardown
|
@@ -14,17 +17,7 @@ class FieldsTest < MiniTest::Spec
|
|
14
17
|
end
|
15
18
|
|
16
19
|
context "Fields" do
|
17
|
-
|
18
|
-
class ::Page < Spontaneous::Page; end
|
19
|
-
class ::Piece < Spontaneous::Piece; end
|
20
|
-
end
|
21
|
-
|
22
|
-
teardown do
|
23
|
-
Object.send(:remove_const, :Page)
|
24
|
-
Object.send(:remove_const, :Piece)
|
25
|
-
end
|
26
|
-
|
27
|
-
context "New content instances" do
|
20
|
+
context "New content instances xxx" do
|
28
21
|
setup do
|
29
22
|
@content_class = Class.new(Piece) do
|
30
23
|
field :title, :default => "Magic"
|
@@ -35,7 +28,7 @@ class FieldsTest < MiniTest::Spec
|
|
35
28
|
|
36
29
|
should "have fields with values defined by prototypes" do
|
37
30
|
f = @instance.fields[:title]
|
38
|
-
assert f.class < Spontaneous::
|
31
|
+
assert f.class < Spontaneous::Field::String
|
39
32
|
f.value.should == "Magic"
|
40
33
|
end
|
41
34
|
|
@@ -54,6 +47,14 @@ class FieldsTest < MiniTest::Spec
|
|
54
47
|
@instance.title = "Boing!"
|
55
48
|
@instance.fields[:title].value.should == "Boing!"
|
56
49
|
end
|
50
|
+
|
51
|
+
# TODO: I want to allow this but don't like overwriting the ::fields
|
52
|
+
# method like this.
|
53
|
+
# should "allow the definition of multiple fields at once" do
|
54
|
+
# content_class = Class.new(Piece) do
|
55
|
+
# fields :title, :photo, :date
|
56
|
+
# end
|
57
|
+
# end
|
57
58
|
end
|
58
59
|
|
59
60
|
context "Overwriting fields" do
|
@@ -80,7 +81,7 @@ class FieldsTest < MiniTest::Spec
|
|
80
81
|
@class2.fields.title.title.should == "Two"
|
81
82
|
@class3.fields.date.title.should == "Three"
|
82
83
|
@class3.fields.date.schema_id.should == @class1.fields.date.schema_id
|
83
|
-
assert @instance.title.class < Spontaneous::
|
84
|
+
assert @instance.title.class < Spontaneous::Field::Image
|
84
85
|
@instance.title.value.to_s.should == "Two"
|
85
86
|
instance1 = @class1.new
|
86
87
|
instance3 = @class3.new
|
@@ -109,11 +110,11 @@ class FieldsTest < MiniTest::Spec
|
|
109
110
|
end
|
110
111
|
|
111
112
|
should "default to basic string class" do
|
112
|
-
assert @content_class.field_prototypes[:title].instance_class < Spontaneous::
|
113
|
+
assert @content_class.field_prototypes[:title].instance_class < Spontaneous::Field::String
|
113
114
|
end
|
114
115
|
|
115
|
-
should "map :string type to
|
116
|
-
assert @content_class.field_prototypes[:synopsis].instance_class < Spontaneous::
|
116
|
+
should "map :string type to Field::String" do
|
117
|
+
assert @content_class.field_prototypes[:synopsis].instance_class < Spontaneous::Field::String
|
117
118
|
end
|
118
119
|
|
119
120
|
should "be listable" do
|
@@ -162,9 +163,9 @@ class FieldsTest < MiniTest::Spec
|
|
162
163
|
field :chunky
|
163
164
|
end
|
164
165
|
|
165
|
-
assert content_class.field_prototypes[:image].field_class < Spontaneous::
|
166
|
-
assert content_class.field_prototypes[:date].field_class < Spontaneous::
|
167
|
-
assert content_class.field_prototypes[:chunky].field_class < Spontaneous::
|
166
|
+
assert content_class.field_prototypes[:image].field_class < Spontaneous::Field::Image
|
167
|
+
assert content_class.field_prototypes[:date].field_class < Spontaneous::Field::Date
|
168
|
+
assert content_class.field_prototypes[:chunky].field_class < Spontaneous::Field::String
|
168
169
|
end
|
169
170
|
end
|
170
171
|
|
@@ -195,7 +196,7 @@ class FieldsTest < MiniTest::Spec
|
|
195
196
|
end
|
196
197
|
|
197
198
|
should "parse field class" do
|
198
|
-
assert @prototype.field_class < Spontaneous::
|
199
|
+
assert @prototype.field_class < Spontaneous::Field::Image
|
199
200
|
end
|
200
201
|
|
201
202
|
should "parse default value" do
|
@@ -233,7 +234,7 @@ class FieldsTest < MiniTest::Spec
|
|
233
234
|
|
234
235
|
context "Values" do
|
235
236
|
setup do
|
236
|
-
@field_class = Class.new(
|
237
|
+
@field_class = Class.new(S::Field::Base) do
|
237
238
|
def outputs
|
238
239
|
[:html, :plain, :fancy]
|
239
240
|
end
|
@@ -256,6 +257,17 @@ class FieldsTest < MiniTest::Spec
|
|
256
257
|
@field = @field_class.new
|
257
258
|
end
|
258
259
|
|
260
|
+
should "be used as the comparator" do
|
261
|
+
f1 = @field_class.new
|
262
|
+
f1.value = "a"
|
263
|
+
f2 = @field_class.new
|
264
|
+
f2.value = "b"
|
265
|
+
(f1 <=> f2).should == -1
|
266
|
+
(f2 <=> f1).should == 1
|
267
|
+
(f1 <=> f1).should == 0
|
268
|
+
[f2, f1].sort.map(&:value).should == ["<a>", "<b>"]
|
269
|
+
end
|
270
|
+
|
259
271
|
should "be transformed by the update method" do
|
260
272
|
@field.value = "Hello"
|
261
273
|
@field.value.should == "<Hello>"
|
@@ -273,7 +285,7 @@ class FieldsTest < MiniTest::Spec
|
|
273
285
|
end
|
274
286
|
|
275
287
|
should "escape ampersands by default" do
|
276
|
-
field_class = Class.new(
|
288
|
+
field_class = Class.new(S::Field::String) do
|
277
289
|
end
|
278
290
|
field = field_class.new
|
279
291
|
field.value = "Hello & Welcome"
|
@@ -282,7 +294,7 @@ class FieldsTest < MiniTest::Spec
|
|
282
294
|
end
|
283
295
|
|
284
296
|
should "educate quotes" do
|
285
|
-
field_class = Class.new(
|
297
|
+
field_class = Class.new(S::Field::String)
|
286
298
|
field = field_class.new
|
287
299
|
field.value = %("John's first... example")
|
288
300
|
field.value(:html).should == "“John’s first… example”"
|
@@ -432,7 +444,7 @@ class FieldsTest < MiniTest::Spec
|
|
432
444
|
|
433
445
|
context "Available output formats" do
|
434
446
|
should "include HTML & PDF and default to default value" do
|
435
|
-
f =
|
447
|
+
f = S::Field::Base.new
|
436
448
|
f.value = "Value"
|
437
449
|
f.to_html.should == "Value"
|
438
450
|
f.to_pdf.should == "Value"
|
@@ -452,10 +464,10 @@ class FieldsTest < MiniTest::Spec
|
|
452
464
|
end
|
453
465
|
|
454
466
|
should "be available as the :markdown type" do
|
455
|
-
assert MarkdownContent.field_prototypes[:text1].field_class < Spontaneous::
|
467
|
+
assert MarkdownContent.field_prototypes[:text1].field_class < Spontaneous::Field::Markdown
|
456
468
|
end
|
457
469
|
should "be available as the :text type" do
|
458
|
-
assert MarkdownContent.field_prototypes[:text2].field_class < Spontaneous::
|
470
|
+
assert MarkdownContent.field_prototypes[:text2].field_class < Spontaneous::Field::Markdown
|
459
471
|
end
|
460
472
|
|
461
473
|
should "process input into HTML" do
|
@@ -473,18 +485,18 @@ class FieldsTest < MiniTest::Spec
|
|
473
485
|
|
474
486
|
context "Editor classes" do
|
475
487
|
should "be defined in base types" do
|
476
|
-
base_class = Spontaneous::
|
477
|
-
base_class.editor_class.should == "Spontaneous.
|
478
|
-
base_class = Spontaneous::
|
479
|
-
base_class.editor_class.should == "Spontaneous.
|
480
|
-
base_class = Spontaneous::
|
481
|
-
base_class.editor_class.should == "Spontaneous.
|
482
|
-
base_class = Spontaneous::
|
483
|
-
base_class.editor_class.should == "Spontaneous.
|
488
|
+
base_class = Spontaneous::Field::Image
|
489
|
+
base_class.editor_class.should == "Spontaneous.Field.Image"
|
490
|
+
base_class = Spontaneous::Field::Date
|
491
|
+
base_class.editor_class.should == "Spontaneous.Field.Date"
|
492
|
+
base_class = Spontaneous::Field::Markdown
|
493
|
+
base_class.editor_class.should == "Spontaneous.Field.Markdown"
|
494
|
+
base_class = Spontaneous::Field::String
|
495
|
+
base_class.editor_class.should == "Spontaneous.Field.String"
|
484
496
|
end
|
485
497
|
|
486
498
|
should "be inherited in subclasses" do
|
487
|
-
base_class = Spontaneous::
|
499
|
+
base_class = Spontaneous::Field::Image
|
488
500
|
@field_class = Class.new(base_class)
|
489
501
|
@field_class.stubs(:name).returns("CustomField")
|
490
502
|
@field_class.editor_class.should == base_class.editor_class
|
@@ -493,17 +505,17 @@ class FieldsTest < MiniTest::Spec
|
|
493
505
|
@field_class2.editor_class.should == base_class.editor_class
|
494
506
|
end
|
495
507
|
should "correctly defined by field prototypes" do
|
496
|
-
base_class = Spontaneous::
|
497
|
-
class ::CustomField < Spontaneous::
|
508
|
+
base_class = Spontaneous::Field::Image
|
509
|
+
class ::CustomField < Spontaneous::Field::Image
|
498
510
|
self.register(:custom)
|
499
511
|
end
|
500
512
|
|
501
|
-
class ::CustomContent <
|
513
|
+
class ::CustomContent < ::Piece
|
502
514
|
field :custom
|
503
515
|
end
|
504
516
|
assert CustomContent.fields.custom.instance_class < CustomField
|
505
517
|
|
506
|
-
CustomContent.fields.custom.instance_class.editor_class.should == Spontaneous::
|
518
|
+
CustomContent.fields.custom.instance_class.editor_class.should == Spontaneous::Field::Image.editor_class
|
507
519
|
|
508
520
|
Object.send(:remove_const, :CustomContent)
|
509
521
|
Object.send(:remove_const, :CustomField)
|
@@ -525,8 +537,8 @@ class FieldsTest < MiniTest::Spec
|
|
525
537
|
teardown do
|
526
538
|
# Object.send(:remove_const, :Piece) rescue nil
|
527
539
|
Spontaneous::Permissions::User.delete
|
528
|
-
|
529
|
-
S::FieldVersion.delete
|
540
|
+
::Content.delete
|
541
|
+
S::Field::FieldVersion.delete
|
530
542
|
end
|
531
543
|
|
532
544
|
should "start out as empty" do
|
@@ -548,20 +560,23 @@ class FieldsTest < MiniTest::Spec
|
|
548
560
|
@instance.reload
|
549
561
|
vv = @instance.title.versions
|
550
562
|
v = vv.first
|
551
|
-
v.created_at.should == now
|
563
|
+
v.created_at.to_i.should == now.to_i
|
552
564
|
end
|
553
565
|
|
554
566
|
should "save the previous value" do
|
567
|
+
stub_time(@now)
|
555
568
|
@instance.title.value = "one"
|
556
569
|
@instance.save.reload
|
557
570
|
vv = @instance.title.versions
|
558
571
|
v = vv.first
|
559
572
|
v.value.should == ""
|
573
|
+
stub_time(@now+10)
|
560
574
|
@instance.title.value = "two"
|
561
575
|
@instance.save.reload
|
562
576
|
vv = @instance.title.versions
|
563
577
|
v = vv.first
|
564
578
|
v.value.should == "one"
|
579
|
+
stub_time(@now+20)
|
565
580
|
@instance.title.value = "three"
|
566
581
|
@instance.save.reload
|
567
582
|
vv = @instance.title.versions
|
@@ -570,11 +585,13 @@ class FieldsTest < MiniTest::Spec
|
|
570
585
|
end
|
571
586
|
|
572
587
|
should "keep a track of the version number" do
|
588
|
+
stub_time(@now)
|
573
589
|
@instance.title.value = "one"
|
574
590
|
@instance.save.reload
|
575
591
|
vv = @instance.title.versions
|
576
592
|
v = vv.first
|
577
593
|
v.version.should == 1
|
594
|
+
stub_time(@now+10)
|
578
595
|
@instance.title.value = "two"
|
579
596
|
@instance.save.reload
|
580
597
|
vv = @instance.title.versions
|
@@ -593,11 +610,13 @@ class FieldsTest < MiniTest::Spec
|
|
593
610
|
end
|
594
611
|
|
595
612
|
should "have quick access to the last version" do
|
613
|
+
stub_time(@now)
|
596
614
|
@instance.title.value = "one"
|
597
615
|
@instance.save.reload
|
598
616
|
vv = @instance.title.versions
|
599
617
|
v = vv.first
|
600
618
|
v.value.should == ""
|
619
|
+
stub_time(@now+10)
|
601
620
|
@instance.title.value = "two"
|
602
621
|
@instance.save.reload
|
603
622
|
vv = @instance.title.versions
|
@@ -614,7 +633,7 @@ class FieldsTest < MiniTest::Spec
|
|
614
633
|
field :something, :title
|
615
634
|
end
|
616
635
|
instance = @content_class.new
|
617
|
-
assert instance.fields.title.class.ancestors.include?(Spontaneous::
|
636
|
+
assert instance.fields.title.class.ancestors.include?(Spontaneous::Field::String), ":title type should inherit from StringField"
|
618
637
|
instance.title.value.should == "Right"
|
619
638
|
end
|
620
639
|
end
|
@@ -629,7 +648,7 @@ class FieldsTest < MiniTest::Spec
|
|
629
648
|
end
|
630
649
|
|
631
650
|
should "have their own editor type" do
|
632
|
-
@content_class.fields.video.export(nil)[:type].should == "Spontaneous.
|
651
|
+
@content_class.fields.video.export(nil)[:type].should == "Spontaneous.Field.WebVideo"
|
633
652
|
@instance.video = "http://www.youtube.com/watch?v=_0jroAM_pO4&feature=feedrec_grec_index"
|
634
653
|
fields = @instance.export(nil)[:fields]
|
635
654
|
fields[0][:processed_value].should == @instance.video.src
|
@@ -705,7 +724,7 @@ class FieldsTest < MiniTest::Spec
|
|
705
724
|
|
706
725
|
should "provide a version of the YouTube player params in JSON/JS format" do
|
707
726
|
@field.value = "http://www.youtube.com/watch?v=_0jroAM_pO4&feature=feedrec_grec_index"
|
708
|
-
json = JSON.parse(@field.render(:json))
|
727
|
+
json = Spontaneous::JSON.parse(@field.render(:json))
|
709
728
|
json[:"tagname"].should == "iframe"
|
710
729
|
json[:"tag"].should == "<iframe/>"
|
711
730
|
attr = json[:"attr"]
|
@@ -726,7 +745,7 @@ class FieldsTest < MiniTest::Spec
|
|
726
745
|
|
727
746
|
should "provide a version of the Vimeo player params in JSON/JS format" do
|
728
747
|
@field.value = "http://vimeo.com/31836285"
|
729
|
-
json = JSON.parse(@field.render(:json))
|
748
|
+
json = Spontaneous::JSON.parse(@field.render(:json))
|
730
749
|
json[:"tagname"].should == "iframe"
|
731
750
|
json[:"tag"].should == "<iframe/>"
|
732
751
|
attr = json[:"attr"]
|
@@ -781,7 +800,7 @@ class FieldsTest < MiniTest::Spec
|
|
781
800
|
end
|
782
801
|
|
783
802
|
should "use a standard string editor" do
|
784
|
-
@content_class.fields.location.export(nil)[:type].should == "Spontaneous.
|
803
|
+
@content_class.fields.location.export(nil)[:type].should == "Spontaneous.Field.String"
|
785
804
|
end
|
786
805
|
|
787
806
|
should "successfullt geolocate an address" do
|
@@ -816,12 +835,12 @@ class FieldsTest < MiniTest::Spec
|
|
816
835
|
end
|
817
836
|
|
818
837
|
should "use a specific editor class" do
|
819
|
-
@content_class.fields.options.export(nil)[:type].should == "Spontaneous.
|
838
|
+
@content_class.fields.options.export(nil)[:type].should == "Spontaneous.Field.Select"
|
820
839
|
end
|
821
840
|
|
822
841
|
should "select the options class for fields named options" do
|
823
842
|
@content_class.field :type, :select, :options => [["a", "A"]]
|
824
|
-
assert @content_class.fields.options.instance_class.ancestors.include?(Spontaneous::
|
843
|
+
assert @content_class.fields.options.instance_class.ancestors.include?(Spontaneous::Field::Select)
|
825
844
|
end
|
826
845
|
|
827
846
|
should "accept a list of strings as options" do
|
@@ -849,11 +868,11 @@ class FieldsTest < MiniTest::Spec
|
|
849
868
|
end
|
850
869
|
|
851
870
|
should "have a distinct editor class" do
|
852
|
-
@prototype.instance_class.editor_class.should == "Spontaneous.
|
871
|
+
@prototype.instance_class.editor_class.should == "Spontaneous.Field.File"
|
853
872
|
end
|
854
873
|
|
855
874
|
should "adopt any field called 'file'" do
|
856
|
-
assert @field.is_a?(Spontaneous::
|
875
|
+
assert @field.is_a?(Spontaneous::Field::File), "Field should be an instance of FileField but instead has the following ancestors #{ @prototype.instance_class.ancestors }"
|
857
876
|
end
|
858
877
|
|
859
878
|
should "copy files to the media folder" do
|
@@ -915,11 +934,11 @@ class FieldsTest < MiniTest::Spec
|
|
915
934
|
end
|
916
935
|
|
917
936
|
should "have a distinct editor class" do
|
918
|
-
@prototype.instance_class.editor_class.should == "Spontaneous.
|
937
|
+
@prototype.instance_class.editor_class.should == "Spontaneous.Field.Date"
|
919
938
|
end
|
920
939
|
|
921
940
|
should "adopt any field called 'date'" do
|
922
|
-
assert @field.is_a?(Spontaneous::
|
941
|
+
assert @field.is_a?(Spontaneous::Field::Date), "Field should be an instance of DateField but instead has the following ancestors #{ @prototype.instance_class.ancestors }"
|
923
942
|
end
|
924
943
|
|
925
944
|
should "default to an empty string" do
|
@@ -943,5 +962,475 @@ class FieldsTest < MiniTest::Spec
|
|
943
962
|
field.value(:plain).should == %(08 Jun 2012, Fri)
|
944
963
|
end
|
945
964
|
end
|
965
|
+
|
966
|
+
context "Asynchronous processing" do
|
967
|
+
setup do
|
968
|
+
S::Site.background_mode = :simultaneous
|
969
|
+
@image = File.expand_path("../../fixtures/images/rose.jpg", __FILE__)
|
970
|
+
@model = (::Piece)
|
971
|
+
@model.field :title
|
972
|
+
@model.field :image
|
973
|
+
@model.field :description, :markdown
|
974
|
+
@model.box :items do
|
975
|
+
field :title
|
976
|
+
field :image
|
977
|
+
end
|
978
|
+
@instance = @model.create
|
979
|
+
end
|
980
|
+
|
981
|
+
# should "be disabled if the background mode is set to immediate" do
|
982
|
+
# S::Site.background_mode = :immediate
|
983
|
+
# S::Field::Update.asynchronous_update_class.should == S::Field::Update::Immediate
|
984
|
+
# end
|
985
|
+
|
986
|
+
# should "be enabled if the background mode is set to simultaneous" do
|
987
|
+
# S::Site.background_mode = :simultaneous
|
988
|
+
# S::Field::Update.asynchronous_update_class.should == S::Field::Update::Simultaneous
|
989
|
+
# end
|
990
|
+
|
991
|
+
should "be able to resolve fields id" do
|
992
|
+
S::Field.find(@instance.image.id, @instance.items.title.id).should == [
|
993
|
+
@instance.image, @instance.items.title
|
994
|
+
]
|
995
|
+
end
|
996
|
+
|
997
|
+
should "not raise errors for invalid fields" do
|
998
|
+
S::Field.find("0", "#{@instance.id}/xxx/#{@instance.items.title.schema_id}", "#{@instance.items.id}/nnn", @instance.items.title.id).should == [ @instance.items.title ]
|
999
|
+
end
|
1000
|
+
|
1001
|
+
should "return a single field if given a single id" do
|
1002
|
+
S::Field.find(@instance.image.id).should == @instance.image
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
should "be disabled for Date fields" do
|
1006
|
+
f = S::Field::Date.new
|
1007
|
+
f.asynchronous?.should be_false
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
should "be disabled for Location fields" do
|
1011
|
+
f = S::Field::Location.new
|
1012
|
+
f.asynchronous?.should be_false
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
should "be disabled for LongString fields" do
|
1016
|
+
f = S::Field::LongString.new
|
1017
|
+
f.asynchronous?.should be_false
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
should "be disabled for Markdown fields" do
|
1021
|
+
f = S::Field::Markdown.new
|
1022
|
+
f.asynchronous?.should be_false
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
should "be disabled for Select fields" do
|
1026
|
+
f = S::Field::Select.new
|
1027
|
+
f.asynchronous?.should be_false
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
should "be disabled for String fields" do
|
1031
|
+
f = S::Field::String.new
|
1032
|
+
f.asynchronous?.should be_false
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
should "be disabled for WebVideo fields" do
|
1036
|
+
f = S::Field::WebVideo.new
|
1037
|
+
f.asynchronous?.should be_false
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
should "be enabled for File fields" do
|
1041
|
+
f = S::Field::File.new
|
1042
|
+
f.asynchronous?.should be_true
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
should "be enabled for Image fields" do
|
1046
|
+
f = S::Field::Image.new
|
1047
|
+
f.asynchronous?.should be_true
|
1048
|
+
end
|
1049
|
+
|
1050
|
+
should "immediately update a group of fields passed in parameter format" do
|
1051
|
+
File.open(@image, "r") do |file|
|
1052
|
+
fields = {
|
1053
|
+
@instance.title.schema_id.to_s => "Updated title",
|
1054
|
+
@instance.image.schema_id.to_s => {:tempfile => file, :filename => "something.gif", :type => "image/gif"},
|
1055
|
+
@instance.description.schema_id.to_s => "Updated description"
|
1056
|
+
}
|
1057
|
+
Spontaneous::Field.update(@instance, fields, nil, false)
|
1058
|
+
@instance.reload
|
1059
|
+
@instance.title.value.should == "Updated title"
|
1060
|
+
@instance.description.value.should == "<p>Updated description</p>\n"
|
1061
|
+
@instance.image.value.should == "/media/#{S::Media.pad_id(@instance.id)}/0001/something.gif"
|
1062
|
+
end
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
should "asynchronously update a group of fields passed in parameter format" do
|
1066
|
+
Spontaneous::Simultaneous.expects(:fire).with(:update_fields, {
|
1067
|
+
"fields" => [@instance.image.id]
|
1068
|
+
})
|
1069
|
+
|
1070
|
+
File.open(@image, "r") do |file|
|
1071
|
+
fields = {
|
1072
|
+
@instance.title.schema_id.to_s => "Updated title",
|
1073
|
+
@instance.image.schema_id.to_s => {:tempfile => file, :filename => "something.gif", :type => "image/gif"},
|
1074
|
+
@instance.description.schema_id.to_s => "Updated description"
|
1075
|
+
}
|
1076
|
+
@instance.expects(:save).at_least_once
|
1077
|
+
|
1078
|
+
Spontaneous::Field.update(@instance, fields, nil, true)
|
1079
|
+
|
1080
|
+
@instance.title.value.should == "Updated title"
|
1081
|
+
@instance.description.value.should == "<p>Updated description</p>\n"
|
1082
|
+
@instance.image.value.should == ""
|
1083
|
+
@instance.image.pending_value.should == {
|
1084
|
+
:timestamp => S::Field.timestamp(@now),
|
1085
|
+
:version => 1,
|
1086
|
+
:value => {
|
1087
|
+
:width=>400, :height=>533, :filesize=>54746,
|
1088
|
+
:type=>"image/gif",
|
1089
|
+
:tempfile=>"#{@site.root}/cache/media/tmp/#{S::Media.pad_id(@instance.id)}/something.gif",
|
1090
|
+
:filename=>"something.gif",
|
1091
|
+
:src => "/media/tmp/#{S::Media.pad_id(@instance.id)}/something.gif"
|
1092
|
+
}
|
1093
|
+
}
|
1094
|
+
@instance.image.process_pending_value
|
1095
|
+
@instance.image.value.should == "/media/#{S::Media.pad_id(@instance.id)}/0001/something.gif"
|
1096
|
+
@instance.image.pending_value.should be_nil
|
1097
|
+
end
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
should "asynchronously update a single field value" do
|
1101
|
+
Spontaneous::Simultaneous.expects(:fire).with(:update_fields, {
|
1102
|
+
"fields" => [@instance.image.id]
|
1103
|
+
})
|
1104
|
+
File.open(@image, "r") do |file|
|
1105
|
+
@instance.image.pending_version.should == 0
|
1106
|
+
Spontaneous::Field.set(@instance.image, {:tempfile => file, :filename => "something.gif", :type => "image/gif"}, nil, true)
|
1107
|
+
@instance.image.value.should == ""
|
1108
|
+
@instance.image.pending_value.should == {
|
1109
|
+
:timestamp => S::Field.timestamp(@now),
|
1110
|
+
:version => 1,
|
1111
|
+
:value => {
|
1112
|
+
:width=>400, :height=>533, :filesize=>54746,
|
1113
|
+
:type=>"image/gif",
|
1114
|
+
:tempfile=>"#{@site.root}/cache/media/tmp/#{S::Media.pad_id(@instance.id)}/something.gif",
|
1115
|
+
:filename=>"something.gif",
|
1116
|
+
:src => "/media/tmp/#{S::Media.pad_id(@instance.id)}/something.gif"
|
1117
|
+
}
|
1118
|
+
}
|
1119
|
+
@instance.image.pending_version.should == 1
|
1120
|
+
@instance.image.process_pending_value
|
1121
|
+
@instance.image.value.should == "/media/#{S::Media.pad_id(@instance.id)}/0001/something.gif"
|
1122
|
+
end
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
should "synchronously update box fields" do
|
1126
|
+
box = @instance.items
|
1127
|
+
File.open(@image, "r") do |file|
|
1128
|
+
fields = {
|
1129
|
+
box.title.schema_id.to_s => "Updated title",
|
1130
|
+
box.image.schema_id.to_s => {:tempfile => file, :filename => "something.gif", :type => "image/gif"},
|
1131
|
+
}
|
1132
|
+
Spontaneous::Field.update(box, fields, nil, false)
|
1133
|
+
box.title.value.should == "Updated title"
|
1134
|
+
box.image.value.should == "/media/#{S::Media.pad_id(@instance.id)}/#{box.schema_id}/0001/something.gif"
|
1135
|
+
box.image.pending_version.should == 1
|
1136
|
+
end
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
should "asynchronously update box fields" do
|
1140
|
+
box = @instance.items
|
1141
|
+
Spontaneous::Simultaneous.expects(:fire).with(:update_fields, {
|
1142
|
+
"fields" => [box.image.id]
|
1143
|
+
})
|
1144
|
+
File.open(@image, "r") do |file|
|
1145
|
+
fields = {
|
1146
|
+
box.title.schema_id.to_s => "Updated title",
|
1147
|
+
box.image.schema_id.to_s => {:tempfile => file, :filename => "something.gif", :type => "image/gif"},
|
1148
|
+
}
|
1149
|
+
Spontaneous::Field.update(box, fields, nil, true)
|
1150
|
+
box.title.value.should == "Updated title"
|
1151
|
+
box.image.value.should == ""
|
1152
|
+
box.image.pending_value.should == {
|
1153
|
+
:timestamp => S::Field.timestamp(@now),
|
1154
|
+
:version => 1,
|
1155
|
+
:value => {
|
1156
|
+
:width=>400, :height=>533, :filesize=>54746,
|
1157
|
+
:type=>"image/gif",
|
1158
|
+
:tempfile=>"#{@site.root}/cache/media/tmp/#{S::Media.pad_id(@instance.id)}/#{box.schema_id}/something.gif",
|
1159
|
+
:filename=>"something.gif",
|
1160
|
+
:src => "/media/tmp/#{S::Media.pad_id(@instance.id)}/#{box.schema_id}/something.gif"
|
1161
|
+
}
|
1162
|
+
}
|
1163
|
+
end
|
1164
|
+
end
|
1165
|
+
|
1166
|
+
should "immediately update asynchronous fields if background mode is :immediate" do
|
1167
|
+
S::Site.background_mode = :immediate
|
1168
|
+
File.open(@image, "r") do |file|
|
1169
|
+
fields = {
|
1170
|
+
@instance.image.schema_id.to_s => {:tempfile => file, :filename => "something.gif", :type => "image/gif"}
|
1171
|
+
}
|
1172
|
+
Spontaneous::Simultaneous.expects(:fire).never
|
1173
|
+
Spontaneous::Field.update(@instance, fields, nil, true)
|
1174
|
+
@instance.image.value.should == "/media/#{S::Media.pad_id(@instance.id)}/0001/something.gif"
|
1175
|
+
end
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
should "not update a field if user does not have necessary permissions" do
|
1179
|
+
user = mock()
|
1180
|
+
@instance.title.expects(:writable?).with(user).at_least_once.returns(false)
|
1181
|
+
fields = {
|
1182
|
+
@instance.title.schema_id.to_s => "Updated title"
|
1183
|
+
}
|
1184
|
+
Spontaneous::Field.update(@instance, fields, user, true)
|
1185
|
+
@instance.title.value.should == ""
|
1186
|
+
end
|
1187
|
+
|
1188
|
+
should "call Fields::Update::Immediate from the cli" do
|
1189
|
+
immediate = mock()
|
1190
|
+
immediate.expects(:pages).returns([])
|
1191
|
+
immediate.expects(:run)
|
1192
|
+
Spontaneous::Field::Update::Immediate.expects(:new).with([@instance.image, @instance.items.title]).returns(immediate)
|
1193
|
+
# Thor generates a warning about creating a task with no 'desc'
|
1194
|
+
silence_logger {
|
1195
|
+
Spontaneous::Cli::Fields.any_instance.stubs(:prepare!)
|
1196
|
+
}
|
1197
|
+
Spontaneous::Cli::Fields.start(["update", "--fields", @instance.image.id, @instance.items.title.id])
|
1198
|
+
end
|
1199
|
+
|
1200
|
+
should "call Fields::Update::Immediate from the cli with a single field" do
|
1201
|
+
silence_logger {
|
1202
|
+
Spontaneous::Cli::Fields.any_instance.stubs(:prepare!)
|
1203
|
+
}
|
1204
|
+
Spontaneous::Cli::Fields.start(["update", "--fields", @instance.image.id])
|
1205
|
+
end
|
1206
|
+
|
1207
|
+
should "revert to immediate updating if connection to simultaneous fails" do
|
1208
|
+
File.open(@image, "r") do |file|
|
1209
|
+
Spontaneous::Field.set(@instance.image, {:tempfile => file, :filename => "something.gif", :type => "image/gif"}, nil, true)
|
1210
|
+
@instance.image.value.should == "/media/#{S::Media.pad_id(@instance.id)}/0001/something.gif"
|
1211
|
+
@instance.image.pending_value.should be_nil
|
1212
|
+
end
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
context "page locks" do
|
1216
|
+
setup do
|
1217
|
+
@now = Time.now
|
1218
|
+
stub_time(@now)
|
1219
|
+
LockedPage = Class.new(::Page)
|
1220
|
+
LockedPage.field :image
|
1221
|
+
LockedPage.box :instances do
|
1222
|
+
field :image
|
1223
|
+
field :title
|
1224
|
+
end
|
1225
|
+
LockedPiece = @model
|
1226
|
+
@page = LockedPage.create
|
1227
|
+
@instance = LockedPiece.create
|
1228
|
+
@page.instances << @instance
|
1229
|
+
@page.save.reload
|
1230
|
+
@instance.save.reload
|
1231
|
+
# The PageLock associations cache the Content model
|
1232
|
+
# but since this changes every time later tests
|
1233
|
+
# use an old version of Content with an old schema
|
1234
|
+
S::PageLock.all_association_reflections.each do |r|
|
1235
|
+
# Clear the cached class
|
1236
|
+
r[:cache] = {}
|
1237
|
+
end
|
1238
|
+
end
|
1239
|
+
|
1240
|
+
teardown do
|
1241
|
+
Spontaneous::PageLock.delete
|
1242
|
+
self.class.send :remove_const, :LockedPage rescue nil
|
1243
|
+
self.class.send :remove_const, :LockedPiece rescue nil
|
1244
|
+
end
|
1245
|
+
|
1246
|
+
should "be created when scheduling a page field for async updating" do
|
1247
|
+
Spontaneous::Simultaneous.expects(:fire).with(:update_fields, {
|
1248
|
+
"fields" => [@page.image.id]
|
1249
|
+
})
|
1250
|
+
File.open(@image, "r") do |file|
|
1251
|
+
Spontaneous::Field.set(@page.image, {:tempfile => file, :filename => "something.gif", :type => "image/gif"}, nil, true)
|
1252
|
+
@page.image.value.should == ""
|
1253
|
+
@page.update_locks.length.should == 1
|
1254
|
+
lock = @page.update_locks.first
|
1255
|
+
lock.field.should == @page.image
|
1256
|
+
lock.content.should == @page
|
1257
|
+
lock.page.should == @page
|
1258
|
+
lock.description.should =~ /something\.gif/
|
1259
|
+
lock.created_at.should == @now
|
1260
|
+
lock.location.should == "Field ‘image’"
|
1261
|
+
@page.locked_for_update?.should be_true
|
1262
|
+
end
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
should "not create locks for fields processed immediately" do
|
1266
|
+
field = @instance.title
|
1267
|
+
Spontaneous::Field.set(field, "Updated Title", nil, true)
|
1268
|
+
field.value.should == "Updated Title"
|
1269
|
+
@page.update_locks.length.should == 0
|
1270
|
+
@page.locked_for_update?.should be_false
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
should "be created when scheduling a box field for async updating" do
|
1274
|
+
field = @page.instances.image
|
1275
|
+
Spontaneous::Simultaneous.expects(:fire).with(:update_fields, {
|
1276
|
+
"fields" => [field.id]
|
1277
|
+
})
|
1278
|
+
File.open(@image, "r") do |file|
|
1279
|
+
Spontaneous::Field.set(field, {:tempfile => file, :filename => "something.gif", :type => "image/gif"}, nil, true)
|
1280
|
+
field.value.should == ""
|
1281
|
+
@page.update_locks.length.should == 1
|
1282
|
+
lock = @page.update_locks.first
|
1283
|
+
lock.field.should == field.reload
|
1284
|
+
lock.content.should == @page.reload
|
1285
|
+
lock.page.should == @page
|
1286
|
+
lock.description.should =~ /something\.gif/
|
1287
|
+
lock.created_at.should == @now
|
1288
|
+
lock.location.should == "Field ‘image’ of box ‘instances’"
|
1289
|
+
@page.locked_for_update?.should be_true
|
1290
|
+
end
|
1291
|
+
end
|
1292
|
+
|
1293
|
+
should "be created when scheduling a piece field for async updating" do
|
1294
|
+
field = @instance.image
|
1295
|
+
Spontaneous::Simultaneous.expects(:fire).with(:update_fields, {
|
1296
|
+
"fields" => [field.id]
|
1297
|
+
})
|
1298
|
+
File.open(@image, "r") do |file|
|
1299
|
+
Spontaneous::Field.set(field, {:tempfile => file, :filename => "something.gif", :type => "image/gif"}, nil, true)
|
1300
|
+
field.value.should == ""
|
1301
|
+
@page.update_locks.length.should == 1
|
1302
|
+
lock = @page.update_locks.first
|
1303
|
+
lock.field.should == field
|
1304
|
+
lock.content.should == @instance
|
1305
|
+
lock.page.should == @page
|
1306
|
+
lock.description.should =~ /something\.gif/
|
1307
|
+
lock.created_at.should == @now
|
1308
|
+
lock.location.should == "Field ‘image’ of entry 1 in box ‘instances’"
|
1309
|
+
@page.locked_for_update?.should be_true
|
1310
|
+
end
|
1311
|
+
end
|
1312
|
+
|
1313
|
+
should "be removed when the field has been processed" do
|
1314
|
+
Spontaneous::Simultaneous.expects(:fire).with(:update_fields, {
|
1315
|
+
"fields" => [@page.image.id]
|
1316
|
+
})
|
1317
|
+
File.open(@image, "r") do |file|
|
1318
|
+
Spontaneous::Field.set(@page.image, {:tempfile => file, :filename => "something.gif", :type => "image/gif"}, nil, true)
|
1319
|
+
@page.image.value.should == ""
|
1320
|
+
@page.update_locks.length.should == 1
|
1321
|
+
@page.locked_for_update?.should be_true
|
1322
|
+
# The lock manipulation is done by the updater
|
1323
|
+
# so calling update_pending_value on the field
|
1324
|
+
# won't clear any locks
|
1325
|
+
Spontaneous::Field::Update::Immediate.process([@page.image])
|
1326
|
+
@page.image.value.should == "/media/#{@page.id.to_s.rjust(5, "0")}/0001/something.gif"
|
1327
|
+
@page.reload.locked_for_update?.should be_false
|
1328
|
+
end
|
1329
|
+
end
|
1330
|
+
|
1331
|
+
should "send a completion event that includes a list of unlocked pages" do
|
1332
|
+
field = @instance.image
|
1333
|
+
Spontaneous::Simultaneous.expects(:fire).with(:update_fields, {
|
1334
|
+
"fields" => [field.id]
|
1335
|
+
})
|
1336
|
+
Simultaneous.expects(:send_event).with('page_lock_status', "[#{@page.id}]")
|
1337
|
+
|
1338
|
+
File.open(@image, "r") do |file|
|
1339
|
+
Spontaneous::Field.set(field, {:tempfile => file, :filename => "something.gif", :type => "image/gif"}, nil, true)
|
1340
|
+
@page.locked_for_update?.should be_true
|
1341
|
+
silence_logger {
|
1342
|
+
Spontaneous::Cli::Fields.any_instance.stubs(:prepare!)
|
1343
|
+
}
|
1344
|
+
Spontaneous::Cli::Fields.start(["update", "--fields", field.id])
|
1345
|
+
end
|
1346
|
+
end
|
1347
|
+
|
1348
|
+
should "ignore an update that has been superceded" do
|
1349
|
+
# user uploads an image and then changes their mind and uploads another
|
1350
|
+
# before the first one has been processed.
|
1351
|
+
# Pending value might have changed between the start of the update and the end
|
1352
|
+
# especially in the case of video processing or file upload
|
1353
|
+
# Before we update the value of a field or
|
1354
|
+
# clear pending values we need to be sure that they aren't still needed
|
1355
|
+
#
|
1356
|
+
|
1357
|
+
field = @instance.image
|
1358
|
+
Spontaneous::Simultaneous.expects(:fire).at_least_once.with(:update_fields, {
|
1359
|
+
"fields" => [field.id]
|
1360
|
+
})
|
1361
|
+
File.open(@image, "r") do |file|
|
1362
|
+
Spontaneous::Field.set(field, {:tempfile => file, :filename => "something.gif", :type => "image/gif"}, nil, true)
|
1363
|
+
end
|
1364
|
+
update = Spontaneous::Field::Update::Immediate.new(field)
|
1365
|
+
old, field = field, field.reload
|
1366
|
+
later = @now + 1
|
1367
|
+
t = S::Field.timestamp(later)
|
1368
|
+
S::Field.stubs(:timestamp).returns(t)
|
1369
|
+
File.open(@image, "r") do |file|
|
1370
|
+
Spontaneous::Field.set(field, {:tempfile => file, :filename => "else.gif", :type => "image/jpeg"}, nil, true)
|
1371
|
+
end
|
1372
|
+
update.run
|
1373
|
+
|
1374
|
+
pending = field.pending_value
|
1375
|
+
pending[:value][:filename].should == "else.gif"
|
1376
|
+
end
|
1377
|
+
|
1378
|
+
should "merge async updates with synchronous ones effected during processing" do
|
1379
|
+
# Scenario:
|
1380
|
+
# - User uploads file to content item which gets scheduled for async processing
|
1381
|
+
# - User modifies synchronous field of same content item that gets immediately updated
|
1382
|
+
# - Async process completes and...
|
1383
|
+
# SHOULD
|
1384
|
+
# Keep the updated values from the immediate change
|
1385
|
+
# Merge in the results of the async change
|
1386
|
+
field = @instance.image
|
1387
|
+
Spontaneous::Simultaneous.expects(:fire).at_least_once.with(:update_fields, {
|
1388
|
+
"fields" => [field.id]
|
1389
|
+
})
|
1390
|
+
File.open(@image, "r") do |file|
|
1391
|
+
Spontaneous::Field.set(field, {:tempfile => file, :filename => "something.gif", :type => "image/gif"}, nil, true)
|
1392
|
+
end
|
1393
|
+
# Create update but don't run it
|
1394
|
+
update = Spontaneous::Field::Update::Immediate.new(field)
|
1395
|
+
# Someone updates a field before the async update is run...
|
1396
|
+
content = ::Content.get(@instance.id)
|
1397
|
+
content.title = "Updated Title"
|
1398
|
+
content.save
|
1399
|
+
|
1400
|
+
# Now run the update with a field that's out of sync with the version in the db
|
1401
|
+
update.run
|
1402
|
+
|
1403
|
+
content = ::Content.get(@instance.id)
|
1404
|
+
content.title.value.should == "Updated Title"
|
1405
|
+
content.image.value.should == "/media/#{S::Media.pad_id(@instance.id)}/0001/something.gif"
|
1406
|
+
end
|
1407
|
+
|
1408
|
+
should "merge async updates to box fields with synchronous ones effected during processing" do
|
1409
|
+
# The scenario for boxes is more complex because their fields are stored by their owner
|
1410
|
+
# not directly by themselves
|
1411
|
+
field = @page.instances.image
|
1412
|
+
Spontaneous::Simultaneous.expects(:fire).at_least_once.with(:update_fields, {
|
1413
|
+
"fields" => [field.id]
|
1414
|
+
})
|
1415
|
+
File.open(@image, "r") do |file|
|
1416
|
+
Spontaneous::Field.set(field, {:tempfile => file, :filename => "something.gif", :type => "image/gif"}, nil, true)
|
1417
|
+
end
|
1418
|
+
# Create update but don't run it
|
1419
|
+
update = Spontaneous::Field::Update::Immediate.new(field)
|
1420
|
+
# Someone updates a field before the async update is run...
|
1421
|
+
content = ::Content.get(@page.id)
|
1422
|
+
content.instances.title = "Updated Title"
|
1423
|
+
content.save
|
1424
|
+
|
1425
|
+
# Now run the update with a field that's out of sync with the version in the db
|
1426
|
+
update.run
|
1427
|
+
|
1428
|
+
|
1429
|
+
content = ::Content.get(@page.id)
|
1430
|
+
content.instances.title.value.should == "Updated Title"
|
1431
|
+
content.instances.image.value.should == "/media/#{S::Media.pad_id(@page.id)}/#{@page.instances.schema_id}/0001/something.gif"
|
1432
|
+
end
|
1433
|
+
end
|
1434
|
+
end
|
946
1435
|
end
|
947
1436
|
end
|