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
@@ -3,7 +3,7 @@ Capistrano::Configuration.instance(:must_exist).load do
3
3
  set :normalize_asset_timestamps, false
4
4
 
5
5
  set :bundle_cmd, "bundle"
6
- set :bundle_flags, "--deployment --quiet --binstubs --shebang ruby-local-exec"
6
+ set :bundle_flags, "--deployment --quiet --binstubs"
7
7
 
8
8
  # Remove tmp/pids from list of shared dirs that get symlinked into the release
9
9
  set :shared_children, %w(public/system log)
@@ -19,7 +19,7 @@ Capistrano::Configuration.instance(:must_exist).load do
19
19
  end
20
20
 
21
21
  task :symlink_application do
22
- run "cd #{release_path} && ln -s `bundle show spontaneous`/application public/.spontaneous"
22
+ run "cd #{release_path} && ln -s `#{fetch(:bundle_cmd, 'bundle')} show spontaneous`/application public/.spontaneous"
23
23
  end
24
24
 
25
25
  # Capistrano automatically creates a tmp directory - I don't like that
@@ -53,7 +53,7 @@ Capistrano::Configuration.instance(:must_exist).load do
53
53
  dumper.dump(dump_file)
54
54
  remote_dump_file = File.join(deploy_to, dumpfilename)
55
55
  top.upload(dump_file, remote_dump_file)
