spontaneous 0.1.0.alpha1

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 (556) hide show
  1. data/Gemfile +49 -0
  2. data/Gemfile.lock +146 -0
  3. data/LICENSE +0 -0
  4. data/README +0 -0
  5. data/Rakefile +284 -0
  6. data/Readme.markdown +7 -0
  7. data/application/css/add_alias_dialogue.scss +27 -0
  8. data/application/css/definitions.scss +249 -0
  9. data/application/css/developer.scss +9 -0
  10. data/application/css/editing.scss +649 -0
  11. data/application/css/login.scss +91 -0
  12. data/application/css/min/54ee0ed3c7fac7632bd5c020d69e9a2503e0c88c.css +1 -0
  13. data/application/css/min/c256adc144e2bdd0b0539356b04eb62db01e1dc3.css +1 -0
  14. data/application/css/popover.scss +335 -0
  15. data/application/css/schema_error.scss +90 -0
  16. data/application/css/spontaneous.scss +111 -0
  17. data/application/css/unsupported.scss +16 -0
  18. data/application/css/v2.scss +1606 -0
  19. data/application/css/variables.scss +80 -0
  20. data/application/js/add_alias_dialogue.js +59 -0
  21. data/application/js/add_home_dialogue.js +59 -0
  22. data/application/js/ajax.js +99 -0
  23. data/application/js/authentication.js +22 -0
  24. data/application/js/box.js +104 -0
  25. data/application/js/box_container.js +82 -0
  26. data/application/js/compatibility.js +132 -0
  27. data/application/js/conflicted_field_dialogue.js +92 -0
  28. data/application/js/content.js +224 -0
  29. data/application/js/content_area.js +44 -0
  30. data/application/js/dialogue.js +196 -0
  31. data/application/js/dom.js +71 -0
  32. data/application/js/edit_dialogue.js +137 -0
  33. data/application/js/edit_panel.js +232 -0
  34. data/application/js/editing.js +42 -0
  35. data/application/js/entry.js +13 -0
  36. data/application/js/extensions.js +104 -0
  37. data/application/js/field.js +4 -0
  38. data/application/js/field_preview.js +55 -0
  39. data/application/js/field_types/date_field.js +16 -0
  40. data/application/js/field_types/file_field.js +71 -0
  41. data/application/js/field_types/image_field.js +358 -0
  42. data/application/js/field_types/markdown_field.js +656 -0
  43. data/application/js/field_types/string_field.js +185 -0
  44. data/application/js/image.js +72 -0
  45. data/application/js/init.js +34 -0
  46. data/application/js/load.js +4 -0
  47. data/application/js/location.js +157 -0
  48. data/application/js/login.js +53 -0
  49. data/application/js/min/492a209de8ee955fa9c729a765377495001e11b1.js +17 -0
  50. data/application/js/min/80f684d77c940887a1d4a63e3a96102e993baa98.js +88 -0
  51. data/application/js/min/b8abf302a824c35385ff517b34111e1710ff3b37.js +2 -0
  52. data/application/js/min/c7140ec9475e5bf868b901e0621338d7d162358b.js +3 -0
  53. data/application/js/min/f07f2bd6630ee31e1c2288ec223383d8f0658ba6.js +2 -0
  54. data/application/js/page.js +43 -0
  55. data/application/js/page_browser.js +147 -0
  56. data/application/js/page_entry.js +47 -0
  57. data/application/js/popover.js +99 -0
  58. data/application/js/popover_view.js +56 -0
  59. data/application/js/preview.js +64 -0
  60. data/application/js/progress.js +358 -0
  61. data/application/js/properties.js +90 -0
  62. data/application/js/publish.js +187 -0
  63. data/application/js/require.js +129 -0
  64. data/application/js/sharded_upload.js +206 -0
  65. data/application/js/side_bar.js +30 -0
  66. data/application/js/spontaneous.js +6 -0
  67. data/application/js/state.js +64 -0
  68. data/application/js/status_bar.js +47 -0
  69. data/application/js/top_bar.js +368 -0
  70. data/application/js/types.js +98 -0
  71. data/application/js/upload.js +88 -0
  72. data/application/js/upload_manager.js +319 -0
  73. data/application/js/user.js +37 -0
  74. data/application/js/vendor/.DS_Store +0 -0
  75. data/application/js/vendor/JS.Class-2.1.5/CHANGELOG +283 -0
  76. data/application/js/vendor/JS.Class-2.1.5/MIT-LICENSE +30 -0
  77. data/application/js/vendor/JS.Class-2.1.5/README +30 -0
  78. data/application/js/vendor/JS.Class-2.1.5/min/command.js +1 -0
  79. data/application/js/vendor/JS.Class-2.1.5/min/comparable.js +1 -0
  80. data/application/js/vendor/JS.Class-2.1.5/min/constant_scope.js +1 -0
  81. data/application/js/vendor/JS.Class-2.1.5/min/core.js +1 -0
  82. data/application/js/vendor/JS.Class-2.1.5/min/decorator.js +1 -0
  83. data/application/js/vendor/JS.Class-2.1.5/min/enumerable.js +1 -0
  84. data/application/js/vendor/JS.Class-2.1.5/min/forwardable.js +1 -0
  85. data/application/js/vendor/JS.Class-2.1.5/min/hash.js +1 -0
  86. data/application/js/vendor/JS.Class-2.1.5/min/linked_list.js +1 -0
  87. data/application/js/vendor/JS.Class-2.1.5/min/loader.js +1 -0
  88. data/application/js/vendor/JS.Class-2.1.5/min/method_chain.js +1 -0
  89. data/application/js/vendor/JS.Class-2.1.5/min/observable.js +1 -0
  90. data/application/js/vendor/JS.Class-2.1.5/min/package.js +1 -0
  91. data/application/js/vendor/JS.Class-2.1.5/min/proxy.js +1 -0
  92. data/application/js/vendor/JS.Class-2.1.5/min/ruby.js +1 -0
  93. data/application/js/vendor/JS.Class-2.1.5/min/set.js +1 -0
  94. data/application/js/vendor/JS.Class-2.1.5/min/stack_trace.js +1 -0
  95. data/application/js/vendor/JS.Class-2.1.5/min/state.js +1 -0
  96. data/application/js/vendor/JS.Class-2.1.5/min/stdlib.js +16 -0
  97. data/application/js/vendor/JS.Class-2.1.5/src/command.js +93 -0
  98. data/application/js/vendor/JS.Class-2.1.5/src/comparable.js +37 -0
  99. data/application/js/vendor/JS.Class-2.1.5/src/constant_scope.js +48 -0
  100. data/application/js/vendor/JS.Class-2.1.5/src/core.js +1060 -0
  101. data/application/js/vendor/JS.Class-2.1.5/src/decorator.js +50 -0
  102. data/application/js/vendor/JS.Class-2.1.5/src/enumerable.js +505 -0
  103. data/application/js/vendor/JS.Class-2.1.5/src/forwardable.js +22 -0
  104. data/application/js/vendor/JS.Class-2.1.5/src/hash.js +334 -0
  105. data/application/js/vendor/JS.Class-2.1.5/src/linked_list.js +114 -0
  106. data/application/js/vendor/JS.Class-2.1.5/src/loader.js +553 -0
  107. data/application/js/vendor/JS.Class-2.1.5/src/method_chain.js +172 -0
  108. data/application/js/vendor/JS.Class-2.1.5/src/observable.js +55 -0
  109. data/application/js/vendor/JS.Class-2.1.5/src/package.js +472 -0
  110. data/application/js/vendor/JS.Class-2.1.5/src/proxy.js +58 -0
  111. data/application/js/vendor/JS.Class-2.1.5/src/ruby.js +44 -0
  112. data/application/js/vendor/JS.Class-2.1.5/src/set.js +332 -0
  113. data/application/js/vendor/JS.Class-2.1.5/src/stack_trace.js +151 -0
  114. data/application/js/vendor/JS.Class-2.1.5/src/state.js +95 -0
  115. data/application/js/vendor/JS.Class-2.1.5/src/stdlib.js +2612 -0
  116. data/application/js/vendor/crypto-2.3.0-crypto.js +160 -0
  117. data/application/js/vendor/crypto-2.3.0-sha1.js +91 -0
  118. data/application/js/vendor/diff_match_patch.js +2153 -0
  119. data/application/js/vendor/jquery-1.4.2.min.js +154 -0
  120. data/application/js/vendor/jquery-1.4.3.min.js +166 -0
  121. data/application/js/vendor/jquery-1.5.1.min.js +16 -0
  122. data/application/js/vendor/jquery-1.5.1rc1.min.js +24 -0
  123. data/application/js/vendor/jquery-1.6.2.min.js +18 -0
  124. data/application/js/vendor/jquery-ui-1.8.6.custom.min.js +265 -0
  125. data/application/js/vendor/jquery-ui-1.8.9.custom.min.js +415 -0
  126. data/application/js/vendor/jquery-ui-1.8.custom.min.js +106 -0
  127. data/application/js/vendor/jquery.hotkeys-0.7.9.js +248 -0
  128. data/application/js/vendor/jquery.hotkeys-0.7.9.min.js +19 -0
  129. data/application/js/vendor/jsdiff.js +169 -0
  130. data/application/js/views/box_view.js +229 -0
  131. data/application/js/views/page_piece_view.js +45 -0
  132. data/application/js/views/page_view.js +238 -0
  133. data/application/js/views/piece_view.js +178 -0
  134. data/application/js/views.js +110 -0
  135. data/application/static/editing-0-noise.png +0 -0
  136. data/application/static/editing-1-noise.png +0 -0
  137. data/application/static/editing-texture-1.png +0 -0
  138. data/application/static/editing-texture.png +0 -0
  139. data/application/static/editing-toolbar-shadow-bottom.png +0 -0
  140. data/application/static/editing-toolbar-shadow-top.png +0 -0
  141. data/application/static/favicon.ico +0 -0
  142. data/application/static/inner-glow.png +0 -0
  143. data/application/static/item-buttons.png +0 -0
  144. data/application/static/location-arrow.png +0 -0
  145. data/application/static/logo-400px-transparent.png +0 -0
  146. data/application/static/missing.png +0 -0
  147. data/application/static/orange-down-arrow.png +0 -0
  148. data/application/static/page-browser-next.png +0 -0
  149. data/application/static/paper-texture-dark.png +0 -0
  150. data/application/static/px.gif +0 -0
  151. data/application/static/select-arrow-root.png +0 -0
  152. data/application/static/select-arrow.png +0 -0
  153. data/application/static/slot-down-arrow.png +0 -0
  154. data/application/static/splash.png +0 -0
  155. data/application/static/spontaneous.png +0 -0
  156. data/application/static/spot.png +0 -0
  157. data/application/static/spot.svg +40 -0
  158. data/application/static/texture.png +0 -0
  159. data/application/views/index.erubis +46 -0
  160. data/application/views/login.erubis +69 -0
  161. data/application/views/schema_modification_error.html.erb +61 -0
  162. data/application/views/unsupported.erubis +23 -0
  163. data/bin/limit-upload +5 -0
  164. data/bin/spot +10 -0
  165. data/bin/unlimit-upload +3 -0
  166. data/config/nginx.conf +60 -0
  167. data/db/migrations/20100610142136_init.rb +66 -0
  168. data/db/migrations/20101130104334_timestamps.rb +44 -0
  169. data/db/migrations/20101202113205_site_publishing_flags.rb +12 -0
  170. data/db/migrations/20101206124543_aliases.rb +16 -0
  171. data/db/migrations/20110201133550_visibility.rb +27 -0
  172. data/db/migrations/20110209152710_users_and_groups.rb +58 -0
  173. data/db/migrations/20110215133910_boxes.rb +25 -0
  174. data/db/migrations/20110521114145_remove_slots_and_entries.rb +21 -0
  175. data/db/migrations/20110604192145_rename_schema_id_columns.rb +22 -0
  176. data/db/migrations/20110805141925_rename_site_to_state.rb +11 -0
  177. data/lib/cutaneous/context_helper.rb +82 -0
  178. data/lib/cutaneous/first_pass_parser.rb +23 -0
  179. data/lib/cutaneous/first_pass_renderer.rb +18 -0
  180. data/lib/cutaneous/parser_core.rb +18 -0
  181. data/lib/cutaneous/preview_context.rb +31 -0
  182. data/lib/cutaneous/preview_renderer.rb +15 -0
  183. data/lib/cutaneous/publish_context.rb +9 -0
  184. data/lib/cutaneous/renderer.rb +122 -0
  185. data/lib/cutaneous/request_context.rb +8 -0
  186. data/lib/cutaneous/second_pass_parser.rb +23 -0
  187. data/lib/cutaneous/second_pass_renderer.rb +18 -0
  188. data/lib/cutaneous.rb +47 -0
  189. data/lib/sequel/plugins/content_table_inheritance.rb +196 -0
  190. data/lib/sequel/plugins/yajl_serialization.rb +154 -0
  191. data/lib/spontaneous/application/feature.rb +9 -0
  192. data/lib/spontaneous/application/plugin.rb +13 -0
  193. data/lib/spontaneous/application.rb +8 -0
  194. data/lib/spontaneous/box.rb +232 -0
  195. data/lib/spontaneous/box_style.rb +64 -0
  196. data/lib/spontaneous/change.rb +107 -0
  197. data/lib/spontaneous/cli/adapter.rb +13 -0
  198. data/lib/spontaneous/cli/base.rb +184 -0
  199. data/lib/spontaneous/cli/console.rb +0 -0
  200. data/lib/spontaneous/cli/media.rb +13 -0
  201. data/lib/spontaneous/cli/server.rb +50 -0
  202. data/lib/spontaneous/cli/site.rb +46 -0
  203. data/lib/spontaneous/cli/sync.rb +42 -0
  204. data/lib/spontaneous/cli/tasks.rb +9 -0
  205. data/lib/spontaneous/cli.rb +83 -0
  206. data/lib/spontaneous/collections/box_set.rb +56 -0
  207. data/lib/spontaneous/collections/change_set.rb +43 -0
  208. data/lib/spontaneous/collections/entry_set.rb +83 -0
  209. data/lib/spontaneous/collections/field_set.rb +53 -0
  210. data/lib/spontaneous/collections/prototype_set.rb +131 -0
  211. data/lib/spontaneous/collections/style_set.rb +13 -0
  212. data/lib/spontaneous/config.rb +156 -0
  213. data/lib/spontaneous/constants.rb +24 -0
  214. data/lib/spontaneous/content.rb +113 -0
  215. data/lib/spontaneous/content_query.rb +17 -0
  216. data/lib/spontaneous/errors.rb +48 -0
  217. data/lib/spontaneous/extensions/array.rb +18 -0
  218. data/lib/spontaneous/extensions/class.rb +17 -0
  219. data/lib/spontaneous/extensions/hash.rb +18 -0
  220. data/lib/spontaneous/extensions/json.rb +26 -0
  221. data/lib/spontaneous/extensions/kernel.rb +7 -0
  222. data/lib/spontaneous/extensions/object.rb +30 -0
  223. data/lib/spontaneous/extensions/object_space.rb +12 -0
  224. data/lib/spontaneous/extensions/string.rb +44 -0
  225. data/lib/spontaneous/facet.rb +47 -0
  226. data/lib/spontaneous/field_types/date_field.rb +12 -0
  227. data/lib/spontaneous/field_types/field.rb +252 -0
  228. data/lib/spontaneous/field_types/image_field.rb +329 -0
  229. data/lib/spontaneous/field_types/markdown_field.rb +37 -0
  230. data/lib/spontaneous/field_types/string_field.rb +14 -0
  231. data/lib/spontaneous/field_types.rb +40 -0
  232. data/lib/spontaneous/generators/page/inline.html.cut +1 -0
  233. data/lib/spontaneous/generators/page/page.html.cut.tt +4 -0
  234. data/lib/spontaneous/generators/page/page.rb.tt +9 -0
  235. data/lib/spontaneous/generators/page.rb +38 -0
  236. data/lib/spontaneous/generators/site/.gitignore +4 -0
  237. data/lib/spontaneous/generators/site/Gemfile.tt +31 -0
  238. data/lib/spontaneous/generators/site/Rakefile.tt +6 -0
  239. data/lib/spontaneous/generators/site/config/back.ru +7 -0
  240. data/lib/spontaneous/generators/site/config/boot.rb +19 -0
  241. data/lib/spontaneous/generators/site/config/database.yml.tt +21 -0
  242. data/lib/spontaneous/generators/site/config/deploy.rb.tt +0 -0
  243. data/lib/spontaneous/generators/site/config/environment.rb.tt +8 -0
  244. data/lib/spontaneous/generators/site/config/environments/development.rb.tt +15 -0
  245. data/lib/spontaneous/generators/site/config/environments/production.rb.tt +5 -0
  246. data/lib/spontaneous/generators/site/config/front.ru +8 -0
  247. data/lib/spontaneous/generators/site/config/user_levels.yml +22 -0
  248. data/lib/spontaneous/generators/site/lib/site.rb.tt +4 -0
  249. data/lib/spontaneous/generators/site/lib/tasks/site.rake.tt +8 -0
  250. data/lib/spontaneous/generators/site/public/css/site.css +0 -0
  251. data/lib/spontaneous/generators/site/public/favicon.ico +0 -0
  252. data/lib/spontaneous/generators/site/public/js/.empty_directory +0 -0
  253. data/lib/spontaneous/generators/site/public/js/site.js +0 -0
  254. data/lib/spontaneous/generators/site/public/robots.txt +0 -0
  255. data/lib/spontaneous/generators/site/schema/.map +1 -0
  256. data/lib/spontaneous/generators/site/schema/page.rb.tt +8 -0
  257. data/lib/spontaneous/generators/site/schema/piece.rb.tt +4 -0
  258. data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +13 -0
  259. data/lib/spontaneous/generators/site.rb +77 -0
  260. data/lib/spontaneous/generators.rb +23 -0
  261. data/lib/spontaneous/image_size.rb +117 -0
  262. data/lib/spontaneous/json.rb +33 -0
  263. data/lib/spontaneous/layout.rb +15 -0
  264. data/lib/spontaneous/loader.rb +280 -0
  265. data/lib/spontaneous/logger.rb +369 -0
  266. data/lib/spontaneous/media.rb +84 -0
  267. data/lib/spontaneous/page.rb +92 -0
  268. data/lib/spontaneous/page_controller.rb +18 -0
  269. data/lib/spontaneous/page_piece.rb +77 -0
  270. data/lib/spontaneous/paths.rb +30 -0
  271. data/lib/spontaneous/permissions/access_group.rb +50 -0
  272. data/lib/spontaneous/permissions/access_key.rb +35 -0
  273. data/lib/spontaneous/permissions/user.rb +167 -0
  274. data/lib/spontaneous/permissions/user_level.rb +177 -0
  275. data/lib/spontaneous/permissions.rb +55 -0
  276. data/lib/spontaneous/piece.rb +30 -0
  277. data/lib/spontaneous/plugins/aliases.rb +128 -0
  278. data/lib/spontaneous/plugins/allowed_types.rb +173 -0
  279. data/lib/spontaneous/plugins/application/facets.rb +25 -0
  280. data/lib/spontaneous/plugins/application/paths.rb +137 -0
  281. data/lib/spontaneous/plugins/application/render.rb +29 -0
  282. data/lib/spontaneous/plugins/application/serialisation.rb +16 -0
  283. data/lib/spontaneous/plugins/application/state.rb +86 -0
  284. data/lib/spontaneous/plugins/boxes.rb +84 -0
  285. data/lib/spontaneous/plugins/controllers.rb +52 -0
  286. data/lib/spontaneous/plugins/entries.rb +193 -0
  287. data/lib/spontaneous/plugins/entry.rb +51 -0
  288. data/lib/spontaneous/plugins/fields.rb +103 -0
  289. data/lib/spontaneous/plugins/instance_code.rb +18 -0
  290. data/lib/spontaneous/plugins/layouts.rb +87 -0
  291. data/lib/spontaneous/plugins/media.rb +41 -0
  292. data/lib/spontaneous/plugins/page/formats.rb +67 -0
  293. data/lib/spontaneous/plugins/page/request.rb +89 -0
  294. data/lib/spontaneous/plugins/page_search.rb +64 -0
  295. data/lib/spontaneous/plugins/page_tree.rb +25 -0
  296. data/lib/spontaneous/plugins/paths.rb +125 -0
  297. data/lib/spontaneous/plugins/permissions.rb +63 -0
  298. data/lib/spontaneous/plugins/prototypes.rb +84 -0
  299. data/lib/spontaneous/plugins/publishing.rb +255 -0
  300. data/lib/spontaneous/plugins/render.rb +24 -0
  301. data/lib/spontaneous/plugins/schema_hierarchy.rb +76 -0
  302. data/lib/spontaneous/plugins/schema_id.rb +60 -0
  303. data/lib/spontaneous/plugins/schema_title.rb +33 -0
  304. data/lib/spontaneous/plugins/serialisation.rb +67 -0
  305. data/lib/spontaneous/plugins/site/instance.rb +22 -0
  306. data/lib/spontaneous/plugins/site/map.rb +19 -0
  307. data/lib/spontaneous/plugins/site/publishing.rb +74 -0
  308. data/lib/spontaneous/plugins/site/revisions.rb +28 -0
  309. data/lib/spontaneous/plugins/site/selectors.rb +41 -0
  310. data/lib/spontaneous/plugins/site_map.rb +34 -0
  311. data/lib/spontaneous/plugins/styles.rb +119 -0
  312. data/lib/spontaneous/plugins/supertype.rb +11 -0
  313. data/lib/spontaneous/plugins/visibility.rb +151 -0
  314. data/lib/spontaneous/plugins.rb +20 -0
  315. data/lib/spontaneous/prototypes/box_prototype.rb +168 -0
  316. data/lib/spontaneous/prototypes/field_prototype.rb +112 -0
  317. data/lib/spontaneous/prototypes/layout_prototype.rb +17 -0
  318. data/lib/spontaneous/prototypes/style_prototype.rb +42 -0
  319. data/lib/spontaneous/proxy_object.rb +12 -0
  320. data/lib/spontaneous/publishing/fire_and_forget.rb +57 -0
  321. data/lib/spontaneous/publishing/immediate.rb +197 -0
  322. data/lib/spontaneous/publishing/threaded.rb +25 -0
  323. data/lib/spontaneous/publishing.rb +10 -0
  324. data/lib/spontaneous/rack/around_back.rb +44 -0
  325. data/lib/spontaneous/rack/around_front.rb +29 -0
  326. data/lib/spontaneous/rack/around_preview.rb +26 -0
  327. data/lib/spontaneous/rack/assets.rb +98 -0
  328. data/lib/spontaneous/rack/back.rb +729 -0
  329. data/lib/spontaneous/rack/front.rb +41 -0
  330. data/lib/spontaneous/rack/http.rb +18 -0
  331. data/lib/spontaneous/rack/media.rb +29 -0
  332. data/lib/spontaneous/rack/public.rb +232 -0
  333. data/lib/spontaneous/rack/reloader.rb +42 -0
  334. data/lib/spontaneous/rack/static.rb +25 -0
  335. data/lib/spontaneous/rack.rb +55 -0
  336. data/lib/spontaneous/render/context.rb +100 -0
  337. data/lib/spontaneous/render/development_renderer.rb +14 -0
  338. data/lib/spontaneous/render/engine.rb +19 -0
  339. data/lib/spontaneous/render/format/html.rb +5 -0
  340. data/lib/spontaneous/render/format.rb +70 -0
  341. data/lib/spontaneous/render/preview_renderer.rb +18 -0
  342. data/lib/spontaneous/render/published_renderer.rb +54 -0
  343. data/lib/spontaneous/render/publishing_renderer.rb +13 -0
  344. data/lib/spontaneous/render/renderer.rb +46 -0
  345. data/lib/spontaneous/render.rb +173 -0
  346. data/lib/spontaneous/revision.rb +7 -0
  347. data/lib/spontaneous/schema/schema_modification.rb +260 -0
  348. data/lib/spontaneous/schema/uid.rb +221 -0
  349. data/lib/spontaneous/schema.rb +295 -0
  350. data/lib/spontaneous/server.rb +65 -0
  351. data/lib/spontaneous/site.rb +87 -0
  352. data/lib/spontaneous/state.rb +53 -0
  353. data/lib/spontaneous/style.rb +144 -0
  354. data/lib/spontaneous/tasks/database.rake +9 -0
  355. data/lib/spontaneous/tasks.rb +5 -0
  356. data/lib/spontaneous/version.rb +6 -0
  357. data/lib/spontaneous.rb +179 -0
  358. data/spontaneous.gemspec.tmpl +66 -0
  359. data/test/disabled/test_slots.rb +287 -0
  360. data/test/experimental/test_formats.rb +92 -0
  361. data/test/experimental/test_plugins.rb +64 -0
  362. data/test/fixtures/application/css/test.less +5 -0
  363. data/test/fixtures/application/js/test.js +1 -0
  364. data/test/fixtures/application/static/favicon.ico +1 -0
  365. data/test/fixtures/application/static/test.html +1 -0
  366. data/test/fixtures/application/views/index.erubis +1 -0
  367. data/test/fixtures/back/public/test.html +1 -0
  368. data/test/fixtures/back/templates/layouts/standard.html.cut +1 -0
  369. data/test/fixtures/config/config/environment.rb +4 -0
  370. data/test/fixtures/config/config/environments/development.rb +13 -0
  371. data/test/fixtures/config/config/environments/production.rb +22 -0
  372. data/test/fixtures/config/config/environments/staging.rb +2 -0
  373. data/test/fixtures/example_application/Gemfile +6 -0
  374. data/test/fixtures/example_application/Gemfile.lock +76 -0
  375. data/test/fixtures/example_application/Rakefile +6 -0
  376. data/test/fixtures/example_application/config/back.rb +15 -0
  377. data/test/fixtures/example_application/config/back.ru +8 -0
  378. data/test/fixtures/example_application/config/back.yml +8 -0
  379. data/test/fixtures/example_application/config/boot.rb +16 -0
  380. data/test/fixtures/example_application/config/database.yml +24 -0
  381. data/test/fixtures/example_application/config/environment.rb +4 -0
  382. data/test/fixtures/example_application/config/environments/development.rb +16 -0
  383. data/test/fixtures/example_application/config/environments/production.rb +21 -0
  384. data/test/fixtures/example_application/config/environments/staging.rb +1 -0
  385. data/test/fixtures/example_application/config/front.rb +8 -0
  386. data/test/fixtures/example_application/config/front.ru +8 -0
  387. data/test/fixtures/example_application/config/front.yml +8 -0
  388. data/test/fixtures/example_application/config/schema.yml +48 -0
  389. data/test/fixtures/example_application/config/unicorn.rb +1 -0
  390. data/test/fixtures/example_application/config/user_levels.yml +19 -0
  391. data/test/fixtures/example_application/public/css/test.css +0 -0
  392. data/test/fixtures/example_application/public/favicon.ico +1 -0
  393. data/test/fixtures/example_application/public/js/test.js +0 -0
  394. data/test/fixtures/example_application/public/test.html +1 -0
  395. data/test/fixtures/example_application/schema/client_project.rb +18 -0
  396. data/test/fixtures/example_application/schema/client_projects.rb +8 -0
  397. data/test/fixtures/example_application/schema/home_page.rb +22 -0
  398. data/test/fixtures/example_application/schema/info_page.rb +13 -0
  399. data/test/fixtures/example_application/schema/inline_image.rb +11 -0
  400. data/test/fixtures/example_application/schema/page.rb +4 -0
  401. data/test/fixtures/example_application/schema/piece.rb +3 -0
  402. data/test/fixtures/example_application/schema/project.rb +21 -0
  403. data/test/fixtures/example_application/schema/project_image.rb +18 -0
  404. data/test/fixtures/example_application/schema/projects_page.rb +12 -0
  405. data/test/fixtures/example_application/schema/text.rb +8 -0
  406. data/test/fixtures/example_application/templates/client_project/images.html.cut +1 -0
  407. data/test/fixtures/example_application/templates/client_project.html.cut +4 -0
  408. data/test/fixtures/example_application/templates/client_projects.html.cut +6 -0
  409. data/test/fixtures/example_application/templates/info_page/inline.html.cut +0 -0
  410. data/test/fixtures/example_application/templates/inline_image.html.cut +1 -0
  411. data/test/fixtures/example_application/templates/layouts/home.html.cut +15 -0
  412. data/test/fixtures/example_application/templates/layouts/info.html.cut +3 -0
  413. data/test/fixtures/example_application/templates/layouts/project.html.cut +13 -0
  414. data/test/fixtures/example_application/templates/layouts/projects.html.cut +11 -0
  415. data/test/fixtures/example_application/templates/layouts/standard.html.cut +0 -0
  416. data/test/fixtures/example_application/templates/project/inline.html.cut +5 -0
  417. data/test/fixtures/example_application/templates/project.html.cut +5 -0
  418. data/test/fixtures/example_application/templates/project_image.html.cut +1 -0
  419. data/test/fixtures/example_application/templates/text.html.cut +1 -0
  420. data/test/fixtures/images/rose.greyscale.jpg +0 -0
  421. data/test/fixtures/images/rose.jpg +0 -0
  422. data/test/fixtures/images/size.gif +0 -0
  423. data/test/fixtures/images/size.jpg +0 -0
  424. data/test/fixtures/images/size.png24 +0 -0
  425. data/test/fixtures/images/size.png8 +0 -0
  426. data/test/fixtures/layouts/layouts/custom1.html.cut +1 -0
  427. data/test/fixtures/layouts/layouts/custom1.pdf.cut +0 -0
  428. data/test/fixtures/layouts/layouts/custom1.xml.cut +0 -0
  429. data/test/fixtures/layouts/layouts/custom2.html.cut +1 -0
  430. data/test/fixtures/layouts/layouts/custom3.html.cut +0 -0
  431. data/test/fixtures/layouts/layouts/standard.html.cut +1 -0
  432. data/test/fixtures/media/101/003/rose.jpg +0 -0
  433. data/test/fixtures/permissions/config/user_levels.yml +9 -0
  434. data/test/fixtures/permissions/media/image.jpg +0 -0
  435. data/test/fixtures/plugins/schema_plugin/init.rb +1 -0
  436. data/test/fixtures/plugins/schema_plugin/schema/external.rb +5 -0
  437. data/test/fixtures/plugins/schema_plugin/templates/external.html.cut +1 -0
  438. data/test/fixtures/plugins/schema_plugin/templates/from_plugin.html.cut +0 -0
  439. data/test/fixtures/plugins/schema_plugin/templates/layouts/from_plugin.html.cut +0 -0
  440. data/test/fixtures/public/templates/layouts/default.html.cut +1 -0
  441. data/test/fixtures/public/templates/layouts/default.pdf.cut +1 -0
  442. data/test/fixtures/public/templates/layouts/default.rss.cut +1 -0
  443. data/test/fixtures/public/templates/layouts/dynamic.html.cut +1 -0
  444. data/test/fixtures/public/templates/layouts/standard.html.cut +0 -0
  445. data/test/fixtures/schema/before.yml +24 -0
  446. data/test/fixtures/schema/resolvable.yml +12 -0
  447. data/test/fixtures/schema/schema.yml +7 -0
  448. data/test/fixtures/serialisation/class_hash.yaml.erb +53 -0
  449. data/test/fixtures/serialisation/root_hash.yaml.erb +184 -0
  450. data/test/fixtures/sharding/rose.jpg +0 -0
  451. data/test/fixtures/sharding/xaa +0 -0
  452. data/test/fixtures/sharding/xab +0 -0
  453. data/test/fixtures/sharding/xac +0 -0
  454. data/test/fixtures/sharding/xad +0 -0
  455. data/test/fixtures/sharding/xae +0 -0
  456. data/test/fixtures/sharding/xaf +0 -0
  457. data/test/fixtures/sharding/xag +0 -0
  458. data/test/fixtures/styles/box_a/runny.html.cut +0 -0
  459. data/test/fixtures/styles/box_a.html.cut +1 -0
  460. data/test/fixtures/styles/named2.html.cut +1 -0
  461. data/test/fixtures/styles/orange/apple.html.cut +1 -0
  462. data/test/fixtures/styles/template_class/named1.html.cut +1 -0
  463. data/test/fixtures/styles/template_class/results.html.cut +1 -0
  464. data/test/fixtures/styles/template_class/walky.html.cut +0 -0
  465. data/test/fixtures/styles/template_class.epub.cut +0 -0
  466. data/test/fixtures/styles/template_class.html.cut +1 -0
  467. data/test/fixtures/styles/template_class.pdf.cut +0 -0
  468. data/test/fixtures/styles/template_sub_class1.html.cut +1 -0
  469. data/test/fixtures/templates/aliases/a/a_style.html.cut +0 -0
  470. data/test/fixtures/templates/aliases/a/page.html.cut +0 -0
  471. data/test/fixtures/templates/aliases/a_alias/a_alias_style.html.cut +0 -0
  472. data/test/fixtures/templates/aliases/layouts/b.html.cut +1 -0
  473. data/test/fixtures/templates/aliases/layouts/b_alias.html.cut +1 -0
  474. data/test/fixtures/templates/aliases/layouts/c_alias.html.cut +1 -0
  475. data/test/fixtures/templates/boxes/blank_content/things.html.cut +1 -0
  476. data/test/fixtures/templates/boxes/my_box_class/christy.html.cut +1 -0
  477. data/test/fixtures/templates/boxes/thangs.html.cut +1 -0
  478. data/test/fixtures/templates/boxes/with_template_box.html.cut +1 -0
  479. data/test/fixtures/templates/content/include.html.cut +1 -0
  480. data/test/fixtures/templates/content/include_dir.html.cut +1 -0
  481. data/test/fixtures/templates/content/included.epub.cut +1 -0
  482. data/test/fixtures/templates/content/included.html.cut +1 -0
  483. data/test/fixtures/templates/content/partial/included.html.cut +1 -0
  484. data/test/fixtures/templates/content/preprocess.html.cut +1 -0
  485. data/test/fixtures/templates/content/second.html.cut +1 -0
  486. data/test/fixtures/templates/content/template.epub.cut +1 -0
  487. data/test/fixtures/templates/content/template.html.cut +1 -0
  488. data/test/fixtures/templates/default_style_class.html.cut +1 -0
  489. data/test/fixtures/templates/direct.html.cut +1 -0
  490. data/test/fixtures/templates/extended/grandparent.html.cut +10 -0
  491. data/test/fixtures/templates/extended/main.html.cut +6 -0
  492. data/test/fixtures/templates/extended/parent.html.cut +10 -0
  493. data/test/fixtures/templates/layouts/entries.html.cut +7 -0
  494. data/test/fixtures/templates/layouts/page_style.html.cut +1 -0
  495. data/test/fixtures/templates/layouts/params.html.cut +1 -0
  496. data/test/fixtures/templates/layouts/preview_render.html.cut +2 -0
  497. data/test/fixtures/templates/layouts/standard_page.html.cut +1 -0
  498. data/test/fixtures/templates/layouts/subdir_style.html.cut +1 -0
  499. data/test/fixtures/templates/layouts/template_params.html.cut +1 -0
  500. data/test/fixtures/templates/page_class/inline_style.html.cut +1 -0
  501. data/test/fixtures/templates/preview_render/inline.html.cut +0 -0
  502. data/test/fixtures/templates/publishing/layouts/dynamic.html.cut +1 -0
  503. data/test/fixtures/templates/publishing/layouts/static.html.cut +1 -0
  504. data/test/fixtures/templates/template_class/anonymous_style.html.cut +4 -0
  505. data/test/fixtures/templates/template_class/another_template.html.cut +0 -0
  506. data/test/fixtures/templates/template_class/complex_template.html.cut +6 -0
  507. data/test/fixtures/templates/template_class/complex_template.pdf.cut +6 -0
  508. data/test/fixtures/templates/template_class/default_template_style.html.cut +4 -0
  509. data/test/fixtures/templates/template_class/images_with_template.html.cut +5 -0
  510. data/test/fixtures/templates/template_class/slots_template.html.cut +5 -0
  511. data/test/fixtures/templates/template_class/slots_template.pdf.cut +5 -0
  512. data/test/fixtures/templates/template_class/this_template.epub.cut +1 -0
  513. data/test/fixtures/templates/template_class/this_template.html.cut +1 -0
  514. data/test/fixtures/templates/template_class/this_template.pdf.cut +1 -0
  515. data/test/fixtures/templates/with_default_style_class.html.cut +1 -0
  516. data/test/functional/test_application.rb +176 -0
  517. data/test/functional/test_back.rb +902 -0
  518. data/test/functional/test_front.rb +571 -0
  519. data/test/javascript/test_dom.rb +94 -0
  520. data/test/javascript/test_markdown.rb +97 -0
  521. data/test/slow/test_publishing.rb +987 -0
  522. data/test/slow/test_visibility.rb +250 -0
  523. data/test/support/custom_matchers.rb +77 -0
  524. data/test/support/timing.rb +23 -0
  525. data/test/test_helper.rb +164 -0
  526. data/test/test_javascript.rb +34 -0
  527. data/test/ui/test_page_editing.rb +167 -0
  528. data/test/ui_helper.rb +114 -0
  529. data/test/unit/test_alias.rb +254 -0
  530. data/test/unit/test_authentication.rb +510 -0
  531. data/test/unit/test_boxes.rb +497 -0
  532. data/test/unit/test_config.rb +156 -0
  533. data/test/unit/test_content.rb +221 -0
  534. data/test/unit/test_content_inheritance.rb +103 -0
  535. data/test/unit/test_extensions.rb +14 -0
  536. data/test/unit/test_fields.rb +392 -0
  537. data/test/unit/test_generators.rb +97 -0
  538. data/test/unit/test_image_size.rb +25 -0
  539. data/test/unit/test_images.rb +265 -0
  540. data/test/unit/test_layouts.rb +111 -0
  541. data/test/unit/test_logger.rb +80 -0
  542. data/test/unit/test_media.rb +70 -0
  543. data/test/unit/test_page.rb +244 -0
  544. data/test/unit/test_permissions.rb +834 -0
  545. data/test/unit/test_piece.rb +80 -0
  546. data/test/unit/test_prototype_set.rb +192 -0
  547. data/test/unit/test_prototypes.rb +102 -0
  548. data/test/unit/test_render.rb +359 -0
  549. data/test/unit/test_schema.rb +1009 -0
  550. data/test/unit/test_serialisation.rb +215 -0
  551. data/test/unit/test_site.rb +145 -0
  552. data/test/unit/test_structure.rb +85 -0
  553. data/test/unit/test_styles.rb +417 -0
  554. data/test/unit/test_templates.rb +224 -0
  555. data/test/unit/test_type_hierarchy.rb +28 -0
  556. metadata +1017 -0
