spontaneous 0.2.0.beta5 → 0.2.0.beta6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (227) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +39 -0
  4. data/Gemfile +2 -0
  5. data/Readme.markdown +4 -4
  6. data/application/css/core.css.scss +144 -43
  7. data/application/css/definitions.css.scss +50 -16
  8. data/application/css/dialogue.css.scss +5 -2
  9. data/application/css/editing.css.scss +7 -7
  10. data/application/css/font.css.scss +1 -1
  11. data/application/css/meta.css.scss +6 -6
  12. data/application/css/popover.css.scss +6 -6
  13. data/application/css/top.css.scss +8 -1
  14. data/application/js/add_alias_dialogue.js +137 -36
  15. data/application/js/add_home_dialogue.js +10 -10
  16. data/application/js/ajax.js +26 -26
  17. data/application/js/authentication.js +2 -2
  18. data/application/js/box.js +21 -10
  19. data/application/js/box_container.js +13 -7
  20. data/application/js/compatibility.js +19 -17
  21. data/application/js/conflicted_field_dialogue.js +5 -5
  22. data/application/js/content.js +22 -16
  23. data/application/js/content_area.js +62 -33
  24. data/application/js/dialogue.js +16 -16
  25. data/application/js/dom.js +9 -10
  26. data/application/js/edit_panel.js +25 -20
  27. data/application/js/editing.js +21 -8
  28. data/application/js/entry.js +1 -1
  29. data/application/js/extensions.js +11 -11
  30. data/application/js/field/boolean.js +6 -6
  31. data/application/js/field/date.js +1 -1
  32. data/application/js/field/file.js +17 -17
  33. data/application/js/field/image.js +27 -27
  34. data/application/js/field/markdown.js +72 -71
  35. data/application/js/field/select.js +9 -9
  36. data/application/js/field/string.js +3 -3
  37. data/application/js/field/webvideo.js +2 -2
  38. data/application/js/field_preview.js +3 -0
  39. data/application/js/init.js +3 -2
  40. data/application/js/jquery-selection-position.js +13 -13
  41. data/application/js/location.js +17 -12
  42. data/application/js/login.js +2 -2
  43. data/application/js/meta_view/user_admin.js +101 -101
  44. data/application/js/metadata.js +1 -1
  45. data/application/js/page.js +2 -2
  46. data/application/js/page_browser.js +13 -13
  47. data/application/js/page_entry.js +1 -1
  48. data/application/js/panel/root_menu.js +10 -10
  49. data/application/js/popover.js +6 -5
  50. data/application/js/popover_view.js +5 -5
  51. data/application/js/preview.js +10 -4
  52. data/application/js/progress.js +6 -6
  53. data/application/js/properties.js +35 -6
  54. data/application/js/publish.js +43 -43
  55. data/application/js/require.js +14 -14
  56. data/application/js/services.js +3 -3
  57. data/application/js/sharded_upload.js +9 -8
  58. data/application/js/side_bar.js +5 -5
  59. data/application/js/state.js +2 -2
  60. data/application/js/status_bar.js +6 -6
  61. data/application/js/top_bar.js +97 -65
  62. data/application/js/types.js +9 -6
  63. data/application/js/upload.js +4 -4
  64. data/application/js/upload_manager.js +21 -21
  65. data/application/js/user.js +1 -1
  66. data/application/js/vendor/jquery.velocity.min.js +7 -0
  67. data/application/js/views.js +32 -8
  68. data/application/js/views/box_view.js +51 -31
  69. data/application/js/views/page_piece_view.js +17 -15
  70. data/application/js/views/page_view.js +54 -43
  71. data/application/js/views/piece_view.js +44 -37
  72. data/application/static/font/fontawesome-webfont-4f0022f25672c7f501c339cbf98d9117.ttf +0 -0
  73. data/application/views/index.erb +1 -0
  74. data/db/migrations/20130114120000_create_revision_tables.rb +2 -1
  75. data/db/migrations/20130813111009_increase_path_length.rb +11 -2
  76. data/db/migrations/20140506171823_add_index_to_target_id.rb +11 -0
  77. data/db/migrations/20140514090204_add_content_hash.rb +59 -0
  78. data/db/migrations/20140519150253_add_content_hash_timestamp.rb +20 -0
  79. data/lib/spontaneous.rb +0 -1
  80. data/lib/spontaneous/asset/environment.rb +77 -15
  81. data/lib/spontaneous/box.rb +21 -0
  82. data/lib/spontaneous/capistrano/deploy.rb +1 -1
  83. data/lib/spontaneous/capistrano/sync.rb +8 -7
  84. data/lib/spontaneous/change.rb +4 -2
  85. data/lib/spontaneous/cli/fields.rb +7 -3
  86. data/lib/spontaneous/cli/generate.rb +2 -0
  87. data/lib/spontaneous/cli/init.rb +24 -93
  88. data/lib/spontaneous/cli/init/db.rb +94 -0
  89. data/lib/spontaneous/cli/init/mysql.rb +17 -0
  90. data/lib/spontaneous/cli/init/postgresql.rb +33 -0
  91. data/lib/spontaneous/cli/init/sqlite.rb +14 -0
  92. data/lib/spontaneous/cli/site.rb +45 -20
  93. data/lib/spontaneous/collections/box_set.rb +3 -0
  94. data/lib/spontaneous/collections/entry_set.rb +43 -4
  95. data/lib/spontaneous/collections/field_set.rb +14 -2
  96. data/lib/spontaneous/data_mapper.rb +40 -7
  97. data/lib/spontaneous/data_mapper/content_model.rb +1 -1
  98. data/lib/spontaneous/data_mapper/content_model/associations.rb +63 -12
  99. data/lib/spontaneous/data_mapper/content_model/timestamps.rb +9 -14
  100. data/lib/spontaneous/data_mapper/content_table.rb +4 -2
  101. data/lib/spontaneous/data_mapper/dataset.rb +31 -2
  102. data/lib/spontaneous/data_mapper/scope.rb +37 -20
  103. data/lib/spontaneous/errors.rb +6 -0
  104. data/lib/spontaneous/facet.rb +20 -10
  105. data/lib/spontaneous/field/base.rb +8 -1
  106. data/lib/spontaneous/field/file.rb +28 -3
  107. data/lib/spontaneous/field/image.rb +2 -0
  108. data/lib/spontaneous/field/update.rb +6 -0
  109. data/lib/spontaneous/field/webvideo/vimeo.rb +6 -1
  110. data/lib/spontaneous/field/webvideo/vine.rb +1 -1
  111. data/lib/spontaneous/field/webvideo/youtube.rb +1 -1
  112. data/lib/spontaneous/generators/site.rb +6 -4
  113. data/lib/spontaneous/generators/site/.gitignore +1 -0
  114. data/lib/spontaneous/generators/site/Gemfile.tt +3 -3
  115. data/lib/spontaneous/generators/site/config/{indexes.rb.tt → initializers/indexes.rb.tt} +0 -0
  116. data/lib/spontaneous/generators/site/config/initializers/publishing.rb.tt +78 -0
  117. data/lib/spontaneous/generators/site/{config/database.yml.tt → db/mysql2.yml.tt} +7 -6
  118. data/lib/spontaneous/generators/site/db/postgres.yml.tt +25 -0
  119. data/lib/spontaneous/generators/site/db/sqlite3.yml.tt +18 -0
  120. data/lib/spontaneous/generators/site/public/humans.txt.tt +14 -0
  121. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +51 -0
  122. data/lib/spontaneous/loader.rb +1 -1
  123. data/lib/spontaneous/logger.rb +1 -1
  124. data/lib/spontaneous/media/image/optimizer.rb +1 -1
  125. data/lib/spontaneous/media/image/processor.rb +11 -2
  126. data/lib/spontaneous/media/image/renderable.rb +2 -0
  127. data/lib/spontaneous/model.rb +3 -0
  128. data/lib/spontaneous/model/box/allowed_types.rb +17 -4
  129. data/lib/spontaneous/model/core.rb +36 -3
  130. data/lib/spontaneous/model/core/aliases.rb +5 -2
  131. data/lib/spontaneous/model/core/boxes.rb +6 -0
  132. data/lib/spontaneous/model/core/cascading_change.rb +38 -0
  133. data/lib/spontaneous/model/core/content_hash.rb +171 -0
  134. data/lib/spontaneous/model/core/entries.rb +0 -19
  135. data/lib/spontaneous/model/core/fields.rb +11 -0
  136. data/lib/spontaneous/model/core/modifications.rb +22 -21
  137. data/lib/spontaneous/model/core/render.rb +3 -0
  138. data/lib/spontaneous/model/core/serialisation.rb +18 -17
  139. data/lib/spontaneous/model/page.rb +35 -8
  140. data/lib/spontaneous/model/page/page_tree.rb +20 -8
  141. data/lib/spontaneous/model/page/paths.rb +79 -50
  142. data/lib/spontaneous/model/page/singleton.rb +71 -0
  143. data/lib/spontaneous/model/page/site_map.rb +2 -1
  144. data/lib/spontaneous/model/page/site_timestamps.rb +2 -2
  145. data/lib/spontaneous/model/piece.rb +10 -0
  146. data/lib/spontaneous/output/context.rb +13 -6
  147. data/lib/spontaneous/output/format.rb +30 -5
  148. data/lib/spontaneous/output/helpers/script_helper.rb +8 -0
  149. data/lib/spontaneous/output/helpers/stylesheet_helper.rb +7 -0
  150. data/lib/spontaneous/output/renderable.rb +16 -0
  151. data/lib/spontaneous/output/store.rb +1 -1
  152. data/lib/spontaneous/output/template/renderer.rb +2 -2
  153. data/lib/spontaneous/page_piece.rb +25 -1
  154. data/lib/spontaneous/prototypes/box_prototype.rb +13 -0
  155. data/lib/spontaneous/prototypes/field_prototype.rb +7 -4
  156. data/lib/spontaneous/publishing.rb +10 -5
  157. data/lib/spontaneous/publishing/immediate.rb +32 -349
  158. data/lib/spontaneous/publishing/pipeline.rb +43 -0
  159. data/lib/spontaneous/publishing/progress.rb +186 -0
  160. data/lib/spontaneous/publishing/publish.rb +107 -0
  161. data/lib/spontaneous/publishing/rerender.rb +17 -0
  162. data/lib/spontaneous/publishing/revision.rb +53 -18
  163. data/lib/spontaneous/publishing/simultaneous.rb +1 -1
  164. data/lib/spontaneous/publishing/steps.rb +154 -0
  165. data/lib/spontaneous/publishing/steps/activate_revision.rb +45 -0
  166. data/lib/spontaneous/publishing/steps/archive_old_revisions.rb +22 -0
  167. data/lib/spontaneous/publishing/steps/base_step.rb +49 -0
  168. data/lib/spontaneous/publishing/steps/copy_static_files.rb +74 -0
  169. data/lib/spontaneous/publishing/steps/create_revision_directory.rb +24 -0
  170. data/lib/spontaneous/publishing/steps/generate_rackup_file.rb +51 -0
  171. data/lib/spontaneous/publishing/steps/generate_search_indexes.rb +24 -0
  172. data/lib/spontaneous/publishing/steps/render_revision.rb +69 -0
  173. data/lib/spontaneous/publishing/steps/write_revision_file.rb +43 -0
  174. data/lib/spontaneous/rack/back.rb +3 -1
  175. data/lib/spontaneous/rack/back/alias.rb +9 -8
  176. data/lib/spontaneous/rack/front.rb +1 -1
  177. data/lib/spontaneous/rack/middleware.rb +7 -4
  178. data/lib/spontaneous/rack/middleware/transaction.rb +14 -0
  179. data/lib/spontaneous/rack/page_controller.rb +23 -8
  180. data/lib/spontaneous/revision.rb +5 -10
  181. data/lib/spontaneous/schema.rb +5 -0
  182. data/lib/spontaneous/server.rb +3 -1
  183. data/lib/spontaneous/site.rb +17 -10
  184. data/lib/spontaneous/site/publishing.rb +25 -3
  185. data/lib/spontaneous/site/state.rb +7 -3
  186. data/lib/spontaneous/tasks/database.rake +5 -10
  187. data/lib/spontaneous/utils/database/mysql_dumper.rb +5 -1
  188. data/lib/spontaneous/version.rb +1 -1
  189. data/spontaneous.gemspec +4 -3
  190. data/test/fixtures/example_application/config/initializers/initializer1.rb +1 -0
  191. data/test/fixtures/example_application/config/initializers/initializer2.rb +1 -0
  192. data/test/fixtures/example_application/config/initializers/publishing.rb +13 -0
  193. data/test/fixtures/search/config/{indexes.rb → initializers/indexes.rb} +0 -0
  194. data/test/fixtures/serialisation/root_hash.yaml.erb +10 -4
  195. data/test/functional/test_application.rb +10 -0
  196. data/test/functional/test_back.rb +23 -5
  197. data/test/functional/test_cli.rb +98 -34
  198. data/test/functional/test_front.rb +7 -3
  199. data/test/test_helper.rb +35 -28
  200. data/test/unit/test_alias.rb +20 -3
  201. data/test/unit/test_assets.rb +58 -30
  202. data/test/unit/test_changesets.rb +20 -12
  203. data/test/unit/test_content_hash.rb +496 -0
  204. data/test/unit/test_context.rb +28 -1
  205. data/test/unit/test_controllers.rb +96 -61
  206. data/test/unit/test_crypt.rb +1 -8
  207. data/test/unit/test_datamapper.rb +95 -19
  208. data/test/unit/test_features.rb +1 -4
  209. data/test/unit/test_fields.rb +61 -12
  210. data/test/unit/test_generators.rb +39 -2
  211. data/test/unit/test_images.rb +3 -1
  212. data/test/unit/test_modifications.rb +224 -219
  213. data/test/unit/test_output_store.rb +10 -0
  214. data/test/unit/{test_formats.rb → test_outputs.rb} +75 -6
  215. data/test/unit/test_page.rb +61 -15
  216. data/test/unit/test_plugins.rb +2 -42
  217. data/test/unit/test_publishing_pipeline.rb +1050 -0
  218. data/test/unit/test_render.rb +30 -0
  219. data/test/unit/test_revisions.rb +110 -2
  220. data/test/unit/test_schema.rb +4 -0
  221. data/test/unit/test_search.rb +1 -1
  222. data/test/unit/test_serialisation.rb +6 -1
  223. data/test/unit/test_singletons.rb +159 -0
  224. data/test/unit/test_site.rb +71 -44
  225. metadata +140 -86
  226. data/application/static/font/fontawesome-webfont-1c66a4738b40ef0f6b1abca0ba9a796d.ttf +0 -0
  227. data/test/unit/test_publishing.rb +0 -330
