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
@@ -0,0 +1,41 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'coffee-script'
4
+
5
+ module Spontaneous::Rack
6
+ class JS
7
+ JS_EXTENSION = /\.js$/o
8
+
9
+ def initialize(app, options = {})
10
+ @roots = options[:root]
11
+ @app = app
12
+ end
13
+
14
+ def call(env)
15
+ try_coffeescript(env[S::PATH_INFO]) or @app.call(env)
16
+ end
17
+
18
+ def try_coffeescript(request_path)
19
+ return nil unless request_path =~ JS_EXTENSION
20
+ try_paths = @roots.map { |root| File.join(root, request_path) }
21
+ # if the css file itself exists then we want to use that
22
+ return nil if try_paths.detect { |file| ::File.exists?(file) }
23
+
24
+ try_paths.each do |path|
25
+ template = template_path(path)
26
+ return render_coffeescript(template) if File.exists?(template)
27
+ end
28
+ nil
29
+ end
30
+
31
+ def render_coffeescript(template)
32
+ script = CoffeeScript.compile(File.read(template))
33
+ [200, {'Content-type' => 'application/javascript;charset=utf-8'}, StringIO.new(script)]
34
+ end
35
+
36
+ def template_path(path)
37
+ path.gsub(JS_EXTENSION, ".coffee")
38
+ end
39
+ end
40
+ end
41
+
@@ -13,6 +13,7 @@ module Spontaneous
13
13
  attr_accessor :page
14
14
 
15
15
  def render_path(path)
16
+ @template_params = {}
16
17
  find_page!(path)
17
18
 
18
19
  response = catch(:halt) do
@@ -52,7 +53,7 @@ module Spontaneous
52
53
  # stolen from Sinatra
53
54
  def parse_response(response)
54
55
  case
55
- when response.respond_to?(:spontaneous_content?)
56
+ when response.is_a?(Spontaneous::Content)
56
57
  @page = response
57
58
  when response.respond_to?(:to_str)
58
59
  @response.body = [response]
@@ -88,6 +89,11 @@ module Spontaneous
88
89
  status(status)
89
90
  end
90
91
 
