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
@@ -50,21 +50,22 @@ class PermissionsTest < MiniTest::Spec
50
50
  end
51
51
 
52
52
  should "provide a sorted list of all levels" do
53
- Permissions::UserLevel.all.should == [:none, :editor, :admin, :designer, :root]
53
+ Permissions::UserLevel.all.map(&:to_sym).should == [:none, :editor, :admin, :designer, :root]
54
54
  end
55
+
55
56
  should "provide a list of all levels <= provided level" do
56
- Permissions::UserLevel.all(:editor).should == [:none, :editor]
57
- Permissions::UserLevel.all(:designer).should == [:none, :editor, :admin, :designer]
57
+ Permissions::UserLevel.all(:editor).map(&:to_sym).should == [:none, :editor]
58
+ Permissions::UserLevel.all(:designer).map(&:to_sym).should == [:none, :editor, :admin, :designer]
58
59
  end
59
60
 
60
61
  should "have a root level" do
61
62
  Permissions::UserLevel.root.should == Permissions::UserLevel::Root
62
63
  end
63
64
 
64
- should "have a root level that is always greater than other levels" do
65
+ should "have a root level that is always greater than other levels except root" do
65
66
  Permissions::UserLevel.root.should > Permissions::UserLevel['designer']
66
67
  Permissions::UserLevel.root.should >= Permissions::UserLevel['designer']
67
- Permissions::UserLevel.root.should > Permissions::UserLevel::Root
68
+ Permissions::UserLevel.root.should_not > Permissions::UserLevel::Root
68
69
  Permissions::UserLevel.root.should >= Permissions::UserLevel::Root
69
70
  Permissions::UserLevel[:root].should == Permissions::UserLevel::Root
70
71
  end
@@ -97,8 +98,8 @@ class PermissionsTest < MiniTest::Spec
97
98
  end
98
99
  should "Have a developer flag" do
99
100
  Permissions::UserLevel[:none].developer?.should be_false
100
- Permissions::UserLevel[:editor].developer?.should be_nil
101
- Permissions::UserLevel[:admin].developer?.should be_nil
101
+ Permissions::UserLevel[:editor].developer?.should be_false
102
+ Permissions::UserLevel[:admin].developer?.should be_false
102
103
  Permissions::UserLevel[:designer].developer?.should be_true
103
104
  Permissions::UserLevel[:root].developer?.should be_true
104
105
  end
@@ -112,14 +113,58 @@ class PermissionsTest < MiniTest::Spec
112
113
  :name => "A Person",
113
114
  :email => "person@example.org",
114
115
  :login => "person",
115
- :password => "xxxxxx",
116
- :password_confirmation => "xxxxxx"
116
+ :password => "xxxxxxxx"
117
+ }
118
+ @valid2 = {
119
+ :name => "Another Person",
120
+ :email => "person2@example.org",
121
+ :login => "person2",
122
+ :password => "xxxxxxxxxx"
117
123
  }
118
124
  end
119
125
 
120
126
  teardown do
121
127
  end
122
128
 
129
+ should "be retrievable as a list" do
130
+ user1 = Permissions::User.create(@valid.merge(:level => S::Permissions[:editor]))
131
+ user2 = Permissions::User.create(@valid2.merge(:level => S::Permissions[:admin]))
132
+ user1.logged_in!("196.168.1.11")
133
+ exported = Permissions::User.export(nil)
134
+ exported[:users].should == [
135
+ { :id => user1.id, :name => "A Person", :email => "person@example.org", :login => "person", :level => "editor",
136
+ :keys => [:last_access_at => @now.httpdate, :last_access_ip => "196.168.1.11"], :disabled => false },
137
+ { :id => user2.id, :name => "Another Person", :email => "person2@example.org", :login => "person2", :level => "admin", :disabled => false,
138
+ :keys => [] }
139
+ ]
140
+ exported[:levels].should == [
141
+ { :level => "none", :can_publish => false, :is_admin => false },
142
+ { :level => "editor", :can_publish => false, :is_admin => false },
143
+ { :level => "admin", :can_publish => false, :is_admin => true },
144
+ { :level => "designer", :can_publish => true, :is_admin => false },
145
+ { :level => "root", :can_publish => true, :is_admin => true }
146
+ ]
147
+ end
148
+
149
+ should "filter exported user list to remove users with a higher level" do
150
+ user1 = Permissions::User.create(@valid.merge(:level => S::Permissions[:editor]))
151
+ user2 = Permissions::User.create(@valid2.merge(:level => S::Permissions[:admin]))
152
+ user3 = Permissions::User.create(@valid.merge(:login => "person3", :email => "person3@example.com", :level => S::Permissions[:root]))
153
+ user1.logged_in!("196.168.1.11")
154
+ exported = Permissions::User.export(user2)
155
+ exported[:users].should == [
156
+ { :id => user1.id, :name => "A Person", :email => "person@example.org", :login => "person", :level => "editor", :disabled => false,
157
+ :keys => [:last_access_at => @now.httpdate, :last_access_ip => "196.168.1.11"] },
158
+ { :id => user2.id, :name => "Another Person", :email => "person2@example.org", :login => "person2", :level => "admin", :disabled => false,
159
+ :keys => [] }
160
+ ]
161
+ exported[:levels].should == [
162
+ { :level => "none", :can_publish => false, :is_admin => false },
163
+ { :level => "editor", :can_publish => false, :is_admin => false },
164
+ { :level => "admin", :can_publish => false, :is_admin => true },
165
+ ]
166
+ end
167
+
123
168
  should "be creatable with valid params" do
