spontaneous 0.2.0.beta1 → 0.2.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (335) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/.locat +42 -0
  4. data/.travis/gemfiles/Gemfile.empty +7 -0
  5. data/.travis.yml +18 -0
  6. data/Gemfile +12 -8
  7. data/LICENSE +1 -1
  8. data/Rakefile +15 -157
  9. data/Readme.markdown +1 -1
  10. data/application/css/core.css.scss +22 -146
  11. data/application/css/definitions.css.scss +7 -3
  12. data/application/css/dialogue.css.scss +26 -1
  13. data/application/css/editing.css.scss +70 -28
  14. data/application/css/font.css.scss +1 -1
  15. data/application/css/popover.css.scss +2 -0
  16. data/application/css/top.css.scss +231 -0
  17. data/application/js/add_alias_dialogue.js +1 -1
  18. data/application/js/add_home_dialogue.js +1 -1
  19. data/application/js/ajax.js +61 -31
  20. data/application/js/box.js +4 -4
  21. data/application/js/conflicted_field_dialogue.js +1 -1
  22. data/application/js/content.js +5 -5
  23. data/application/js/dom.js +5 -0
  24. data/application/js/edit_panel.js +1 -0
  25. data/application/js/editing.js +1 -1
  26. data/application/js/extensions.js +8 -0
  27. data/application/js/field/boolean.js +31 -0
  28. data/application/js/field/file.js +32 -4
  29. data/application/js/field/image.js +24 -9
  30. data/application/js/field/markdown.js +87 -59
  31. data/application/js/field/select.js +1 -1
  32. data/application/js/field/webvideo.js +6 -1
  33. data/application/js/init.js +2 -2
  34. data/application/js/jquery-selection-position.js +130 -0
  35. data/application/js/location.js +4 -25
  36. data/application/js/meta_view/user_admin.js +2 -2
  37. data/application/js/metadata.js +2 -2
  38. data/application/js/page_browser.js +1 -1
  39. data/application/js/panel/root_menu.js +0 -1
  40. data/application/js/popover.js +27 -12
  41. data/application/js/popover_view.js +20 -4
  42. data/application/js/preview.js +31 -16
  43. data/application/js/progress.js +22 -21
  44. data/application/js/publish.js +18 -7
  45. data/application/js/sharded_upload.js +9 -6
  46. data/application/js/spontaneous.js +3 -1
  47. data/application/js/top_bar.js +264 -173
  48. data/application/js/upload.js +12 -5
  49. data/application/js/upload_manager.js +4 -3
  50. data/application/js/user.js +1 -2
  51. data/application/js/views/box_view.js +1 -1
  52. data/application/js/views/page_view.js +16 -5
  53. data/application/js/views/piece_view.js +5 -4
  54. data/application/static/font/fontawesome-webfont-1c66a4738b40ef0f6b1abca0ba9a796d.ttf +0 -0
  55. data/application/views/index.erb +6 -14
  56. data/application/views/login.erb +6 -25
  57. data/application/views/schema_modification_error.html.erb +3 -7
  58. data/db/migrations/20130114120000_create_revision_tables.rb +2 -2
  59. data/db/migrations/20130813111009_increase_path_length.rb +14 -0
  60. data/gem-public_cert.pem +20 -0
  61. data/lib/spontaneous/asset/app_compiler.rb +44 -0
  62. data/lib/spontaneous/asset/environment.rb +225 -0
  63. data/lib/spontaneous/asset.rb +2 -67
  64. data/lib/spontaneous/box.rb +0 -1
  65. data/lib/spontaneous/capistrano/deploy.rb +2 -2
  66. data/lib/spontaneous/capistrano/sync.rb +1 -1
  67. data/lib/spontaneous/cli/init.rb +36 -13
  68. data/lib/spontaneous/cli/server.rb +0 -1
  69. data/lib/spontaneous/cli/site.rb +2 -1
  70. data/lib/spontaneous/cli.rb +3 -1
  71. data/lib/spontaneous/collections/entry_set.rb +4 -12
  72. data/lib/spontaneous/collections/hash_with_fallback.rb +20 -0
  73. data/lib/spontaneous/collections/prototype_set.rb +6 -5
  74. data/lib/spontaneous/crypt.rb +2 -2
  75. data/lib/spontaneous/data_mapper/content_model/associations.rb +115 -63
  76. data/lib/spontaneous/data_mapper.rb +1 -1
  77. data/lib/spontaneous/errors.rb +6 -0
  78. data/lib/spontaneous/extensions/object_space.rb +6 -0
  79. data/lib/spontaneous/facet.rb +1 -0
  80. data/lib/spontaneous/field/base.rb +86 -13
  81. data/lib/spontaneous/field/boolean.rb +65 -0
  82. data/lib/spontaneous/field/file.rb +17 -6
  83. data/lib/spontaneous/field/html.rb +13 -0
  84. data/lib/spontaneous/field/image/size.rb +76 -0
  85. data/lib/spontaneous/field/image.rb +99 -414
  86. data/lib/spontaneous/field/tags.rb +36 -0
  87. data/lib/spontaneous/field/update.rb +1 -1
  88. data/lib/spontaneous/field/webvideo/fallback.rb +41 -0
  89. data/lib/spontaneous/field/webvideo/vimeo.rb +113 -0
  90. data/lib/spontaneous/field/webvideo/vine.rb +94 -0
  91. data/lib/spontaneous/field/webvideo/youtube.rb +133 -0
  92. data/lib/spontaneous/field/webvideo.rb +100 -250
  93. data/lib/spontaneous/field.rb +1 -1
  94. data/lib/spontaneous/generators/site/Gemfile.tt +5 -14
  95. data/lib/spontaneous/generators/site/assets/README.md +20 -0
  96. data/lib/spontaneous/generators/site/assets/css/site.scss +8 -0
  97. data/lib/spontaneous/generators/site/assets/js/site.js +6 -0
  98. data/lib/spontaneous/generators/site/config/deploy.rb.tt +9 -0
  99. data/lib/spontaneous/generators/site/config/user_levels.yml +14 -3
  100. data/lib/spontaneous/generators/site/public/README.md +12 -0
  101. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +2 -2
  102. data/lib/spontaneous/generators/site.rb +77 -35
  103. data/lib/spontaneous/layout.rb +6 -7
  104. data/lib/spontaneous/loader.rb +21 -13
  105. data/lib/spontaneous/media/file.rb +22 -9
  106. data/lib/spontaneous/media/image/attributes.rb +33 -0
  107. data/lib/spontaneous/media/image/format/gif.rb +4 -0
  108. data/lib/spontaneous/media/image/format/jpg.rb +17 -0
  109. data/lib/spontaneous/media/image/format/png.rb +4 -0
  110. data/lib/spontaneous/media/image/format/webp.rb +26 -0
  111. data/lib/spontaneous/media/image/format.rb +79 -0
  112. data/lib/spontaneous/media/image/optimizer.rb +69 -0
  113. data/lib/spontaneous/media/image/processor.rb +17 -0
  114. data/lib/spontaneous/media/image/renderable.rb +52 -0
  115. data/lib/spontaneous/media/image/skeptick.rb +70 -0
  116. data/lib/spontaneous/media/image.rb +50 -0
  117. data/lib/spontaneous/media/temp_file.rb +4 -0
  118. data/lib/spontaneous/media.rb +1 -0
  119. data/lib/spontaneous/model/core/aliases.rb +14 -8
  120. data/lib/spontaneous/model/core/boxes.rb +5 -2
  121. data/lib/spontaneous/model/core/entries.rb +4 -0
  122. data/lib/spontaneous/model/core/entry.rb +1 -0
  123. data/lib/spontaneous/model/core/fields.rb +5 -2
  124. data/lib/spontaneous/model/core/locks.rb +16 -0
  125. data/lib/spontaneous/model/core/media.rb +1 -15
  126. data/lib/spontaneous/model/core.rb +31 -1
  127. data/lib/spontaneous/model/page/controllers.rb +2 -2
  128. data/lib/spontaneous/model/page/formats.rb +1 -4
  129. data/lib/spontaneous/model/page/layouts.rb +6 -2
  130. data/lib/spontaneous/model/page/locks.rb +8 -2
  131. data/lib/spontaneous/model/page/page_tree.rb +2 -2
  132. data/lib/spontaneous/model/page/paths.rb +74 -9
  133. data/lib/spontaneous/model/page.rb +11 -3
  134. data/lib/spontaneous/model.rb +6 -6
  135. data/lib/spontaneous/output/context/render_cache.rb +23 -0
  136. data/lib/spontaneous/output/context.rb +56 -30
  137. data/lib/spontaneous/output/helpers/script_helper.rb +9 -53
  138. data/lib/spontaneous/output/helpers/stylesheet_helper.rb +8 -40
  139. data/lib/spontaneous/output/template/renderer.rb +17 -5
  140. data/lib/spontaneous/output.rb +0 -1
  141. data/lib/spontaneous/paths.rb +6 -2
  142. data/lib/spontaneous/permissions/access_key.rb +18 -0
  143. data/lib/spontaneous/permissions/user.rb +1 -1
  144. data/lib/spontaneous/permissions.rb +4 -1
  145. data/lib/spontaneous/plugins/application/state.rb +19 -12
  146. data/lib/spontaneous/prototypes/field_prototype.rb +14 -8
  147. data/lib/spontaneous/published_revision.rb +7 -0
  148. data/lib/spontaneous/publishing/immediate.rb +43 -34
  149. data/lib/spontaneous/publishing/revision.rb +9 -6
  150. data/lib/spontaneous/rack/asset_server.rb +20 -0
  151. data/lib/spontaneous/rack/back/alias.rb +46 -0
  152. data/lib/spontaneous/rack/back/application_assets.rb +28 -0
  153. data/lib/spontaneous/rack/back/base.rb +34 -0
  154. data/lib/spontaneous/rack/back/changes.rb +19 -0
  155. data/lib/spontaneous/rack/back/content.rb +54 -0
  156. data/lib/spontaneous/rack/back/events.rb +38 -0
  157. data/lib/spontaneous/rack/back/field.rb +37 -0
  158. data/lib/spontaneous/rack/back/file.rb +118 -0
  159. data/lib/spontaneous/rack/back/helpers.rb +71 -0
  160. data/lib/spontaneous/rack/back/index.rb +16 -0
  161. data/lib/spontaneous/rack/back/login.rb +47 -0
  162. data/lib/spontaneous/rack/back/map.rb +24 -0
  163. data/lib/spontaneous/rack/back/page.rb +46 -0
  164. data/lib/spontaneous/rack/back/preview.rb +43 -0
  165. data/lib/spontaneous/rack/back/schema.rb +30 -0
  166. data/lib/spontaneous/rack/back/site.rb +25 -0
  167. data/lib/spontaneous/rack/back/site_assets.rb +13 -0
  168. data/lib/spontaneous/rack/back/unsupported_browser.rb +7 -0
  169. data/lib/spontaneous/rack/{user_admin.rb → back/user_admin.rb} +2 -5
  170. data/lib/spontaneous/rack/back.rb +85 -764
  171. data/lib/spontaneous/rack/cacheable_file.rb +3 -3
  172. data/lib/spontaneous/rack/front.rb +16 -9
  173. data/lib/spontaneous/rack/middleware/authenticate.rb +65 -0
  174. data/lib/spontaneous/rack/middleware/csrf.rb +66 -0
  175. data/lib/spontaneous/rack/middleware/reloader.rb +52 -0
  176. data/lib/spontaneous/rack/middleware/scope.rb +60 -0
  177. data/lib/spontaneous/rack/middleware.rb +6 -0
  178. data/lib/spontaneous/rack/page_controller.rb +18 -5
  179. data/lib/spontaneous/rack/public.rb +17 -11
  180. data/lib/spontaneous/rack.rb +34 -24
  181. data/lib/spontaneous/revision.rb +29 -2
  182. data/lib/spontaneous/schema/uid.rb +4 -3
  183. data/lib/spontaneous/schema/uid_map.rb +5 -24
  184. data/lib/spontaneous/schema.rb +1 -0
  185. data/lib/spontaneous/search/database.rb +8 -0
  186. data/lib/spontaneous/search/field.rb +1 -1
  187. data/lib/spontaneous/search/index.rb +3 -5
  188. data/lib/spontaneous/server.rb +1 -1
  189. data/lib/spontaneous/simultaneous.rb +1 -1
  190. data/lib/spontaneous/site/features.rb +4 -5
  191. data/lib/spontaneous/site/helpers.rb +22 -5
  192. data/lib/spontaneous/site/instance.rb +2 -2
  193. data/lib/spontaneous/site/selectors.rb +22 -3
  194. data/lib/spontaneous/storage/cloud.rb +13 -9
  195. data/lib/spontaneous/storage/local.rb +11 -6
  196. data/lib/spontaneous/style.rb +40 -23
  197. data/lib/spontaneous/utils/database/mysql_dumper.rb +1 -1
  198. data/lib/spontaneous/utils/smush_it.rb +1 -1
  199. data/lib/spontaneous/version.rb +1 -1
  200. data/lib/spontaneous.rb +35 -33
  201. data/spontaneous.gemspec +53 -787
  202. data/test/experimental/test_crypt.rb +56 -56
  203. data/test/experimental/test_features.rb +16 -27
  204. data/test/fixtures/assets/public1/css/data.css.scss +3 -0
  205. data/test/fixtures/assets/public1/css/image1.css.scss +4 -0
  206. data/test/fixtures/assets/public1/css/import.css.scss +1 -0
  207. data/test/fixtures/assets/public1/css/urlhash.css.scss +3 -0
  208. data/test/fixtures/assets/public1/js/a.js +1 -1
  209. data/test/fixtures/assets/public1/js/all.js +4 -0
  210. data/test/fixtures/assets/public1/js/{m.coffee → m.js.coffee} +1 -0
  211. data/test/fixtures/assets/public1/x.js +1 -0
  212. data/test/fixtures/assets/public2/css/all.css +4 -0
  213. data/test/fixtures/assets/public2/css/missing.css.scss +3 -0
  214. data/test/fixtures/assets/public2/i/y.png +0 -0
  215. data/test/fixtures/assets/public2/js/b.js +1 -1
  216. data/test/fixtures/assets/public2/js/c.js +1 -1
  217. data/test/fixtures/images/size.extended.webp +0 -0
  218. data/test/fixtures/images/size.lossless.webp +0 -0
  219. data/test/fixtures/images/size.lossy.webp +0 -0
  220. data/test/fixtures/schema/before.yml +4 -4
  221. data/test/fixtures/schema/schema.yml +1 -1
  222. data/test/fixtures/templates/aliases/aaa.html.cut +0 -0
  223. data/test/fixtures/templates/extended/partial_with_renderer.html.cut +1 -0
  224. data/test/fixtures/templates/extended/with_includes_and_renderer.html.cut +2 -0
  225. data/test/functional/test_application.rb +108 -106
  226. data/test/functional/test_back.rb +924 -930
  227. data/test/functional/test_front.rb +285 -238
  228. data/test/functional/test_user_manager.rb +75 -100
  229. data/test/integration/test_installation.rb +1 -1
  230. data/test/support/matchers.rb +12 -0
  231. data/test/support/minitest.rb +121 -0
  232. data/test/support/rack.rb +45 -0
  233. data/test/support/test_start_finish.rb +103 -0
  234. data/test/test_helper.rb +21 -68
  235. data/test/test_integration_helper.rb +1 -3
  236. data/test/unit/test_alias.rb +432 -408
  237. data/test/unit/test_asset_bundler.rb +58 -58
  238. data/test/unit/test_assets.rb +485 -155
  239. data/test/unit/test_async.rb +16 -37
  240. data/test/unit/test_authentication.rb +425 -457
  241. data/test/unit/test_boxes.rb +191 -191
  242. data/test/unit/test_changesets.rb +244 -254
  243. data/test/unit/test_config.rb +128 -142
  244. data/test/unit/test_content.rb +313 -359
  245. data/test/unit/test_content_inheritance.rb +29 -30
  246. data/test/unit/test_datamapper.rb +1205 -1080
  247. data/test/unit/test_datamapper_content.rb +49 -51
  248. data/test/unit/test_extensions.rb +23 -23
  249. data/test/unit/test_fields.rb +1488 -1180
  250. data/test/unit/test_formats.rb +158 -158
  251. data/test/unit/test_generators.rb +98 -40
  252. data/test/unit/test_helpers.rb +73 -76
  253. data/test/unit/test_image_size.rb +53 -22
  254. data/test/unit/test_images.rb +164 -165
  255. data/test/unit/test_layouts.rb +133 -122
  256. data/test/unit/test_logger.rb +14 -17
  257. data/test/unit/test_media.rb +69 -84
  258. data/test/unit/test_modifications.rb +513 -525
  259. data/test/unit/test_page.rb +462 -361
  260. data/test/unit/test_permissions.rb +379 -364
  261. data/test/unit/test_piece.rb +67 -75
  262. data/test/unit/test_plugins.rb +82 -89
  263. data/test/unit/test_prototype_set.rb +215 -216
  264. data/test/unit/test_prototypes.rb +114 -124
  265. data/test/unit/test_publishing.rb +252 -289
  266. data/test/unit/test_render.rb +167 -115
  267. data/test/unit/test_revisions.rb +436 -444
  268. data/test/unit/test_schema.rb +339 -309
  269. data/test/unit/test_search.rb +577 -574
  270. data/test/unit/test_serialisation.rb +136 -147
  271. data/test/unit/test_site.rb +252 -227
  272. data/test/unit/test_skeptick.rb +130 -0
  273. data/test/unit/test_storage.rb +46 -40
  274. data/test/unit/test_structure.rb +57 -66
  275. data/test/unit/test_styles.rb +104 -104
  276. data/test/unit/test_templates.rb +72 -57
  277. data/test/unit/test_type_hierarchy.rb +15 -16
  278. data/test/unit/test_visibility.rb +239 -257
  279. metadata +455 -326
  280. data/application/js/vendor/JS.Class-2.1.5/CHANGELOG +0 -283
  281. data/application/js/vendor/JS.Class-2.1.5/MIT-LICENSE +0 -30
  282. data/application/js/vendor/JS.Class-2.1.5/README +0 -30
  283. data/application/js/vendor/JS.Class-2.1.5/min/command.js +0 -1
  284. data/application/js/vendor/JS.Class-2.1.5/min/comparable.js +0 -1
  285. data/application/js/vendor/JS.Class-2.1.5/min/constant_scope.js +0 -1
  286. data/application/js/vendor/JS.Class-2.1.5/min/decorator.js +0 -1
  287. data/application/js/vendor/JS.Class-2.1.5/min/enumerable.js +0 -1
  288. data/application/js/vendor/JS.Class-2.1.5/min/forwardable.js +0 -1
  289. data/application/js/vendor/JS.Class-2.1.5/min/hash.js +0 -1
  290. data/application/js/vendor/JS.Class-2.1.5/min/linked_list.js +0 -1
  291. data/application/js/vendor/JS.Class-2.1.5/min/loader.js +0 -1
  292. data/application/js/vendor/JS.Class-2.1.5/min/method_chain.js +0 -1
  293. data/application/js/vendor/JS.Class-2.1.5/min/observable.js +0 -1
  294. data/application/js/vendor/JS.Class-2.1.5/min/package.js +0 -1
  295. data/application/js/vendor/JS.Class-2.1.5/min/proxy.js +0 -1
  296. data/application/js/vendor/JS.Class-2.1.5/min/ruby.js +0 -1
  297. data/application/js/vendor/JS.Class-2.1.5/min/set.js +0 -1
  298. data/application/js/vendor/JS.Class-2.1.5/min/stack_trace.js +0 -1
  299. data/application/js/vendor/JS.Class-2.1.5/min/state.js +0 -1
  300. data/application/js/vendor/JS.Class-2.1.5/min/stdlib.js +0 -16
  301. data/application/js/vendor/jquery-1.6.2.min.js +0 -18
  302. data/application/js/vendor/jquery-ui-1.8.16.custom.min.js +0 -791
  303. data/application/js/vendor/jquery-ui-1.8.9.custom.min.js +0 -415
  304. data/application/static/font/fontawesome-webfont-5c5c21100a346972a82c34c5e96ffcfe.ttf +0 -0
  305. data/application/static/select-arrow-6e7dd3745b00e934b0d7a3250c46558b.png +0 -0
  306. data/bin/limit-upload +0 -5
  307. data/bin/unlimit-upload +0 -3
  308. data/lib/spontaneous/asset/file.rb +0 -25
  309. data/lib/spontaneous/asset/source.rb +0 -28
  310. data/lib/spontaneous/image_size.rb +0 -123
  311. data/lib/spontaneous/output/assets/compression.rb +0 -58
  312. data/lib/spontaneous/output/assets.rb +0 -32
  313. data/lib/spontaneous/rack/around_back.rb +0 -20
  314. data/lib/spontaneous/rack/around_front.rb +0 -27
  315. data/lib/spontaneous/rack/around_preview.rb +0 -22
  316. data/lib/spontaneous/rack/assets.rb +0 -126
  317. data/lib/spontaneous/rack/authentication.rb +0 -20
  318. data/lib/spontaneous/rack/cookie_authentication.rb +0 -38
  319. data/lib/spontaneous/rack/helpers.rb +0 -52
  320. data/lib/spontaneous/rack/http.rb +0 -18
  321. data/lib/spontaneous/rack/media.rb +0 -30
  322. data/lib/spontaneous/rack/query_authentication.rb +0 -35
  323. data/lib/spontaneous/rack/reloader.rb +0 -45
  324. data/lib/spontaneous/rack/user_helpers.rb +0 -28
  325. /data/{README → application/js/field/markdown/text_command.js} +0 -0
  326. /data/application/js/vendor/{JS.Class-2.1.5/min/core.js → js.class-2.1.5.min.js} +0 -0
  327. /data/test/fixtures/assets/public1/css/{a.scss → a.css.scss} +0 -0
  328. /data/{lib/spontaneous/generators/site/public/css/site.scss → test/fixtures/assets/public1/x.css} +0 -0
  329. /data/{lib/spontaneous/generators/site/public/js/.empty_directory → test/fixtures/assets/public1/x.png} +0 -0
  330. /data/test/fixtures/assets/public2/css/{b.scss → b.css.scss} +0 -0
  331. /data/test/fixtures/assets/public2/js/{n.coffee → n.js.coffee} +0 -0
  332. /data/test/fixtures/back/{public → assets}/css/sass_include.scss +0 -0
  333. /data/test/fixtures/back/{public → assets}/css/sass_template.scss +0 -0
  334. /data/test/fixtures/back/{public → assets}/js/coffeescript.coffee +0 -0
  335. /data/{lib/spontaneous/generators/site/public/js/site.js → test/fixtures/templates/aliases/aa_alias.html.cut} +0 -0