92
+ def render(page, template_params = {})
93
+ @template_params = template_params
94
+ show(page)
95
+ end
96
+
91
97
  REDIRECTS = {
92
98
  :permanent => 301,
93
99
  :temporary => 302
@@ -122,12 +128,12 @@ module Spontaneous
122
128
  end
123
129
 
124
130
  def find_page!(path)
125
- @path, @format, @action = parse_path(path)
131
+ @path, @output, @action = parse_path(path)
126
132
  @page = Site[@path]
127
133
  end
128
134
 
129
- def format
130
- @format
135
+ def output
136
+ @output
131
137
  end
132
138
 
133
139
  def action
@@ -135,25 +141,17 @@ module Spontaneous
135
141
  end
136
142
 
137
143
  def render_get
138
- # return not_found! unless @page
139
-
140
- @format = (@format || @page.default_format).to_sym if @page
141
-
142
144
  if @action
143
145
  call_action!
144
146
  else
145
147
  block = page.request_block(request)
146
148
  parse_response(instance_eval(&block)) if (block)
147
-
148
- @format = (@format || @page.default_format).to_sym if @page
149
- render_page_with_format(@page, @format)
149
+ render_page_with_output
150
150
  end
151
151
  end
152
152
 
153
153
  # non-action urls shouldn't respond to post requests
154
154
  def render_post
155
- # return not_found! unless @page
156
-
157
155
  block = page.request_block(request)
158
156
  return not_found! unless (block or @action)
159
157
 
@@ -161,21 +159,18 @@ module Spontaneous
161
159
  call_action!
162
160
  else
163
161
  parse_response(instance_eval(&block)) if (block)
164
-
165
- @format = (@format || @page.default_format).to_sym if @page
166
- render_page_with_format(@page, @format)
162
+ render_page_with_output
167
163
  end
168
164
  end
169
165
 
170
166
  def call_action!
171
- # get
172
- status, headers, result = @page.process_action(action, request.env, format)
173
- # our 404 page should come from the CMS
167
+ status, headers, result = @page.process_action(action, request.env, output)
174
168
  if status == 404
175
169
  not_found!
176
170
  else
177
- if result.respond_to?(:spontaneous_content?)
178
- render_page_with_format(result, format)
171
+ if result.is_a?(Spontaneous::Content)
172
+ @page = result
173
+ render_page_with_output
179
174
  else
180
175
  [status, headers, result]
181
176
  end
@@ -185,46 +180,41 @@ module Spontaneous
185
180
  def parse_path(path)
186
181
  if path =~ %r(#{ACTION})
187
182
  path, action = path.split(ACTION)
183
+ path = "/" if path.empty?
188
184
  action, format = action.split(DOT)
189
185
  else
190
186
  path, format = path.split(DOT)
191
187
  end
192
- # format = (format || :html).to_sym
193
188
  [path, format, action]
194
189
  end
195
190
 
196
- def render_page_with_format(page, format)
197
- if page && page.provides_format?(format)
198
- content_type(page.mime_type(format))
199
- render_page(page, format)
191
+ def render_page_with_output
192
+ return not_found! if @page.nil?
193
+ return not_found! unless @page.provides_output?(@output)
194
+
195
+ output = @page.output(@output)
196
+
197
+ if output.public?
198
+ content_type(output.mime_type)
199
+ render_page(@page, output, @template_params)
200
200
  else
201
- # perhaps we should return the html version if the page exists but
202
- # doesn't respond to the requested format?
203
- # or even redirect to the html?
204
201
  not_found!
205
202
  end
206
203
  end
207
204
 
208
- def render_page(page, format = :html, local_params = {})
209
- response.body = page.render(format, local_params.merge({
210
- :params => request.params,
205
+ def renderer
206
+ env[Rack::RENDERER]
207
+ end
208
+
209
+ def render_page(page, output, local_params = {})
210
+ response.body = output.render_using(renderer, local_params.merge({
211
+ :params => params, # use sinatras indifferent params
211
212
  :request => request,
212
213
  :session => request.session
213
214
  }))
214
215
  end
215
216
 
216
- # def redirect?(page)
217
- # redirection, redirect_code = page.request_redirect(request.params, request, request.session)
218
- # if redirection
219
- # redirection = redirection.path if redirection.respond_to?(:path)
220
- # redirect_code = REDIRECTS[redirect_code] if Symbol === redirect_code
221
- # redirect_code ||= REDIRECTS[:temporary]
222
- # [redirection.to_s, redirect_code]
223
- # else
224
- # nil
225
- # end
226
- # end
227
-
217
+ # our 404 page should come from the CMS
228
218
  def not_found!
229
219
  404
230
220
  end
@@ -0,0 +1,18 @@
1
+
2
+ module Spontaneous
3
+ module Rack
4
+ class SSE
5
+ attr_reader :event, :data
6
+
7
+ def initialize(params)
8
+ @event = params[:event]
9
+ @data = params[:data]
10
+ end
11
+
12
+ def to_sse
13
+ lines = ["event: #{event}", "data: #{data}", "\n"]
14
+ lines.join("\n")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -2,6 +2,8 @@
2
2
  module Spontaneous
3
3
  module Rack
4
4
  class Static
5
+ ALLOWED_METHODS = %w(GET HEAD).freeze
6
+
5
7
  def initialize(app, options)
6
8
  @app = app
7
9
  @try = ['', *options.delete(:try)].compact
@@ -11,6 +13,7 @@ module Spontaneous
11
13
  end
12
14
 
13
15
  def call(env)
16
+ return @app.call(env) unless ALLOWED_METHODS.include?(env[S::REQUEST_METHOD])
14
17
  orig_path = env['PATH_INFO']
15
18
  found = nil
16
19
  @try.each do |path|
@@ -0,0 +1,100 @@
1
+ module Spontaneous::Rack
2
+ class UserAdmin < ServerBase
3
+ helpers UserHelpers
4
+ helpers Helpers
5
+
6
+ User = Spontaneous::Permissions::User unless defined?(User)
7
+
8
+ def with_account
9
+ User.db.transaction do
10
+ account = User.for_update.first(:id => params[:user_id])
11
+ halt 403 unless user.level >= account.level
12
+ yield account
13
+ end
14
+ end
15
+
16
+ def load_level
17
+ attr = params[:user]
18
+ level_name = attr.delete(:level) || attr.delete("level")
19
+ return nil if level_name.blank?
20
+ level = Spontaneous::Permissions[level_name]
21
+ halt 403 unless user.level >= level
22
+ level
23
+ end
24
+
25
+ before {
26
+ halt 403 unless user.admin?
27
+ }
28
+
29
+ get "/" do
30
+ json User.export(user)
31
+ end
32
+
33
+ post "/" do
34
+ level = load_level
35
+ account = User.new params[:user]
36
+ if account.save
37
+ account.update(:level => level)
38
+ json User.export_user(account)
39
+ else
40
+ status 422
41
+ json account.errors#.full_messages
42
+ end
43
+ end
44
+
45
+ put "/:user_id" do
46
+ with_account do |account|
47
+ level = load_level
48
+ account.update_fields(params[:user], [:login, :name, :email])
49
+ if account.save
50
+ account.update(:level => level) if level
51
+ json User.export_user(account)
52
+ else
53
+ status 422
54
+ json account.errors#.full_messages
55
+ end
56
+ end
57
+ end
58
+
59
+ delete "/:user_id" do
60
+ with_account do |account|
61
+ account.destroy
62
+ 200
63
+ end
64
+ end
65
+
66
+ put "/password/:user_id" do
67
+ with_account do |account|
68
+ account.password = params[:password]
69
+ if account.save
70
+ # TODO: changing the password should log the user out?
71
+ 200
72
+ else
73
+ status 422
74
+ json account.errors#.full_messages
75
+ end
76
+ end
77
+ end
78
+
79
+ delete "/keys/:user_id" do
80
+ with_account do |account|
81
+ account.clear_access_keys!
82
+ 200
83
+ end
84
+ end
85
+
86
+ put "/disable/:user_id" do
87
+ with_account do |account|
88
+ account.disable!
89
+ 200
90
+ end
91
+ end
92
+
93
+ put "/enable/:user_id" do
94
+ with_account do |account|
95
+ account.enable!
96
+ 200
97
+ end
98
+ end
99
+ end
100
+ end
@@ -5,7 +5,7 @@ module Spontaneous
5
5
  module UserHelpers
6
6
 
7
7
  def unauthorised!
8
- halt 401#, "You do not have the necessary permissions to update the '#{name}' field"
8
+ halt 403#, "You do not have the necessary permissions to update the '#{name}' field"
9
9
  end
10
10
 
11
11
  def api_key
@@ -1,8 +1,7 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  require "rack"
4
- # require "sinatra"
5
- require 'sinatra/base'
4
+ require "sinatra/base"
6
5
 
7
6
  module Spontaneous
8
7
  module Rack
@@ -11,6 +10,7 @@ module Spontaneous
11
10
  ACTIVE_KEY = "SPONTANEOUS_KEY".freeze
12
11
  AUTH_COOKIE = "spontaneous_api_key".freeze
13
12
  KEY_PARAM = "__key".freeze
13
+ RENDERER = "spot.renderer".freeze
14
14
 
15
15
  EXPIRES_MAX = DateTime.parse("Thu, 31 Dec 2037 23:55:55 GMT").httpdate
16
16
 
@@ -54,6 +54,7 @@ module Spontaneous
54
54
  autoload :CacheableFile, 'spontaneous/rack/cacheable_file'
55
55
  autoload :Static, 'spontaneous/rack/static'
56
56
  autoload :UserHelpers, 'spontaneous/rack/user_helpers'
57
+ autoload :UserAdmin, 'spontaneous/rack/user_admin'
57
58
  autoload :Helpers, 'spontaneous/rack/helpers'
58
59
  autoload :CookieAuthentication, 'spontaneous/rack/cookie_authentication'
59
60
  autoload :QueryAuthentication, 'spontaneous/rack/query_authentication'
@@ -63,5 +64,8 @@ module Spontaneous
63
64
  autoload :Reloader, 'spontaneous/rack/reloader'
64
65
  autoload :EventSource, 'spontaneous/rack/event_source'
65
66
  autoload :CSS, 'spontaneous/rack/css'
67
+ autoload :JS, 'spontaneous/rack/js'
68
+ autoload :SSE, 'spontaneous/rack/sse'
69
+ autoload :FiberPool, 'spontaneous/rack/fiber_pool'
66
70
  end
67
71
  end
@@ -208,7 +208,7 @@ module Spontaneous
208
208
  # will check that each of the classes in the schema has a
209
209
  # corresponding id
210
210
  self.classes.each do | schema_class |
211
- schema_class.schema_validate
211
+ schema_class.schema_validate(self)
212
212
  end
213
213
 
214
214
  # now check that each of the ids in the map has a
@@ -227,15 +227,15 @@ module Spontaneous
227
227
  end
228
228
 
229
229
 
230
- def export
230
+ def export(user = nil)
231
231
  self.content_classes.inject({}) do |hash, klass|
232
- hash[klass.ui_class] = klass.export
232
+ hash[klass.ui_class] = klass.export(user)
233
233
  hash
234
234
  end
235
235
  end
236
236
 
237
237
  def serialise_http(user = nil)
238
- Spontaneous.serialise_http(export)
238
+ Spontaneous.serialise_http(export(user))
239
239
  end
240
240
 
241
241
  # all classes including boxes
@@ -321,6 +321,33 @@ module Spontaneous
321
321
  def [](schema_id)
322
322
  map[schema_id]
323
323
  end
324
+
325
+ def groups
326
+ @groups ||= Hash.new { |h, k| h[k] = [] }
327
+ end
328
+
329
+ def add_group_member(schema_class, group_names)
330
+ group_names.each do |name|
331
+ group = groups[name.to_sym]
332
+ group << schema_class.to_s unless group.include?(schema_class.to_s)
333
+ end
334
+ end
335
+
336
+ def is_group?(group_name)
337
+ groups.key?(group_name.to_sym)
338
+ end
339
+
340
+ def group_memberships(klass)
341
+ classname = klass.to_s
342
+ groups.select { |group, members| members.include?(classname) }.keys
343
+ end
344
+
345
+ def remove_group_members(klass)
346
+ type = klass.to_s
347
+ groups.each do |group, members|
348
+ members.delete(type)
349
+ end
350
+ end
324
351
  end
325
352
  end
326
353
  end
@@ -67,19 +67,35 @@ module Spontaneous::Search
67
67
  values = Hash.new { |h, k| h[k] = [] }
68
68
  # not sure that I need the include? test here as page.content only returns Pieces
69
69
  # and I'm not sure that there is a particular need to exclude Pieces from indexes
70
- pieces = [page].concat(page.content).select { |content| include?(content) }
71
- pieces += page.boxes.select { |box| include?(box) }
72
- pieces.each do |content|
70
+ indexable = [page]
71
+ indexable.concat(page.pieces.select { |content| include?(content) })
72
+ indexable += page.boxes.select { |box| include?(box) }
73
+ indexable.each do |content|
73
74
  content.fields.each do |field|
74
75
  prototype = field.prototype
75
76
  values[prototype.index_id(self)] << field.indexable_value if prototype.in_index?(self)
76
77
  end
78
+ insert_additional_indexable_values(content, values)
77
79
  end
78
80
  result = Hash[ values.map { |id, values| [id, values.join("\n")] } ]
79
81
  result[:id] = page.id
80
82
  result
81
83
  end
82
84
 
85
+ def insert_additional_indexable_values(content, values)
86
+ if content.respond_to?(:additional_search_values)
87
+ add = content.additional_search_values
88
+ case add
89
+ when Array
90
+ add.each do |row|
91
+ row.each { |k, v| values[k.to_s] << v }
92
+ end
93
+ when Hash
94
+ add.each { |k, v| values[k.to_s] << v }
95
+ end
96
+ end
97
+ end
98
+
83
99
  def fields
84
100
  field_lists = Hash.new { |h, k| h[k] = [] }
85
101
  # collect all the definitions for a particular field or group
@@ -28,7 +28,7 @@ module Spontaneous::Search
28
28
  end
29
29
 
30
30
  def pages
31
- @page_list ||= Spontaneous::Content.filter(:id => @results.map { |doc| doc.id })
31
+ @page_list ||= @results.map { |doc| Spontaneous::Content.first(:id => doc.id) }
32
32
  end
33
33
  end # Results
34
34
  end
@@ -0,0 +1,17 @@
1
+ require "sequel"
2
+
3
+ Sequel.extension :inflector
4
+
5
+ require 'sequel/plugins/serialization'
6
+
7
+ # Sequel::Plugins::Serialization.register_format(
8
+ # :yajl,
9
+ # lambda { |v| Yajl::Encoder.new.encode(v) },
10
+ # lambda { |v| Yajl::Parser.new(:symbolize_keys => true).parse(v) }
11
+ # )
12
+ Sequel::Plugins::Serialization.register_format(
13
+ :ojson,
14
+ lambda { |v| Oj.dump(v) },
15
+ lambda { |v| Oj.load(v) }
16
+ )
17
+
@@ -4,7 +4,7 @@ module Spontaneous
4
4
  class Site < Spontaneous::Facet
5
5
  include Plugins::Site::Instance
6
6
  include Plugins::Site::Publishing
7
- include Plugins::Site::Revisions
7
+ include Plugins::Site::State
8
8
  include Plugins::Site::Selectors
9
9
  include Plugins::Site::Map
10
10
  include Plugins::Site::Search
@@ -12,6 +12,10 @@ module Spontaneous
12
12
  include Plugins::Site::Schema
13
13
  include Plugins::Site::Level
14
14
  include Plugins::Site::Storage
15
+ include Plugins::Site::URL
16
+ include Plugins::Site::Hooks
17
+ include Plugins::Site::Paths
18
+ include Plugins::Site::Helpers
15
19
 
16
20
  attr_accessor :database
17
21
  attr_reader :environment, :mode
@@ -102,14 +106,17 @@ module Spontaneous
102
106
  end
103
107
 
104
108
  def revision_root
105
- @revision_dir ||= File.expand_path(@root / 'cache/revisions')
106
- # Spontaneous.relative_dir(@revision_dir, *path)
109
+ @revision_dir ||= begin
110
+ path = Pathname.new(@root / 'cache/revisions')
111
+ path.mkpath unless path.exist?
112
+ path.realpath.to_s
113
+ end
107
114
  end
108
115
 
109
116
  def revision_dir(revision=nil, root = revision_root)
110
117
  root ||= revision_root
111
118
  return root / 'current' if revision.nil?
112
- root / revision.to_s.rjust(5, "0")
119
+ root / Spontaneous::Paths.pad_revision_number(revision)
113
120
  end
114
121
 
115
122
  def media_dir(*path)
@@ -48,6 +48,17 @@ module Spontaneous
48
48
  instance.pending_revision
49
49
  end
50
50
 
51
+ # Returns the last date at which a Page was added or removed from the site
52
+ # Used to avoid un-necessary loading of the navigation map during editing
53
+ def modified_at
54
+ instance.modified_at || Time.now
55
+ end
56
+
57
+ # Called by Page.after_create and Page.after_destroy in order to update
58
+ # the Site's modification time
59
+ def site_modified!
60
+ instance.update :modified_at => Time.now
61
+ end
51
62
  end
52
63
  end
53
64
  end
@@ -35,6 +35,9 @@ module Spontaneous::Storage
35
35
  #
36
36
  attr_reader :bucket_name
37
37
 
38
+ # Don't verify my ssl certs when uploading images
39
+ ::Excon.defaults[:ssl_verify_peer] = false
40
+
38
41
  def initialize(config, bucket_name, accepts = nil)
39
42
  @config, @bucket_name, @accepts = config, bucket_name, accepts
40
43
  @public_host = @config.delete(:public_host)
@@ -55,6 +58,7 @@ module Spontaneous::Storage
55
58
  :idempotent => false,
56
59
  :body => existing_file,
57
60
  :public => true,
61
+ :expires => (DateTime.now + 20.years).to_s(:rfc822),
58
62
  :content_type => mimetype
59
63
  }
60
64
  params[:body] = File.open(existing_file) if existing_file.is_a?(String)
@@ -10,6 +10,12 @@ module Spontaneous::Storage
10
10
 
11
11
  def copy(existing_file, media_path, mimetype)
12
12
  dest_path = create_absolute_path(media_path)
13
+ copy_file(existing_file, dest_path)
14
+ set_permissions(dest_path)
15
+ dest_path
16
+ end
17
+
18
+ def copy_file(existing_file, dest_path)
13
19
  if existing_file.respond_to?(:read)
14
20
  File.open(dest_path, "wb") do |f|
15
21
  f.binmode
@@ -28,6 +34,7 @@ module Spontaneous::Storage
28
34
  f.binmode
29
35
  block.call(f)
30
36
  end
37
+ set_permissions(dest_path)
31
38
  end
32
39
 
33
40
  def create_absolute_path(relative_path)
@@ -48,5 +55,9 @@ module Spontaneous::Storage
48
55
  def local?
49
56
  true
50
57
  end
58
+
59
+ def set_permissions(filepath)
60
+ File.chmod(0644, filepath)
61
+ end
51
62
  end
52
63
  end
@@ -40,9 +40,9 @@ module Spontaneous
40
40
 
41
41
  def local_template(format)
42
42
  template_path = nil
43
- Spontaneous.template_paths.each do |template_root|
43
+ Site.paths(:templates).each do |template_root|
44
44
  template_path = try_template_paths.detect do |path|
45
- Spontaneous::Render.exists?(template_root, path, format)
45
+ Spontaneous::Output.template_exists?(template_root, path, format)
46
46
  end
47
47
  return (template_root / template_path) if template_path
48
48
  end