spontaneous 0.2.0.alpha2 → 0.2.0.alpha3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (404) hide show
  1. data/Gemfile +3 -40
  2. data/Rakefile +29 -41
  3. data/Readme.markdown +21 -8
  4. data/application/css/add_alias_dialogue.css.scss +79 -0
  5. data/application/css/{v2.scss → core.css.scss} +537 -550
  6. data/application/css/{definitions.scss → definitions.css.scss} +121 -33
  7. data/application/css/dialogue.css.scss +409 -0
  8. data/application/css/{editing.scss → editing.css.scss} +25 -262
  9. data/application/css/font.css.scss +8 -0
  10. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  11. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  12. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_flat_10_000000_40x100.png +0 -0
  13. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  14. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  15. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  16. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  17. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  18. data/application/css/jquery-ui-1.8.21.custom/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  19. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_222222_256x240.png +0 -0
  20. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_228ef1_256x240.png +0 -0
  21. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ef8c08_256x240.png +0 -0
  22. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ffd27a_256x240.png +0 -0
  23. data/application/css/jquery-ui-1.8.21.custom/images/ui-icons_ffffff_256x240.png +0 -0
  24. data/application/css/jquery-ui-1.8.21.custom/ui-lightness.css.scss +565 -0
  25. data/application/css/{login.scss → login.css.scss} +4 -4
  26. data/application/css/meta.css.scss +331 -0
  27. data/application/css/{popover.scss → popover.css.scss} +9 -8
  28. data/application/css/{schema_error.scss → schema_error.css.scss} +4 -4
  29. data/application/css/spontaneous.css +5 -0
  30. data/application/css/unsupported.css.scss +42 -0
  31. data/application/js/add_alias_dialogue.js +72 -10
  32. data/application/js/ajax.js +50 -16
  33. data/application/js/compatibility.js +19 -15
  34. data/application/js/content.js +39 -36
  35. data/application/js/content_area.js +53 -5
  36. data/application/js/dialogue.js +17 -0
  37. data/application/js/dom.js +1 -1
  38. data/application/js/edit_panel.js +23 -8
  39. data/application/js/extensions.js +7 -2
  40. data/application/js/field_preview.js +2 -1
  41. data/application/js/field_types/date_field.js +11 -8
  42. data/application/js/field_types/file_field.js +188 -9
  43. data/application/js/field_types/image_field.js +46 -29
  44. data/application/js/field_types/markdown_field.js +57 -14
  45. data/application/js/field_types/select_field.js +72 -0
  46. data/application/js/field_types/string_field.js +8 -0
  47. data/application/js/field_types/webvideo_field.js +8 -0
  48. data/application/js/init.js +1 -7
  49. data/application/js/location.js +41 -13
  50. data/application/js/login.js +3 -0
  51. data/application/js/meta_view/user_admin.js +543 -0
  52. data/application/js/meta_view.js +1 -0
  53. data/application/js/metadata.js +20 -0
  54. data/application/js/page.js +17 -3
  55. data/application/js/page_browser.js +40 -30
  56. data/application/js/page_entry.js +4 -0
  57. data/application/js/panel/root_menu.js +66 -0
  58. data/application/js/popover.js +2 -2
  59. data/application/js/preview.js +1 -1
  60. data/application/js/publish.js +138 -30
  61. data/application/js/services.js +43 -0
  62. data/application/js/sharded_upload.js +2 -2
  63. data/application/js/spontaneous.js +64 -5
  64. data/application/js/state.js +20 -9
  65. data/application/js/top_bar.js +273 -150
  66. data/application/js/types.js +20 -15
  67. data/application/js/upload.js +1 -2
  68. data/application/js/user.js +18 -4
  69. data/application/js/vendor/date.js +104 -0
  70. data/application/js/vendor/jquery-ui-1.8.18.custom.min.js +356 -0
  71. data/application/js/views/box_view.js +15 -8
  72. data/application/js/views/page_piece_view.js +11 -8
  73. data/application/js/views/page_view.js +21 -3
  74. data/application/js/views/piece_view.js +19 -10
  75. data/application/js/views.js +3 -0
  76. data/application/static/chromelogo-200x52-45c7cbc93be080bea342df5fcda2ef8b.png +0 -0
  77. data/application/static/dot-texture-9eea29e4ac7ad9a772285252078ec127.png +0 -0
  78. data/application/static/editing-textarea-resize-s-b5af62365eb7e19ea4beccf7242d508e.png +0 -0
  79. data/application/static/editing-texture-1-42b06a3439752490988f30f2a06d5e7c.png +0 -0
  80. data/application/static/font/fontawesome-webfont-5c5c21100a346972a82c34c5e96ffcfe.ttf +0 -0
  81. data/application/static/loop_alt1-white-7894b458528e92216196cae26b4c2c96.svg +12 -0
  82. data/application/static/spontaneous-states-e91ec89db525c62da0105b97cdd781ce.png +0 -0
  83. data/application/views/index.erb +2 -2
  84. data/application/views/login.erb +4 -8
  85. data/application/views/schema_modification_error.html.erb +1 -4
  86. data/application/views/unsupported.erb +9 -7
  87. data/bin/spot +1 -1
  88. data/db/migrations/20110209152710_users_and_groups.rb +10 -10
  89. data/db/migrations/20120305112647_site_modification_time.rb +11 -0
  90. data/db/migrations/20120418153903_add_ownership_of_content.rb +14 -0
  91. data/db/migrations/20120423175416_add_pending_modifications.rb +21 -0
  92. data/db/migrations/20120525164947_add_field_versions.rb +27 -0
  93. data/lib/sequel/plugins/scoped_table_name.rb +10 -1
  94. data/lib/spontaneous/asset/file.rb +25 -0
  95. data/lib/spontaneous/asset/source.rb +28 -0
  96. data/lib/spontaneous/asset.rb +75 -0
  97. data/lib/spontaneous/box.rb +6 -4
  98. data/lib/spontaneous/capistrano/deploy.rb +47 -0
  99. data/lib/spontaneous/capistrano/sync.rb +81 -0
  100. data/lib/spontaneous/capistrano.rb +13 -0
  101. data/lib/spontaneous/change.rb +60 -68
  102. data/lib/spontaneous/cli/assets.rb +29 -0
  103. data/lib/spontaneous/cli/base.rb +0 -48
  104. data/lib/spontaneous/cli/console.rb +1 -1
  105. data/lib/spontaneous/cli/server.rb +6 -4
  106. data/lib/spontaneous/cli/site.rb +28 -17
  107. data/lib/spontaneous/cli/user.rb +107 -0
  108. data/lib/spontaneous/cli.rb +100 -4
  109. data/lib/spontaneous/collections/entry_set.rb +2 -2
  110. data/lib/spontaneous/collections/field_set.rb +48 -22
  111. data/lib/spontaneous/collections/prototype_set.rb +20 -13
  112. data/lib/spontaneous/constants.rb +3 -0
  113. data/lib/spontaneous/content.rb +22 -5
  114. data/lib/spontaneous/errors.rb +3 -3
  115. data/lib/spontaneous/extensions/array.rb +12 -0
  116. data/lib/spontaneous/extensions/enumerable.rb +30 -0
  117. data/lib/spontaneous/extensions/nil.rb +3 -1
  118. data/lib/spontaneous/extensions/string.rb +16 -0
  119. data/lib/spontaneous/field_types/date_field.rb +45 -2
  120. data/lib/spontaneous/field_types/field.rb +42 -9
  121. data/lib/spontaneous/field_types/file_field.rb +68 -0
  122. data/lib/spontaneous/field_types/image_field.rb +63 -0
  123. data/lib/spontaneous/field_types/select_field.rb +109 -0
  124. data/lib/spontaneous/field_types/string_field.rb +6 -1
  125. data/lib/spontaneous/field_types/webvideo_field.rb +85 -27
  126. data/lib/spontaneous/field_types.rb +1 -1
  127. data/lib/spontaneous/field_version.rb +8 -0
  128. data/lib/spontaneous/generators/page.rb +1 -1
  129. data/lib/spontaneous/generators/site/Capfile.tt +1 -4
  130. data/lib/spontaneous/generators/site/Gemfile.tt +13 -6
  131. data/lib/spontaneous/generators/site/config/deploy.rb.tt +28 -0
  132. data/lib/spontaneous/generators/site/config/environments/production.rb.tt +7 -2
  133. data/lib/spontaneous/generators/site.rb +1 -0
  134. data/lib/spontaneous/json.rb +34 -11
  135. data/lib/spontaneous/layout.rb +22 -0
  136. data/lib/spontaneous/media/file.rb +4 -0
  137. data/lib/spontaneous/output/assets/compression.rb +58 -0
  138. data/lib/spontaneous/output/assets.rb +32 -0
  139. data/lib/spontaneous/output/context.rb +179 -0
  140. data/lib/spontaneous/output/format/html.rb +5 -0
  141. data/lib/spontaneous/output/format/plain.rb +5 -0
  142. data/lib/spontaneous/output/format.rb +180 -0
  143. data/lib/spontaneous/output/helpers/classes_helper.rb +18 -0
  144. data/lib/spontaneous/{render/helpers/html_helper.rb → output/helpers/conditional_comment_helper.rb} +3 -12
  145. data/lib/spontaneous/output/helpers/script_helper.rb +73 -0
  146. data/lib/spontaneous/output/helpers/stylesheet_helper.rb +61 -0
  147. data/lib/spontaneous/output/helpers.rb +28 -0
  148. data/lib/spontaneous/output/template/engine.rb +59 -0
  149. data/lib/spontaneous/output/template/renderer.rb +153 -0
  150. data/lib/spontaneous/output/template.rb +21 -0
  151. data/lib/spontaneous/output.rb +163 -0
  152. data/lib/spontaneous/page.rb +2 -1
  153. data/lib/spontaneous/paths.rb +6 -1
  154. data/lib/spontaneous/permissions/access_key.rb +5 -5
  155. data/lib/spontaneous/permissions/user.rb +81 -35
  156. data/lib/spontaneous/permissions/user_level.rb +26 -22
  157. data/lib/spontaneous/plugins/aliases.rb +76 -12
  158. data/lib/spontaneous/plugins/allowed_types.rb +60 -18
  159. data/lib/spontaneous/plugins/application/paths.rb +0 -28
  160. data/lib/spontaneous/plugins/application/system.rb +35 -0
  161. data/lib/spontaneous/plugins/boxes.rb +4 -0
  162. data/lib/spontaneous/plugins/content_groups.rb +16 -0
  163. data/lib/spontaneous/plugins/entries.rb +50 -30
  164. data/lib/spontaneous/plugins/fields.rb +15 -0
  165. data/lib/spontaneous/plugins/layouts.rb +8 -2
  166. data/lib/spontaneous/plugins/modifications.rb +228 -0
  167. data/lib/spontaneous/plugins/page/formats.rb +67 -42
  168. data/lib/spontaneous/plugins/page/request.rb +10 -0
  169. data/lib/spontaneous/plugins/page/site_timestamps.rb +28 -0
  170. data/lib/spontaneous/plugins/paths.rb +15 -3
  171. data/lib/spontaneous/plugins/publishing.rb +124 -45
  172. data/lib/spontaneous/plugins/render.rb +13 -8
  173. data/lib/spontaneous/plugins/schema_hierarchy.rb +18 -6
  174. data/lib/spontaneous/plugins/site/helpers.rb +53 -0
  175. data/lib/spontaneous/plugins/site/hooks.rb +50 -0
  176. data/lib/spontaneous/plugins/site/map.rb +1 -1
  177. data/lib/spontaneous/plugins/site/paths.rb +13 -0
  178. data/lib/spontaneous/plugins/site/publishing.rb +6 -2
  179. data/lib/spontaneous/plugins/site/{revisions.rb → state.rb} +5 -1
  180. data/lib/spontaneous/plugins/site/storage.rb +4 -0
  181. data/lib/spontaneous/plugins/site/url.rb +15 -0
  182. data/lib/spontaneous/plugins/site_map.rb +13 -3
  183. data/lib/spontaneous/plugins/styles.rb +5 -1
  184. data/lib/spontaneous/plugins/visibility.rb +39 -12
  185. data/lib/spontaneous/prototypes/box_prototype.rb +4 -0
  186. data/lib/spontaneous/prototypes/field_prototype.rb +15 -10
  187. data/lib/spontaneous/publishing/event_client.rb +46 -0
  188. data/lib/spontaneous/publishing/immediate.rb +81 -44
  189. data/lib/spontaneous/publishing/simultaneous.rb +23 -6
  190. data/lib/spontaneous/publishing.rb +4 -3
  191. data/lib/spontaneous/rack/around_back.rb +1 -5
  192. data/lib/spontaneous/rack/around_front.rb +4 -4
  193. data/lib/spontaneous/rack/around_preview.rb +4 -3
  194. data/lib/spontaneous/rack/assets.rb +81 -54
  195. data/lib/spontaneous/rack/authentication.rb +0 -1
  196. data/lib/spontaneous/rack/back.rb +160 -72
  197. data/lib/spontaneous/rack/cookie_authentication.rb +2 -2
  198. data/lib/spontaneous/rack/css.rb +18 -15
  199. data/lib/spontaneous/rack/event_source.rb +9 -21
  200. data/lib/spontaneous/rack/fiber_pool.rb +26 -0
  201. data/lib/spontaneous/rack/front.rb +12 -4
  202. data/lib/spontaneous/rack/helpers.rb +35 -13
  203. data/lib/spontaneous/rack/js.rb +41 -0
  204. data/lib/spontaneous/rack/public.rb +34 -44
  205. data/lib/spontaneous/rack/sse.rb +18 -0
  206. data/lib/spontaneous/rack/static.rb +3 -0
  207. data/lib/spontaneous/rack/user_admin.rb +100 -0
  208. data/lib/spontaneous/rack/user_helpers.rb +1 -1
  209. data/lib/spontaneous/rack.rb +6 -2
  210. data/lib/spontaneous/schema.rb +31 -4
  211. data/lib/spontaneous/search/index.rb +19 -3
  212. data/lib/spontaneous/search/results.rb +1 -1
  213. data/lib/spontaneous/sequel.rb +17 -0
  214. data/lib/spontaneous/site.rb +11 -4
  215. data/lib/spontaneous/state.rb +11 -0
  216. data/lib/spontaneous/storage/cloud.rb +4 -0
  217. data/lib/spontaneous/storage/local.rb +11 -0
  218. data/lib/spontaneous/style.rb +2 -2
  219. data/lib/spontaneous/tasks/database.rake +21 -22
  220. data/lib/spontaneous/utils/database/mysql_dumper.rb +4 -0
  221. data/lib/spontaneous/utils/database/postgres_dumper.rb +78 -0
  222. data/lib/spontaneous/utils/database.rb +6 -3
  223. data/lib/spontaneous/utils/smart_quotes.rb +499 -0
  224. data/lib/spontaneous/utils/smush_it.rb +66 -0
  225. data/lib/spontaneous/utils.rb +3 -1
  226. data/lib/spontaneous/version.rb +2 -2
  227. data/lib/spontaneous.rb +25 -29
  228. data/spontaneous.gemspec +186 -106
  229. data/test/experimental/test_features.rb +1 -1
  230. data/test/fixtures/asset_pipeline/application/css/basic.css.scss +4 -0
  231. data/test/fixtures/asset_pipeline/application/css/complex.css.scss.erb +6 -0
  232. data/test/fixtures/asset_pipeline/application/css/simple.css +3 -0
  233. data/test/fixtures/asset_pipeline/application/css/spontaneous.css +7 -0
  234. data/test/fixtures/asset_pipeline/application/css/subdir/complex.css.scss.erb +6 -0
  235. data/test/fixtures/asset_pipeline/application/css/subdir/library.css.scss +1 -0
  236. data/test/fixtures/asset_pipeline/application/css/subdir/simple.css +3 -0
  237. data/test/fixtures/asset_pipeline/application/js/basic.js.coffee +1 -0
  238. data/test/fixtures/asset_pipeline/application/js/complex.js.coffee.erb +1 -0
  239. data/test/fixtures/asset_pipeline/application/js/login.js +1 -0
  240. data/test/fixtures/asset_pipeline/application/js/require.js +1 -0
  241. data/test/fixtures/asset_pipeline/application/js/simple.js +1 -0
  242. data/test/fixtures/asset_pipeline/application/js/spontaneous.js +5 -0
  243. data/test/fixtures/asset_pipeline/application/js/subdir/complex.js.coffee.erb +1 -0
  244. data/test/fixtures/asset_pipeline/application/js/subdir/library.js.coffee +1 -0
  245. data/test/fixtures/asset_pipeline/application/js/subdir/simple.js +1 -0
  246. data/test/fixtures/asset_pipeline/application/js/vendor/jquery.js +1 -0
  247. data/test/fixtures/asset_pipeline/application/static/dot-texture.png +0 -0
  248. data/test/fixtures/asset_pipeline/application/static/subdir/px.gif +0 -0
  249. data/test/fixtures/assets/public1/css/a.scss +1 -0
  250. data/test/fixtures/assets/public1/js/a.js +1 -0
  251. data/test/fixtures/assets/public1/js/m.coffee +1 -0
  252. data/test/fixtures/assets/public2/css/b.scss +1 -0
  253. data/test/fixtures/assets/public2/css/c.css +1 -0
  254. data/test/fixtures/assets/public2/js/b.js +1 -0
  255. data/test/fixtures/assets/public2/js/c.js +1 -0
  256. data/test/fixtures/assets/public2/js/n.coffee +1 -0
  257. data/test/fixtures/back/config/user_levels.yml +3 -0
  258. data/test/fixtures/back/public/js/coffeescript.coffee +1 -0
  259. data/test/fixtures/back/templates/layouts/standard.css.cut +1 -0
  260. data/test/fixtures/back/templates/layouts/standard.js.cut +1 -0
  261. data/test/fixtures/example_application/config/database.yml +4 -4
  262. data/test/fixtures/helpers/templates/layouts/standard.html.cut +1 -0
  263. data/test/fixtures/helpers/templates/layouts/standard.mobile.cut +1 -0
  264. data/test/fixtures/images/vimlogo.pdf +0 -0
  265. data/test/fixtures/outputs/templates/layouts/standard.atom.cut +1 -0
  266. data/test/fixtures/permissions/config/user_levels.yml +6 -3
  267. data/test/fixtures/serialisation/class_hash.yaml.erb +1 -0
  268. data/test/fixtures/serialisation/root_hash.yaml.erb +2 -2
  269. data/test/fixtures/templates/extended/grandparent.html.cut +7 -7
  270. data/test/fixtures/templates/extended/main.html.cut +5 -5
  271. data/test/fixtures/templates/extended/parent.html.cut +8 -8
  272. data/test/fixtures/templates/extended/partial_with_locals.html.cut +1 -1
  273. data/test/fixtures/templates/extended/with_includes.html.cut +6 -6
  274. data/test/fixtures/templates/extended/with_includes_and_locals.html.cut +6 -7
  275. data/test/fixtures/templates/layouts/entries.html.cut +4 -4
  276. data/test/fixtures/templates/layouts/standard.html.cut +1 -0
  277. data/test/fixtures/templates/layouts/variables.html.cut +1 -1
  278. data/test/fixtures/templates/publishing/templates/layouts/static.html.cut +1 -1
  279. data/test/fixtures/templates/publishing/templates/layouts/static.rtf.cut +1 -0
  280. data/test/fixtures/templates/template_class/complex_template.html.cut +2 -2
  281. data/test/fixtures/templates/template_class/complex_template.pdf.cut +2 -2
  282. data/test/fixtures/templates/template_class/default_template_style.html.cut +1 -1
  283. data/test/fixtures/templates/template_class/images_with_template.html.cut +2 -2
  284. data/test/fixtures/templates/template_class/slots_template.html.cut +2 -2
  285. data/test/fixtures/templates/template_class/slots_template.pdf.cut +2 -2
  286. data/test/fixtures/user_manager/config/user_levels.yml +9 -0
  287. data/test/functional/test_application.rb +7 -7
  288. data/test/functional/test_back.rb +352 -97
  289. data/test/functional/test_front.rb +71 -20
  290. data/test/functional/test_user_manager.rb +284 -0
  291. data/test/javascript/env.js +13505 -0
  292. data/test/javascript/test_markdown.rb +43 -3
  293. data/test/support/custom_matchers.rb +3 -2
  294. data/test/test_helper.rb +50 -9
  295. data/test/test_javascript.rb +13 -13
  296. data/test/ui_helper.rb +1 -1
  297. data/test/unit/test_alias.rb +79 -8
  298. data/test/unit/test_asset_bundler.rb +220 -0
  299. data/test/unit/test_assets.rb +213 -0
  300. data/test/unit/test_async.rb +55 -0
  301. data/test/unit/test_authentication.rb +52 -39
  302. data/test/unit/test_boxes.rb +20 -15
  303. data/test/unit/test_changesets.rb +261 -0
  304. data/test/unit/test_content.rb +73 -33
  305. data/test/unit/test_content_inheritance.rb +18 -18
  306. data/test/unit/test_extensions.rb +26 -0
  307. data/test/unit/test_fields.rb +303 -16
  308. data/test/unit/test_formats.rb +267 -34
  309. data/test/unit/test_helpers.rb +79 -2
  310. data/test/unit/test_images.rb +10 -0
  311. data/test/unit/test_layouts.rb +21 -13
  312. data/test/unit/test_modifications.rb +648 -0
  313. data/test/unit/test_page.rb +6 -2
  314. data/test/unit/test_permissions.rb +101 -27
  315. data/test/unit/test_piece.rb +4 -4
  316. data/test/unit/test_plugins.rb +3 -2
  317. data/test/unit/test_publishing.rb +332 -0
  318. data/test/unit/test_render.rb +118 -67
  319. data/test/unit/test_revisions.rb +546 -0
  320. data/test/unit/test_schema.rb +83 -1
  321. data/test/unit/test_search.rb +59 -0
  322. data/test/unit/test_serialisation.rb +2 -47
  323. data/test/unit/test_site.rb +217 -108
  324. data/test/unit/test_storage.rb +26 -0
  325. data/test/unit/test_structure.rb +2 -2
  326. data/test/unit/test_styles.rb +90 -75
  327. data/test/unit/test_table_scoping.rb +21 -17
  328. data/test/unit/test_templates.rb +75 -69
  329. data/test/{slow → unit}/test_visibility.rb +78 -22
  330. metadata +528 -221
  331. data/application/css/add_alias_dialogue.scss +0 -27
  332. data/application/css/min/14c2a35812c443001b15d8b12a4780f88c678035.css +0 -1
  333. data/application/css/min/565d4c25e82148acb01c45c8d675b37a08676d77.css +0 -1
  334. data/application/css/min/84dbe894ea96eafd321c30823d630817bfc4b03b.css +0 -1
  335. data/application/css/spontaneous.scss +0 -111
  336. data/application/css/unsupported.scss +0 -16
  337. data/application/css/variables.scss +0 -80
  338. data/application/js/min/2a0c2962537a3181fedfff5c92596ba6d3122dc9.js +0 -3
  339. data/application/js/min/4cf1c493d3379ecba5287758c61238034c0893f9.js +0 -2
  340. data/application/js/min/78ac6b99d96750bb6b9f9aad4cb9cd91cd03f391.js +0 -3
  341. data/application/js/min/b8abf302a824c35385ff517b34111e1710ff3b37.js +0 -2
  342. data/application/js/min/c8efb9b9f7c3f6613fcebc6be60f605b6570a382.js +0 -90
  343. data/application/static/diagonal-texture.png +0 -0
  344. data/application/static/editing-0-noise.png +0 -0
  345. data/application/static/editing-1-noise.png +0 -0
  346. data/application/static/editing-texture-1.png +0 -0
  347. data/application/static/editing-texture.png +0 -0
  348. data/application/static/editing-toolbar-shadow-bottom.png +0 -0
  349. data/application/static/editing-toolbar-shadow-top.png +0 -0
  350. data/application/static/inner-glow.png +0 -0
  351. data/application/static/item-buttons-highlight.png +0 -0
  352. data/application/static/item-buttons.png +0 -0
  353. data/application/static/paper-texture-dark.png +0 -0
  354. data/application/static/plus_alt.svg +0 -8
  355. data/application/static/select-arrow-root.png +0 -0
  356. data/application/static/slot-up-arrow.png +0 -0
  357. data/application/static/spontaneous.png +0 -0
  358. data/lib/cutaneous/context_helper.rb +0 -187
  359. data/lib/cutaneous/preview_context.rb +0 -32
  360. data/lib/cutaneous/preview_renderer.rb +0 -10
  361. data/lib/cutaneous/publish_context.rb +0 -10
  362. data/lib/cutaneous/publish_renderer.rb +0 -14
  363. data/lib/cutaneous/publish_template.rb +0 -62
  364. data/lib/cutaneous/publish_token_parser.rb +0 -8
  365. data/lib/cutaneous/renderer.rb +0 -124
  366. data/lib/cutaneous/request_context.rb +0 -9
  367. data/lib/cutaneous/request_renderer.rb +0 -15
  368. data/lib/cutaneous/request_template.rb +0 -11
  369. data/lib/cutaneous/request_token_parser.rb +0 -9
  370. data/lib/cutaneous/token_parser.rb +0 -125
  371. data/lib/cutaneous.rb +0 -48
  372. data/lib/spontaneous/render/context_base.rb +0 -143
  373. data/lib/spontaneous/render/development_renderer.rb +0 -14
  374. data/lib/spontaneous/render/engine.rb +0 -19
  375. data/lib/spontaneous/render/format/html.rb +0 -5
  376. data/lib/spontaneous/render/format.rb +0 -75
  377. data/lib/spontaneous/render/helpers/script_helper.rb +0 -17
  378. data/lib/spontaneous/render/helpers/stylesheet_helper.rb +0 -16
  379. data/lib/spontaneous/render/helpers.rb +0 -14
  380. data/lib/spontaneous/render/preview_context.rb +0 -8
  381. data/lib/spontaneous/render/preview_renderer.rb +0 -24
  382. data/lib/spontaneous/render/publish_context.rb +0 -22
  383. data/lib/spontaneous/render/published_renderer.rb +0 -53
  384. data/lib/spontaneous/render/publishing_renderer.rb +0 -16
  385. data/lib/spontaneous/render/render_cache.rb +0 -26
  386. data/lib/spontaneous/render/renderer.rb +0 -50
  387. data/lib/spontaneous/render/request_context.rb +0 -8
  388. data/lib/spontaneous/render.rb +0 -214
  389. data/test/experimental/test_cutaneous.rb +0 -309
  390. data/test/fixtures/application/css/test.less +0 -5
  391. data/test/slow/test_publishing.rb +0 -1006
  392. /data/application/css/{developer.scss → developer.css.scss} +0 -0
  393. /data/application/js/vendor/{jquery-1.7.1.min.js → jquery.js} +0 -0
  394. /data/application/static/{location-arrow.png → location-arrow-c1c1d3ca472481c61a0a5f8cb289d743.png} +0 -0
  395. /data/application/static/{missing.png → missing-911ce6dbd9f4602e0f3fbcd7e78846a2.png} +0 -0
  396. /data/application/static/{orange-down-arrow.png → orange-down-arrow-395ae1929e8662b2ff0977daf12c35bb.png} +0 -0
  397. /data/application/static/{page-browser-next.png → page-browser-next-ce781a242c23b980b99b9db7abc20b05.png} +0 -0
  398. /data/application/static/{plus-box.png → plus-box-dcde74a1e496f68298c9b443caa1c5d5.png} +0 -0
  399. /data/application/static/{select-arrow.png → select-arrow-6e7dd3745b00e934b0d7a3250c46558b.png} +0 -0
  400. /data/application/static/{slot-down-arrow.png → slot-down-arrow-59ad5f5ee5b52a7ebd00bca4b3104194.png} +0 -0
  401. /data/application/static/{splash.png → splash-65b493a714df9b8b3ab170103401b53d.png} +0 -0
  402. /data/application/static/{spot.png → spot-71fab1d2f065034f5fc15e7bea2ad36c.png} +0 -0
  403. /data/application/static/{spot.svg → spot-8505041082d8d3bbe8d34c29dddb3b7d.svg} +0 -0
  404. /data/application/static/{texture.png → texture-03f7627e8264b1d607113ab32c593a58.png} +0 -0
