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
@@ -32,15 +32,17 @@ class BackTest < MiniTest::Spec
32
32
 
33
33
  def setup
34
34
  @site = setup_site(self.class.site_root)
35
+ Spot::Permissions::UserLevel.reset!
36
+ Spot::Permissions::UserLevel.init!
35
37
  end
36
38
 
37
39
 
38
- def auth_post(path, params={})
39
- post(path, params.merge("__key" => @key))
40
+ def auth_post(path, params={}, env={})
41
+ post(path, params.merge("__key" => @key), env)
40
42
  end
41
43
 
42
- def auth_get(path, params={})
43
- get(path, params.merge("__key" => @key))
44
+ def auth_get(path, params={}, env={})
45
+ get(path, params.merge("__key" => @key), env)
44
46
  end
45
47
 
46
48
  context "Editing interface" do
@@ -52,6 +54,7 @@ class BackTest < MiniTest::Spec
52
54
  config.stubs(:auto_login).returns('root')
53
55
  config.stubs(:default_charset).returns('utf-8')
54
56
  config.stubs(:publishing_method).returns(:immediate)
57
+ config.stubs(:services).returns(nil)
55
58
  config.stubs(:site_domain).returns('example.org')
56
59
  config.stubs(:site_id).returns('example_org')
57
60
  config.stubs(:site_id).returns('example_org')
@@ -70,8 +73,8 @@ class BackTest < MiniTest::Spec
70
73
  # Spontaneous::Rack::Back.application.send :set, :show_exceptions, false
71
74
 
72
75
  # annoying to have to do this, but there you go
73
- @user = Spontaneous::Permissions::User.create(:email => "root@example.com", :login => "root", :name => "root", :password => "rootpass", :password_confirmation => "rootpass")
74
- @user.update(:level => Spontaneous::Permissions.root)
76
+ @user = Spontaneous::Permissions::User.create(:email => "root@example.com", :login => "root", :name => "root name", :password => "rootpass")
77
+ @user.update(:level => Spontaneous::Permissions[:editor])
75
78
  @user.save
76
79
  @key = "c5AMX3r5kMHX2z9a5ExLKjAmCcnT6PFf22YQxzb4Codj"
77
80
  @key.stubs(:user).returns(@user)
@@ -79,6 +82,7 @@ class BackTest < MiniTest::Spec
79
82
  @user.stubs(:access_keys).returns([@key])
80
83
 
81
84
  Spontaneous::Permissions::User.stubs(:[]).with(:login => 'root').returns(@user)
85
+ Spontaneous::Permissions::User.stubs(:[]).with(@user.id).returns(@user)
82
86
  Spontaneous::Permissions::AccessKey.stubs(:authenticate).with(@key).returns(@key)
83
87
  Spontaneous::Permissions::AccessKey.stubs(:valid?).with(@key, @user).returns(true)
84
88
 
@@ -114,6 +118,7 @@ class BackTest < MiniTest::Spec
114
118
  end
115
119
  box :in_progress do
116
120
  allow Job
121
+ allow Image
117
122
  end
118
123
 
119
124
  box :featured_jobs do
@@ -121,6 +126,10 @@ class BackTest < MiniTest::Spec
121
126
  end
122
127
  end
123
128
 
129
+ class AdminAccess < Page
130
+ field :title
131
+ field :private, :user_level => :root
132
+ end
124
133
 
125
134
 
126
135
  @home = HomePage.new(:title => "Home")
@@ -140,12 +149,14 @@ class BackTest < MiniTest::Spec
140
149
  @home.in_progress << @job2
141
150
  @home.in_progress << @job3
142
151
 
152
+
143
153
  @home.save
144
154
  @home = Content[@home.id]
155
+
145
156
  end
146
157
 
147
158
  teardown do
148
- [:Page, :Piece, :HomePage, :Job, :Project, :Image, :LinkedJob].each { |klass| BackTest.send(:remove_const, klass) rescue nil }
159
+ [:Page, :Piece, :HomePage, :Job, :Project, :Image, :LinkedJob, :AdminAccess].each { |klass| BackTest.send(:remove_const, klass) rescue nil }
149
160
  Spontaneous::Permissions::User.delete
150
161
  Content.delete
151
162
  end
@@ -176,26 +187,62 @@ class BackTest < MiniTest::Spec
176
187
  assert_equal S::JSON.encode(page.export), last_response.body
177
188
  end
178
189
 
179
- should "return json for all types" do
180
- auth_get "/@spontaneous/types"
181
- assert last_response.ok?
190
+ should "respect user levels in page json" do
191
+ page = AdminAccess.create
192
+ auth_get "/@spontaneous/page/#{page.id}"
193
+ result = Spot::JSON.parse(last_response.body)
194
+ result[:fields].map { |f| f[:name] }.should == ["title"]
195
+ end
196
+
197
+ should "return the typelist as part of the site metadata" do
198
+ auth_get "/@spontaneous/metadata"
199
+ assert last_response.ok?, "Should have recieved a 200 OK but got a #{ last_response.status }"
182
200
  last_response.content_type.should == "application/json;charset=utf-8"