@@ -1,130 +1,117 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'sass'
4
- require 'sinatra/streaming'
5
- require 'sprockets'
6
-
7
3
  module Spontaneous
8
4
  module Rack
9
5
  module Back
10
- include Assets
11
-
12
- def self.messenger
13
- @messenger ||= event_source
14
- end
15
6
 
16
- def self.event_source
17
- messenger = ::Spontaneous::Rack::EventSource.new
18
- # Find a way to move this into a more de-centralised place
19
- # at some point we are going to want to have some configurable, extendable
20
- # list of event handlers
21
- ::Simultaneous.on_event("publish_progress") { |event|
22
- messenger.deliver_event(event)
23
- }
24
- ::Simultaneous.on_event("page_lock_status") { |event|
25
- messenger.deliver_event(event)
26
- }
27
- messenger
7
+ autoload :Base, 'spontaneous/rack/back/base'
8
+ autoload :Alias, 'spontaneous/rack/back/alias'
9
+ autoload :ApplicationAssets, 'spontaneous/rack/back/application_assets'
10
+ autoload :Changes, 'spontaneous/rack/back/changes'
11
+ autoload :Content, 'spontaneous/rack/back/content'
12
+ autoload :Events, 'spontaneous/rack/back/events'
13
+ autoload :Field, 'spontaneous/rack/back/field'
14
+ autoload :File, 'spontaneous/rack/back/file'
15
+ autoload :Helpers, 'spontaneous/rack/back/helpers'
16
+ autoload :Index, 'spontaneous/rack/back/index'
17
+ autoload :Login, 'spontaneous/rack/back/login'
18
+ autoload :Map, 'spontaneous/rack/back/map'
19
+ autoload :Page, 'spontaneous/rack/back/page'
20
+ autoload :Preview, 'spontaneous/rack/back/preview'
21
+ autoload :Schema, 'spontaneous/rack/back/schema'
22
+ autoload :Site, 'spontaneous/rack/back/site'
23
+ autoload :SiteAssets, 'spontaneous/rack/back/site_assets'
24
+ autoload :UnsupportedBrowser, 'spontaneous/rack/back/unsupported_browser'
25
+ autoload :UserAdmin, 'spontaneous/rack/back/user_admin'
26
+
27
+ include Spontaneous::Rack::Constants
28
+ include Spontaneous::Rack::Middleware
29
+
30
+ def self.make_controller(controller_class)
31
+ controller_class.helpers Helpers
32
+ ::Rack::Builder.app do
33
+ use Scope::Edit
34
+ use Authenticate::Init
35
+ use Authenticate::Edit
36
+ use CSRF::Header
37
+ use CSRF::Verification
38
+ run controller_class
39
+ end
28
40
  end