56
- run %(cd #{current_path} && bundle exec rake db:load dumpfile=#{remote_dump_file} )
56
+ run %(cd #{current_path} && #{fetch(:bundle_cmd, 'bundle')} exec rake db:load dumpfile=#{remote_dump_file} )
57
57
  end
58
58
  end
59
59
 
@@ -16,6 +16,7 @@ module Spontaneous::Cli
16
16
  method_option :user, :type => :string, :default => nil, :aliases => "-u", :desc => "Database admin user"
17
17
  method_option :password, :type => :string, :default => "", :aliases => "-p", :desc => "Database admin password"
18
18
  method_option :account, :type => :hash, :default => {}, :aliases => "-a", :desc => "Details of the root login"
19
+ method_option :create_user, :type => :boolean, :default => true, :desc => "Enable creation of a root user"
19
20
 
20
21
  def init
21
22
  prepare :init
@@ -35,7 +36,7 @@ module Spontaneous::Cli
35
36
  boot!
36
37
 
37
38
  # Add a root user if this is a new site
38
- insert_root_user if ::Spontaneous::Permissions::User.count == 0
39
+ insert_root_user if (options.create_user && ::Spontaneous::Permissions::User.count == 0)
39
40
 
40
41
  end
41
42
 
@@ -74,6 +75,7 @@ module Spontaneous::Cli
74
75
  say " >> Done"
75
76
  rescue => e
76
77
  say " >>> Error running migrations on database `#{site_config[:database]}`:\n > #{e}", :red
78
+ raise e
77
79
  end
78
80
  end
79
81
  end
@@ -99,18 +101,11 @@ module Spontaneous::Cli
99
101
 
100
102
  def create_database(connection, config)
101
103
  commands = case connection.database_type
102
- when :postgres
103
- [
104
- [%(CREATE ROLE "#{config[:user]}" LOGIN PASSWORD '#{config[:password]}'), false],
105
- [%(CREATE DATABASE "#{config[:database]}" WITH TEMPLATE=template0 ENCODING='UTF8' LC_COLLATE='C.UTF-8' LC_CTYPE='C.UTF-8' OWNER="#{config[:user]}"), true]
106
- ]
107
- when :mysql
108
- host = config[:host].blank? ? "" : "@#{config[:host]}"
109
- [
110
- ["CREATE DATABASE `#{config[:database]}` CHARACTER SET UTF8", true],
111
- ["GRANT ALL ON `#{config[:database]}`.* TO `#{config[:user]}`#{host} IDENTIFIED BY '#{config[:password]}'", false]
112
- ]
113
- end
104
+ when :postgres
105
+ create_postgres_database_commands(config)
106
+ when :mysql
107
+ create_mysql_database_commands(config)
108
+ end
114
109
  commands.each do |command, raise_error|
115
110
  begin
116
111
  connection.run(command)
@@ -119,5 +114,33 @@ module Spontaneous::Cli
119
114
  end
120
115
  end
121
116
  end
117
+
118
+ def create_mysql_database_commands(config)
119
+ host = config[:host].blank? ? "" : "@#{config[:host]}"
120
+ cmds = [ ["CREATE DATABASE `#{config[:database]}` CHARACTER SET UTF8", true] ]
121
+ unless config[:user] == "root"
122
+ cmds << ["GRANT ALL ON `#{config[:database]}`.* TO `#{config[:user]}`#{host} IDENTIFIED BY '#{config[:password]}'", false]
123
+ end
124
+ cmds
125
+ end
126
+
127
+ # On some machines the db creation fails due to incompabilities between the UTF8 encoding
128
+ # and the configured locale.
129
+ # You can force a locale for the db by adding LC_COLLATE & LC_CTYPE params
130
+ # to the CREATE command:
131
+ #
132
+ # LC_COLLATE='C.UTF-8' LC_CTYPE='C.UTF-8'
133
+ #
134
+ # but I don't know a good/the best way to determine the most appropriate UTF-8 locale
135
+ # C.UTF-8 doesn't exist on OS X.
136
+ def create_postgres_database_commands(config)
137
+ create_cmd = %(CREATE DATABASE "#{config[:database]}" WITH TEMPLATE=template0 ENCODING='UTF8')
138
+ cmds = []
139
+ unless config[:user].blank?
140
+ create_cmd << %( OWNER="#{config[:user]}")
141
+ cmds << [%(CREATE ROLE "#{config[:user]}" LOGIN PASSWORD '#{config[:password]}'), false]
142
+ end
143
+ cmds << [create_cmd, true]
144
+ end
122
145
  end # Init
123
146
  end # Spontaneous::Cli
@@ -68,7 +68,6 @@ module Spontaneous
68
68
  prepare! :server, mode
69
69
  Spontaneous::Server.run!(options)
70
70
  end
71
-
72
71
  end
73
72
  end
74
73
  end
@@ -129,7 +129,8 @@ module Spontaneous
129
129
  Spontaneous::Site.publish_all
130
130
  end
131
131
  # Rescue all errors to feed back to the UI
132
- rescue ::Exception => e
132
+ rescue => e
133
+ $stderr.puts(e.message)
133
134
  send_error_notification(e)
134
135
  end
135
136
 
@@ -33,7 +33,7 @@ module Spontaneous
33
33
  if choice and choice <= actions.length and choice > 0
34
34
  action = actions[choice - 1]
35
35
  begin
36
- Spontaneous::Schema.apply(action)
36
+ Spontaneous.schema.apply(action)
37
37
  rescue Spontaneous::SchemaModificationError => error
38
38
  fix_schema(error)
39
39
  end
@@ -97,11 +97,13 @@ module Spontaneous
97
97
 
98
98
  class Root < ::Thor
99
99
  register Spontaneous::Cli::Console, "console", "console", "Gives you console access to the current site"
100
+ register Spontaneous::Cli::Console, "c", "c", "Gives you console access to the current site"
100
101
  register Spontaneous::Cli::User, "user", "user [ACTION]", "Administer site users"
101
102
  register Spontaneous::Cli::Generate, "generate", "generate [OBJECT]", "Generates things"
102
103
  register Spontaneous::Cli::Site, "site", "site [ACTION]", "Run site-wide actions"
103
104
  register Spontaneous::Cli::Init, "init", "init", "Creates databases and initialises a new Spontaneous site"
104
105
  register Spontaneous::Cli::Server, "server", "server [ACTION]", "Launch development server(s)"
106
+ register Spontaneous::Cli::Server, "s", "s [ACTION]", "Launch development server(s)"
105
107
  register Spontaneous::Cli::Media, "media", "media [ACTION]", "Manage site media"
106
108
  register Spontaneous::Cli::Sync, "sync", "sync [DIRECTION]", "Sync database and media to and from the production server"
107
109
  register Spontaneous::Cli::Migrate, "migrate", "migrate", "Runs Spontaneous migrations"
@@ -12,17 +12,9 @@ module Spontaneous::Collections
12
12
  @store = Hash.new { |hash, key| hash[key] = [] }
13
13
  (piece_store || []).each do |data|
14
14
  id = data[0]
15
- entry = \
16
- if data.length == 2
17
- page = @owner._pieces.detect { |piece| piece.id == id }
18
- if page
19
- Spontaneous::PagePiece.new(@owner, page, data[1])
20
- else
21
- nil
22
- end
23
- else
24
- @owner._pieces.detect { |piece| piece.id == id }
25
- end
15
+ entry = if (content = @owner._pieces.detect { |piece| piece.id == id })
16
+ content.page? ? Spontaneous::PagePiece.new(@owner, content, data[1]) : content
17
+ end
26
18
  # if the piece/page has been deleted or is invisible
27
19
  # then we just want to silently skip it
28
20
  if entry
@@ -118,7 +110,7 @@ module Spontaneous::Collections
118
110
  end
119
111
 
120
112
  def ==(set)
121
- super or entries == set
113
+ super || (entries == set)
122
114
  end
123
115
 
124
116
  protected
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+
3
+
4
+ module Spontaneous::Collections
5
+ class HashWithFallback < Hash
6
+ def initialize(fallback, use_fallback_proc, obj = nil, &block)
7
+ use_fallback_proc ||= proc { |val| val.nil? }
8
+ @fallback, @use_fallback_proc = fallback, use_fallback_proc
9
+ super(obj, &block)
10
+ end
11
+
12
+ def [](key)
13
+ val = super
14
+ if @use_fallback_proc[val]
15
+ val = @fallback[key]
16
+ end
17
+ val
18
+ end
19
+ end
20
+ end
@@ -32,8 +32,8 @@ module Spontaneous::Collections
32
32
  local_order << key unless order.include?(key)
33
33
  end
34
34
 
35
- def key?(key)
36
- keys.include?(key.to_sym)
35
+ def key?(key, inherited = true)
36
+ keys(inherited).include?(key.to_sym)
37
37
  end
38
38
 
39
39
  alias_method :has_key?, :key?
@@ -86,8 +86,8 @@ module Spontaneous::Collections
86
86
  end
87
87
  end
88
88
 
89
- def keys
90
- order.map { |name| name }
89
+ def keys(inherited = true)
90
+ order(inherited).map { |name| name }
91
91
  end
92
92
 
93
93
  def values
@@ -120,8 +120,9 @@ module Spontaneous::Collections
120
120
  end
121
121
 
122
122
 
123
- def order
123
+ def order(inherited = true)
124
124
  return @custom_order if @custom_order
125
+ return local_order unless inherited
125
126
  superset? ? (superset.order + local_order) : local_order
126
127
  end
127
128
 
@@ -22,7 +22,7 @@ module Spontaneous
22
22
  Version.subclasses.sort { |v1, v2| v1.version <=> v2.version }
23
23
  end
24
24
 
25
- def hash(password)
25
+ def hash_password(password)
26
26
  current.create(password)
27
27
  end
28
28
 
@@ -71,7 +71,7 @@ module Spontaneous
71
71
  alias_method :needs_upgrade?, :outdated?
72
72
 
73
73
  def upgrade
74
- Spontaneous::Crypt.hash(@password)
74
+ Spontaneous::Crypt.hash_password(@password)
75
75
  end
76
76
 
77
77
  def salt
@@ -58,28 +58,20 @@ module Spontaneous
58
58
  end
59
59
  end
60
60
 
61
- def has_many(name, opts = {})
62
- opts[:association] = :one_to_many
63
- opts[:model] ||= self
64
- opts[:mapper_method] = "#{name}_mapper"
61
+ def has_many_content(name, opts = {})
62
+ opts[:association] = :one_to_many
65
63
  opts[:dataset_method] = "#{name}_dataset"
66
64
  opts[:add_method] = "add_#{name.to_s.singularize}"
67
- opts[:module] ||= association_method_module
65
+ mod = opts[:module] ||= association_method_module
68
66
 
69
- where = opts[:model].respond_to?(:where!) ? :where! : :where
70
-
71
- define_association_method(opts, opts[:mapper_method]) {
72
- opts[:model] == model ? self.mapper : opts[:model]
73
- }
74
- define_association_method(opts, opts[:dataset_method]) {
75
- m = send(opts[:mapper_method])
76
- c = m.respond_to?(:qualify_column) ? m.send(:qualify_column, opts[:key]) : opts[:key]
77
- m.send(where, [[c, id]])
67
+ define_association_method(mod, opts[:dataset_method]) {
68
+ m = mapper
69
+ m.where!([[m.qualify_column(opts[:key]), id]])
78
70
  }
79
- define_association_method(opts, name) { |options = {}|
80
- cached_has_many_association(name, options)
71
+ define_association_method(mod, name) { |options = {}|
72
+ load_cached_association(name, options)
81
73
  }
82
- define_association_method(opts, opts[:add_method]) { |member|
74
+ define_association_method(mod, opts[:add_method]) { |member|
83
75
  member.send("#{opts[:key]}=", self.id)
84
76
  member.save
85
77
  }
@@ -87,35 +79,20 @@ module Spontaneous
87
79
  associations[name] = opts
88
80
  end
89
81
 
90
- def define_association_method(opts, name, &block)
91
- opts[:module].module_eval{ define_method(name, &block) }
92
- end
93
-
94
- alias_method :one_to_many, :has_many
95
-
96
- def belongs_to(name, opts = {})
97
- opts[:association] = :many_to_one
98
- opts[:model] ||= self
99
- opts[:mapper_method] = "#{name}_mapper"
82
+ def belongs_to_content(name, opts = {})
83
+ opts[:association] = :many_to_one
100
84
  opts[:dataset_method] = "#{name}_dataset"
101
85
  opts[:add_method] = "#{name}="
102
- opts[:module] ||= association_method_module
103
-
104
- where = opts[:model].respond_to?(:where!) ? :where! : :where
86
+ mod = opts[:module] ||= association_method_module
105
87
 
106
- define_association_method(opts, opts[:mapper_method]) {
107
- opts[:model] == model ? self.mapper : opts[:model]
108
- }
109
- define_association_method(opts, opts[:dataset_method]) {
110
- m = send(opts[:mapper_method])
111
- id = send(opts[:key])
112
- c = m.respond_to?(:qualify_column) ? m.send(:qualify_column, :id) : :id
113
- m.send(where, [[c, id]])
88
+ define_association_method(mod, opts[:dataset_method]) {
89
+ m = mapper
90
+ m.where!([[m.qualify_column(:id), send(opts[:key])]])
114
91
  }
115
- define_association_method(opts, name) { |options = {}|
116
- cached_belongs_to_association(name, options)
92
+ define_association_method(mod, name) { |options = {}|
93
+ load_cached_association(name, options)
117
94
  }
118
- define_association_method(opts, opts[:add_method]) { |owner|
95
+ define_association_method(mod, opts[:add_method]) { |owner|
119
96
  set_association_cache(name, owner)
120
97
  send("#{opts[:key]}=", owner.id) if owner
121
98
  }
@@ -123,7 +100,84 @@ module Spontaneous
123
100
  associations[name] = opts
124
101
  end
125
102
 
126
- alias_method :many_to_one, :belongs_to
103
+ alias_method :many_to_one_content, :belongs_to_content
104
+
105
+ def define_association_method(mod, name, &block)
106
+ mod.module_eval{ define_method(name, &block) }
107
+ end
108
+
109
+ alias_method :one_to_many_content, :has_many_content
110
+
111
+ def one_to_many(name, opts={}, &block)
112
+ define_plural_proxy_association(:one_to_many, name, opts, &block)
113
+ end
114
+
115
+ alias_method :has_many, :one_to_many
116
+
117
+ def many_to_one(name, opts = {}, &block)
118
+ association = define_singular_proxy_association(:many_to_one, name, opts, &block)
119
+ # We need to feed back changes to the association key to the owning
120
+ # content model. It doesn't matter if the proxy class never recieves
121
+ # the message because we don't care about its state at all
122
+ association[:keys].map { |key| "#{key}=" }.each do |method|
123
+ association_proxy_class.class_eval(<<-RB)
124
+ def #{method}(value)
125
+ __content__.send(:#{method}, value)
126
+ end
127
+ RB
128
+ end
129
+ association
130
+ end
131
+
132
+ alias_method :belongs_to, :many_to_one
133
+
134
+ def one_to_one(name, opts = {}, &block)
135
+ define_singular_proxy_association(:one_to_one, name, opts, &block)
136
+ end
137
+
138
+ alias_method :has_one, :one_to_one
139
+
140
+ def define_plural_proxy_association(type, name, opts, &block)
141
+ singular = name.to_s.singularize
142
+ plural = name.to_s.pluralize
143
+ methods = [ name, "#{plural}_dataset", "add_#{singular}", "remove_#{singular}", "remove_all_#{plural}", ]
144
+ define_proxy_association(type, methods, name, opts, &block)
145
+ end
146
+
147
+ def define_singular_proxy_association(type, name, opts, &block)
148
+ methods = [ name, "#{name}=", "#{name}_dataset" ]
149
+ define_proxy_association(type, methods, name, opts, &block)
150
+ end
151
+
152
+ def define_proxy_association(association, proxy_methods, name, opts = {}, &block)
153
+ assoc = association_proxy_class.send(association, name, opts, &block)
154
+ proxy_methods.each do |method_name|
155
+ association_method_module.module_eval(<<-RB, __FILE__, __LINE__)
156
+ def #{method_name}(*args, &block)
157
+ association_proxy_instance.send(:#{method_name}, *args, &block)
158
+ end
159
+ RB
160
+ end
161
+ assoc
162
+ end
163
+
164
+ def association_proxy_class
165
+ @association_proxy_class ||= Class.new(association_proxy_superclass)
166
+ end
167
+
168
+ # If we have a superclass that is a content object then we want to
169
+ # inherit its associations. If not then we need to create a base
170
+ # class.
171
+ def association_proxy_superclass
172
+ if superclass.respond_to?(:association_proxy_class)
173
+ superclass.association_proxy_class
174
+ else
175
+ ::Sequel::Model(mapper.table.dataset).tap do |klass|
176
+ klass.send :plugin, :association_dependencies
177
+ klass.send :attr_reader, :__content__
178
+ end
179
+ end
180
+ end
127
181
 
128
182
  module InstanceMethods
129
183
  def after_destroy
@@ -140,33 +194,19 @@ module Spontaneous
140
194
 
141
195
  private
142
196
 
143
- def cached_belongs_to_association(name, options)
144
- clear_association_cache(name) if options[:reload]
145
- ac = associations_cache
146
- unless ac.key?(name)
147
- ac[name] = load_belongs_to_association(name)
197
+ def association_proxy_instance
198
+ @association_proxy_instance ||= self.class.association_proxy_class.call(attributes).tap do |instance|
199
+ instance.instance_variable_set(:@__content__, self)
148
200
  end
149
- ac[name]
150
201
  end
151
202
 
152
- def load_belongs_to_association(name)
153
- assoc = model.associations[name]
154
- id = send(assoc[:key])
203
+ def load_many_to_one_association(assoc)
204
+ id = send(assoc[:key])
155
205
  return nil if id.nil?
156
- self.send(assoc[:mapper_method])[id]
206
+ mapper[id]
157
207
  end
158
208
 
159
- def cached_has_many_association(name, options)
160
- clear_association_cache(name) if options[:reload]
161
- ac = associations_cache
162
- unless ac.key?(name)
163
- ac[name] = load_has_many_association(name)
164
- end
165
- ac[name]
166
- end
167
-
168
- def load_has_many_association(name)
169
- assoc = model.associations[name]
209
+ def load_one_to_many_association(assoc)
170
210
  members = self.send(assoc[:dataset_method]).all
171
211
  if (reciprocal = assoc[:reciprocal])
172
212
  members.each do |member|
@@ -176,6 +216,17 @@ module Spontaneous
176
216
  members
177
217
  end
178
218
 
219
+ def load_cached_association(name, options)
220
+ assoc = model.associations[name]
221
+ clear_association_cache(name) if options[:reload]
222
+ ac = associations_cache
223
+ unless ac.key?(name)
224
+ load_method = "load_#{assoc[:association]}_association"
225
+ ac[name] = send(load_method, assoc)
226
+ end
227
+ ac[name]
228
+ end
229
+
179
230
  def associations_cache
180
231
  @associations_cache ||= {}
181
232
  end
@@ -190,6 +241,7 @@ module Spontaneous
190
241
 
191
242
  def refresh
192
243
  associations_cache.clear
244
+ @association_proxy_instance = nil
193
245
  super
194
246
  end
195
247
  end
@@ -19,7 +19,7 @@ module Spontaneous
19
19
  class ScopingMapper
20
20
  extend Forwardable
21
21
 
22
- attr_reader :schema
22
+ attr_reader :schema, :table
23
23
 
24
24
  def initialize(table, schema)
25
25
  @table, @schema = table, schema
@@ -46,6 +46,12 @@ module Spontaneous
46
46
 
47
47
  class InvalidPrototypeDefinitionError < Error; end
48
48
 
49
+ class AnonymousRootException < Error
50
+ def initialize
51
+ super("Content roots must have a valid slug")
52
+ end
53
+ end
54
+
49
55
  class SchemaModificationError < Error
50
56
  extend Forwardable
51
57
 
@@ -7,6 +7,12 @@ module ObjectSpace
7
7
  ObjectSpace.each_object(Class) { |o| klasses << o }
8
8
  klasses
9
9
  end
10
+
11
+ def modules
12
+ modules = []
13
+ ObjectSpace.each_object(Module) { |o| modules << o }
14
+ modules
15
+ end
10
16
  end
11
17
  end unless ObjectSpace.respond_to?(:classes)
12
18
 
@@ -10,6 +10,7 @@ module Spontaneous
10
10
  paths.add :templates, "templates"
11
11
  paths.add :config, "config"
12
12
  paths.add :public, "public"
13
+ paths.add :assets, "assets"
13
14
  paths.add :tasks, ["lib/tasks", "**/*.rake"]
14
15
  paths.add :migrations, ["db/migrations", "**/*.rake"]
15
16
  paths.add :plugins, ["plugins", "*"]