183
- assert_equal Site.schema.serialise_http, last_response.body
201
+ result = Spot::JSON.parse(last_response.body)
202
+ result[:types].stringify_keys.should == Site.schema.export(@user)
184
203
  end
185
204
 
186
- should "return scripts from js dir" do
187
- get '/@spontaneous/js/test.js'
205
+ should "apply the current user's permissions to the exported schema" do
206
+ auth_get "/@spontaneous/metadata"
188
207
  assert last_response.ok?
189
- # last_response.content_type.should == "application/javascript;charset=utf-8"
190
- last_response.content_type.should == "application/javascript"
191
- assert_equal File.read(@app_dir / 'js/test.js'), last_response.body
208
+ result = Spot::JSON.parse(last_response.body)
209
+ result[:types][:'BackTest.AdminAccess'][:fields].map { |f| f[:name] }.should == %w(title)
192
210
  end
193
211
 
194
- should "return less rendered to css from css dir" do
195
- get '/@spontaneous/css/test.css'
196
- assert last_response.ok?
197
- last_response.content_type.should == "text/css;charset=utf-8"
198
- assert_equal "h1 { color: #4d926f; }\n", last_response.body
212
+ should "return info about the current user in the metadata" do
213
+ auth_get "/@spontaneous/metadata"
214
+ assert last_response.ok?, "Should have recieved a 200 OK but got a #{ last_response.status }"
215
+ result = Spot::JSON.parse(last_response.body)
216
+ result[:user][:email].should == "root@example.com"
217
+ result[:user][:login].should == "root"
218
+ result[:user][:name].should == "root name"
219
+ result[:user][:developer].should == false # although the login is root, the level is :editor
220
+ end
221
+
222
+ should "return an empty list of service URLs by default" do
223
+ auth_get "/@spontaneous/metadata"
224
+ assert last_response.ok?, "Should have recieved a 200 OK but got a #{ last_response.status }"
225
+ result = Spot::JSON.parse(last_response.body)
226
+ result[:services].should == []
227
+ end
228
+
229
+ should "return the configured list of service URLs in the metadata" do
230
+ Site.config.stubs(:services).returns([
231
+ {:title => "Google Analytics", :url => "http://google.com/analytics"},
232
+ {:title => "Facebook", :url => "http://facebook.com/spontaneous"}
233
+ ])
234
+ auth_get "/@spontaneous/metadata"
235
+ assert last_response.ok?, "Should have recieved a 200 OK but got a #{ last_response.status }"
236
+ result = Spot::JSON.parse(last_response.body)
237
+ result[:services].should == Site.config.services
238
+ end
239
+
240
+ should "return scripts from js dir" do
241
+ get '/@spontaneous/js/test.js'
242
+ assert last_response.ok?, "Expected a 200 but received a #{last_response.status}"
243
+ last_response.content_type.should == "application/javascript"
244
+ # Sprockets appends sone newlines and a semicolon onto our test file
245
+ assert_equal File.read(@app_dir / 'js/test.js') + "\n;\n", last_response.body
199
246
  end
200
247
 
201
248
  should "return a site map for root by default" do
@@ -227,15 +274,47 @@ class BackTest < MiniTest::Spec
227
274
  assert last_response.status == 404
228
275
  end
229
276
 
277
+ should "return the correct Last-Modified header for the site map" do
278
+ now = Time.at(Time.now.to_i + 10000)
279
+ S::Site.stubs(:modified_at).returns(now)
280
+ auth_get '/@spontaneous/map'
281
+ Time.httpdate(last_response.headers["Last-Modified"]).should == now
282
+ auth_get "/@spontaneous/location#{@project1.path}"
283
+ Time.httpdate(last_response.headers["Last-Modified"]).should == now
284
+ end
285
+
286
+ should "reply with a 304 Not Modified if the site hasn't been updated since last request" do
287
+ datestring = "Sat, 03 Mar 2012 00:49:44 GMT"
288
+ now = Time.httpdate(datestring)
289
+ S::Site.stubs(:modified_at).returns(now)
290
+ auth_get "/@spontaneous/map/#{@home.id}", {}, {"HTTP_IF_MODIFIED_SINCE" => datestring}
291
+ last_response.status.should == 304
292
+ auth_get "/@spontaneous/map", {}, {"HTTP_IF_MODIFIED_SINCE" => datestring}
293
+ last_response.status.should == 304
294
+ auth_get "/@spontaneous/location#{@project1.path}", {}, {"HTTP_IF_MODIFIED_SINCE" => datestring}
295
+ last_response.status.should == 304
296
+ end
297
+
298
+ should "return the map data if the site has been updated since last request" do
299
+ datestring1 = "Sat, 03 Mar 2012 00:49:44 GMT"
300
+ datestring2 = "Sat, 03 Mar 2012 01:49:44 GMT"
301
+ now = Time.httpdate(datestring2)
302
+ S::Site.stubs(:modified_at).returns(now)
303
+ auth_get "/@spontaneous/map/#{@home.id}", {}, {"HTTP_IF_MODIFIED_SINCE" => datestring1}
304
+ last_response.status.should == 200
305
+ auth_get "/@spontaneous/location#{@project1.path}", {}, {"HTTP_IF_MODIFIED_SINCE" => datestring1}
306
+ last_response.status.should == 200
307
+ end
308
+
230
309
  should "reorder pieces" do