29
41
 
30
- class EventSource < ServerBase
31
- helpers Sinatra::Streaming
32
-
33
- get "/", :provides => "text/event-stream" do
34
- headers "X-Accel-Buffering" => "no"
35
- stream(:keep_open) do |out|
36
- messenger = Spontaneous::Rack::Back.messenger
37
- out.errback { messenger.delete(out) }
38
- out.callback { messenger.delete(out) }
39
- messenger << out
40
- end
41
- end
42
+ def self.api_handlers
43
+ [["/events", Events],
44
+ ["/users", UserAdmin],
45
+ ["/site", Site],
46
+ ["/map", Map],
47
+ ["/field", Field],
48
+ ["/page", Page],
49
+ ["/content", Content],
50
+ ["/alias", Alias],
51
+ ["/changes", Changes],
52
+ ["/file", File::Simple],
53
+ ["/shard", File::Sharded]]
42
54
  end
43
55
 
44
56
  def self.editing_app
45
57
  ::Rack::Builder.app do
46
- use ::Rack::Lint
47
- use Spontaneous::Rack::Static, :root => Spontaneous.application_dir, :urls => %W(/static)
48
- use Spontaneous::Rack::Static, :root => Spontaneous.root / "public/@spontaneous", :urls => %W(/assets)
49
- use AssetsHandler
50
- use UnsupportedBrowserHandler
51
- use SchemaModification
52
- map "/users" do
53
- run UserAdmin
54
- end
55
- run EditingInterface
58
+ use Scope::Edit
59
+ use ApplicationAssets
60
+ use UnsupportedBrowser
61
+ use Authenticate::Init
62
+ use Login
63
+ # Everything after this handler requires authentication
64
+ use Authenticate::Edit
65
+ use CSRF::Header
66
+ # Schema has to come before Reloader because we need to be able to
67
+ # present the conflict resolution interface without running through
68
+ # the schema validation step
69
+ map("/schema") { run Schema }
70
+ use Reloader
71
+ use Index
72
+ # Everything after this middleware requires a valid CSRF token
73
+ use CSRF::Verification
74
+
75
+ Back.api_handlers.each do |path, app|
76
+ map(path) { run app }
77
+ end
78
+ run lambda { |env| [ 404, {}, ["Not Found"] ] }
56
79
  end