124
169
  user = Permissions::User.new(@valid)
125
170
  user.save.must_be_instance_of(Permissions::User)
@@ -161,7 +206,7 @@ class PermissionsTest < MiniTest::Spec
161
206
  user.errors[:login].should_not be_blank
162
207
  end
163
208
 
164
- should "reject duplicate logins" do
209
+ should "reject duplicate logins on creation" do
165
210
  user1 = Permissions::User.create(@valid)
166
211
  user2 = Permissions::User.new(@valid)
167
212
  user2.save
@@ -169,22 +214,23 @@ class PermissionsTest < MiniTest::Spec
169
214
  user2.errors[:login].should_not be_blank
170
215
  end
171
216
 
172
- should "require a non-blank password & password_confirmation" do
173
- user = Permissions::User.new(@valid.merge(:password => "", :password_confirmation => ""))
174
- user.save
175
- user.valid?.should be_false
176
- user.errors[:password].should_not be_blank
217
+ should "reject duplicate logins" do
218
+ user1 = Permissions::User.create(@valid)
219
+ user2 = Permissions::User.create(@valid.merge(:login => "other"))
220
+ user2.update_fields({:login => @valid[:login]}, [:login])
221
+ user2.valid?.should be_false
222
+ user2.errors[:login].should_not be_blank
177
223
  end
178
224
 
179
- should "require a matching password & password_confirmation" do
180
- user = Permissions::User.new(@valid.merge(:password => "sdfsddfsdf", :password_confirmation => "sdf"))
225
+ should "require a non-blank password" do
226
+ user = Permissions::User.new(@valid.merge(:password => ""))
181
227
  user.save
182
228
  user.valid?.should be_false
183
- user.errors[:password_confirmation].should_not be_blank
229
+ user.errors[:password].should_not be_blank
184
230
  end
185
231
 
186
- should "require passwords to be at least 6 characters" do
187
- user = Permissions::User.new(@valid.merge(:password => "12345", :password_confirmation => "12345"))
232
+ should "require passwords to be at least 8 characters" do
233
+ user = Permissions::User.new(@valid.merge(:password => "1234567"))
188
234
  user.save
189
235
  user.valid?.should be_false
190
236
  user.errors[:password].should_not be_blank
@@ -289,16 +335,38 @@ class PermissionsTest < MiniTest::Spec
289
335
 
290
336
  should "have a test for developer status" do
291
337
  @user.update(:level => Permissions::UserLevel.editor)
292
- @user.developer?.should be_nil
338
+ @user.developer?.should be_false
293
339
  @user.update(:level => Permissions::UserLevel.designer)
294
340
  @user.developer?.should be_true
295
341
  end
296
342
 
343
+ should "be testable for ability to publish depending on their user level" do
344
+ @user.update(:level => Permissions::UserLevel.editor)
345
+ @user.can_publish?.should be_false
346
+ @user.update(:level => Permissions::UserLevel.designer)
347
+ @user.can_publish?.should be_true
348
+ end
349
+
350
+ should "be testable for admin privileges" do
351
+ @user.update(:level => Permissions::UserLevel.none)
352
+ @user.admin?.should be_false
353
+ @user.update(:level => Permissions::UserLevel.editor)
354
+ @user.admin?.should be_false
355
+ @user.update(:level => Permissions::UserLevel.designer)
356
+ @user.admin?.should be_false
357
+ @user.update(:level => Permissions::UserLevel.admin)
358
+ @user.admin?.should be_true
359
+ @user.update(:level => Permissions::UserLevel.root)
360
+ @user.admin?.should be_true
361
+ end
362
+
297
363
  should "serialise to JSON" do