231
310
  auth_post "/@spontaneous/content/#{@job2.id}/position/0"
232
311
  assert last_response.ok?
233
312
  last_response.content_type.should == "application/json;charset=utf-8"
234
313
  @home.reload
235
- @home.in_progress.pieces.first.id.should == @job2.id
314
+ @home.in_progress.contents.first.id.should == @job2.id
236
315
 
237
316
  page = Content[@home.id]
238
- page.in_progress.pieces.first.id.should == @job2.id
317
+ page.in_progress.contents.first.id.should == @job2.id
239
318
  end
240
319
 
241
320
  # should "reorder pages" do
@@ -280,6 +359,7 @@ class BackTest < MiniTest::Spec
280
359
  @home.fields.title.value.should == "Updated title"
281
360
  @home.fields.introduction.value.should == "<p>Updated intro</p>\n"
282
361
  end
362
+
283
363
  should "update box field values" do
284
364
  box = @job1.images
285
365
  box.fields.title.to_s.should_not == "Updated title"
@@ -349,7 +429,7 @@ class BackTest < MiniTest::Spec
349
429
  Spot::JSON.parse(last_response.body).should == {:id => @job1.id, :hidden => true}
350
430
  @job1.reload.visible?.should == false
351
431
  auth_post "/@spontaneous/toggle/#{@job1.id}"
352
- assert last_response.ok?
432
+ assert last_response.ok?, "Expected status 200 but recieved #{last_response.status}"
353
433
  @job1.reload.visible?.should == true
354
434
  Spot::JSON.parse(last_response.body).should == {:id => @job1.id, :hidden => false}
355
435
  end
@@ -360,19 +440,36 @@ class BackTest < MiniTest::Spec
360
440
  Spontaneous.stubs(:reload!)
361
441
  @now = Time.now
362
442
  Time.stubs(:now).returns(@now)
443
+ @renderer = Spontaneous::Output.preview_renderer
363
444
  end
364
445
  should "return rendered root page" do
365
446
  get "/"
366
447
  assert last_response.ok?
367
448
  last_response.content_type.should == "text/html;charset=utf-8"
368
- assert_equal S::Render.with_preview_renderer { @home.render }, last_response.body
449
+ assert_equal @renderer.render(@home.output(:html)), last_response.body
369
450
  end
370
451
 
371
452
  should "return rendered child-page" do
372
453
  get "/project1"
373
454
  assert last_response.ok?
374
455
  last_response.content_type.should == "text/html;charset=utf-8"
375
- assert_equal S::Render.with_preview_renderer { @project1.render }, last_response.body
456
+ assert_equal @renderer.render(@project1.output(:html)), last_response.body
457
+ end
458
+
459
+ should "return alternate formats" do
460
+ Project.add_output :js
461
+ get "/project1.js"
462
+ assert last_response.ok?
463
+ last_response.content_type.should == "application/javascript;charset=utf-8"
464
+ assert_equal @renderer.render(@project1.output(:js)), last_response.body
465
+ end
466
+
467
+ should "allow pages to have css formats" do
468
+ Project.add_output :css
469
+ get "/project1.css"
470
+ assert last_response.ok?
471
+ last_response.content_type.should == "text/css;charset=utf-8"
472
+ assert_equal @renderer.render(@project1.output(:css)), last_response.body
376
473
  end
377
474
 
378
475
  should "return cache-busting headers" do
@@ -399,6 +496,21 @@ class BackTest < MiniTest::Spec
399
496
  assert last_response.ok?, "Should return 200 but got #{last_response.status}"
400
497
  last_response.body.should =~ /color: #ffeeff/
401
498
  end