57
80
  end
58
81
 
82
+
59
83
  def self.preview_app
60
84
  ::Rack::Builder.app do
61
- use ::Rack::Lint
85
+ use ::Rack::Lint if Spontaneous.development?
86
+ use Scope::Preview
87
+ use Authenticate::Init
88
+ # Preview authentication redirects to /@spontaneous rather than
89
+ # showing a login screen. This way if you go to rhe root of the site
90
+ # as an unauthorised user (say for the first time) you will get sent
91
+ # to the editing interface wrapper rather than being presented with
92
+ # the preview site.
93
+ use Authenticate::Preview
94
+ use CSRF::Header
95
+ map("/assets") { run SiteAssets.new }
62
96
  use Spontaneous::Rack::Static, :root => Spontaneous.root / "public",
63
97
  :urls => %w[/],
64
98
  :try => ['.html', 'index.html', '/index.html']
65
- use Spontaneous::Rack::CSS, :root => Spontaneous.instance.paths.expanded(:public)
66
- use Spontaneous::Rack::JS, :root => Spontaneous.instance.paths.expanded(:public)
99
+ use Reloader
67
100
  run Preview
68
101
  end
69
102
  end
70
103
 
71
- def self.assets_app(dir)
72
- ::Sprockets::Environment.new(Spontaneous.application_dir) do |environment|
73
- environment.append_path("#{dir}")
74
- end
75
- end
76
-
77
104
  def self.application