@@ -1,1006 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path('../../test_helper', __FILE__)
4
-
5
-
6
- class PublishingTest < MiniTest::Spec
7
-
8
- def self.site_root
9
- @site_root
10
- end
11
-
12
- def self.startup
13
- @site_root = Dir.mktmpdir
14
- FileUtils.cp_r(File.expand_path(File.dirname(__FILE__) / "../fixtures/templates/publishing/templates"), @site_root)
15
- end
16
-
17
- def self.shutdown
18
- teardown_site
19
- end
20
-
21
- def self.shutdown
22
- S::Content.delete_all_revisions! rescue nil
23
- end
24
-
25
- @@now = Time.now
26
-
27
- def setup
28
- @site = setup_site(self.class.site_root)
29
- Site.publishing_method = :immediate
30
- end
31
-
32
- def assert_content_equal(result, compare)
33
- serialised_columns = [:field_store, :entry_store]
34
- columns = Content.columns - serialised_columns
35
- columns.each do |col|
36
- assert_equal(result[col], compare[col], "Column '#{col}' should be equal")
37
- end
38
- serialised_columns.each do |col|
39
- result.send(col).should == compare.send(col)
40
- end
41
- end
42
-
43
- context "publishing" do
44
-
45
- setup do
46
- Sequel.datetime_class.stubs(:now).returns(@@now)
47
- Time.stubs(:now).returns(@@now)
48
-
49
- # DB.logger = Logger.new($stdout)
50
- Content.delete
51
-
52
- class Page < Spontaneous::Page
53
- field :title, :string, :default => "New Page"
54
- box :things
55
- end
56
- class Piece < Spontaneous::Piece
57
- box :things
58
- end
59
-
60
- 2.times do |i|
61
- c = Page.new(:uid => i)
62
- 2.times do |j|
63
- d = Piece.new(:uid => "#{i}.#{j}")
64
- c.things << d
65
- 2.times do |k|
66
- d.things << Page.new(:uid => "#{i}.#{j}.#{k}")
67
- d.save
68
- end
69
- end
70
- c.save
71
- end
72
- end
73
-
74
- teardown do
75
- PublishingTest.send(:remove_const, :Page) rescue nil
76
- PublishingTest.send(:remove_const, :Piece) rescue nil
77
- Content.delete
78
- Change.delete
79
- DB.logger = nil
80
- end
81
-
82
- context "data sources" do
83
-
84
- should "have the right names" do
85
- Content.revision_table(23).should == '__r00023_content'
86
- Content.revision_table(nil).should == 'content'
87
- end
88
-
89
- should "be recognisable" do
90
- Content.revision_table?('content').should be_false
91
- Content.revision_table?('__r00023_content').should be_true
92
- Content.revision_table?('__r00023_not').should be_false
93
- Content.revision_table?('subscribers').should be_false
94
- end
95
-
96
- should "be switchable within blocks" do
97
- Content.dataset.should be_content_revision
98
- Content.with_revision(23) do
99
- Content.revision.should ==23
100
- Content.dataset.should be_content_revision(23)
101
- end
102
- Content.dataset.should be_content_revision
103
- Content.revision.should be_nil
104
- end
105
-
106
- should "know which revision is active" do
107
- Content.with_revision(23) do
108
- Content.revision.should == 23
109
- end
110
- end
111
-
112
- should "understand the with_editable" do
113
- Content.with_revision(23) do
114
- Content.dataset.should be_content_revision(23)
115
- Content.with_editable do
116
- Content.dataset.should be_content_revision
117
- end
118
- Content.dataset.should be_content_revision(23)
119
- end
120
- Content.dataset.should be_content_revision
121
- end
122
-
123
- should "understand with_published" do
124
- Site.stubs(:published_revision).returns(99)
125
- Content.with_published do
126
- Content.dataset.should be_content_revision(99)
127
- Content.with_editable do
128
- Content.dataset.should be_content_revision
129
- end
130
- Content.dataset.should be_content_revision(99)
131
- end
132
- Content.dataset.should be_content_revision
133
- end
134
-
135
- should "be stackable" do
136
- Content.dataset.should be_content_revision
137
- Content.with_revision(23) do
138
- Content.dataset.should be_content_revision(23)
139
- Content.with_revision(24) do
140
- Content.dataset.should be_content_revision(24)
141
- end
142
- Content.dataset.should be_content_revision(23)
143
- end
144
- Content.dataset.should be_content_revision
145
- end
146
-
147
- should "reset datasource after an exception" do
148
- Content.dataset.should be_content_revision
149
- begin
150
- Content.with_revision(23) do
151
- Content.dataset.should be_content_revision(23)
152
- raise Exception.new
153
- end
154
- rescue Exception
155
- end
156
- Content.dataset.should be_content_revision
157
- end
158
-
159
- should "read revision from the environment if present" do
160
- ENV["SPOT_REVISION"] = '1001'
161
- Content.with_published do
162
- Content.dataset.should be_content_revision(1001)
163
- end
164
- ENV.delete("SPOT_REVISION")
165
- end
166
-
167
- context "subclasses" do
168
- setup do
169
- class ::Subclass < Page; end
170
- end
171
-
172
- teardown do
173
- Object.send(:remove_const, :Subclass)
174
- end
175
-
176
- should "set all subclasses to use the same dataset" do
177
- Content.with_revision(23) do
178
- Subclass.revision.should ==23
179
- Subclass.dataset.should be_content_revision(23, Subclass.schema_id)
180
- # piece wasn't loaded until this point
181
- Piece.dataset.should be_content_revision(23)
182
- Piece.revision.should == 23
183
- end
184
- Subclass.dataset.should be_content_revision(nil, Subclass.schema_id)
185
- Piece.dataset.should be_content_revision(nil)
186
- end
187
- end
188
- end
189
-
190
- context "content revisions" do
191
- setup do
192
- @revision = 1
193
- end
194
- teardown do
195
- Content.delete_revision(@revision)
196
- Content.delete_revision(@revision+1) rescue nil
197
- end
198
- should "be testable for existance" do
199
- Content.revision_exists?(@revision).should be_false
200
- Content.create_revision(@revision)
201
- Content.revision_exists?(@revision).should be_true
202
- end
203
- should "be deletable en masse" do
204
- tables = (1..10).map { |i| Content.revision_table(i).to_sym }
205
- tables.each do |t|
206
- DB.create_table(t){Integer :id}
207
- end
208
- tables.each do |t|
209
- DB.tables.include?(t).should be_true
210
- end
211
- Content.delete_all_revisions!
212
- tables.each do |t|
213
- DB.tables.include?(t).should be_false
214
- end
215
- end
216
-
217
- should "be creatable from current content" do
218
- DB.tables.include?(Content.revision_table(@revision).to_sym).should be_false
219
- Content.create_revision(@revision)
220
- DB.tables.include?(Content.revision_table(@revision).to_sym).should be_true
221
- count = Content.count
222
- Content.with_revision(@revision) do
223
- Content.count.should == count
224
- Content.all.each do |published|
225
- Content.with_editable do
226
- e = Content[published.id]
227
- e.should == published
228
- end
229
- end
230
- end
231
- end
232
-
233
- should "be creatable from any revision" do
234
- revision = 2
235
- source_revision = @revision
236
- source_revision_count = nil
237
-
238
- Content.create_revision(source_revision)
239
-
240
- Content.with_revision(source_revision) do
241
- Content.filter(:depth => 0).limit(1).each do |c|
242
- c.destroy
243
- end
244
- source_revision_count = Content.count
245
- end
246
-
247
- Content.count.should == source_revision_count + 7
248
-
249
- Content.create_revision(revision, source_revision)
250
-
251
- Content.with_revision(revision) do
252
- Content.count.should == source_revision_count
253
- Content.all.each do |published|
254
- Content.with_revision(source_revision) do
255
- e = Content[published.id]
256
- e.should == published
257
- end
258
- end
259
- end
260
- end
261
-
262
- should "have the correct indexes" do
263
- Content.create_revision(@revision)
264
- content_indexes = DB.indexes(:content)
265
- published_indexes = DB.indexes(Content.revision_table(@revision))
266
- # made slightly complex by the fact that the index names depend on the table names
267
- # (which are different)
268
- assert_same_elements published_indexes.values, content_indexes.values
269
- end
270
-
271
-
272
- context "incremental publishing" do
273
- setup do
274
- @initial_revision = 1
275
- @final_revision = 2
276
- Content.create_revision(@initial_revision)
277
- Content.delete_revision(@final_revision) rescue nil
278
- Content.delete_revision(@final_revision+1) rescue nil
279
- # DB.logger = Logger.new($stdout)
280
- end
281
-
282
- teardown do
283
- begin
284
- Content.delete_revision(@initial_revision)
285
- Content.delete_revision(@final_revision)
286
- Content.delete_revision(@final_revision+1)
287
- rescue
288
- end
289
- DB.logger = nil
290
- end
291
-
292
- should "duplicate changes to only a single item" do
293
- editable1 = Content.first(:uid => '1.0')
294
- editable1.label.should be_nil
295
- editable1.label = "published"
296
- editable1.save
297
- # editable1.reload
298
- editable2 = Content.first(:uid => '1.1')
299
- editable2.label = "unpublished"
300
- editable2.save
301
- # editable2.reload
302
- Content.publish(@final_revision, [editable1.id])
303
- editable1.reload
304
- Content.with_revision(@final_revision) do
305
- published = Content[editable1.id]
306
- unpublished = Content[editable2.id]
307
- assert_content_equal(published, editable1)
308
-
309
- # published.should == editable1
310
- unpublished.should_not == editable2
311
- end
312
- end
313
-
314
- should "publish additions to contents of a page" do
315
- editable1 = Content.first(:uid => '0')
316
- new_content = Content.new(:uid => "new")
317
-
318
- editable1.things << new_content
319
- editable1.save
320
- Content.publish(@final_revision, [editable1.id])
321
- new_content.reload
322
- editable1.reload
323
- Content.with_revision(@final_revision) do
324
- published1 = Content[editable1.id]
325
- published2 = Content[new_content.id]
326
- # published2.should == new_content
327
- assert_content_equal(published2, new_content)
328
- # published1.should == editable1
329
- assert_content_equal(published1, editable1)
330
- end
331
- end
332
-
333
- should "publish deletions to contents of page" do
334
- editable1 = Content.first(:uid => '0')
335
- deleted = editable1.pieces.first
336
- editable1.pieces.first.destroy
337
- Content.publish(@final_revision, [editable1.id])
338
- editable1.reload
339
- Content.with_revision(@final_revision) do
340
- published1 = Content[editable1.id]
341
- assert_content_equal(published1, editable1)
342
- # published1.should == editable1
343
- Content[deleted.id].should be_nil
344
- end
345
- end
346
-
347
- should "publish page additions" do
348
- editable1 = Content.first(:uid => '0')
349
- new_page = Page.new(:uid => "new")
350
- slot = editable1.pieces.first
351
- slot.things << new_page
352
- editable1.save
353
- slot.save
354
- new_page.save
355
- Content.publish(@final_revision, [editable1.id])
356
- new_page.reload
357
- editable1.reload
358
- slot.reload
359
- Content.with_revision(@final_revision) do
360
- published1 = Content[editable1.id]
361
- published2 = Content[new_page.id]
362
- published3 = Content[slot.id]
363
- # published1.should == editable1
364
- assert_content_equal(published1, editable1)
365
- # published2.should == new_page
366
- assert_content_equal(published2, new_page)
367
- # published3.should == slot
368
- assert_content_equal(published3, slot)
369
- end
370
- end
371
-
372
- should "not publish changes to existing pages unless explicitly asked" do
373
- editable1 = Content.first(:uid => '0')
374
- editable1.things << Content.new(:uid => "added")
375
- editable1.save
376
- editable2 = Content.first(:uid => '0.0.0')
377
- new_content = Content.new(:uid => "new")
378
- editable2.things << new_content
379
- editable2.save
380
- Content.publish(@final_revision, [editable1.id])
381
- editable1.reload
382
- editable2.reload
383
- new_content.reload
384
- Content.with_revision(@final_revision) do
385
- published1 = Content[editable1.id]
386
- Content.first(:uid => "added").should_not be_nil
387
- published3 = Content[editable2.id]
388
- assert_content_equal(published1, editable1)
389
- # published1.should == editable1
390
- published3.should_not == editable2
391
- published3.uid.should_not == "new"
392
- end
393
- Content.publish(@final_revision+1, [editable2.id])
394
- editable1.reload
395
- editable2.reload
396
- new_content.reload
397
- Content.with_revision(@final_revision+1) do
398
- published1 = Content[editable1.id]
399
- # published1.should == editable1
400
- assert_content_equal(published1, editable1)
401
- assert_content_equal(published1, editable1)
402
- published3 = Content[editable2.id]
403
- # published3.should == editable2
404
- assert_content_equal(published3, editable2)
405
- published4 = Content[editable2.pieces.first.id]
406
- # published4.should == editable2.pieces.first
407
- assert_content_equal(published4, editable2.pieces.first)
408
- end
409
- end
410
- end
411
-
412
-
413
- end
414
-
415
- context "modification timestamps" do
416
- setup do
417
- end
418
- should "register creation date of all content" do
419
- c = Content.create
420
- c.created_at.should == @@now
421
- p = Page.create
422
- p.created_at.should == @@now
423
- end
424
-
425
- should "register modification date of all content" do
426
- now = @@now + 100
427
- Time.stubs(:now).returns(now)
428
- c = Content.first
429
- (c.modified_at.to_i - @@now.to_i).abs.should <= 1
430
- c.label = "changed"
431
- c.save
432
- (c.modified_at - now).abs.should <= 1
433
- end
434
-
435
- should "update page timestamps on modification of a piece" do
436
- Time.stubs(:now).returns(@@now+3600)
437
- page = Page.first
438
- (page.modified_at.to_i - @@now.to_i).abs.should <= 1
439
- content = page.pieces.first
440
- content.page.should == page
441
- content.label = "changed"
442
- content.save
443
- page.reload
444
- page.modified_at.to_i.should == @@now.to_i + 3600
445
- end
446
-
447
- should "update page timestamp on addition of piece" do
448
- Sequel.datetime_class.stubs(:now).returns(@@now+3600)
449
- page = Page.first
450
- content = Content[page.pieces.first.id]
451
- content.things << Piece.new
452
- content.save
453
- content.modified_at.to_i.should == @@now.to_i + 3600
454
- page.reload
455
- page.modified_at.to_i.should == @@now.to_i + 3600
456
- end
457
- end
458
-
459
- context "change sets" do
460
- setup do
461
- Change.delete
462
- end
463
-
464
- should "have a testable state" do
465
- Change.recording?.should be_false
466
- Change.record do
467
- Change.recording?.should be_true
468
- end
469
- Change.recording?.should be_false
470
- end
471
-
472
- should "be created on updating a page's attributes" do
473
- page = Page.first
474
- Change.record do
475
- page.label = "changed"
476
- page.save
477
- end
478
- page.reload
479
- Change.count.should == 1
480
- change = Change.first
481
- change.modified_list.must_be_instance_of(Array)
482
- change.modified_list.length.should == 1
483
- change.modified_list.should == [page.id]
484
- change.modified.should == [page]
485
- # don't know why this fails in certain circumstances
486
- # change.created_at.to_i.should == @@now.to_i
487
- end
488
-
489
- should "be created on updating a page's content" do
490
- page = Page.first
491
- content = Content[page.pieces.first.id]
492
- Change.record do
493
- content.label = "changed"
494
- content.save
495
- end
496
- page.reload
497
- Change.count.should == 1
498
- change = Change.first
499
- change.modified_list.must_be_instance_of(Array)
500
- change.modified_list.length.should == 1
501
- change.modified_list.should == [page.id]
502
- change.modified.should == [page]
503
- end
504
-
505
- should "include newly created pages" do
506
- page = Page.first
507
- content = Content[page.pieces.first.id]
508
- new_page = nil
509
- Change.record do
510
- new_page = Page.new
511
- page.things << new_page
512
- page.save
513
- end
514
- new_page.reload
515
- page = Content[page.id]
516
- new_page = Content[new_page.id]
517
- Change.count.should == 1
518
- change = Change.first
519
- change.modified_list.must_be_instance_of(Array)
520
- change.modified_list.length.should == 2
521
- change.modified_list.should == [page.id, new_page.id]
522
- change.modified.should == [page, new_page]
523
- end
524
-
525
-
526
- should "handle being called twice" do
527
- page = Page.first
528
- p2 = Page.filter(~{:id => page.id}).first
529
- Change.record do
530
- page.label = "changed"
531
- page.save
532
- Change.record do
533
- p2.label = "another change"
534
- p2.save
535
- end
536
- end
537
- page.reload
538
- p2.reload
539
- Change.count.should == 1
540
- change = Change.first
541
- change.modified_list.must_be_instance_of(Array)
542
- change.modified_list.length.should == 2
543
- change.modified_list.should == [page.id, p2.id]
544
- change.modified.should == [page, p2]
545
- end
546
-
547
- should "not create a change if nothing actually happens" do
548
- Change.record do
549
- end
550
- Change.count.should == 0
551
- end
552
-
553
- should "reset state despite exceptions" do
554
- page = Page.first
555
- begin
556
- Change.record do
557
- page.label = "caught"
558
- page.save
559
- Change.recording?.should be_true
560
- raise Exception.new
561
- end
562
- rescue Exception
563
- end
564
- Change.recording?.should be_false
565
- Change.count.should == 1
566
- end
567
-
568
-
569
-
570
- should "correctly calculate dependencies" do
571
- Change.delete
572
- changes = [
573
- [201, 202],
574
- [104, 105, 106],
575
- [100, 101],
576
- [100],
577
- [101],
578
- [100],
579
- [101, 102],
580
- [102],
581
- [101],
582
- [102, 103],
583
- [103, 104],
584
- [200],
585
- [200, 201],
586
- [201]
587
- ]
588
- publish_sets = [
589
- [1, 13, 14, 12],
590
- [2, 11, 8, 10, 3, 4, 5, 6, 7, 9]
591
- ]
592
- changes.each_with_index do |ids, i|
593
- Change.insert(:id => (i+1), :modified_list => ids.to_json)
594
- ids.each { |id| Content.insert(:id => id) rescue nil }
595
- end
596
- result = Change.outstanding
597
- result.must_be_instance_of(Array)
598
- result.length.should == 2
599
- page_ids = [
600
- [200, 201, 202],
601
- [100, 101, 102, 103, 104, 105, 106]
602
- ]
603
- result.each_with_index do |set, i|
604
- changes = publish_sets[i].map { |id| Change[id] }
605
- pages = page_ids[i].map { |id| Content[id] }
606
- set.must_be_instance_of(Spontaneous::Collections::ChangeSet)
607
- set.changes.should == changes
608
- set.pages.should == pages
609
- end
610
- end
611
-
612
- should "serialize changes to json" do
613
- Change.delete
614
- @page1 = Page.new(:title => "Page \"1\"", :path => "/page-1")
615
- @page2 = Page.new(:title => "Page 2", :path => "/page-2")
616
- @page1[:id] = 1
617
- @page2[:id] = 2
618
- @page1.stubs(:path).returns("/page-1")
619
- @page2.stubs(:path).returns("/page-2")
620
- Content.stubs(:[]).with(1).returns(@page1)
621
- Content.stubs(:[]).with(2).returns(@page2)
622
- change = Change.new
623
- change.push(@page1)
624
- change.push(@page2)
625
- change.save
626
- result = Change.outstanding
627
- result.first.export.should == {
628
- :changes => [{:id => change.id, :created_at => change.created_at.to_s, :page_ids => [1, 2]}],
629
- :pages => [
630
- {:id => 1, :title => "Page \"1\"", :path => "/page-1", :depth => 0},
631
- {:id => 2, :title => "Page 2", :path => "/page-2", :depth => 0}
632
- ]
633
- }
634
- end
635
-
636
- should "silently work around deleted content" do
637
- Change.delete
638
- @page1 = Page.create(:title => "Page \"1\"", :path => "/page-1")
639
- @page2 = Page.create(:title => "Page 2", :path => "/page-2")
640
- @page3 = Page.create(:title => "Page 3", :path => "/page-3")
641
- change = Change.new
642
- change.push(@page1)
643
- change.push(@page2)
644
- change.push(@page3)
645
- change.save
646
- @page2.destroy
647
- result = Change.outstanding
648
- result.first.export.must_be_instance_of(Hash)
649
- end
650
- end
651
-
652
- context "publication timestamps" do
653
- setup do
654
- @revision = 1
655
- Content.delete_revision(@revision+1)
656
- end
657
- teardown do
658
- Content.delete_revision(@revision)
659
- Content.delete_revision(@revision+1)
660
- end
661
-
662
- should "set correct timestamps on first publish" do
663
- Content.first.first_published_at.should be_nil
664
- Content.first.last_published_at.should be_nil
665
- Content.publish(@revision)
666
- Content.first.first_published_at.to_i.should == @@now.to_i
667
- Content.first.last_published_at.to_i.should == @@now.to_i
668
- Content.first.first_published_revision.should == @revision
669
- Content.with_editable do
670
- Content.first.first_published_at.to_i.should == @@now.to_i
671
- Content.first.last_published_at.to_i.should == @@now.to_i
672
- Content.first.first_published_revision.should == @revision
673
- end
674
- Content.with_revision(@revision) do
675
- Content.first.first_published_at.to_i.should == @@now.to_i
676
- Content.first.last_published_at.to_i.should == @@now.to_i
677
- Content.first.first_published_revision.should == @revision
678
- end
679
- end
680
-
681
- should "set correct timestamps on later publishes" do
682
- Content.first.first_published_at.should be_nil
683
- Content.publish(@revision)
684
- Content.first.first_published_at.to_i.should == @@now.to_i
685
- c = Content.create
686
- c.first_published_at.should be_nil
687
- Sequel.datetime_class.stubs(:now).returns(@@now+100)
688
- Content.publish(@revision+1)
689
- Content.first.first_published_at.to_i.should == @@now.to_i
690
- Content.first.last_published_at.to_i.should == @@now.to_i + 100
691
- Content.with_editable do
692
- c = Content[c.id]
693
- c.first_published_at.to_i.should == @@now.to_i + 100
694
- end
695
- Content.with_revision(@revision+1) do
696
- c = Content[c.id]
697
- c.first_published_at.to_i.should == @@now.to_i + 100
698
- end
699
- end
700
-
701
- should "not set publishing date for items not published" do
702
- Content.publish(@revision)
703
- page = Content.first
704
- page.uid = "fish"
705
- page.save
706
- added = Content.create
707
- added.first_published_at.should be_nil
708
- Content.publish(@revision+1, [page])
709
- page.first_published_at.to_i.should == @@now.to_i
710
- added.first_published_at.should be_nil
711
- added.last_published_at.should be_nil
712
- end
713
-
714
- should "not set publishing dates if exception raised in passed block" do
715
- Content.first.first_published_at.should be_nil
716
- begin
717
- Content.publish(@revision) do
718
- raise Exception
719
- end
720
- rescue Exception; end
721
- Content.first.first_published_at.should be_nil
722
- end
723
-
724
- should "delete revision tables if exception raised in passed block" do
725
- Content.revision_exists?(@revision).should be_false
726
- begin
727
- Content.publish(@revision) do
728
- Content.revision_exists?(@revision).should be_true
729
- Content.revision.should == @revision
730
- raise Exception
731
- end
732
- rescue Exception; end
733
- Content.revision_exists?(@revision).should be_false
734
- end
735
-
736
- should "always publish all if no previous revisions exist" do
737
- page = Content.first
738
- Content.filter(:first_published_at => nil).count.should == Content.count
739
- Content.publish(@revision, [page])
740
- Content.filter(:first_published_at => nil).count.should == 0
741
- end
742
- end
743
- context "site publishing" do
744
- setup do
745
- Content.delete
746
- @revision = 3
747
- State.delete
748
- Change.delete
749
- State.create(:revision => @revision, :published_revision => 2)
750
- State.revision.should == @revision
751
- end
752
-
753
- teardown do
754
- Content.delete_revision(@revision)
755
- Revision.delete
756
- Change.delete
757
- end
758
-
759
- should "work with lists of change sets" do
760
- change1 = Change.new
761
- change1.modified_list = [1, 2, 3]
762
- change1.save
763
- change2 = Change.new
764
- change2.modified_list = [3, 4, 5]
765
- change2.save
766
- change3 = Change.new
767
- change3.modified_list = [8, 9]
768
- change3.save
769
- Content.expects(:publish).with(@revision, [1, 2, 3, 4, 5])
770
- Site.publish_changes([change1.id, change2.id])
771
- end
772
-
773
- should "issue a publish_all if passed list including all change sets" do
774
- change1 = Change.new
775
- change1.modified_list = [1, 2, 3]
776
- change1.save
777
- change2 = Change.new
778
- change2.modified_list = [3, 4, 5]
779
- change2.save
780
- change3 = Change.new
781
- change3.modified_list = [8, 9]
782
- change3.save
783
- Content.expects(:publish).with(@revision, nil)
784
- Site.publish_changes([change1.id, change2.id, change3.id])
785
- end
786
-
787
- should "publish all" do
788
- Content.expects(:publish).with(@revision, nil)
789
- Site.publish_all
790
- end
791
-
792
- ## publishing individual pages without dependencies is a bad idea
793
- ## if this were to be an option we would have to do it properly
794
- ## and calculate the full revision set involved
795
- # should "publish individual pages" do
796
- # page = Page.new
797
- # Content.expects(:publish).with(@revision, [page])
798
- # Site.publish_page(page)
799
- # end
800
-
801
- should "record date and time of publish" do
802
- Content.expects(:publish).with(@revision, nil)
803
- Revision.expects(:create).with(:revision => @revision, :published_at => @@now)
804
- Site.publish_all
805
- end
806
- should "bump revision after a publish" do
807
- Site.publish_all
808
- Site.revision.should == @revision + 1
809
- Site.published_revision.should == @revision
810
- end
811
- should "delete included changes after partial publish" do
812
- change1 = Change.new
813
- change1.modified_list = [1, 2, 3]
814
- change1.save
815
- change2 = Change.new
816
- change2.modified_list = [3, 4, 5]
817
- change2.save
818
- Change.count.should == 2
819
- Site.publish_changes([change1.id])
820
- Change.count.should == 1
821
- Change[change1.id].should be_nil
822
- end
823
- should "delete all changes after full publish" do
824
- change1 = Change.new
825
- change1.modified_list = [1, 2, 3]
826
- change1.save
827
- change2 = Change.new
828
- change2.modified_list = [3, 4, 5]
829
- change2.save
830
- Change.count.should == 2
831
- Site.publish_all
832
- Change.count.should == 0
833
- end
834
-
835
- should "not delete changes after an exception during publish" do
836
- change1 = Change.new
837
- change1.modified_list = [1, 2, 3]
838
- change1.save
839
- change2 = Change.new
840
- change2.modified_list = [3, 4, 5]
841
- change2.save
842
- Content.expects(:publish).at_least_once.raises(Exception)
843
- Change.count.should == 2
844
- begin
845
- silence_logger { Site.publish_all }
846
- rescue Exception; end
847
- Change.count.should == 2
848
- begin
849
- silence_logger { Site.publish_changes([change1]) }
850
- rescue Exception; end
851
- Change.count.should == 2
852
- end
853
-
854
- should "set Site.pending_revision before publishing" do
855
- Content.expects(:publish).with(@revision, nil) { Site.pending_revision == @revision }
856
- Site.publish_all
857
- end
858
-
859
- should "reset Site.pending_revision after publishing" do
860
- Site.publish_all
861
- Site.pending_revision.should be_nil
862
- end
863
-
864
- should "not update first_published or last_published if rendering fails" do
865
- c = Content.create
866
- Content.first.first_published_at.should be_nil
867
- Spontaneous::Page.expects(:order).returns([c])
868
- c.expects(:render).raises(Exception)
869
- begin
870
- silence_logger { Site.publish_all }
871
- rescue Exception; end
872
- Content.with_editable do
873
- Content.first.first_published_at.should be_nil
874
- end
875
- end
876
-
877
- should "clean up state on publishing failure" do
878
- Site.pending_revision.should be_nil
879
- Content.revision_exists?(@revision).should be_false
880
- # don't like peeking into implementation here but don't know how else
881
- # to simulate the right error
882
- root = Page.create()
883
- Spontaneous::Page.expects(:order).returns([root])
884
- root.expects(:render).raises(Exception)
885
- begin
886
- silence_logger { Site.publish_all }
887
- rescue Exception; end
888
- Site.pending_revision.should be_nil
889
- Content.revision_exists?(@revision).should be_false
890
- begin
891
- silence_logger { Site.publish_changes([change1]) }
892
- rescue Exception; end
893
- Site.pending_revision.should be_nil
894
- Content.revision_exists?(@revision).should be_false
895
- end
896
- end
897
-
898
- context "rendering" do
899
- setup do
900
- @revision = 2
901
- Content.delete_revision(@revision)
902
- Content.delete
903
- State.delete
904
- State.create(:revision => @revision, :published_revision => 2)
905
- Site.revision.should == @revision
906
-
907
-
908
- class ::PublishablePage < Page; end
909
- class ::DynamicPublishablePage < Page; end
910
- PublishablePage.box :box1
911
- DynamicPublishablePage.box :box1
912
- PublishablePage.layout :"static"
913
- PublishablePage.layout :"dynamic"
914
-
915
- DynamicPublishablePage.layout :"static"
916
- DynamicPublishablePage.layout :"dynamic"
917
-
918
- DynamicPublishablePage.request { show "/about" }
919
-
920
- @home = PublishablePage.create(:title => 'Home')
921
- @home.layout = :"dynamic"
922
- @about = PublishablePage.create(:title => "About", :slug => "about")
923
- @blog = PublishablePage.create(:title => "Blog", :slug => "blog")
924
- @post1 = PublishablePage.create(:title => "Post 1", :slug => "post-1")
925
- @post2 = PublishablePage.create(:title => "Post 2", :slug => "post-2")
926
- @post3 = PublishablePage.create(:title => "Post 3", :slug => "post-3")
927
- @news = DynamicPublishablePage.create(:title => "News", :slug => "news")
928
- @contact = DynamicPublishablePage.create(:title => "Contact", :slug => "contact")
929
- @contact.layout = :dynamic
930
- @home.box1 << @about
931
- @home.box1 << @blog
932
- @home.box1 << @news
933
- @home.box1 << @contact
934
- @blog.box1 << @post1
935
- @blog.box1 << @post2
936
- @blog.box1 << @post3
937
- @pages = [@home, @about, @blog, @news, @post1, @post2, @post3]
938
- @pages.each { |p| p.save }
939
- Site.publish_all
940
- end
941
-
942
- teardown do
943
- Content.delete_revision(@revision)
944
- Content.delete_revision(@revision+1)
945
- Content.delete
946
- State.delete
947
- Object.send(:remove_const, :PublishablePage) rescue nil
948
- Object.send(:remove_const, :DynamicPublishablePage) rescue nil
949
- end
950
-
951
- should "put its files into a numbered revision directory" do
952
- Spontaneous.revision_dir(2).should == @site.root / 'cache/revisions' / "00002"
953
- end
954
-
955
- should "symlink the latest revision to 'current'" do
956
- revision_dir = @site.revision_root / "00002"
957
- current_dir = @site.revision_root / "current"
958
- File.exists?(current_dir).should be_true
959
- File.symlink?(current_dir).should be_true
960
- File.readlink(current_dir).should == revision_dir
961
- end
962
-
963
- should "produce rendered versions of each page" do
964
- revision_dir = @site.revision_root / "00002"
965
- file = result = nil
966
- @pages.each do |page|
967
- case page.slug
968
- when "" # root is a dynamic page with no request handler
969
- file = revision_dir / "dynamic/index.html.cut"
970
- result = "Page: '#{page.title}' {{Time.now.to_i}}\n"
971
- when "news" # news produces a static template but has a request handler
972
- file = revision_dir / "protected/news/index.html"
973
- result = "Page: 'News'\n"
974
- when "contact" # contact is both dynamic and has a request handler
975
- file = revision_dir / "dynamic/contact/index.html.cut"
976
- result = "Page: 'Contact' {{Time.now.to_i}}\n"
977
- else # the other pages are static
978
- file = revision_dir / "static/#{page.path}/index.html"
979
- result = "Page: '#{page.title}'\n"
980
- end
981
- assert File.exists?(file), "File '#{file}' should exist"
982
- File.read(file).should == result
983
- end
984
- revision_dir = @site.revision_root / "00002"
985
- Dir[S.root / "public/**/*"].each do |public_file|
986
- site_file = public_file.gsub(%r(^#{S.root}/), '')
987
- publish_file = revision_dir / site_file
988
- File.exists?(publish_file).should be_true
989
- end
990
- end
991
-
992
- should "generate a config.ru file pointing to the current root" do
993
- config_file = @site.revision_root / "00002/config.ru"
994
- File.exists?(config_file).should be_true
995
- File.read(config_file).should =~ %r(#{Spontaneous.root})
996
- end
997
-
998
- should "transparently support previously unknown formats by assuming a simple HTML like rendering model" do
999
- PublishablePage.add_format :rtf
1000
- Content.delete_revision(@revision+1)
1001
- Site.publish_all
1002
- File.read("#{@site.revision_root}/00003/static/index.rtf").should == "RICH!\n"
1003
- end
1004
- end
1005
- end
1006
- end