499
+
500
+ should "compile CoffeeScript" do
501
+ get "/js/coffeescript.js"
502
+ assert last_response.ok?, "Should return 200 but got #{last_response.status}"
503
+ last_response.body.should =~ /square = function/
504
+ last_response.content_type.should == "application/javascript;charset=utf-8"
505
+ end
506
+
507
+ should "accept POST requests" do
508
+ Project.expects(:posted!).with(@project1)
509
+ Project.request :post do
510
+ Project.posted!(page)
511
+ end
512
+ post "/project1"
513
+ end
402
514
  end
403
515
 
404
516
  context "static files" do
@@ -488,15 +600,15 @@ class BackTest < MiniTest::Spec
488
600
 
489
601
  should "be able to wrap pieces around files using default addable class" do
490
602
  box = @job1.images
491
- current_count = box.pieces.length
492
- first_id = box.pieces.first.id.to_s
603
+ current_count = box.contents.length
604
+ first_id = box.contents.first.id.to_s
493
605
 
494
606
  auth_post "/@spontaneous/file/wrap/#{@job1.id}/#{box.schema_id.to_s}", "file" => ::Rack::Test::UploadedFile.new(@src_file, "image/jpeg")
495
607
  assert last_response.ok?
496
608
  last_response.content_type.should == "application/json;charset=utf-8"
497
609
  box = @job1.reload.images
498
- first = box.pieces.first
499
- box.pieces.length.should == current_count+1
610
+ first = box.contents.first
611
+ box.contents.length.should == current_count+1
500
612
  first.image.src.should =~ /^\/media(.+)\/#{File.basename(@src_file)}$/