298
364
  @user.export.should == {
299
365
  :name => "A Person",
300
366
  :email => "person@example.org",
301
367
  :login => "person",
368
+ :can_publish => false,
369
+ :admin => false,
302
370
  :developer => false
303
371
  }
304
372
  end
@@ -313,8 +381,7 @@ class PermissionsTest < MiniTest::Spec
313
381
  :name => "A Person",
314
382
  :email => "person@example.org",
315
383
  :login => "person",
316
- :password => "xxxxxx",
317
- :password_confirmation => "xxxxxx"
384
+ :password => "xxxxxxxx"
318
385
  }
319
386
  end
320
387
 
@@ -426,10 +493,10 @@ class PermissionsTest < MiniTest::Spec
426
493
  context "Guards" do
427
494
  setup do
428
495
  Permissions::User.delete
429
- @visitor = Permissions::User.create(:email => "visitor@example.com", :login => "visitor", :name => "visitor", :password => "visitorpass", :password_confirmation => "visitorpass")
430
- @editor = Permissions::User.create(:email => "editor@example.com", :login => "editor", :name => "editor", :password => "editorpass", :password_confirmation => "editorpass")
431
- @admin = Permissions::User.create(:email => "admin@example.com", :login => "admin", :name => "admin", :password => "adminpass", :password_confirmation => "adminpass")
432
- @root = Permissions::User.create(:email => "root@example.com", :login => "root", :name => "root", :password => "rootpass", :password_confirmation => "rootpass")
496
+ @visitor = Permissions::User.create(:email => "visitor@example.com", :login => "visitor", :name => "visitor", :password => "visitorpass")
497
+ @editor = Permissions::User.create(:email => "editor@example.com", :login => "editor", :name => "editor", :password => "editorpass")
498
+ @admin = Permissions::User.create(:email => "admin@example.com", :login => "admin", :name => "admin", :password => "adminpass")
499
+ @root = Permissions::User.create(:email => "root@example.com", :login => "root", :name => "root", :password => "rootpass")
433
500
  @editor.update(:level => Permissions::UserLevel.editor)
434
501
  @admin.update(:level => Permissions::UserLevel.admin)
435
502
  @root.update(:level => Permissions::UserLevel.root)
@@ -813,5 +880,12 @@ class PermissionsTest < MiniTest::Spec
813
880
  # end
814
881
 
815
882
  end
883
+
884
+ should "determine what fields are visible in the exoported schema" do
885
+ schema = Site.schema.export(@editor)
886
+ c_schema = schema["C"]
887
+ c_schema[:fields].map { |f| f[:name] }.should == %w(editor_level mixed_level default_level)
888
+ c_schema[:boxes].map { |b| b[:name] }.should == %w(editor_level mixed_level default_level)
889
+ end
816
890
  end
817
891
  end
@@ -84,13 +84,13 @@ class PieceTest < MiniTest::Spec
84
84
 
85
85
  should "be available from their containing page" do
86
86
  @page.content.length.should == 3
87
- @page.content.should == [@f1, @f2, @f3]
88
- @page.content.last.class.should == Fridge
87
+ Set.new(@page.content).should == Set.new([@f1, @f2, @f3])
88
+ Set.new(@page.content.map(&:class)).should == Set.new([::Piece, ::Piece, Fridge])
89
89
  end
90
90
 
91
91
  should "have a link to their pieces" do
92
- @f1.entry.should == @page.pieces.first
93
- @f2.entry.should == @page.pieces.first.pieces.first
92
+ @f1.entry.should == @page.contents.first
93
+ @f2.entry.should == @page.contents.first.contents.first
94
94
  end
95
95
  end
96
96
  end
@@ -14,6 +14,7 @@ class PluginsTest < MiniTest::Spec
14
14
 
15
15
 
16
16
  klass = Class.new(Spontaneous::Page)
17
+ klass.box :box1
17
18
  Object.send(:const_set, :Page, klass)
18
19
  klass = Class.new(Spontaneous::Piece)
19
20
  Object.send(:const_set, :Piece, klass)