@@ -0,0 +1,834 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+
6
+ class PermissionsTest < MiniTest::Spec
7
+
8
+ def setup
9
+ Spontaneous::Schema.reset!
10
+ Spontaneous::Content.delete
11
+ Permissions::UserLevel.reset!
12
+ Permissions::UserLevel.level_file = File.expand_path('../../fixtures/permissions', __FILE__) / 'config/user_levels.yml'
13
+ end
14
+
15
+ def teardown
16
+ Permissions::AccessGroup.delete
17
+ Permissions::AccessKey.delete
18
+ Permissions::User.delete
19
+ end
20
+
21
+ context "Permissions" do
22
+ should "be able to generate random strings of any length" do
23
+ (2..256).each do |length|
24
+ s1 = Permissions.random_string(length)
25
+ s2 = Permissions.random_string(length)
26
+ s1.length.should == length
27
+ s2.length.should == length
28
+ s1.should_not == s2
29
+ end
30
+ end
31
+ end
32
+ context "Levels" do
33
+ setup do
34
+ end
35
+ teardown do
36
+ end
37
+
38
+ should "always have a level of :none/0" do
39
+ Permissions::UserLevel.none.should == Permissions::UserLevel::None
40
+ Permissions::UserLevel[:none].should == Permissions::UserLevel.none
41
+ Permissions::UserLevel['none'].should == Permissions::UserLevel.none
42
+ end
43
+
44
+ should "load from the config/user_levels.yml file" do
45
+ Permissions::UserLevel[:editor].must_be_instance_of(Permissions::UserLevel::Level)
46
+ Permissions::UserLevel['editor'].must_be_instance_of(Permissions::UserLevel::Level)
47
+ Permissions::UserLevel['admin'].must_be_instance_of(Permissions::UserLevel::Level)
48
+ Permissions::UserLevel['designer'].must_be_instance_of(Permissions::UserLevel::Level)
49
+ end
50
+
51
+ should "provide a sorted list of all levels" do
52
+ Permissions::UserLevel.all.should == [:none, :editor, :admin, :designer, :root]
53
+ end
54
+ should "provide a list of all levels <= provided level" do
55
+ Permissions::UserLevel.all(:editor).should == [:none, :editor]
56
+ Permissions::UserLevel.all(:designer).should == [:none, :editor, :admin, :designer]
57
+ end
58
+
59
+ should "have a root level" do
60
+ Permissions::UserLevel.root.should == Permissions::UserLevel::Root
61
+ end
62
+
63
+ should "have a root level that is always greater than other levels" do
64
+ Permissions::UserLevel.root.should > Permissions::UserLevel['designer']
65
+ Permissions::UserLevel.root.should >= Permissions::UserLevel['designer']
66
+ Permissions::UserLevel.root.should > Permissions::UserLevel::Root
67
+ Permissions::UserLevel.root.should >= Permissions::UserLevel::Root
68
+ Permissions::UserLevel[:root].should == Permissions::UserLevel::Root
69
+ end
70
+
71
+ should "work with > operator" do
72
+ Permissions::UserLevel[:admin].should > Permissions::UserLevel[:editor]
73
+ Permissions::UserLevel[:editor].should > Permissions::UserLevel[:none]
74
+ end
75
+ should "work with >= operator" do
76
+ Permissions::UserLevel[:admin].should >= Permissions::UserLevel[:admin]
77
+ Permissions::UserLevel[:editor].should >= Permissions::UserLevel[:editor]
78
+ end
79
+
80
+ should "return a minimum level > none" do
81
+ Permissions::UserLevel.minimum.should == Permissions::UserLevel.editor
82
+ end
83
+ should "have a valid string representation" do
84
+ Permissions::UserLevel[:editor].to_s.should == 'editor'
85
+ Permissions::UserLevel[:none].to_s.should == 'none'
86
+ Permissions::UserLevel[:root].to_s.should == 'root'
87
+ Permissions::UserLevel[:designer].to_s.should == 'designer'
88
+ end
89
+
90
+ should "have configurable level above which you have access to the publishing mechanism" do
91
+ Permissions::UserLevel[:none].can_publish?.should be_false
92
+ Permissions::UserLevel[:editor].can_publish?.should be_false
93
+ Permissions::UserLevel[:admin].can_publish?.should be_false
94
+ Permissions::UserLevel[:designer].can_publish?.should be_true
95
+ Permissions::UserLevel[:root].can_publish?.should be_true
96
+ end
97
+ should "Have a developer flag" do
98
+ Permissions::UserLevel[:none].developer?.should be_false
99
+ Permissions::UserLevel[:editor].developer?.should be_nil
100
+ Permissions::UserLevel[:admin].developer?.should be_nil
101
+ Permissions::UserLevel[:designer].developer?.should be_true
102
+ Permissions::UserLevel[:root].developer?.should be_true
103
+ end
104
+ end
105
+
106
+ context "Users" do
107
+ setup do
108
+ @now = Time.now
109
+ Time.stubs(:now).returns(@now)
110
+ @valid = {
111
+ :name => "A Person",
112
+ :email => "person@example.org",
113
+ :login => "person",
114
+ :password => "xxxxxx",
115
+ :password_confirmation => "xxxxxx"
116
+ }
117
+ end
118
+
119
+ teardown do
120
+ end
121
+
122
+ should "be creatable with valid params" do
123
+ user = Permissions::User.new(@valid)
124
+ user.save.must_be_instance_of(Permissions::User)
125
+ user.valid?.should be_true
126
+ end
127
+
128
+ should "validate name" do
129
+ user = Permissions::User.new(@valid.merge(:name => ""))
130
+ user.save.should be_nil
131
+ user.valid?.should be_false
132
+ user.errors[:name].should_not be_blank
133
+ end
134
+
135
+ should "validate presence of email address" do
136
+ user = Permissions::User.new(@valid.merge(:email => ""))
137
+ user.save
138
+ user.valid?.should be_false
139
+ user.errors[:email].should_not be_blank
140
+ end
141
+
142
+ should "validate format of email address" do
143
+ user = Permissions::User.new(@valid.merge(:email => "invalid.email.address"))
144
+ user.save
145
+ user.valid?.should be_false
146
+ user.errors[:email].should_not be_blank
147
+ end
148
+
149
+ should "validate presence of login" do
150
+ user = Permissions::User.new(@valid.merge(:login => ""))
151
+ user.save
152
+ user.valid?.should be_false
153
+ user.errors[:login].should_not be_blank
154
+ end
155
+
156
+ should "validate length of login" do
157
+ user = Permissions::User.new(@valid.merge(:login => "xx"))
158
+ user.save
159
+ user.valid?.should be_false
160
+ user.errors[:login].should_not be_blank
161
+ end
162
+
163
+ should "reject duplicate logins" do
164
+ user1 = Permissions::User.create(@valid)
165
+ user2 = Permissions::User.new(@valid)
166
+ user2.save
167
+ user2.valid?.should be_false
168
+ user2.errors[:login].should_not be_blank
169
+ end
170
+
171
+ should "require a non-blank password & password_confirmation" do
172
+ user = Permissions::User.new(@valid.merge(:password => "", :password_confirmation => ""))
173
+ user.save
174
+ user.valid?.should be_false
175
+ user.errors[:password].should_not be_blank
176
+ end
177
+
178
+ should "require a matching password & password_confirmation" do
179
+ user = Permissions::User.new(@valid.merge(:password => "sdfsddfsdf", :password_confirmation => "sdf"))
180
+ user.save
181
+ user.valid?.should be_false
182
+ user.errors[:password_confirmation].should_not be_blank
183
+ end
184
+
185
+ should "require passwords to be at least 6 characters" do
186
+ user = Permissions::User.new(@valid.merge(:password => "12345", :password_confirmation => "12345"))
187
+ user.save
188
+ user.valid?.should be_false
189
+ user.errors[:password].should_not be_blank
190
+ end
191
+
192
+
193
+ should "have a random salt" do
194
+ user1 = Permissions::User.create(@valid)
195
+ user2 = Permissions::User.create(@valid.merge(:login => "person2"))
196
+ user1.salt.should_not be_blank
197
+ user2.salt.should_not be_blank
198
+ user1.salt.should_not == user2.salt
199
+ end
200
+
201
+ context "who are valid" do
202
+ setup do
203
+ @user = Permissions::User.create(@valid)
204
+ @user.reload
205
+ end
206
+
207
+ should "have a created_at date" do
208
+ @user.created_at.to_i.should == @now.to_i
209
+ end
210
+
211
+ should "have an associated 'invisible' group" do
212
+ @user.group.must_be_instance_of(Permissions::AccessGroup)
213
+ @user.group.invisible?.should be_true
214
+ @user.group.level.should == Permissions::UserLevel::None
215
+ end
216
+
217
+ # the following actually works on the associated silent group
218
+ should "default to a user level of Permissions::UserLevel.minimum" do
219
+ @user.level.should == Permissions::UserLevel.none
220
+ end
221
+
222
+ should "have a settable user level" do
223
+ @user.update(:level => Permissions::UserLevel[:root])
224
+ @user.reload.level.should == Permissions::UserLevel.root
225
+ end
226
+
227
+ should "have a list of groups it belongs to" do
228
+ @user.memberships.should == [@user.group]
229
+ end
230
+
231
+ should "be able to login with right login/password combination" do
232
+ key = Permissions::User.authenticate(@user.login, @user.password)
233
+ key.user.id.should == @user.id
234
+ key = Permissions::User.authenticate(@user.login, "wrong password")
235
+ key.should be_nil
236
+ end
237
+
238
+ should "have a last login date" do
239
+ @user.last_login_at.should be_nil
240
+ key = Permissions::User.authenticate(@user.login, @user.password)
241
+ @user.reload.last_login_at.to_i.should == @now.to_i
242
+ end
243
+
244
+ should "generate a new access key on successful login" do
245
+ @user.access_keys.should be_blank
246
+ key = Permissions::User.authenticate(@user.login, @user.password)
247
+ @user.reload.access_keys.length.should == 1
248
+ @user.access_keys.first.created_at.to_i.should == @now.to_i
249
+ @user.access_keys.first.last_access_at.to_i.should == @now.to_i
250
+ end
251
+
252
+ should "have a list of access keys" do
253
+ @user.access_keys.must_be_instance_of(Array)
254
+ end
255
+
256
+ should "be blockable" do
257
+ @user.update(:disabled => true)
258
+ key = Permissions::User.authenticate(@user.login, @user.password)
259
+ key.should be_nil
260
+ end
261
+
262
+ should "be able to belong to more than one group" do
263
+ group1 = Permissions::AccessGroup.create(:name => "Group 1")
264
+ group2 = Permissions::AccessGroup.create(:name => "Group 2")
265
+ @user.add_group(group1)
266
+ @user.add_group(group2)
267
+ @user.groups.length.should == 2
268
+ group1.members.should == [@user]
269
+ group2.members.should == [@user]
270
+ end
271
+
272
+ should "return the right user level for a piece of content" do
273
+ page = Page.create
274
+ @user.update(:level => Permissions::UserLevel.admin)
275
+ @user.access_selector.should == "*"
276
+ @user.level_for(page).should == Permissions::UserLevel.admin
277
+ end
278
+
279
+ should "return the highest access level when multiple exist" do
280
+ page = Page.create
281
+ @user.update(:level => Permissions::UserLevel.none)
282
+ group1 = Permissions::AccessGroup.create(:name => "Group 1", :level => Permissions::UserLevel.admin)
283
+ group2 = Permissions::AccessGroup.create(:name => "Group 1", :level => Permissions::UserLevel.editor)
284
+ group1.add_member(@user)
285
+ group2.add_member(@user)
286
+ @user.level_for(page).should == Permissions::UserLevel.admin
287
+ end
288
+
289
+ should "have a test for developer status" do
290
+ @user.update(:level => Permissions::UserLevel.editor)
291
+ @user.developer?.should be_nil
292
+ @user.update(:level => Permissions::UserLevel.designer)
293
+ @user.developer?.should be_true
294
+ end
295
+
296
+ should "serialise to JSON" do
297
+ @user.export.should == {
298
+ :name => "A Person",
299
+ :email => "person@example.org",
300
+ :login => "person",
301
+ :developer => false
302
+ }
303
+ end
304
+ end
305
+ end
306
+
307
+ context "access keys" do
308
+ setup do
309
+ @now = Time.now
310
+ Time.stubs(:now).returns(@now)
311
+ @valid = {
312
+ :name => "A Person",
313
+ :email => "person@example.org",
314
+ :login => "person",
315
+ :password => "xxxxxx",
316
+ :password_confirmation => "xxxxxx"
317
+ }
318
+ end
319
+
320
+ teardown do
321
+ end
322
+
323
+ should "have a generated key_id" do
324
+ key1 = Permissions::AccessKey.create
325
+ key1.key_id.length.should == 44
326
+ key2 = Permissions::AccessKey.create
327
+ key2.key_id.length.should == 44
328
+ key1.key_id.should_not == key2.key_id
329
+ end
330
+
331
+ should "allow authentication of a user" do
332
+ key1 = Permissions::AccessKey.create
333
+ key2 = Permissions::AccessKey.authenticate(key1.key_id)
334
+ key1.id.should == key2.id
335
+ end
336
+
337
+ should "update timestamps when authenticated" do
338
+ user = Permissions::User.create(@valid)
339
+ key1 = Permissions::AccessKey.create(:user_id => user.id)
340
+ Time.stubs(:now).returns(@now + 1000)
341
+ key2 = Permissions::AccessKey.create(:user_id => user.id)
342
+ key3 = Permissions::AccessKey.authenticate(key2.key_id)
343
+ key2.id.should == key3.id
344
+ key2.reload.last_access_at.to_i.should == (@now+1000).to_i
345
+ key2.user.last_access_at.to_i.should == (@now+1000).to_i
346
+ end
347
+
348
+ should "be guaranteed unique" do
349
+ Permissions.stubs(:random_string).returns("xxxx")
350
+ key1 = Permissions::AccessKey.create()
351
+ lambda { Permissions::AccessKey.create() }.must_raise(Sequel::DatabaseError)
352
+ end
353
+
354
+ should "have a creation date" do
355
+ key1 = Permissions::AccessKey.create
356
+ key1.created_at.to_i.should == @now.to_i
357
+ end
358
+
359
+ should "have a source IP address"
360
+
361
+ should "retrieve their associated user" do
362
+ user = Permissions::User.create(@valid)
363
+ key1 = Permissions::AccessKey.create(:user_id => user.id)
364
+ key1.reload.user.should == user
365
+ end
366
+
367
+ should "be disabled when user blocked" do
368
+ user = Permissions::User.create(@valid)
369
+ key1 = Permissions::AccessKey.create(:user_id => user.id)
370
+ user.update(:disabled => true)
371
+ key3 = Permissions::AccessKey.authenticate(key1.key_id)
372
+ key3.should be_nil
373
+ end
374
+ end
375
+
376
+
377
+
378
+ context "Groups" do
379
+ setup do
380
+ @valid_group = {
381
+ :name => "Some People"
382
+ }
383
+ end
384
+
385
+ teardown do
386
+ end
387
+
388
+ should "always have a name" do
389
+ group = Permissions::AccessGroup.new(@valid_group.merge(:name => ""))
390
+ group.valid?.should be_false
391
+ group.errors[:name].should_not be_blank
392
+ end
393
+
394
+ should "default to a user level of :none" do
395
+ group = Permissions::AccessGroup.create(@valid_group)
396
+ group.reload
397
+ group.level.should == Permissions::UserLevel::None
398
+ end
399
+
400
+ # disabling a user and blocking a group are different
401
+ # if you disable a user you disable their login
402
+ # if you block a group they belong to you remove the permissions
403
+ # granted by that group but you aren't stopping them from logging in
404
+ should "be blockable" do
405
+ group = Permissions::AccessGroup.create(@valid_group.merge(:level => Permissions::UserLevel.admin))
406
+ group.level.should == Permissions::UserLevel.admin
407
+ group.update(:disabled => true)
408
+ group.level.should == Permissions::UserLevel.none
409
+ end
410
+
411
+ should "default to applying to the whole site" do
412
+ group = Permissions::AccessGroup.create(@valid_group)
413
+ group.access_selector.should == "*"
414
+ end
415
+
416
+ should "return the right user level for a piece of content" do
417
+ group = Permissions::AccessGroup.create(@valid_group)
418
+ page = Page.create
419
+ group.update(:level => Permissions::UserLevel.admin)
420
+ group.access_selector.should == "*"
421
+ group.level_for(page).should == Permissions::UserLevel.admin
422
+ end
423
+ end
424
+
425
+ context "Guards" do
426
+ setup do
427
+ @visitor = Permissions::User.create(:email => "visitor@example.com", :login => "visitor", :name => "visitor", :password => "visitorpass", :password_confirmation => "visitorpass")
428
+ @editor = Permissions::User.create(:email => "editor@example.com", :login => "editor", :name => "editor", :password => "editorpass", :password_confirmation => "editorpass")
429
+ @admin = Permissions::User.create(:email => "admin@example.com", :login => "admin", :name => "admin", :password => "adminpass", :password_confirmation => "adminpass")
430
+ @root = Permissions::User.create(:email => "root@example.com", :login => "root", :name => "root", :password => "rootpass", :password_confirmation => "rootpass")
431
+ @editor.update(:level => Permissions::UserLevel.editor)
432
+ @admin.update(:level => Permissions::UserLevel.admin)
433
+ @root.update(:level => Permissions::UserLevel.root)
434
+
435
+ class ::C < Piece; end
436
+ class ::D < Piece; end
437
+
438
+ C.field :editor_level, :user_level => :editor
439
+ C.field :admin_level, :user_level => :admin
440
+ C.field :root_level, :user_level => :root
441
+ C.field :mixed_level, :read_level => :editor, :write_level => :root
442
+ C.field :default_level
443
+
444
+ C.box :editor_level, :user_level => :editor do
445
+ field :editor_level, :user_level => :editor
446
+ field :admin_level, :user_level => :admin
447
+ field :root_level, :user_level => :root
448
+ field :mixed_level, :read_level => :editor, :write_level => :root
449
+ field :default_level
450
+
451
+ allow :D, :user_level => :editor
452
+ allow :C, :user_level => :admin
453
+ end
454
+
455
+ C.box :admin_level, :user_level => :admin do
456
+ field :editor_level, :user_level => :editor
457
+ field :admin_level, :user_level => :admin
458
+ field :root_level, :user_level => :root
459
+ field :mixed_level, :read_level => :editor, :write_level => :root
460
+ field :default_level
461
+
462
+ allow :C, :user_level => :admin
463
+ end
464
+
465
+ C.box :root_level, :user_level => :root do
466
+ field :editor_level, :user_level => :editor
467
+ field :admin_level, :user_level => :admin
468
+ field :root_level, :user_level => :root
469
+ field :mixed_level, :read_level => :editor, :write_level => :root
470
+ field :default_level
471
+
472
+ allow :C, :user_level => :root
473
+ end
474
+
475
+ C.box :mixed_level, :read_level => :editor, :write_level => :root do
476
+ field :editor_level, :user_level => :editor
477
+ field :admin_level, :user_level => :admin
478
+ field :root_level, :user_level => :root
479
+ field :mixed_level, :read_level => :editor, :write_level => :root
480
+ field :default_level
481
+
482
+ allow :C, :user_level => :editor
483
+ end
484
+
485
+ C.box :default_level do
486
+ field :editor_level, :user_level => :editor
487
+ field :admin_level, :user_level => :admin
488
+ field :root_level, :user_level => :root
489
+ field :mixed_level, :read_level => :editor, :write_level => :root
490
+ field :default_level
491
+
492
+ allow :C
493
+ end
494
+
495
+ @i = C.new
496
+ end
497
+
498
+ teardown do
499
+ Object.send(:remove_const, :C) rescue nil
500
+ Object.send(:remove_const, :D) rescue nil
501
+ end
502
+
503
+ should "protect field reads" do
504
+ # without user (e.g. terminal/console access) everything is always
505
+ # possible
506
+ @i.field_readable?(:editor_level).should be_true
507
+ @i.field_readable?(:admin_level).should be_true
508
+ @i.field_readable?(:root_level).should be_true
509
+ @i.field_readable?(:mixed_level).should be_true
510
+ @i.field_readable?(:default_level).should be_true
511
+
512
+ Permissions.with_user(@visitor) do
513
+ @i.field_readable?(:editor_level).should be_false
514
+ @i.field_readable?(:admin_level).should be_false
515
+ @i.field_readable?(:root_level).should be_false
516
+ @i.field_readable?(:mixed_level).should be_false
517
+ @i.field_readable?(:default_level).should be_true
518
+ end
519
+ Permissions.with_user(@editor) do
520
+ @i.field_readable?(:editor_level).should be_true
521
+ @i.field_readable?(:admin_level).should be_false
522
+ @i.field_readable?(:root_level).should be_false
523
+ @i.field_readable?(:mixed_level).should be_true
524
+ @i.field_readable?(:default_level).should be_true
525
+ end
526
+ Permissions.with_user(@admin) do
527
+ @i.field_readable?(:editor_level).should be_true
528
+ @i.field_readable?(:admin_level).should be_true
529
+ @i.field_readable?(:root_level).should be_false
530
+ @i.field_readable?(:mixed_level).should be_true
531
+ @i.field_readable?(:default_level).should be_true
532
+ end
533
+ Permissions.with_user(@root) do
534
+ @i.field_readable?(:editor_level).should be_true
535
+ @i.field_readable?(:admin_level).should be_true
536
+ @i.field_readable?(:root_level).should be_true
537
+ @i.field_readable?(:mixed_level).should be_true
538
+ @i.field_readable?(:default_level).should be_true
539
+ end
540
+ end
541
+
542
+ should "protect field writes" do
543
+ # without user (e.g. terminal/console access) everything is always
544
+ # possible
545
+ @i.field_writable?(:editor_level).should be_true
546
+ @i.field_writable?(:admin_level).should be_true
547
+ @i.field_writable?(:root_level).should be_true
548
+ @i.field_writable?(:mixed_level).should be_true
549
+ @i.field_writable?(:default_level).should be_true
550
+
551
+ Permissions.with_user(@visitor) do
552
+ @i.field_writable?(:editor_level).should be_false
553
+ @i.field_writable?(:admin_level).should be_false
554
+ @i.field_writable?(:root_level).should be_false
555
+ @i.field_writable?(:mixed_level).should be_false
556
+ @i.field_writable?(:default_level).should be_false
557
+ end
558
+ Permissions.with_user(@editor) do
559
+ @i.field_writable?(:editor_level).should be_true
560
+ @i.field_writable?(:admin_level).should be_false
561
+ @i.field_writable?(:root_level).should be_false
562
+ @i.field_writable?(:mixed_level).should be_false
563
+ @i.field_writable?(:default_level).should be_true
564
+ end
565
+ Permissions.with_user(@admin) do
566
+ @i.field_writable?(:editor_level).should be_true
567
+ @i.field_writable?(:admin_level).should be_true
568
+ @i.field_writable?(:root_level).should be_false
569
+ @i.field_writable?(:mixed_level).should be_false
570
+ @i.field_writable?(:default_level).should be_true
571
+ end
572
+ Permissions.with_user(@root) do
573
+ @i.field_writable?(:editor_level).should be_true
574
+ @i.field_writable?(:admin_level).should be_true
575
+ @i.field_writable?(:root_level).should be_true
576
+ @i.field_writable?(:mixed_level).should be_true
577
+ @i.field_writable?(:default_level).should be_true
578
+ end
579
+ end
580
+
581
+ should "protect box reads" do
582
+ @i.box_readable?(:editor_level).should be_true
583
+ @i.box_readable?(:admin_level).should be_true
584
+ @i.box_readable?(:root_level).should be_true
585
+ @i.box_readable?(:mixed_level).should be_true
586
+ @i.box_readable?(:default_level).should be_true
587
+
588
+ Permissions.with_user(@visitor) do
589
+ @i.box_readable?(:editor_level).should be_false
590
+ @i.box_readable?(:admin_level).should be_false
591
+ @i.box_readable?(:root_level).should be_false
592
+ @i.box_readable?(:mixed_level).should be_false
593
+ @i.box_readable?(:default_level).should be_true
594
+ end
595
+ Permissions.with_user(@editor) do
596
+ @i.box_readable?(:editor_level).should be_true
597
+ @i.box_readable?(:admin_level).should be_false
598
+ @i.box_readable?(:root_level).should be_false
599
+ @i.box_readable?(:mixed_level).should be_true
600
+ @i.box_readable?(:default_level).should be_true
601
+ end
602
+ Permissions.with_user(@admin) do
603
+ @i.box_readable?(:editor_level).should be_true
604
+ @i.box_readable?(:admin_level).should be_true
605
+ @i.box_readable?(:root_level).should be_false
606
+ @i.box_readable?(:mixed_level).should be_true
607
+ @i.box_readable?(:default_level).should be_true
608
+ end
609
+ Permissions.with_user(@root) do
610
+ @i.box_readable?(:editor_level).should be_true
611
+ @i.box_readable?(:admin_level).should be_true
612
+ @i.box_readable?(:root_level).should be_true
613
+ @i.box_readable?(:mixed_level).should be_true
614
+ @i.box_readable?(:default_level).should be_true
615
+ end
616
+ end
617
+ should "protect box writes" do
618
+ @i.box_writable?(:editor_level).should be_true
619
+ @i.box_writable?(:admin_level).should be_true
620
+ @i.box_writable?(:root_level).should be_true
621
+ @i.box_writable?(:mixed_level).should be_true
622
+ @i.box_writable?(:default_level).should be_true
623
+
624
+ Permissions.with_user(@visitor) do
625
+ @i.box_writable?(:editor_level).should be_false
626
+ @i.box_writable?(:admin_level).should be_false
627
+ @i.box_writable?(:root_level).should be_false
628
+ @i.box_writable?(:mixed_level).should be_false
629
+ @i.box_writable?(:default_level).should be_false
630
+ end
631
+ Permissions.with_user(@editor) do
632
+ @i.box_writable?(:editor_level).should be_true
633
+ @i.box_writable?(:admin_level).should be_false
634
+ @i.box_writable?(:root_level).should be_false
635
+ @i.box_writable?(:mixed_level).should be_false
636
+ @i.box_writable?(:default_level).should be_true
637
+ end
638
+ Permissions.with_user(@admin) do
639
+ @i.box_writable?(:editor_level).should be_true
640
+ @i.box_writable?(:admin_level).should be_true
641
+ @i.box_writable?(:root_level).should be_false
642
+ @i.box_writable?(:mixed_level).should be_false
643
+ @i.box_writable?(:default_level).should be_true
644
+ end
645
+ Permissions.with_user(@root) do
646
+ @i.box_writable?(:editor_level).should be_true
647
+ @i.box_writable?(:admin_level).should be_true
648
+ @i.box_writable?(:root_level).should be_true
649
+ @i.box_writable?(:mixed_level).should be_true
650
+ @i.box_writable?(:default_level).should be_true
651
+ end
652
+ end
653
+
654
+ should "serialise only things in class viewable by the current user" do
655
+ expected = [
656
+ ["editor_level", true],
657
+ ["admin_level", true],
658
+ ["root_level", true],
659
+ ["mixed_level", true],
660
+ ["default_level", true]
661
+ ]
662
+ C.export[:fields].map { |f| [f[:name], f[:writable]] }.should == expected
663
+ C.export[:boxes].map { |f| [f[:name], f[:writable]] }.should == expected
664
+ C.export[:boxes].map { |b| [b[:name], b[:fields].map {|f| [f[:name], f[:writable]]}] }.should == [
665
+ ["editor_level", expected],
666
+ ["admin_level", expected],
667
+ ["root_level", expected],
668
+ ["mixed_level", expected],
669
+ ["default_level", expected]
670
+ ]
671
+
672
+ Permissions.with_user(@root) do
673
+ C.export[:fields].map { |f| [f[:name], f[:writable]] }.should == expected
674
+ C.export[:boxes].map { |f| [f[:name], f[:writable]] }.should == expected
675
+ C.export[:boxes].map { |b| [b[:name], b[:fields].map {|f| [f[:name], f[:writable]]}] }.should == [
676
+ ["editor_level", expected],
677
+ ["admin_level", expected],
678
+ ["root_level", expected],
679
+ ["mixed_level", expected],
680
+ ["default_level", expected]
681
+ ]
682
+ end
683
+
684
+ Permissions.with_user(@visitor) do
685
+ expected = [
686
+ ["default_level", false]
687
+ ]
688
+ C.export[:fields].map { |f| [f[:name], f[:writable]] }.should == expected
689
+ C.export[:boxes].map { |f| [f[:name], f[:writable]] }.should == expected
690
+ C.export[:boxes].map { |b| [b[:name], b[:fields].map {|f| [f[:name], f[:writable]]}] }.should == [
691
+ ["default_level", expected ]
692
+ ]
693
+ end
694
+
695
+ Permissions.with_user(@editor) do
696
+ expected = [
697
+ ["editor_level", true],
698
+ ["mixed_level", false],
699
+ ["default_level", true]
700
+ ]
701
+ C.export[:fields].map { |f| [f[:name], f[:writable]] }.should == expected
702
+ C.export[:boxes].map { |f| [f[:name], f[:writable]] }.should == expected
703
+ C.export[:boxes].map { |b| [b[:name], b[:fields].map {|f| [f[:name], f[:writable]]}] }.should == [
704
+ ["editor_level", expected],
705
+ ["mixed_level", expected],
706
+ ["default_level", expected]
707
+ ]
708
+ end
709
+
710
+ Permissions.with_user(@admin) do
711
+ expected = [
712
+ ["editor_level", true],
713
+ ["admin_level", true],
714
+ ["mixed_level", false],
715
+ ["default_level", true]
716
+ ]
717
+ C.export[:fields].map { |f| [f[:name], f[:writable]] }.should == expected
718
+ C.export[:boxes].map { |f| [f[:name], f[:writable]] }.should == expected
719
+ C.export[:boxes].map { |b| [b[:name], b[:fields].map {|f| [f[:name], f[:writable]]}] }.should == [
720
+ ["editor_level", expected],
721
+ ["admin_level", expected],
722
+ ["mixed_level", expected],
723
+ ["default_level", expected]
724
+ ]
725
+ end
726
+ end
727
+
728
+ should "only list allowed types addable by the user" do
729
+ expected = [
730
+ ["editor_level", ["D", "C"]],
731
+ ["admin_level", ["C"]],
732
+ ["root_level", ["C"]],
733
+ ["mixed_level", ["C"]],
734
+ ["default_level", ["C"]]
735
+ ]
736
+ C.export[:boxes].map { |b| [b[:name], b[:allowed_types]] }.should == expected
737
+
738
+ Permissions.with_user(@root) do
739
+ C.export[:boxes].map { |b| [b[:name], b[:allowed_types]] }.should == expected
740
+ end
741
+ Permissions.with_user(@visitor) do
742
+ expected = [
743
+ ["default_level", []]
744
+ ]
745
+ C.export[:boxes].map { |b| [b[:name], b[:allowed_types]] }.should == expected
746
+ end
747
+ Permissions.with_user(@editor) do
748
+ expected = [
749
+ ["editor_level", ["D"]],
750
+ ["mixed_level", []],
751
+ ["default_level", ["C"]]
752
+ ]
753
+ C.export[:boxes].map { |b| [b[:name], b[:allowed_types]] }.should == expected
754
+ end
755
+ Permissions.with_user(@admin) do
756
+ expected = [
757
+ ["editor_level", ["D", "C"]],
758
+ ["admin_level", ["C"]],
759
+ ["mixed_level", []],
760
+ ["default_level", ["C"]]
761
+ ]
762
+ C.export[:boxes].map { |b| [b[:name], b[:allowed_types]] }.should == expected
763
+ end
764
+ end
765
+
766
+ should "serialise only things in instance viewable by the current user" do
767
+ expected = [
768
+ "editor_level",
769
+ "admin_level",
770
+ "root_level",
771
+ "mixed_level",
772
+ "default_level"
773
+ ]
774
+ @i.export[:boxes].map { |f| f[:name] }.should == expected
775
+ @i.export[:boxes].map { |b| [b[:name], b[:fields].map {|f| f[:name]}] }.should == [
776
+ ["editor_level", expected],
777
+ ["admin_level", expected],
778
+ ["root_level", expected],
779
+ ["mixed_level", expected],
780
+ ["default_level", expected]
781
+ ]
782
+ Permissions.with_user(@root) do
783
+ @i.export[:boxes].map { |f| f[:name] }.should == expected
784
+ @i.export[:boxes].map { |b| [b[:name], b[:fields].map {|f| f[:name]}] }.should == [
785
+ ["editor_level", expected],
786
+ ["admin_level", expected],
787
+ ["root_level", expected],
788
+ ["mixed_level", expected],
789
+ ["default_level", expected]
790
+ ]
791
+ end
792
+
793
+ Permissions.with_user(@visitor) do
794
+ @i.export[:boxes].map { |f| f[:name] }.should == [
795
+ "default_level"
796
+ ]
797
+ @i.export[:boxes].map { |b| [b[:name], b[:fields].map {|f| f[:name]}] }.should == [
798
+ ["default_level", ["default_level"]]
799
+ ]
800
+ end
801
+
802
+ Permissions.with_user(@editor) do
803
+ expected = [
804
+ "editor_level",
805
+ "mixed_level",
806
+ "default_level"
807
+ ]
808
+ @i.export[:boxes].map { |f| f[:name] }.should == expected
809
+ @i.export[:boxes].map { |b| [b[:name], b[:fields].map {|f| f[:name]}] }.should == [
810
+ ["editor_level", expected],
811
+ ["mixed_level", expected],
812
+ ["default_level", expected]
813
+ ]
814
+ end
815
+
816
+ Permissions.with_user(@admin) do
817
+ expected = [
818
+ "editor_level",
819
+ "admin_level",
820
+ "mixed_level",
821
+ "default_level"
822
+ ]
823
+ @i.export[:boxes].map { |f| f[:name] }.should == expected
824
+ @i.export[:boxes].map { |b| [b[:name], b[:fields].map {|f| f[:name]}] }.should == [
825
+ ["editor_level", expected],
826
+ ["admin_level", expected],
827
+ ["mixed_level", expected],
828
+ ["default_level", expected]
829
+ ]
830
+ end
831
+
832
+ end
833
+ end
834
+ end