501
613
  required_response = {
502
614
  :position => 0,
@@ -505,24 +617,34 @@ class BackTest < MiniTest::Spec
505
617
  Spot::JSON.parse(last_response.body).should == required_response
506
618
  end
507
619
  end
508
- context "pieces" do
620
+ context "Box contents" do
509
621
  setup do
510
622
  Spontaneous.stubs(:reload!)
511
623
  end
512
- should "default to being added at the top" do
513
- current_count = @home.in_progress.pieces.length
514
- first_id = @home.in_progress.pieces.first.id
515
- @home.in_progress.pieces.first.class.name.should_not == "BackTest::Image"
624
+
625
+ should "allow addition of pages" do
626
+ current_count = @home.projects.length
627
+ auth_post "/@spontaneous/add/#{@home.id}/#{@home.projects.schema_id.to_s}/#{Project.schema_id.to_s}"
628
+ assert last_response.ok?, "Recieved #{last_response.status} not 200"
629
+ @home.reload
630
+ @home.projects.length.should == current_count+1
631
+ @home.projects.first.must_be_instance_of(Project)
632
+ end
633
+
634
+ should "default to adding entries at the top" do
635
+ current_count = @home.in_progress.contents.length
636
+ first_id = @home.in_progress.contents.first.id
637
+ @home.in_progress.contents.first.class.name.should_not == "BackTest::Image"
516
638
  auth_post "/@spontaneous/add/#{@home.id}/#{@home.in_progress.schema_id.to_s}/#{Image.schema_id.to_s}"
517
639
  assert last_response.ok?, "Recieved #{last_response.status} not 200"
518
640
  last_response.content_type.should == "application/json;charset=utf-8"
519
641
  @home.reload
520
- @home.in_progress.pieces.length.should == current_count+1
521
- @home.in_progress.pieces.first.id.should_not == first_id
522
- @home.in_progress.pieces.first.class.name.should == "BackTest::Image"
642
+ @home.in_progress.contents.length.should == current_count+1
643
+ @home.in_progress.contents.first.id.should_not == first_id
644
+ @home.in_progress.contents.first.class.name.should == "BackTest::Image"
523
645
  required_response = {
524
646
  :position => 0,
525
- :entry => @home.in_progress.pieces.first.export
647
+ :entry => @home.in_progress.contents.first.export
526
648
  }
527
649
  Spot::JSON.parse(last_response.body).should == required_response
528
650
  end
@@ -536,22 +658,30 @@ class BackTest < MiniTest::Spec
536
658
  end
537
659
 
538
660
  should "be addable at the bottom" do
539
- current_count = @home.in_progress.pieces.length
540
- last_id = @home.in_progress.pieces.last.id
541
- @home.in_progress.pieces.last.class.name.should_not == "BackTest::Image"
661
+ current_count = @home.in_progress.contents.length
662
+ last_id = @home.in_progress.contents.last.id
663
+ @home.in_progress.contents.last.class.name.should_not == "BackTest::Image"
542
664
  auth_post "/@spontaneous/add/#{@home.id}/#{@home.in_progress.schema_id.to_s}/#{Image.schema_id.to_s}", :position => -1
543
665
  assert last_response.ok?, "Recieved #{last_response.status} not 200"
544
666
  last_response.content_type.should == "application/json;charset=utf-8"
545
667
  @home.reload
546
- @home.in_progress.pieces.length.should == current_count+1
547
- @home.in_progress.pieces.last.id.should_not == last_id
548
- @home.in_progress.pieces.last.class.name.should == "BackTest::Image"
668
+ @home.in_progress.contents.length.should == current_count+1
669
+ @home.in_progress.contents.last.id.should_not == last_id
670
+ @home.in_progress.contents.last.class.name.should == "BackTest::Image"
549
671
  required_response = {
550
672
  :position => -1,
551
- :entry => @home.in_progress.pieces.last.export
673
+ :entry => @home.in_progress.contents.last.export
552
674
  }
553
675
  Spot::JSON.parse(last_response.body).should == required_response
554
676
  end
677
+
678
+ should "create pieces with the piece owner set to the logged in user" do
679
+ auth_post "/@spontaneous/add/#{@home.id}/#{@home.in_progress.schema_id.to_s}/#{Image.schema_id.to_s}", :position => 0
680
+ assert last_response.ok?, "Recieved #{last_response.status} not 200"
681
+ @home.reload
682
+ @home.in_progress.first.created_by_id.should == @user.id
683
+ @home.in_progress.first.created_by.should == @user
684
+ end
555
685
  end
556
686
 
557
687
  context "Page paths" do
@@ -586,8 +716,24 @@ class BackTest < MiniTest::Spec
586
716
  last_response.content_type.should == "application/json;charset=utf-8"
587
717
  Spot::JSON.parse(last_response.body).should == %w(project2 project3)
588
718
  end
719
+ should "be syncable with the page title" do
720
+ @project1.title = "This is Project"
721
+ @project1.save
722
+ auth_post "/@spontaneous/slug/#{@project1.id}/titlesync"
723
+ assert last_response.ok?
724
+ last_response.content_type.should == "application/json;charset=utf-8"
725
+ @project1.reload
726
+ @project1.path.should == "/this-is-project"
727
+ Spot::JSON.parse(last_response.body).should == {:path => '/this-is-project', :slug => 'this-is-project' }
728
+ end
589
729
  end
590
730
  context "UIDs" do
731
+ setup do
732
+ # editing UIDs is a developer only activity
733
+ @user.update(:level => Spontaneous::Permissions[:root])
734
+ @user.save
735
+ end
736
+
591
737
  should "be editable" do
592
738
  uid = "fishy"
593
739
  @project1.uid.should_not == uid
@@ -603,23 +749,13 @@ class BackTest < MiniTest::Spec
603
749
  orig = @project1.uid
604
750
  @project1.uid.should_not == uid
605
751
  auth_post "/@spontaneous/uid/#{@project1.id}", 'uid' => uid
606
- assert last_response.status == 401
752
+ assert last_response.status == 403
607
753
  @project1.reload.uid.should == orig
608
754
  end
609
755
  end
610
756
  context "Request cache" do
611
757
  setup do
612
758
  Spontaneous.stubs(:reload!)
613
- Change.delete
614
- end
615
- should "wrap all updates in a Change.record" do
616
- params = {
617
- "field[#{@job1.fields.title.schema_id.to_s}][value]" => "Updated field_name_1"
618
- }
619
- Change.count.should == 0
620
- auth_post "/@spontaneous/save/#{@job1.id}", params
621
- Change.count.should == 1
622
- Change.first.modified_list.should == [@home.id]
623
759
  end
624
760
 
625
761
  end
@@ -627,38 +763,29 @@ class BackTest < MiniTest::Spec
627
763
  context "Publishing" do
628
764
  setup do
629
765
  Spontaneous.stubs(:reload!)
766
+ S::Permissions::UserLevel[:editor].stubs(:can_publish?).returns(true)
630
767
  @now = Time.now
631
768
  Time.stubs(:now).returns(@now)
632
- Change.delete
633
- @c1 = Change.new
634
- @c1.push(@home)
635
- @c1.push(@project1)
636
- @c1.save
637
- @c2 = Change.new
638
- @c2.push(@home)
639
- @c2.push(@project1)
640
- @c2.save
641
769
  end
642
770
 
643
771
  teardown do
644
- Change.delete
645
772
  end
646
773
 
647
774
  should "be able to retrieve a serialised list of all unpublished changes" do
648
775
  auth_get "/@spontaneous/publish/changes"
649
- assert last_response.ok?
776
+ assert last_response.ok?, "Expected 200 recieved #{last_response.status}"
650
777
  last_response.content_type.should == "application/json;charset=utf-8"
651
778
  last_response.body.should == Change.serialise_http
652
779
  end
653
780
 
654
781
  should "be able to start a publish with a set of change sets" do
655
- Site.expects(:publish_changes).with([@c1.id])
656
- auth_post "/@spontaneous/publish/publish", :change_set_ids => [@c1.id]
657
- assert last_response.ok?
782
+ Site.expects(:publish_pages).with([@project1.id])
783
+ auth_post "/@spontaneous/publish/publish", :page_ids => [@project1.id]
784
+ assert last_response.ok?, "Expected 200 recieved #{last_response.status}"
658
785
  end
659
786
 
660
787
  should "not launch publish if list of changes is empty" do
661
- Site.expects(:publish_changes).with().never
788
+ Site.expects(:publish_pages).with().never
662
789
  auth_post "/@spontaneous/publish/publish", :change_set_ids => ""
663
790
  assert last_response.status == 400, "Expected 400, recieved #{last_response.status}"
664
791
 
@@ -666,9 +793,9 @@ class BackTest < MiniTest::Spec
666
793
  assert last_response.status == 400
667
794
  end
668
795
  should "recognise when the list of changes is complete" do
669
- Site.expects(:publish_changes).with([@c1.id, @c2.id])
670
- auth_post "/@spontaneous/publish/publish", :change_set_ids => [@c1.id, @c2.id]
671
- assert last_response.ok?
796
+ Site.expects(:publish_pages).with([@home.id, @project1.id])
797
+ auth_post "/@spontaneous/publish/publish", :page_ids => [@home.id, @project1.id]
798
+ assert last_response.ok?, "Expected 200 recieved #{last_response.status}"
672
799
  end
673
800
  end
674
801
 
@@ -677,7 +804,6 @@ class BackTest < MiniTest::Spec
677
804
  Spontaneous.stubs(:reload!)
678
805
  @root_class = Site.root.class
679
806
  Content.delete
680
- Change.delete
681
807
  end
682
808
  should "raise a 406 Not Acceptable error when downloading page details" do
683
809
  auth_get "/@spontaneous/location/"
@@ -697,14 +823,9 @@ class BackTest < MiniTest::Spec
697
823
  assert last_response.status == 403
698
824
  Content.count.should == 1
699
825
  end
700
- should "have a change reflecting creation of root" do
701
- Change.count.should == 0
702
- auth_post "/@spontaneous/root", 'type' => @root_class.schema_id
703
- Change.count.should == 1
704
- end
705
826
  end
706
827
 
707
- context "Aliases" do
828
+ context "when working with aliases" do
708
829
  setup do
709
830
  Spontaneous.stubs(:reload!)
710
831
  end
@@ -715,41 +836,62 @@ class BackTest < MiniTest::Spec
715
836
  should "be able to retrieve a list of potential targets" do
716
837
  auth_get "/@spontaneous/targets/#{LinkedJob.schema_id}/#{@home.id}/#{@home.in_progress.schema_id}"
717
838
  assert last_response.ok?
718
- Spot::JSON.parse(last_response.body).should == LinkedJob.targets(@home, @home.in_progress).map do |job|
719
- {
720
- :id => job.id,
839
+ expected = LinkedJob.targets(@home, @home.in_progress)
840
+ response = Spot::JSON.parse(last_response.body)
841
+ response[:pages].should == 1
842
+ response[:page].should == 1
843
+ response[:total].should == expected.length
844
+
845
+ response[:targets].should == expected.map { |job|
846
+ { :id => job.id,
721
847
  :title => job.title.to_s,
722
- :icon => job.image.export
723
- }
724
- end
848
+ :icon => job.image.export }
849
+ }
850
+ end
851
+
852
+ should "be able to filter targets using a search string" do
853
+ auth_get "/@spontaneous/targets/#{LinkedJob.schema_id}/#{@home.id}/#{@home.in_progress.schema_id}", {"query" => "job 3"}
854
+ assert last_response.ok?
855
+ expected = [@job3]
856
+ response = Spot::JSON.parse(last_response.body)
857
+ response[:pages].should == 1
858
+ response[:page].should == 1
859
+ response[:total].should == expected.length
860
+ response[:targets].should == expected.map { |job|
861
+ { :id => job.id,
862
+ :title => job.title.to_s,
863
+ :icon => job.image.export }
864
+ }
725
865
  end
866
+
726
867
  should "be able to add an alias to a box" do
727
- @home.featured_jobs.pieces.length.should == 0
868
+ @home.featured_jobs.contents.length.should == 0
728
869
  auth_post "/@spontaneous/alias/#{@home.id}/#{HomePage.boxes[:featured_jobs].schema_id.to_s}", 'alias_id' => LinkedJob.schema_id.to_s, 'target_id' => Job.first.id, "position" => 0
729
870
  assert last_response.ok?, "Recieved #{last_response.status} not 200"
730
871
  last_response.content_type.should == "application/json;charset=utf-8"
731
872
  @home.reload
732
- @home.featured_jobs.pieces.length.should == 1
873
+ @home.featured_jobs.contents.length.should == 1
733
874
  a = @home.featured_jobs.first
734
875
  a.alias?.should be_true
735
876
  a.target.should == Job.first
736
877
  required_response = {
737
878
  :position => 0,
738
- :entry => @home.featured_jobs.pieces.first.export(@user)
879
+ :entry => @home.featured_jobs.contents.first.export(@user)
739
880
  }
740
881
  Spot::JSON.parse(last_response.body).should == required_response
741
882
  end
883
+
742
884
  should "be able to add an alias to a box at any position" do
743
885
  @home.featured_jobs << Job.new
744
886
  @home.featured_jobs << Job.new
745
887
  @home.featured_jobs << Job.new
746
888
  @home.save.reload
747
- @home.featured_jobs.pieces.length.should == 3
889
+ @home.featured_jobs.contents.length.should == 3
748
890
  auth_post "/@spontaneous/alias/#{@home.id}/#{HomePage.boxes[:featured_jobs].schema_id.to_s}", 'alias_id' => LinkedJob.schema_id.to_s, 'target_id' => Job.first.id, "position" => 2
749
891
  assert last_response.ok?, "Recieved #{last_response.status} not 200"
750
892
  last_response.content_type.should == "application/json;charset=utf-8"
751
893
  @home.reload
752
- @home.featured_jobs.pieces.length.should == 4
894
+ @home.featured_jobs.contents.length.should == 4
753
895
  a = @home.featured_jobs[2]
754
896
  a.alias?.should be_true
755
897
  a.target.should == Job.first
@@ -759,6 +901,40 @@ class BackTest < MiniTest::Spec
759
901
  }