@@ -51,7 +52,6 @@ class PluginsTest < MiniTest::Spec
51
52
  Site.publishing_method = :immediate
52
53
  State.delete
53
54
  Content.delete
54
- Change.delete
55
55
  @site = Spontaneous.instance
56
56
  page = ::Page.new
57
57
  page.save
@@ -61,7 +61,6 @@ class PluginsTest < MiniTest::Spec
61
61
  teardown do
62
62
  State.delete
63
63
  Content.delete
64
- Change.delete
65
64
  end
66
65
 
67
66
  should "load their init.rb file" do
@@ -145,7 +144,9 @@ class PluginsTest < MiniTest::Spec
145
144
  should "make content classes available to rest of app" do
146
145
  defined?(::SchemaPlugin).should == "constant"
147
146
  ::SchemaPlugin::External.fields.length.should == 1
147
+ page = ::Page.new
148
148
  piece = ::SchemaPlugin::External.new(:a => "A Field")
149
+ page.box1 << piece
149
150
  piece.render.should == "plugins/templates/external.html.cut\n"
150
151
  end
151
152
  end
@@ -0,0 +1,332 @@
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
+ template_source = File.expand_path(File.dirname(__FILE__) / "../fixtures/templates/publishing/templates")
15
+ FileUtils.cp_r(template_source, @site_root)
16
+ end
17
+
18
+ def self.shutdown
19
+ S::Content.delete_all_revisions! rescue nil
20
+ end
21
+
22
+ @@now = Time.now
23
+
24
+ def setup
25
+ @site = setup_site(self.class.site_root)
26
+ @now = @@now
27
+ Site.publishing_method = :immediate
28
+ end
29
+
30
+ context "publishing" do
31
+
32
+ setup do
33
+ stub_time(@@now)
34
+
35
+ # DB.logger = Logger.new($stdout)
36
+ Content.delete
37
+
38
+ class Page < Spontaneous::Page
39
+ field :title, :string, :default => "New Page"
40
+ box :things
41
+ end
42
+ class Piece < Spontaneous::Piece
43
+ box :things
44
+ end
45
+
46
+ count = 0
47
+ 2.times do |i|
48
+ c = Page.new(:uid => i)
49
+ count += 1
50
+ 2.times do |j|
51
+ d = Piece.new(:uid => "#{i}.#{j}")
52
+ c.things << d
53
+ count += 1
54
+ 2.times do |k|
55
+ d.things << Page.new(:uid => "#{i}.#{j}.#{k}")
56
+ d.save
57
+ count += 1
58
+ end
59
+ end
60
+ c.save
61
+ end
62
+ end
63
+
64
+ teardown do
65
+ PublishingTest.send(:remove_const, :Page) rescue nil
66
+ PublishingTest.send(:remove_const, :Piece) rescue nil
67
+ Content.delete
68
+ DB.logger = nil
69
+ end
70
+
71
+
72
+
73
+
74
+ context "site publishing" do
75
+ setup do
76
+ Content.delete
77
+ @revision = 3
78
+ State.delete
79
+ State.create(:revision => @revision, :published_revision => 2)
80
+ State.revision.should == @revision
81
+ end
82
+
83
+ teardown do
84
+ Content.delete_revision(@revision)
85
+ Revision.delete
86
+ end
87
+
88
+ should "delete any conflicting revision tables" do
89
+ S::Content.create_revision(3)
90
+ Site.publish_all
91
+ end
92
+
93
+
94
+ should "issue a publish_all if passed page id list including all pages (in any order)" do
95
+ skip "Implement after scheduled publishes"
96
+ end
97
+
98
+ should "publish all" do
99
+ Content.expects(:publish).with(@revision, nil)
100
+ Site.publish_all
101
+ end
102
+
103
+ should "record date and time of publish" do
104
+ Content.expects(:publish).with(@revision, nil)
105
+ Revision.expects(:create).with(:revision => @revision, :published_at => @now)
106
+ Site.publish_all
107
+ end
108
+
109
+ should "bump revision after a publish" do
110
+ Site.publish_all
111
+ Site.revision.should == @revision + 1
112
+ Site.published_revision.should == @revision
113
+ end
114
+
115
+ should "not delete scheduled changes after an exception during publish" do
116
+ skip "Implement after scheduled publishes"
117
+ end
118
+
119
+ should "set Site.pending_revision before publishing" do
120
+ Content.expects(:publish).with(@revision, nil) { Site.pending_revision == @revision }
121
+ Site.publish_all
122
+ end
123
+
124
+ should "reset Site.pending_revision after publishing" do
125
+ Site.publish_all
126
+ Site.pending_revision.should be_nil
127
+ end
128
+
129
+ should "not update first_published or last_published if rendering fails" do
130
+ c = Content.create
131
+ c.first_published_at.should be_nil
132
+ Spontaneous::Page.expects(:order).returns([c])
133
+ # c.expects(:render).raises(Exception)
134
+ begin
135
+ silence_logger { Site.publish_all }
136
+ # Site.publish_all
137
+ rescue Exception; end
138
+ c.reload
139
+ Content.with_editable do
140
+ c.first_published_at.should be_nil
141
+ end
142
+ end
143
+
144
+ should "clean up state on publishing failure" do
145
+ Site.pending_revision.should be_nil
146
+ Content.revision_exists?(@revision).should be_false
147
+ # don't like peeking into implementation here but don't know how else
148
+ # to simulate the right error
149
+ root = Page.create()
150
+ Spontaneous::Page.expects(:order).returns([root])
151
+ output = root.output(:html)
152
+ output.expects(:render_using).raises(Exception)
153
+ root.expects(:outputs).at_least_once.returns([output])
154
+ begin
155
+ silence_logger { Site.publish_all }
156
+ rescue Exception; end
157
+ Site.pending_revision.should be_nil
158
+ Content.revision_exists?(@revision).should be_false
159
+ begin
160
+ silence_logger { Site.publish_pages([change1]) }
161
+ rescue Exception; end
162
+ Site.pending_revision.should be_nil
163
+ Content.revision_exists?(@revision).should be_false
164
+ end
165
+ end
166
+
167
+
168
+ context "rendering" do
169
+ setup do
170
+ @revision = 2
171
+ Content.delete_revision(@revision)
172
+ Content.delete
173
+ State.delete
174
+ State.create(:revision => @revision, :published_revision => 2)
175
+ Site.revision.should == @revision
176
+
177
+
178
+ class ::PublishablePage < Page; end
179
+ class ::DynamicPublishablePage < Page; end
180
+ PublishablePage.box :box1
181
+ DynamicPublishablePage.box :box1
182
+ PublishablePage.layout :"static"
183
+ PublishablePage.layout :"dynamic"
184
+
185
+ DynamicPublishablePage.layout :"static"
186
+ DynamicPublishablePage.layout :"dynamic"
187
+
188
+ DynamicPublishablePage.request { show "/about" }
189
+
190
+ @home = PublishablePage.create(:title => 'Home')
191
+ @home.layout = :"dynamic"
192
+ @about = PublishablePage.create(:title => "About", :slug => "about")
193
+ @blog = PublishablePage.create(:title => "Blog", :slug => "blog")
194
+ @post1 = PublishablePage.create(:title => "Post 1", :slug => "post-1")
195
+ @post2 = PublishablePage.create(:title => "Post 2", :slug => "post-2")
196
+ @post3 = PublishablePage.create(:title => "Post 3", :slug => "post-3")
197
+ @news = DynamicPublishablePage.create(:title => "News", :slug => "news")
198
+ @contact = DynamicPublishablePage.create(:title => "Contact", :slug => "contact")
199
+ @contact.layout = :dynamic
200
+ @home.box1 << @about
201
+ @home.box1 << @blog
202
+ @home.box1 << @news
203
+ @home.box1 << @contact
204
+ @blog.box1 << @post1
205
+ @blog.box1 << @post2
206
+ @blog.box1 << @post3
207
+ @pages = [@home, @about, @blog, @news, @post1, @post2, @post3]
208
+ @pages.each { |p| p.save }
209
+ Site.publish_all
210
+ end
211
+
212
+ teardown do
213
+ Content.delete_revision(@revision)
214
+ Content.delete_revision(@revision+1)
215
+ Content.delete
216
+ State.delete
217
+ Object.send(:remove_const, :PublishablePage) rescue nil
218
+ Object.send(:remove_const, :DynamicPublishablePage) rescue nil
219
+ end
220
+
221
+ should "put its files into a numbered revision directory" do
222
+ Spontaneous.revision_dir(2).should == Pathname.new(@site.root / 'cache/revisions' / "00002").realpath.to_s
223
+ end
224
+
225
+ should "symlink the latest revision to 'current'" do
226
+ revision_dir = @site.revision_root / "00002"
227
+ current_dir = @site.revision_root / "current"
228
+ File.exists?(current_dir).should be_true
229
+ File.symlink?(current_dir).should be_true
230
+ File.readlink(current_dir).should == revision_dir
231
+ end
232
+
233
+ should "have access to the current revision within the templates" do
234
+ revision_dir = @site.revision_root / "00002"
235
+ File.read(revision_dir / "static/about.html").should == "Page: 'About' 2\n"
236
+ end
237
+
238
+ should "produce rendered versions of each page" do
239
+ revision_dir = @site.revision_root / "00002"
240
+ file = result = nil
241
+ @pages.each do |page|
242
+ case page.slug
243
+ when "" # root is a dynamic page with no request handler
244
+ file = revision_dir / "dynamic/index.html.cut"
245
+ result = "Page: '#{page.title}' {{Time.now.to_i}}\n"
246
+ when "news" # news produces a static template but has a request handler
247
+ file = revision_dir / "protected/news.html"
248
+ result = "Page: 'News' 2\n"
249
+ when "contact" # contact is both dynamic and has a request handler
250
+ file = revision_dir / "dynamic/contact.html.cut"
251
+ result = "Page: 'Contact' {{Time.now.to_i}}\n"
252
+ else # the other pages are static
253
+ file = revision_dir / "static#{page.path}.html"
254
+ result = "Page: '#{page.title}' 2\n"
255
+ end
256
+ assert File.exists?(file), "File '#{file}' should exist"
257
+ File.read(file).should == result
258
+ end
259
+ revision_dir = @site.revision_root / "00002"
260
+ Dir[S.root / "public/**/*"].each do |public_file|
261
+ site_file = public_file.gsub(%r(^#{S.root}/), '')
262
+ publish_file = revision_dir / site_file
263
+ File.exists?(publish_file).should be_true
264
+ end
265
+ end
266
+
267
+ should "generate a config.ru file pointing to the current root" do
268
+ config_file = @site.revision_root / "00002/config.ru"
269
+ File.exists?(config_file).should be_true
270
+ File.read(config_file).should =~ %r(#{Spontaneous.root})
271
+ end
272
+
273
+ should "transparently support previously unknown formats by assuming a simple HTML like rendering model" do
274
+ PublishablePage.add_output :rtf
275
+ Content.delete_revision(@revision+1)
276
+ Site.publish_all
277
+ File.read("#{@site.revision_root}/00003/static/index.rtf").should == "RICH!\n"
278
+ end
279
+
280
+ should "respect a format's #dynamic? setting when deciding a rendered templates location xxx" do
281
+ PublishablePage.add_output :rtf, :dynamic => true
282
+ Content.delete_revision(@revision+1)
283
+ Site.publish_all
284
+ File.read("#{@site.revision_root}/00003/dynamic/index.rtf.cut").should == "RICH!\n"
285
+ end
286
+
287
+ context "hooks & triggers" do
288
+ setup do
289
+ end
290
+
291
+ should "after_publish hook should be fired after publish is complete" do
292
+ publish1 = mock
293
+ publish1.expects(:finished).with(@revision+1)
294
+ publish2 = mock
295
+ publish2.expects(:finished)
296
+ Site.after_publish do |revision|
297
+ publish1.finished(revision)
298
+ end
299
+ Site.after_publish do
300
+ publish2.finished
301
+ end
302
+ Content.delete_revision(@revision+1)
303
+ Site.publish_all
304
+ Site.published_revision.should == @revision+1
305
+ end
306
+
307
+ should "abort publish if hook raises error" do
308
+ published_revision = @revision+1
309
+ Site.pending_revision.should be_nil
310
+ Content.revision_exists?(published_revision).should be_false
311
+
312
+ Site.after_publish do |revision|
313
+ raise "Boom"
314
+ end
315
+
316
+ begin
317
+ silence_logger { Site.publish_all }
318
+ rescue Exception; end
319
+
320
+ Site.pending_revision.should be_nil
321
+ Site.published_revision.should == @revision
322
+ Content.revision_exists?(published_revision).should be_false
323
+ S::Revision.first(:revision => published_revision).should be_nil
324
+ previous_root = Spontaneous.revision_dir(@revision)
325
+ published_root = Spontaneous.revision_dir(published_revision)
326
+ symlink = Pathname.new Spontaneous.revision_dir
327
+ symlink.realpath.to_s.should == Pathname.new(previous_root).realpath.to_s
328
+ end
329
+ end
330
+ end
331
+ end
332
+ end