78
- messenger = self.messenger
79
105
  app = ::Rack::Builder.new do
80
- # use ::Rack::ShowExceptions if Spontaneous.development?
81
- # AFAIK the only non-thread-safe part of the stack are the renderer calls
82
- # because they rely on the global values of renderer and also Content.with_visible
83
- # I'm not sure that using Rack::Lock here would fix any problems that this causes,
84
- # or even if there are any problems that would be caused
85
- #
86
- # use ::Rack::Lock
87
- # ###################
88
- # Looking at the three Around* middlewares, there shouldn't actually be a problem with
89
- # the renderers, as the only conflict would come from the back server which provides two
90
- # outputs: the preview and the editing interface. Luckily both the preview and the editing
91
- # interface share the same renderer.
92
- # The real problem is the Content::with_visible wrapper as the editing interface and the preview
93
- # renderer use different values for this. As the only way to solve this would be using a global
94
- # to replace the model class (as we need to be able to issue thread save Model.select calls)
95
- # I don't know how to fix this.
96
- # One solution would be to always use the Content::_unfiltered_dataset call within the editing interface
97
- # and then we'd be free (I think) to wrap it in the with_visible call, though I don't know how this would
98
- # affect the loading of content within the page.
99
- #
100
- # Needs testing...
101
- # ###################
102
-
103
-
104
- ################### REMOVE THIS
105
- # map "#{NAMESPACE}/lock" do
106
- # run proc {
107
- # Spontaneous.database.transaction do
108
- # Spontaneous.database.run("LOCK TABLES content WRITE, spontaneous_access_keys READ")
109
- # puts S::Content.first
110
- # Spontaneous.database.run("SELECT SLEEP(10)")
111
- # Spontaneous.database.run("UNLOCK TABLES")
112
- # end
113
- # }
114
- # end
115
- # map "#{NAMESPACE}/unlock" do
116
- # run proc { Spontaneous.database.run("UNLOCK TABLES") }
117
- # end
118
- ################### END REMOVE THIS
119
-
120
106
  Spontaneous.instance.back_controllers.each do |namespace, controller_class|
121
- map namespace do
122
- run controller_class
123
- end
107
+ map(namespace) { run controller_class }
124
108
  end if Spontaneous.instance
125
109
 
126
110
  # Make all the files available under plugin_name/public/**
127
111
  # available under the URL /plugin_name/**
112
+ # This needs to be handled by the asset system
113
+ # so that /assets/<plugin_name>/file.css is properly found
114
+ # and processed through sprockets
128
115
  Spontaneous.instance.plugins.each do |plugin|
129
116
  root = plugin.paths.expanded(:public)
130
117
  map "/#{plugin.file_namespace}" do
@@ -133,681 +120,15 @@ module Spontaneous
133
120
  end
134
121
  end if Spontaneous.instance
135
122
 
136
- map "#{NAMESPACE}/events" do
137
- use CookieAuthentication
138
- use QueryAuthentication
139
- run EventSource
140
- end
141
-
142
- map "#{NAMESPACE}/event" do
143
- run EventListener
144
- end
145
-
146
- map "#{NAMESPACE}/css" do
147
- run Spontaneous::Rack::Back.assets_app("css")
148
- end
149
-
150
- map "#{NAMESPACE}/js" do
151
- run Spontaneous::Rack::Back.assets_app("js")
152
- end
153
-
154
- map NAMESPACE do
155
- run Spontaneous::Rack::Back.editing_app
156
- end
157
-
158
123
  map "/media" do
159
124
  use ::Rack::Lint