760
902
  Spot::JSON.parse(last_response.body).should == required_response
761
903
  end
904
+
905
+ context "of non-content targets" do
906
+ setup do
907
+ @target_id = target_id = 9999
908
+ @target = target = mock()
909
+ @target.stubs(:id).returns(@target_id)
910
+ @target.stubs(:title).returns("custom object")
911
+ @target.stubs(:to_json).returns({:title => "custom object", :id => @target_id}.to_json)
912
+ @target.stubs(:alias_title).returns("custom object")
913
+ @target.stubs(:exported_alias_icon).returns(nil)
914
+
915
+ LinkedSomething = Class.new(Piece) do
916
+ alias_of proc { [target] }, :lookup => lambda { |id|
917
+ return target if id == target_id
918
+ nil
919
+ }
920
+ end
921
+ end
922
+
923
+ teardown do
924
+ BackTest.send(:remove_const, LinkedSomething) rescue nil
925
+ end
926
+
927
+ should "interface with lists of non-content targets" do
928
+ box = @home.boxes[:featured_jobs]
929
+ box._prototype.allow LinkedSomething
930
+ auth_post "/@spontaneous/alias/#{@home.id}/#{box.schema_id.to_s}", 'alias_id' => LinkedSomething.schema_id.to_s, 'target_id' => @target_id, "position" => 0
931
+ assert last_response.status == 200, "Expected a 200 but got #{last_response.status}"
932
+ @home.reload
933
+ a = @home.featured_jobs[0]
934
+ a.alias?.should be_true
935
+ a.target.should == @target
936
+ end
937
+ end
762
938
  end