@@ -61,15 +61,12 @@ describe "Features" do
61
61
 
62
62
  @root = ::Page.create
63
63
  Content.delete_revision(1) rescue nil
64
- Spontaneous.logger.silent! {
64
+ quietly {
65
65
  @site.publish_all
66
66
  }
67
67
  end
68
68
 
69
69
  after do
70
- # (@all_classes.map { |k| k.name.to_sym }).each { |klass|
71
- # Object.send(:remove_const, klass) rescue nil
72
- # } rescue nil
73
70
  Content.delete
74
71
  end
75
72
 
@@ -10,7 +10,7 @@ describe "Fields" do
10
10
  @now = Time.now
11
11
  stub_time(@now)
12
12
  Spontaneous::State.delete
13
- Site.background_mode = :immediate
13
+ @site.background_mode = :immediate
14
14
  end
15
15
 
16
16
  after do
@@ -167,6 +167,24 @@ describe "Fields" do
167
167
  assert content_class.field_prototypes[:date].field_class < Spontaneous::Field::Date
168
168
  assert content_class.field_prototypes[:chunky].field_class < Spontaneous::Field::String
169
169
  end
170
+
171
+ it "assigns the value of the field if the default is a proc" do
172
+ n = 0
173
+ f = @content_class.field :dynamic, :default => proc { (n += 1) }
174
+ f.dynamic_default?.must_equal true
175
+ instance1 = @content_class.create
176
+ instance1.dynamic.value.must_equal "1"
177
+ instance1.reload
178
+ instance1.dynamic.value.must_equal "1"
179
+ end
180
+
181
+ it "uses a dynamic default value to set the page slug" do
182
+ n = 0
183
+ page_class = Class.new(::Page)
184
+ page_class.field :title, default: proc { (n += 1) }
185
+ page = page_class.create
186
+ page.slug.must_equal "1"
187
+ end
170
188
  end
171
189
 
172
190
  describe "Field titles" do
@@ -643,6 +661,12 @@ describe "Fields" do
643
661
  v.count.must_equal 1
644
662
  end
645
663
 
664
+ it "marks a field as unmodified after save" do
665
+ @instance.title.value = "one"
666
+ @instance.save.reload
667
+ @instance.title.modified?.must_equal false
668
+ end
669
+
646
670
  it "have a creation date" do
647
671
  now = Time.now + 1000
648
672
  stub_time(now)
@@ -814,7 +838,7 @@ describe "Fields" do
814
838
  @field.value = "http://www.youtube.com/watch?v=_0jroAM_pO4&feature=feedrec_grec_index"
815
839
  html = @field.render(:html)
816
840
  html.must_match /^<iframe/
817
- html.must_match %r{src="http://www\.youtube\.com/embed/_0jroAM_pO4}
841
+ html.must_match %r{src="//www\.youtube\.com/embed/_0jroAM_pO4}
818
842
  html.must_match /width="680"/
819
843
  html.must_match /height="384"/
820
844
  html.must_match /theme=light/
@@ -834,7 +858,7 @@ describe "Fields" do
834
858
  @field.value = "http://vimeo.com/31836285"
835
859
  html = @field.render(:html)
836
860
  html.must_match /^<iframe/
837
- html.must_match %r{src="http://player\.vimeo\.com/video/31836285}
861
+ html.must_match %r{src="//player\.vimeo\.com/video/31836285}
838
862
  html.must_match /width="680"/
839
863
  html.must_match /height="384"/
840
864
  html.must_match /color=ccc/
@@ -858,7 +882,7 @@ describe "Fields" do
858
882
  json[:"tag"].must_equal "<iframe/>"
859
883
  attr = json[:"attr"]
860
884
  attr.must_be_instance_of(Hash)
861
- attr[:"src"].must_match %r{^http://www\.youtube\.com/embed/_0jroAM_pO4}
885
+ attr[:"src"].must_match %r{^//www\.youtube\.com/embed/_0jroAM_pO4}
862
886
  attr[:"src"].must_match /theme=light/
863
887
  attr[:"src"].must_match /hd=1/
864
888
  attr[:"src"].must_match /fs=1/
@@ -898,7 +922,7 @@ describe "Fields" do
898
922
  @field.value = "https://vine.co/v/brI7pTPb3qU"
899
923
  embed = @field.render(:html)
900
924
  embed.must_match %r(iframe)
901
- embed.must_match %r(src=["']https://vine\.co/v/brI7pTPb3qU/card["'])
925
+ embed.must_match %r(src=["']//vine\.co/v/brI7pTPb3qU/card["'])
902
926
  # Vine videos are square
903
927
  embed.must_match %r(width=["']680["'])
904
928
  embed.must_match %r(height=["']680["'])
@@ -946,7 +970,8 @@ describe "Fields" do
946
970
  @content_class.fields.location.export(nil)[:type].must_equal "Spontaneous.Field.String"
947
971
  end
948
972
 
949
- it "successfullt geolocate an address" do
973
+ it "successfully geolocate an address" do
974
+ # TODO: use mocking to avoid an external API request to googles geolocation service
950
975
  @field.value = "Cambridge, England"
951
976
  @field.value(:lat).must_equal 52.2053370
952
977
  @field.value(:lng).must_equal 0.1218170
@@ -1002,7 +1027,10 @@ describe "Fields" do
1002
1027
  end
1003
1028
 
1004
1029
  describe "File fields" do
1030
+ let(:path) { File.expand_path("../../fixtures/images/vimlogo.pdf", __FILE__) }
1031
+
1005
1032
  before do
1033
+ assert File.exists?(path), "Test file #{path} does not exist"
1006
1034
  @content_class = Class.new(::Piece)
1007
1035
  @prototype = @content_class.field :file
1008
1036
  @content_class.stubs(:name).returns("ContentClass")
@@ -1019,8 +1047,6 @@ describe "Fields" do
1019
1047
  end
1020
1048
 
1021
1049
  it "copy files to the media folder" do
1022
- path = File.expand_path("../../fixtures/images/vimlogo.pdf", __FILE__)
1023
- assert File.exists?(path), "Test file #{path} does not exist"
1024
1050
  File.open(path, 'rb') do |file|
1025
1051
  @field.value = {
1026
1052
  :tempfile => file,
@@ -1034,8 +1060,6 @@ describe "Fields" do
1034
1060
  end
1035
1061
 
1036
1062
  it "generate the requisite file metadata" do
1037
- path = File.expand_path("../../fixtures/images/vimlogo.pdf", __FILE__)
1038
- assert File.exists?(path), "Test file #{path} does not exist"
1039
1063
  File.open(path, 'rb') do |file|
1040
1064
  @field.value = {
1041
1065
  :tempfile => file,
@@ -1060,13 +1084,38 @@ describe "Fields" do
1060
1084
  end
1061
1085
 
1062
1086
  it "copy the given file if passed a path to an existing file" do
1063
- path = File.expand_path("../../fixtures/images/vimlogo.pdf", __FILE__)
1064
1087
  @field.value = path
1065
1088
  @field.value.must_match %r{/media/.+/vimlogo.pdf$}
1066
1089
  @field.filename.must_equal "vimlogo.pdf"
1067
1090
  @field.filesize.must_equal 2254
1068
1091
  end
1069
1092
 
1093
+ it "sets the unprocessed value to a JSON encoded array of MD5 hash & filename" do
1094
+ @field.value = path
1095
+ @instance.save
1096
+ @field.unprocessed_value.must_equal ["vimlogo.pdf", "1de7e866d69c2f56b4a3f59ed1c98b74"].to_json
1097
+ end
1098
+
1099
+ it "sets the field hash to the MD5 hash of the file" do
1100
+ @field.value = path
1101
+ @field.file_hash.must_equal "1de7e866d69c2f56b4a3f59ed1c98b74"
1102
+ end
1103
+
1104
+ it "sets the original filename of the file" do
1105
+ @field.value = path
1106
+ @field.original_filename.must_equal "vimlogo.pdf"
1107
+ end
1108
+
1109
+ it "doesn't set the hash of a file that can't be found" do
1110
+ @field.value = "/images/nosuchfile.rtf"
1111
+ @field.file_hash.must_equal ""
1112
+ end
1113
+
1114
+ it "sets the original filename of a file that can't be found" do
1115
+ @field.value = "/images/nosuchfile.rtf"
1116
+ @field.original_filename.must_equal "/images/nosuchfile.rtf"
1117
+ end
1118
+
1070
1119
  describe "clearing" do
1071
1120
  def assert_file_field_empty
1072
1121
  @field.value.must_equal ''
@@ -1648,7 +1697,7 @@ describe "Fields" do
1648
1697
  lock = @page.update_locks.first
1649
1698
  lock.field.must_equal field
1650
1699
  lock.content.must_equal @instance
1651
- lock.page.must_equal @page
1700
+ lock.page.reload.must_equal @page.reload
1652
1701
  lock.description.must_match /something\.gif/
1653
1702
  lock.created_at.must_equal @now
1654
1703
  lock.location.must_equal "Field ‘image’ of entry 1 in box ‘instances’"
@@ -51,7 +51,7 @@ describe "Generators" do
51
51
  %w(development.rb production.rb).each do |f|
52
52
  assert_file_exists(site_root, 'config/environments', f)
53
53
  end
54
- %w(back.ru front.ru boot.rb database.yml deploy.rb environment.rb user_levels.yml indexes.rb).each do |f|
54
+ %w(back.ru front.ru boot.rb database.yml deploy.rb environment.rb user_levels.yml).each do |f|
55
55
  assert_file_exists(site_root, 'config', f)
56
56
  end
57
57
  %w(favicon.ico robots.txt).each do |f|
@@ -60,6 +60,7 @@ describe "Generators" do
60
60
  %w(standard.html.cut).each do |f|
61
61
  assert_file_exists(site_root, 'templates/layouts', f)
62
62
  end
63
+ assert_file_exists(site_root, 'config/initializers/indexes.rb')
63
64
  assert_file_exists(site_root, 'schema')
64
65
  assert_file_exists(site_root, 'schema/page.rb')
65
66
  assert File.read(site_root / 'schema/page.rb') =~ /class Page < Content::Page/
@@ -101,6 +102,12 @@ describe "Generators" do
101
102
  [:development, :test, :production].each do |environment|
102
103
  config[environment][:adapter].must_equal "mysql2"
103
104
  config[environment][:database].must_match /^example_com(_test)?/
105
+ case environment
106
+ when :production
107
+ config[environment][:user].must_equal "example_com"
108
+ else
109
+ config[environment][:user].must_equal "root"
110
+ end
104
111
  # db connections seem to work if you exclude the host
105
112
  config[environment][:host].must_equal "127.0.0.1"
106
113
  end
@@ -130,7 +137,7 @@ describe "Generators" do
130
137
  config = database_config("example_com")
131
138
  [:development, :test].each do |environment|
132
139
  config[environment][:adapter].must_equal "postgres"
133
- config[environment][:user].must_be_nil
140
+ config[environment][:user].must_equal ENV["USER"]
134
141
  config[environment][:database].must_match /^example_com(_test)?/
135
142
  refute config[environment].key?(:host)
136
143
  end
@@ -183,6 +190,36 @@ describe "Generators" do
183
190
  end
184
191
  end
185
192
 
193
+ describe "configured for a sqlite database" do
194
+ let(:args) { ["example.com", "--root=#{@tmp}", "--database=sqlite"] }
195
+ before do
196
+ @site_root = File.join(@tmp, 'example_com')
197
+ generate(:site, *args)
198
+ end
199
+
200
+
201
+ it "define the correct adapter" do
202
+ config = database_config("example_com")
203
+ [:development, :test, :production].each do |environment|
204
+ config[environment][:adapter].must_equal "sqlite"
205
+ end
206
+ end
207
+
208
+ it "configure the correct gem" do
209
+ gemfile = File.read(File.join(@site_root, "Gemfile"))
210
+ gemfile.must_match /^gem 'sqlite3'/
211
+ end
212
+
213
+ it "setup the right db parameters" do
214
+ config = database_config("example_com")
215
+ [:development, :test].each do |environment|
216
+ config[environment][:database].must_match "db/#{environment}.sqlite3"
217
+ refute config[environment].key?(:user)
218
+ refute config[environment].key?(:host)
219
+ end
220
+ end
221
+ end
222
+
186
223
 
187
224
  it "include specified connection params in the generated database config" do
188
225
  site_root = File.join(@tmp, 'example_com')
@@ -17,6 +17,7 @@ describe "Images" do
17
17
  describe "Image fields set using absolute values" do
18
18
  before do
19
19
  @image = S::Field::Image.new(:name => "image")
20
+ @image.prototype = Spontaneous::Prototypes::FieldPrototype.new(@site.model, :image, :image)
20
21
  end
21
22
  it "accept and not alter URL values" do
22
23
  url = "http://example.com/image.png"
@@ -179,7 +180,8 @@ describe "Images" do
179
180
  @image.src.must_equal "/media/00234/0010/rose.jpg"
180
181
  @image.original.width.must_equal @image.width
181
182
  @image.original.height.must_equal @image.height
182
- @image.filepath.must_equal File.expand_path(File.join(Spontaneous.media_dir, "00234/0010/rose.jpg"))
183
+ md5 = Digest::MD5.file(@src_image).hexdigest
184
+ @image.filepath.must_equal ["rose.jpg", md5].to_json
183
185
  end
184
186
 
185
187
 
@@ -8,7 +8,7 @@ describe "Modifications" do
8
8
  before do
9
9
  @now = Time.now
10
10
  @site = setup_site
11
- stub_time(@now)
11
+ Timecop.freeze(@now)
12
12
 
13
13
  Content.delete
14
14
 
@@ -42,6 +42,7 @@ describe "Modifications" do
42
42
  end
43
43
 
44
44
  after do
45
+ Timecop.return
45
46
  Object.send(:remove_const, :Page) rescue nil
46
47
  Object.send(:remove_const, :Piece) rescue nil
47
48
  Content.delete
@@ -50,28 +51,29 @@ describe "Modifications" do
50
51
 
51
52
  it "register creation date of all content" do
52
53
  c = Content.create
53
- c.created_at.to_i.must_equal @now.to_i
54
+ (c.created_at - @now).must_be :<=, 1
54
55
  page = Page.create
55
- page.created_at.to_i.must_equal @now.to_i
56
+ (page.created_at - @now).must_be :<=, 1
56
57
  end
57
58
 
58
59
  it "update modification date of page when page fields are updated" do
59
60
  now = @now + 100
60
- stub_time(now)
61
- c = Content.first
62
- (c.modified_at.to_i - @now.to_i).abs.must_be :<=, 1
63
- c.label = "changed"
64
- c.save
65
- (c.modified_at - now).abs.must_be :<=, 1
61
+ Timecop.freeze(now) do
62
+ c = Page.first
63
+ (c.modified_at.to_i - @now.to_i).abs.must_be :<=, 1
64
+ c.update(title: "changed")
65
+ (c.modified_at - now).abs.must_be :<=, 1
66
+ end
66
67
  end
67
68
 
68
69
  it "update modification date of path when page visibility is changed" do
69
70
  now = @now + 100
70
- stub_time(now)
71
- c = Page.uid("0")
72
- (c.modified_at.to_i - @now.to_i).abs.must_be :<=, 1
73
- c.toggle_visibility!
74
- (c.modified_at - now).abs.must_be :<=, 1
71
+ Timecop.freeze(now) do
72
+ c = Page.uid("0")
73
+ (c.modified_at.to_i - @now.to_i).abs.must_be :<=, 1
74
+ c.toggle_visibility!
75
+ (c.modified_at - now).abs.must_be :<=, 1
76
+ end
75
77
  end
76
78
 
77
79
  it "update page timestamps on modification of its box fields" do
@@ -79,58 +81,54 @@ describe "Modifications" do
79
81
  field :title
80
82
  end
81
83
 
82
- stub_time(@now+3600)
83
- page = Page.first :uid => "0"
84
- (page.modified_at.to_i - @now.to_i).abs.must_be :<=, 1
85
- page.with_fields.title.value = "updated"
86
- page.save.reload
87
- page.modified_at.to_i.must_equal @now.to_i + 3600
84
+ Timecop.freeze(@now+3600) do
85
+ page = Page.first :uid => "0"
86
+ (page.modified_at.to_i - @now.to_i).abs.must_be :<=, 1
87
+ page.with_fields.title.value = "updated"
88
+ page.save.reload
89
+ page.modified_at.to_i.must_equal @now.to_i + 3600
90
+ end
88
91
  end
89
92
 
90
93
  it "update page timestamps on modification of a piece" do
91
- stub_time(@now+3600)
92
- page = Page.first :uid => "0"
93
- (page.modified_at.to_i - @now.to_i).abs.must_be :<=, 1
94
- content = page.contents.first
95
- content.page.must_equal page
96
- content.label = "changed"
97
- content.save
98
- page.reload
99
- page.modified_at.to_i.must_equal @now.to_i + 3600
94
+ Timecop.freeze(@now+3600) do
95
+ page = Page.first :uid => "0"
96
+ (page.modified_at.to_i - @now.to_i).abs.must_be :<=, 1
97
+ content = page.contents.first
98
+ content.page.must_equal page
99
+ content.label = "changed"
100
+ content.save
101
+ page.reload
102
+ page.modified_at.to_i.must_equal @now.to_i + 3600
103
+ end
100
104
  end
101
105
 
102
106
  it "update page timestamps on modification of a piece's box fields" do
103
107
  Piece.box :with_fields do
104
108
  field :title
105
109
  end
106
- stub_time(@now+3600)
107
- page = Page.first :uid => "0"
108
- (page.modified_at.to_i - @now.to_i).abs.must_be :<=, 1
109
- content = page.contents.first
110
-
111
- content.with_fields.title.value = "updated"
112
- content.save
113
- page.reload
114
- page.modified_at.to_i.must_equal @now.to_i + 3600
110
+ Timecop.freeze(@now+3600) do
111
+ page = Page.first :uid => "0"
112
+ (page.modified_at.to_i - @now.to_i).abs.must_be :<=, 1
113
+ content = page.contents.first
114
+
115
+ content.with_fields.title.value = "updated"
116
+ content.save
117
+ page.reload
118
+ page.modified_at.to_i.must_equal @now.to_i + 3600
119
+ end
115
120
  end
116
121
 
117
122
  it "update page timestamp on addition of piece" do
118
- stub_time(@now+3600)
119
- page = Page.first :uid => "0"
120
- content = Content[page.contents.first.id]
121
- content.things << Piece.new
122
- content.save
123
- content.modified_at.to_i.must_equal @now.to_i + 3600
124
- page.reload
125
- page.modified_at.to_i.must_equal @now.to_i + 3600
126
- end
127
-
128
- it "not update the parent page's timestamp on addition of a child page yyyy" do
129
- stub_time(@now+1000)
130
- page = Page.first :uid => "0"
131
- page.things << Page.new
132
- page.save.reload
133
- page.modified_at.to_i.must_equal @now.to_i
123
+ Timecop.freeze(@now + 3600) do
124
+ page = Page.first :uid => "0"
125
+ content = Content[page.contents.first.id]
126
+ content.things << Piece.new
127
+ content.save
128
+ content.modified_at.to_i.must_equal @now.to_i + 3600
129
+ page.reload
130
+ page.modified_at.to_i.must_equal @now.to_i + 3600
131
+ end
134
132
  end
135
133
 
136
134
  it "update the parent page's modification time if child pages are re-ordered" do
@@ -139,204 +137,209 @@ describe "Modifications" do
139
137
  page.things << Page.new(:uid => "0.0.0.1")
140
138
  page.save
141
139
  page = Page.first :uid => "0.0.0"
142
- stub_time(@now+1000)
143
- child = page.things.first
144
- child.update_position(1)
145
- page.reload.modified_at.to_i.must_equal @now.to_i + 1000
140
+ Timecop.freeze(@now + 1000) do
141
+ child = page.things.first
142
+ child.update_position(1)
143
+ page.reload.modified_at.to_i.must_equal @now.to_i + 1000
144
+ end
146
145
  end
147
146
 
148
147
  it "update a page's timestamp on modification of its slug" do
149
- stub_time(@now+1000)
150
- page = Page.first :uid => "0"
151
- page.slug = "changed"
152
- page.save.reload
153
- page.modified_at.to_i.must_equal @now.to_i + 1000
154
- end
155
-
156
- it "not update child pages timestamps after changing their parent's slug" do
157
- page = Page.first :uid => "0.0.0"
158
- modified = page.modified_at.to_i
159
- stub_time(@now+1000)
160
- page = Page.first :uid => "0"
161
- page.slug = "changed"
162
- page.save.reload
163
- page.modified_at.to_i.must_equal @now.to_i + 1000
164
- page = Page.first :uid => "0.0.0"
165
- page.modified_at.to_i.must_equal modified
148
+ Timecop.freeze(@now + 1000) do
149
+ page = Page.first :uid => "0"
150
+ page.slug = "changed"
151
+ page.save.reload
152
+ page.modified_at.to_i.must_equal @now.to_i + 1000
153
+ end
166
154
  end
167
155
 
168
156
  it "update the pages timestamp if a boxes order is changed" do
169
- stub_time(@now+3600)
170
- page = Page.first :uid => "0"
171
- content = Content[page.contents.first.id]
172
- content.update_position(1)
173
- page.reload.modified_at.to_i.must_equal @now.to_i + 3600
157
+ Timecop.freeze(@now+3600) do
158
+ page = Page.first :uid => "0"
159
+ content = Content[page.contents.first.id]
160
+ content.update_position(1)
161
+ page.reload.modified_at.to_i.must_equal @now.to_i + 3600
162
+ end
174
163
  end
175
164
 
176
165
  it "update the parent page's modification time if the contents of a piece's box are re-ordered" do
177
- stub_time(@now+3600)
178
- page = Page.first :uid => "0"
179
- content = page.things.first.things.first
180
- content.update_position(1)
181
- page.reload.modified_at.to_i.must_equal @now.to_i + 3600
166
+ Timecop.freeze(@now+3600) do
167
+ page = Page.first :uid => "0"
168
+ content = page.things.first.things.first
169
+ content.update_position(1)
170
+ page.reload.modified_at.to_i.must_equal @now.to_i + 3600
171
+ end
182
172
  end
183
173
 
184
174
  it "update the parent page's modification date if a piece is deleted" do
185
- stub_time(@now+3600)
186
- page = Page.first :uid => "0"
187
- content = Content[page.contents.first.id]
188
- content.destroy
189
- page.reload.modified_at.to_i.must_equal @now.to_i + 3600
175
+ Timecop.freeze(@now+3600) do
176
+ page = Page.first :uid => "0"
177
+ content = Content[page.contents.first.id]
178
+ content.destroy
179
+ page.reload.modified_at.to_i.must_equal @now.to_i + 3600
180
+ end
190
181
  end
191
182
 
192
183
  it "update the parent page's modification date if a page is deleted" do
193
- stub_time(@now+3600)
194
- page = Page.first :uid => "0"
195
- content = Content[page.things.first.things.first.id]
196
- content.destroy
197
- page.reload.modified_at.to_i.must_equal @now.to_i + 3600
184
+ Timecop.freeze(@now+3600) do
185
+ page = Page.first :uid => "0"
186
+ content = Content[page.things.first.things.first.id]
187
+ content.destroy
188
+ page.reload.modified_at.to_i.must_equal @now.to_i + 3600
189
+ end
198
190
  end
199
191
 
200
192
  it "add entry to the list of side effects for a visibility change" do
201
- stub_time(@now+3600)
202
- page = Page.first :uid => "1"
203
- old_slug = page.slug
204
- page.slug = "changed"
205
- page.save
206
- page.reload
207
- page.pending_modifications.length.must_equal 1
208
- mods = page.pending_modifications(:slug)
209
- mods.length.must_equal 1
210
- mod = mods.first
211
- mod.must_be_instance_of Spontaneous::Model::Core::Modifications::SlugModification
212
- mod.old_value.must_equal old_slug
213
- mod.new_value.must_equal "changed"
214
- mod.created_at.to_i.must_equal @now.to_i + 3600
193
+ Timecop.freeze(@now+3600) do
194
+ page = Page.first :uid => "1"
195
+ old_slug = page.slug
196
+ page.slug = "changed"
197
+ page.save
198
+ page.reload
199
+ page.pending_modifications.length.must_equal 1
200
+ mods = page.pending_modifications(:slug)
201
+ mods.length.must_equal 1
202
+ mod = mods.first
203
+ mod.must_be_instance_of Spontaneous::Model::Core::Modifications::SlugModification
204
+ mod.old_value.must_equal old_slug
205
+ mod.new_value.must_equal "changed"
206
+ mod.created_at.to_i.must_equal @now.to_i + 3600
207
+ end
215
208
  end
216
209
 
217
210
  it "serialize page modifications" do
218
- stub_time(@now+3600)
219
- page = Page.first :uid => "1"
220
- page.slug = "changed"
221
- page.save
222
- page.pending_modifications.length.must_equal 1
223
- mod = page.pending_modifications(:slug).first
224
- page = Page.first :id => page.id
225
- page.pending_modifications.length.must_equal 1
226
- page.pending_modifications(:slug).first.must_equal mod
227
- page.pending_modifications(:slug).first.created_at.to_i.must_equal @now.to_i + 3600
211
+ Timecop.freeze(@now+3600) do
212
+ page = Page.first :uid => "1"
213
+ page.slug = "changed"
214
+ page.save
215
+ page.pending_modifications.length.must_equal 1
216
+ mod = page.pending_modifications(:slug).first
217
+ page = Page.first :id => page.id
218
+ page.pending_modifications.length.must_equal 1
219
+ page.pending_modifications(:slug).first.must_equal mod
220
+ page.pending_modifications(:slug).first.created_at.to_i.must_equal @now.to_i + 3600
221
+ end
228
222
  end
229
223
 
230
224
  it "concatenate multiple slug modifications together" do
231
- stub_time(@now+3600)
232
- page = Page.first :uid => "1"
233
- old_slug = page.slug
234
- page.slug = "changed"
235
- page.save
236
- page.pending_modifications.length.must_equal 1
237
- page.slug = "changed-again"
238
- page.save
239
- mod = page.pending_modifications(:slug).first
240
- mod.old_value.must_equal old_slug
241
- mod.new_value.must_equal "changed-again"
225
+ Timecop.freeze(@now+3600) do
226
+ page = Page.first :uid => "1"
227
+ old_slug = page.slug
228
+ page.slug = "changed"
229
+ page.save
230
+ page.pending_modifications.length.must_equal 1
231
+ page.slug = "changed-again"
232
+ page.save
233
+ mod = page.pending_modifications(:slug).first
234
+ mod.old_value.must_equal old_slug
235
+ mod.new_value.must_equal "changed-again"
236
+ end
242
237
  end
243
238
 
244
239
  it "know the number of pages affected by slug modification" do
245
- stub_time(@now+3600)
246
- page = Page.first :uid => "1"
247
- page.slug = "changed"
248
- page.save
249
- mod = page.pending_modifications(:slug).first
250
- mod.count.must_equal 4
240
+ Timecop.freeze(@now+3600) do
241
+ page = Page.first :uid => "1"
242
+ page.slug = "changed"
243
+ page.save
244
+ mod = page.pending_modifications(:slug).first
245
+ mod.count.must_equal 4
246
+ end
251
247
  end
252
248
 
253
249
  it "show the number of pages whose visibility is affected in the case of a visibility change" do
254
- stub_time(@now+3600)
255
- page = Page.first :uid => "1"
256
- page.hide!
257
- page.reload
258
- mods = page.pending_modifications(:visibility)
259
- mods.length.must_equal 1
260
- mod = mods.first
261
- mod.count.must_equal 4
262
- mod.owner.must_equal page
250
+ Timecop.freeze(@now+3600) do
251
+ page = Page.first :uid => "1"
252
+ page.hide!
253
+ page.reload
254
+ mods = page.pending_modifications(:visibility)
255
+ mods.length.must_equal 1
256
+ mod = mods.first
257
+ mod.count.must_equal 4
258
+ mod.owner.must_equal page
259
+ end
263
260
  end
264
261
 
265
262
  it "record visibility changes that originate from a content piece" do
266
- stub_time(@now+3600)
267
- page = Page.first :uid => "1"
268
- page.things.first.hide!
269
- page.reload
270
- mods = page.pending_modifications(:visibility)
271
- mods.length.must_equal 1
272
- mod = mods.first
273
- mod.count.must_equal 2
274
- mod.owner.must_equal page.things.first
263
+ Timecop.freeze(@now+3600) do
264
+ page = Page.first :uid => "1"
265
+ page.things.first.hide!
266
+ page.reload
267
+ mods = page.pending_modifications(:visibility)
268
+ mods.length.must_equal 1
269
+ mod = mods.first
270
+ mod.count.must_equal 2
271
+ mod.owner.must_equal page.things.first
272
+ end
275
273
  end
276
274
 
277
275
  it "show number of pages that are to be deleted in the case of a deletion" do
278
- stub_time(@now+3600)
279
- page = Page.first(:uid => "1")
280
- owner = page.owner
281
- page.destroy
282
- page = Page.first(:uid => "root")
283
- mods = page.pending_modifications(:deletion)
284
- mod = mods.first
285
- # count is number of children of deleted page + 1 (for deleted page)
286
- mod.count.must_equal 5
287
- mod.owner.must_equal owner.reload
276
+ Timecop.freeze(@now+3600) do
277
+ page = Page.first(:uid => "1")
278
+ owner = page.owner
279
+ page.destroy
280
+ page = Page.first(:uid => "root")
281
+ mods = page.pending_modifications(:deletion)
282
+ mod = mods.first
283
+ # count is number of children of deleted page + 1 (for deleted page)
284
+ mod.count.must_equal 5
285
+ mod.owner.must_equal owner.reload
286
+ end
288
287
  end
289
288
 
290
289
  it "show number of pages deleted if piece with pages is deleted" do
291
- stub_time(@now+3600)
292
- page = Page.first(:uid => "1")
293
- piece = page.things.first
294
- owner = piece.owner
295
- piece.destroy
296
- page = Page.first(:uid => "1")
297
- mods = page.pending_modifications(:deletion)
298
- mod = mods.first
299
- mod.count.must_equal 2
300
- mod.owner.must_equal owner.reload
290
+ Timecop.freeze(@now+3600) do
291
+ page = Page.first(:uid => "1")
292
+ piece = page.things.first
293
+ owner = piece.owner
294
+ piece.destroy
295
+ page = Page.first(:uid => "1")
296
+ mods = page.pending_modifications(:deletion)
297
+ mod = mods.first
298
+ mod.count.must_equal 2
299
+ mod.owner.must_equal owner.reload
300
+ end
301
301
  end
302
302
 
303
303
  it "show number of pages deleted if page belonging to piece is deleted" do
304
- stub_time(@now+3600)
305
- page = Page.first(:uid => "1")
306
- child = page.things.first.things.first
307
- owner = child.owner
308
- child.destroy
309
- page = Page.first(:uid => "1")
310
- mods = page.pending_modifications(:deletion)
311
- mod = mods.first
312
- mod.count.must_equal 1
313
- mod.owner.must_equal owner.reload
304
+ Timecop.freeze(@now+3600) do
305
+ page = Page.first(:uid => "1")
306
+ child = page.things.first.things.first
307
+ owner = child.owner
308
+ child.destroy
309
+ page = Page.first(:uid => "1")
310
+ mods = page.pending_modifications(:deletion)
311
+ mod = mods.first
312
+ mod.count.must_equal 1
313
+ mod.owner.must_equal owner.reload
314
+ end
314
315
  end
315
316
 
316
317
  it "have an empty modification if the slug has been reverted to original value" do
317
- stub_time(@now+3600)
318
- page = Page.first :uid => "1"
319
- old_slug = page.slug
320
- page.slug = "changed"
321
- page.save
322
- page.pending_modifications.length.must_equal 1
323
- page.slug = "changed-again"
324
- page.save
325
- page.slug = old_slug
326
- page.save
327
- mods = page.reload.pending_modifications(:slug)
328
- mods.length.must_equal 0
318
+ Timecop.freeze(@now+3600) do
319
+ page = Page.first :uid => "1"
320
+ old_slug = page.slug
321
+ page.slug = "changed"
322
+ page.save
323
+ page.pending_modifications.length.must_equal 1
324
+ page.slug = "changed-again"
325
+ page.save
326
+ page.slug = old_slug
327
+ page.save
328
+ mods = page.reload.pending_modifications(:slug)
329
+ mods.length.must_equal 0
330
+ end
329
331
  end
330
332
 
331
333
  it "have an empty modification if the visibility has been reverted to original value" do
332
- stub_time(@now+3600)
333
- page = Page.first :uid => "1"
334
- page.things.first.hide!
335
- page.reload
336
- page.things.first.show!
337
- page.reload
338
- mods = page.pending_modifications(:visibility)
339
- mods.length.must_equal 0
334
+ Timecop.freeze(@now+3600) do
335
+ page = Page.first :uid => "1"
336
+ page.things.first.hide!
337
+ page.reload
338
+ page.things.first.show!
339
+ page.reload
340
+ mods = page.pending_modifications(:visibility)
341
+ mods.length.must_equal 0
342
+ end
340
343
  end
341
344
 
342
345
  describe "during publish" do
@@ -613,24 +616,26 @@ describe "Modifications" do
613
616
  end
614
617
 
615
618
  it "add the editor to any modifications" do
616
- stub_time(@now+3600)
617
- page = Page.first :uid => "1"
618
- page.current_editor = @user
619
- page.slug = "changed"
620
- page.save
621
- mod = page.pending_modifications(:slug).first
622
- mod.user.must_equal @user
619
+ Timecop.freeze(@now+3600) do
620
+ page = Page.first :uid => "1"
621
+ page.current_editor = @user
622
+ page.slug = "changed"
623
+ page.save
624
+ mod = page.pending_modifications(:slug).first
625
+ mod.user.must_equal @user
626
+ end
623
627
  end
624
628
 
625
629
  it "persist the user" do
626
- stub_time(@now+3600)
627
- page = Page.first :uid => "1"
628
- page.current_editor = @user
629
- page.slug = "changed"
630
- page.save
631
- page = Page.first :uid => "1"
632
- mod = page.pending_modifications(:slug).first
633
- mod.user.must_equal @user
630
+ Timecop.freeze(@now+3600) do
631
+ page = Page.first :uid => "1"
632
+ page.current_editor = @user
633
+ page.slug = "changed"
634
+ page.save
635
+ page = Page.first :uid => "1"
636
+ mod = page.pending_modifications(:slug).first
637
+ mod.user.must_equal @user
638
+ end
634
639
  end
635
640
  end
636
641
  end