160
125
  run Spontaneous::Rack::CacheableFile.new(Spontaneous.media_dir)
161
126
  end
162
127
 
163
- map "/" do
164
- run Spontaneous::Rack::Back.preview_app
165
- end
166
- end
167
- end
168
-
169
- class EventListener < ServerBase
170
- put "/" do
171
- Back.messenger.deliver_event(SSE.new(params))
172
- 200
173
- end
174
- end
175
-
176
-
177
- class EditingBase < ServerBase
178
- set :views, Proc.new { Spontaneous.application_dir + '/views' }
179
- set :environment, Proc.new { Spontaneous.env }
180
- enable :dump_errors, :raise_errors, :show_exceptions if Spontaneous.development?
181
-
182
- helpers Spontaneous::Rack::UserHelpers
183
- helpers Spontaneous::Rack::Helpers
184
-
185
- end
186
-
187
- class UnsupportedBrowserHandler < EditingBase
188
- get '/unsupported' do
189
- erb :unsupported
128
+ map(NAMESPACE) { run Spontaneous::Rack::Back.editing_app }
129
+ map("/") { run Spontaneous::Rack::Back.preview_app }
190
130
  end
191
131
  end
192
-
193
- class BackControllerBase < EditingBase
194
- # use CookieAuthentication
195
- # use AroundBack
196
- # register Authentication
197
- end
198
- Spontaneous::Rack.make_back_controller(BackControllerBase)
199
-
200
- class AuthenticatedHandler < BackControllerBase
201
- requires_authentication! :except_all => [%r(^#{NAMESPACE}/unsupported)], :except_key => [%r(^#{NAMESPACE}/?(/\d+/?.*)?$)]
202
- end
203
-
204
- class SchemaModification < AuthenticatedHandler
205
-
206
- post "/schema/delete" do
207
- begin
208
- Spontaneous.schema.apply_fix(:delete, params[:uid])
209
- rescue Spot::SchemaModificationError # ignore remaining errors - they will be fixed later
210
- end
211
- redirect(params[:origin])
212
- end
213
-
214
- post "/schema/rename" do
215
- begin
216
- Spontaneous.schema.apply_fix(:rename, params[:uid], params[:ref])
217
- rescue Spot::SchemaModificationError => e # ignore remaining errors - they will be fixed later
218
- end
219
- redirect(params[:origin])
220
- end
221
-
222
- end
223
-
224
- class EditingInterface < AuthenticatedHandler
225
- use Reloader if Spontaneous::Site.config.reload_classes
226
-
227
- set :views, Proc.new { Spontaneous.application_dir + '/views' }
228
-
229
-
230
- def update_fields(model, field_data)
231
- return unless field_data
232
- Spontaneous::Field.update_asynchronously(model, field_data, user)
233
- json(model)
234
- end
235
-
236
- # def update_fields(model, field_data)
237
- # conflicts = []
238
- # if field_data
239
- # field_data.each do |id, values|
240
- # field = model.fields.sid(id)
241
- # if model.field_writable?(user, field.name.to_sym)
242
- # # version = values.delete("version").to_i
243
- # # if version == field.version
244
- # field.update(values)
245
- # # else
246
- # # conflicts << [field, values]
247
- # # end
248
- # else
249
- # unauthorised!
250
- # end
251
- # end
252
- # end
253
- # if conflicts.empty?
254
- # if model.save
255
- # json(model)
256
- # end
257
- # else
258
- # errors = conflicts.map do |field, new_value|
259
- # [field.schema_id.to_s, [field.version, field.conflicted_value, new_value["unprocessed_value"]]]
260
- # end
261
- # [409, json(Hash[errors])]
262
- # end
263
- # end
264
-
265
- def content_model
266
- Spontaneous::Content
267
- end
268
-
269
- def content_for_request(lock = false)
270
- content_model.db.transaction do
271
- dataset = lock ? content_model.for_update : content_model
272
- content = dataset.get(params[:id])
273
- halt 404 if content.nil?
274
- content.current_editor = user
275
- if box_id = content_model.schema.uids[params[:box_id]]
276
- box = content.boxes.detect { |b| b.schema_id == box_id }
277
- yield(content, box)
278
- else
279
- yield(content)
280
- end
281
- end
282
- end
283
-
284
- def set_authentication_cookie(key)
285
- response.set_cookie(AUTH_COOKIE, {
286
- :value => key.key_id,
287
- :path => '/',
288
- :secure => request.ssl?,
289
- :httponly => true
290
- })
291
- end
292
-
293
- def unset_authentication_cookie
294
- response.delete_cookie(AUTH_COOKIE, {
295
- :path => '/',
296
- :secure => request.ssl?,
297
- :httponly => true
298
- })
299
- end
300
-
301
- post "/reauthenticate" do
302
- origin = "#{NAMESPACE}#{(params[:origin] || "").gsub(%r[^#{NAMESPACE}], "")}"
303
- if key = Spot::Permissions::AccessKey.authenticate(params[:api_key])
304
- set_authentication_cookie(key)
305
- redirect origin, 302
306
- else
307
- show_login_page( :invalid_key => true, :origin => origin )
308
- end
309
- end
310
-
311
- post "/login" do
312
- login = params[:user][:login]
313
- password = params[:user][:password]
314
- origin = "#{NAMESPACE}#{params[:origin]}"
315
- if key = Spontaneous::Permissions::User.authenticate(login, password, env["REMOTE_ADDR"])
316
- set_authentication_cookie(key)
317
- if request.xhr?
318
- json({
319
- :key => key.key_id,
320
- :redirect => origin
321
- })
322
- else
323
- redirect origin, 302
324
- end
325
- else
326
- show_login_page( :login => login, :failed => true )
327
- end
328
- end
329
-
330
- post "/logout" do
331
- unset_authentication_cookie
332
- 401
333
- end
334
-
335
- get '/?' do
336
- erb :index
337
- end
338
-
339
- get %r{^/(\d+/?.*)?$} do
340
- erb :index
341
- end
342
-
343
- get '/root' do
344
- json Spontaneous::Site.root
345
- end
346
-
347
- get '/page/:id' do
348
- content_for_request { |content| json(content)}
349
- end
350
-
351
- get '/metadata' do
352
- json({
353
- :types => Spontaneous::Site.schema.export(user),
354
- :user => user.export,
355
- :services => (Spontaneous::Site.config.services || [])
356
- })
357
- end
358
-
359
- get '/map/?:id?' do
360
- last_modified(Spontaneous::Site.modified_at)
361
- map = Spontaneous::Site.map(params[:id])
362
- if map
363
- json(map)
364
- else
365
- 404
366
- end
367
- end
368
-
369
- get '/location*' do
370
- last_modified(Spontaneous::Site.modified_at)
371
- if content_model::Page.count == 0
372
- 406
373
- else
374
- path = params[:splat].first
375
- page = Spontaneous::Site[path]
376
- json Spontaneous::Site.map(page.id)
377
- end
378
- end
379
-
380
- post '/root' do
381
- if Spontaneous::Site.root.nil?
382
- type = content_model.schema.to_class(params[:type])
383
- root = type.create(:title => "Home")
384
- json({:id => root.id})
385
- else
386
- 403
387
- end
388
- end
389
-
390
- post '/version/:id/?:box_id?' do
391
- content_for_request(true) do |content, box|
392
- generate_conflict_list(box || content)
393
- end
394
- end
395
-
396
- get '/options/:field_sid/:id/?:box_id?' do
397
- content_for_request do |content, box|
398
- field = (box || content).fields.sid(params[:field_sid])
399
- json(field.option_list)
400
- end
401
- end
402
-
403
- def generate_conflict_list(content)
404
- field_versions = params[:fields]
405
- conflicts = []
406
- field_versions.each do |schema_id, version|
407
- field = content.fields.sid(schema_id)
408
- if field.matches_version?(version.to_i)
409
- conflicts << field
410
- end
411
- end
412
- if conflicts.empty?
413
- 200
414
- else
415
- errors = conflicts.map do |field|
416
- [field.schema_id.to_s, [field.version, field.conflicted_value]]
417
- end
418
- [409, json(Hash[errors])]
419
- end
420
- end
421
-
422
- post '/save/:id' do
423
- content_for_request(true) do |content|
424
- update_fields(content, params[:field])
425
- end
426
- end
427
-
428
- post '/savebox/:id/:box_id' do
429
- content_for_request(true) do |content, box|
430
- if box.writable?(user)
431
- update_fields(box, params[:field])
432
- else
433
- unauthorised!
434
- end
435
- end
436
- end
437
-
438
-
439
- post '/content/:id/position/:position' do
440
- content_for_request(true) do |content|
441
- if content.box.writable?(user)
442
- content.update_position(params[:position].to_i)
443
- json( {:message => 'OK'} )
444
- else
445
- unauthorised!
446
- end
447
- end
448
- end
449
-
450
- post '/toggle/:id' do
451
- content_for_request(true) do |content|
452
- if content.box && content.box.writable?(user)
453
- content.toggle_visibility!
454
- json({:id => content.id, :hidden => (content.hidden? ? true : false) })
455
- else
456
- unauthorised!
457
- end
458
- end
459
- end
460
-
461
- post '/file/replace/:id/?:box_id?' do
462
- content_for_request(true) do |content, box|
463
- target = box || content
464
- file = params[:file]
465
- field = target.fields.sid(params['field'])
466
- if target.field_writable?(user, field.name)
467
- # version = params[:version].to_i
468
- # if version == field.version
469
- Spontaneous::Field.set_asynchronously(field, file, user)
470
- json(field.export(user))
471
- # else
472
- # errors = [[field.schema_id.to_s, [field.version, field.conflicted_value]]]
473
- # [409, json(Hash[errors])]
474
- # end
475
- else
476
- unauthorised!
477
- end
478
- end
479
- end
480
-
481
-
482
- post '/file/wrap/:id/:box_id' do
483
- content_for_request(true) do |content, box|
484
- file = params['file']
485
- type = box.type_for_mime_type(file[:type])
486
- if type
487
- if box.writable?(user, type)
488
- position = 0
489
- instance = type.new
490
- box.insert(position, instance)
491
- field = instance.field_for_mime_type(file[:type])
492
- Spontaneous::Field.set_asynchronously(field, file, user)
493
- content.save
494
- json({
495
- :position => position,
496
- :entry => instance.entry.export(user)
497
- })
498
- else
499
- unauthorised!
500
- end
501
- end
502
- end
503
- end
504
-
505
- post '/add/:id/:box_id/:type_name' do
506
- content_for_request(true) do |content, box|
507
- position = (params[:position] || 0).to_i
508
- type = content_model.schema.to_class(params[:type_name])#.constantize
509
-
510
- if box.writable?(user, type)
511
- instance = type.new(:created_by => user)
512
- box.insert(position, instance)
513
- content.save
514
- json({
515
- :position => position,
516
- :entry => instance.entry.export(user)
517
- })
518
- else
519
- unauthorised!
520
- end
521
- end
522
- end
523
-
524
- post '/destroy/:id' do
525
- content_for_request(true) do |content|
526
- if content.box.writable?(user)
527
- content.destroy
528
- json({})
529
- else
530
- unauthorised!
531
- end
532
- end
533
- end
534
-
535
- post '/slug/:id' do
536
- content_for_request(true) do |content|
537
- if params[:slug].nil? or params[:slug].empty?
538
- 406 # Not Acceptable
539
- else
540
- content.slug = params[:slug]
541
- if content.siblings.detect { |s| s.slug == content.slug }
542
- 409 # Conflict
543
- else
544
- content.save
545
- json({:path => content.path, :slug => content.slug })
546
- end
547
- end
548
- end
549
- end
550
-
551
- get '/slug/:id/unavailable' do
552
- content_for_request do |content|
553
- json(content.siblings.map { |c| c.slug })
554
- end
555
- end
556
-
557
- post '/slug/:id/titlesync' do
558
- content_for_request do |page|
559
- page.slug = page.title.unprocessed_value
560
- page.save
561
- json({:path => page.path, :slug => page.slug })
562
- end
563
- end
564
-
565
- post '/uid/:id' do
566
- if user.developer?
567
- content_for_request(true) do |content|
568
- content.uid = params[:uid]
569
- content.save
570
- json({:uid => content.uid })
571
- end
572
- else
573
- unauthorised!
574
- end
575
- end
576
-
577
- get '/targets/:schema_id/:id/:box_id' do
578
- klass = content_model.schema.to_class(params[:schema_id])
579
- if klass.alias?
580
- content_for_request do |content, box|
581
- options = {}
582
- if (query = params[:query])
583
- options[:search] = Regexp.new(query, Regexp::IGNORECASE)
584
- end
585
- targets = klass.targets(content, box, options).map do |t|
586
- { :id => t.id,
587
- :title => t.alias_title,
588
- :icon => t.exported_alias_icon }
589
- end
590
- json({
591
- :pages => 1,
592
- :total => targets.length,
593
- :page => 1,
594
- :targets => targets
595
- })
596
- end
597
- end
598
- end
599
-
600
- post '/alias/:id/:box_id' do
601
- content_for_request(true) do |content, box|
602
- type = content_model.schema.to_class(params[:alias_id])
603
- position = (params[:position] || 0).to_i
604
- if box.writable?(user, type)
605
- instance = type.for_target(params[:target_id])
606
- if instance
607
- box.insert(position, instance)
608
- content.save
609
- json({
610
- :position => position,
611
- :entry => instance.entry.export(user)
612
- })
613
- end
614
- else
615
- unauthorised!
616
- end
617
- end
618
- end
619
-
620
- get '/publish/changes' do
621
- if user.level.can_publish?
622
- json(Change)
623
- else
624
- unauthorised!
625
- end
626
- end
627
-
628
- post '/publish/publish' do
629
- ids = params[:page_ids]
630
- ids = ids.blank? ? [] : ids
631
- pages = ids.map(&:to_i)
632
- if pages.empty?
633
- 400
634
- else
635
- if user.level.can_publish?
636
- Spontaneous::Site.publish_pages(pages)
637
- json({})
638
- else
639
- unauthorised!
640
- end
641
- end
642
- end
643
-
644
- get '/shard/:sha1' do
645
- shard = Spontaneous.shard_path(params[:sha1])
646
- if ::File.file?(shard)
647
- # touch the shard file so that clean up routines can delete unmodified files
648
- # without affecting any uploads in progresss
649
- FileUtils.touch(shard)
650
- 200
651
- else
652
- 404
653
- end
654
- end
655
-
656
- post '/shard/:sha1' do
657
- file = params[:file]
658
- uploaded_hash = Spontaneous::Media.digest(file[:tempfile].path)
659
- if uploaded_hash == params[:sha1] # rand(10000) % 2 == 0 # use to test shard re-uploading
660
- shard_path = Spontaneous.shard_path(params[:sha1])
661
- FileUtils.mv(file[:tempfile].path, shard_path)
662
- 200
663
- else
664
- ::Rack::Utils.status_code(:conflict) #409
665
- end
666
- end
667
-
668
- post '/shard/replace/:id/?:box_id?' do
669
- content_for_request(true) do |content, box|
670
- target = box || content
671
- replace_with_shard(target, content.id)
672
- end
673
- end
674
-
675
- def replace_with_shard(target, target_id)
676
- field = target.fields.sid(params[:field])
677
- if target.field_writable?(user, field.name)
678
- # version = params[:version].to_i
679
- # if version == field.version
680
- Spontaneous::Media.combine_shards(params[:shards]) do |combined|
681
- Spontaneous::Field.set_asynchronously(field, {
682
- :filename => params[:filename],
683
- :tempfile => combined
684
- }, user)
685
- end
686
- json(field.export(user))
687
- # else
688
- # errors = [[field.schema_id.to_s, [field.version, field.conflicted_value]]]
689
- # [409, json(Hash[errors])]
690
- # end
691
- else
692
- unauthorised!
693
- end
694
- end
695
-
696
- # TODO: remove duplication here
697
- post '/shard/wrap/:id/:box_id' do
698
- content_for_request(true) do |content, box|
699
- type = box.type_for_mime_type(params[:mime_type])
700
- if type
701
- if box.writable?(user, type)
702
- position = 0
703
- instance = type.new
704
- box.insert(position, instance)
705
- field = instance.field_for_mime_type(params[:mime_type])
706
- Spontaneous::Media.combine_shards(params[:shards]) do |combined|
707
- Spontaneous::Field.set_asynchronously(field, {
708
- :filename => params[:filename],
709
- :tempfile => combined
710
- }, user)
711
- content.save
712
- # field.value = {
713
- # :filename => params[:filename],
714
- # :tempfile => combined
715
- # }
716
- end
717
- json({
718
- :position => position,
719
- :entry => instance.entry.export(user)
720
- })
721
- else
722
- unauthorised!
723
- end
724
- end
725
- end
726
- end
727
- # get "/favicon.ico" do
728
- # puts "Editing/favicon"
729
- # send_file(Spontaneous.static_dir / "favicon.ico")
730
- # end
731
-
732
-
733
- end # EditingInterface
734
-
735
-
736
-
737
- # Assets are separata from the main editing handlers so that I can still access them
738
- # in the case of a Schema modification error
739
- class AssetsHandler < ::Sinatra::Base
740
- get '/static/*' do
741
- send_file(Spontaneous.static_dir / params[:splat].first)
742
- end
743
-
744
-
745
- get '/js/*' do
746
- content_type :js
747
- File.read(Spontaneous.js_dir / params[:splat].first)
748
- end
749
-
750
- get '/css/*' do
751
- # need to check for file existing and just send that
752
- # though production server would handle that I suppose
753
- # as long as I release pre-compliled CSS files
754
- file = params[:splat].first
755
- if file =~ /\.css$/
756
- css_file = Spontaneous.css_dir / file
757
- if File.exists?(css_file)
758
- send_file(css_file)
759
- else
760
- content_type :css
761
- sass_template = Spontaneous.css_dir / File.basename(file, ".css") + ".scss"
762
- if File.exists?(sass_template)
763
- Sass::Engine.for_file(sass_template, :load_paths => [Spontaneous.css_dir], :filename => sass_template, :cache => false).render
764
- else
765
- raise Sinatra::NotFound
766
- end
767
- end
768
- else
769
- send_file(Spontaneous.css_dir / file)
770
- end
771
- end
772
- end
773
-
774
- class Preview < Sinatra::Base
775
- use CookieAuthentication
776
- use AroundPreview
777
- use Reloader if Spontaneous::Site.config.reload_classes
778
- include Spontaneous::Rack::Public
779
- helpers Spontaneous::Rack::UserHelpers
780
-
781
-
782
- set :views, Proc.new { Spontaneous.application_dir + '/views' }
783
-
784
- # redirect to /@spontaneous unless we're logged in
785
- before {
786
- redirect NAMESPACE, 302 unless user
787
- }
788
-
789
-
790
- # Forward all GETs to the page resolution method
791
- get '*' do
792
- render_path(params[:splat][0])
793
- end
794
-
795
- # Forward all POSTs to the page resolution method
796
- post '*' do
797
- render_path(params[:splat][0])
798
- end
799
-
800
- # Override the S::Rack::Public method to add in some cache-busting headers
801
- def render_page(page, format = :html, local_params = {})
802
- now = Time.now.to_formatted_s(:rfc822)
803
- response.headers[HTTP_EXPIRES] = now
804
- response.headers[HTTP_LAST_MODIFIED] = now
805
- response.headers[HTTP_CACHE_CONTROL] = HTTP_NO_CACHE
806
- super
807
- end
808
- end # Preview
809
-
810
132
  end
811
133
  end
812
134
  end
813
-