763
939
 
764
940
  context "Schema conflicts" do
@@ -780,6 +956,7 @@ class BackTest < MiniTest::Spec
780
956
  lambda { S.schema.validate! }.must_raise(Spontaneous::SchemaModificationError)
781
957
  # hammer, meet nut
782
958
  S::Rack::Back::EditingInterface.use Spontaneous::Rack::Reloader
959
+ S::Rack::Back::Preview.use Spontaneous::Rack::Reloader
783
960
  Spontaneous::Loader.stubs(:reload!)
784
961
  end
785
962
 
@@ -803,6 +980,16 @@ class BackTest < MiniTest::Spec
803
980
  last_response.body.should =~ %r{<input type="hidden" name="ref" value="#{@af1.schema_name}"}
804
981
  end
805
982
 
983
+ should "present a dialogue page with possible solutions when in preview mode" do
984
+ auth_get '/'
985
+ assert last_response.status == 412, "Schema validation errors should raise a 412 but instead recieved a #{last_response.status}"
986
+ last_response.body.should =~ %r{<form action="/@spontaneous/schema/delete" method="post"}
987
+ last_response.body.should =~ %r{<input type="hidden" name="uid" value="#{@df1.schema_id}"}
988
+
989
+ last_response.body.should =~ %r{<form action="/@spontaneous/schema/rename" method="post"}
990
+ last_response.body.should =~ %r{<input type="hidden" name="ref" value="#{@af1.schema_name}"}
991
+ end
992
+
806
993
  should "perform renames via a link" do
807
994
  action ="/@spontaneous/schema/rename"
808
995
  auth_post action, "uid" => @df1.schema_id, "ref" => @af1.schema_name, "origin" => "/@spontaneous"
@@ -912,15 +1099,15 @@ class BackTest < MiniTest::Spec
912
1099
  last_response.status.should == 200
913
1100
  end
914
1101
  box = @job1.images
915
- current_count = box.pieces.length
916
- first_id = box.pieces.first.id.to_s
1102
+ current_count = box.contents.length
1103
+ first_id = box.contents.first.id.to_s
917
1104
 
918
1105
  auth_post "/@spontaneous/shard/wrap/#{@job1.id}/#{box.schema_id.to_s}", "filename" => "rose.jpg", "shards" => hashes, "mime_type" => "image/jpeg"
919
1106
  assert last_response.ok?, "Should have got status 200 but got #{last_response.status}"
920
1107
  last_response.content_type.should == "application/json;charset=utf-8"
921
1108
  box = @job1.reload.images
922
- first = box.pieces.first
923
- box.pieces.length.should == current_count+1
1109
+ first = box.contents.first
1110
+ box.contents.length.should == current_count+1
924
1111
  first.image.src.should =~ %r{^(.+)/rose\.jpg$}
925
1112
  required_response = {
926
1113
  :position => 0,
@@ -929,6 +1116,74 @@ class BackTest < MiniTest::Spec
929
1116
  Spot::JSON.parse(last_response.body).should == required_response
930
1117
  end
931
1118
  end
1119
+
1120
+
1121
+ context "making modifications" do
1122
+ setup do
1123
+ Spontaneous.stubs(:reload!)
1124
+ end
1125
+ should "record the currently logged in user" do
1126
+ page = @home.in_progress.last
1127
+ auth_post "/@spontaneous/toggle/#{page.id}"
1128
+ assert last_response.ok?, "Expected status 200 but received #{last_response.status}"
1129
+ page.reload
1130
+ page.pending_modifications(:visibility).first.user.should == @user
1131
+ end
1132
+ end
1133
+
1134
+ context "date fields" do
1135
+ setup do
1136
+ Spontaneous.stubs(:reload!)
1137
+ end
1138
+ should "provide a format value" do
1139
+ field = Job.field :date, :date, :format => "%Y %d %a"
1140
+ auth_get "/@spontaneous/metadata"
1141
+ schema = Spot::JSON.parse(last_response.body)
1142
+ field = schema[:types][:"BackTest.Job"][:fields].detect { |f| f[:name] == "date" }
1143
+ field[:date_format].should == "%Y %d %a"
1144
+ end
1145
+ end
1146
+
1147
+ context "select fields" do
1148
+ setup do
1149
+ Spontaneous.stubs(:reload!)
1150
+ end
1151
+
1152
+ teardown do
1153
+ end
1154
+
1155
+ should "be able to provide a static value list" do
1156
+ # static lists should be included in the field definitions
1157
+ field = Job.field :client, :select, :options => [["a", "Value A"], ["b", "Value B"]]
1158
+ auth_get "/@spontaneous/metadata"
1159
+
1160
+ schema = Spot::JSON.parse(last_response.body)
1161
+ field = schema[:types][:"BackTest.Job"][:fields].detect { |f| f[:name] == "client" }
1162
+ field[:option_list].should == [["a", "Value A"], ["b", "Value B"]]
1163
+ end
1164
+
1165
+ should "be able to provide a dynamic value list" do
1166
+ list = mock()
1167
+ options = [["a", "Value A"], ["b", "Value B"]]
1168
+ list.expects(:values).with(@job1).returns(options)
1169
+ field = Job.field :client, :select, :options => proc { |content| list.values(content) }
1170
+ auth_get "/@spontaneous/options/#{field.schema_id}/#{@job1.id}"
1171
+ assert last_response.ok?, "Expected status 200 but received #{last_response.status}"
1172
+ result = Spot::JSON.parse(last_response.body)
1173
+ result.should == options
1174
+ end
1175
+
1176
+ should "be able to provide a dynamic value list for a box field" do
1177
+ list = mock()
1178
+ options = [["a", "Value A"], ["b", "Value B"]]
1179
+ list.expects(:values).with(@job1.images).returns(options)
1180
+ field = Job.boxes.images.instance_class.field :client, :select, :options => proc { |box| list.values(box) }
1181
+ auth_get "/@spontaneous/options/#{field.schema_id}/#{@job1.id}/#{Job.boxes.images.schema_id}"
1182
+ assert last_response.ok?, "Expected status 200 but received #{last_response.status}"
1183
+ result = Spot::JSON.parse(last_response.body)
1184
+ result.should == options
1185
+ end
1186
+ end
932
1187
  end
933
1188
  end
934
1189