browsercms 3.4.2 → 3.5.0.rc1

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 (367) hide show
  1. data/README.markdown +1 -0
  2. data/app/assets/images/cms/file-uploading.gif +0 -0
  3. data/app/assets/javascripts/cms/application.js +1 -0
  4. data/app/assets/javascripts/cms/attachment_manager.js.erb +87 -0
  5. data/app/assets/javascripts/cms/core_library.js.erb +38 -25
  6. data/app/assets/stylesheets/cms/application.css.erb +1 -0
  7. data/app/assets/stylesheets/cms/attachment_manager.css.scss +28 -0
  8. data/app/controllers/cms/application_controller.rb +1 -1
  9. data/app/controllers/cms/attachments_controller.rb +45 -10
  10. data/app/controllers/cms/cache_controller.rb +1 -1
  11. data/app/controllers/cms/content_block_controller.rb +134 -122
  12. data/app/controllers/cms/content_controller.rb +143 -155
  13. data/app/controllers/cms/dashboard_controller.rb +11 -9
  14. data/app/controllers/cms/error_handling.rb +19 -7
  15. data/app/controllers/cms/file_blocks_controller.rb +2 -2
  16. data/app/controllers/cms/home_controller.rb +3 -0
  17. data/app/controllers/cms/section_nodes_controller.rb +52 -44
  18. data/app/controllers/cms/sections_controller.rb +4 -2
  19. data/app/controllers/cms/toolbar_controller.rb +14 -10
  20. data/app/helpers/cms/application_helper.rb +23 -19
  21. data/app/helpers/cms/form_builder.rb +65 -18
  22. data/app/helpers/cms/mobile_helper.rb +19 -0
  23. data/app/helpers/cms/path_helper.rb +30 -4
  24. data/app/helpers/cms/rendering_helper.rb +9 -1
  25. data/app/models/cms/abstract_file_block.rb +6 -6
  26. data/app/models/cms/attachment.rb +196 -107
  27. data/app/models/cms/category.rb +3 -0
  28. data/app/models/cms/category_type.rb +2 -0
  29. data/app/models/cms/connector.rb +3 -0
  30. data/app/models/cms/content_type.rb +3 -0
  31. data/app/models/cms/content_type_group.rb +2 -0
  32. data/app/models/cms/dynamic_view.rb +4 -0
  33. data/app/models/cms/email_message.rb +2 -0
  34. data/app/models/cms/file_block.rb +9 -2
  35. data/app/models/cms/group.rb +5 -2
  36. data/app/models/cms/group_permission.rb +2 -0
  37. data/app/models/cms/group_section.rb +3 -0
  38. data/app/models/cms/group_type.rb +2 -0
  39. data/app/models/cms/group_type_permission.rb +2 -0
  40. data/app/models/cms/html_block.rb +3 -2
  41. data/app/models/cms/image_block.rb +13 -2
  42. data/app/models/cms/page.rb +14 -3
  43. data/app/models/cms/page_route.rb +4 -0
  44. data/app/models/cms/page_route_condition.rb +1 -0
  45. data/app/models/cms/page_route_option.rb +2 -0
  46. data/app/models/cms/page_route_requirement.rb +1 -0
  47. data/app/models/cms/permission.rb +3 -0
  48. data/app/models/cms/portlet.rb +2 -2
  49. data/app/models/cms/redirect.rb +2 -0
  50. data/app/models/cms/section.rb +15 -1
  51. data/app/models/cms/section_node.rb +1 -0
  52. data/app/models/cms/site.rb +3 -0
  53. data/app/models/cms/tag.rb +2 -0
  54. data/app/models/cms/tagging.rb +3 -0
  55. data/app/models/cms/task.rb +5 -1
  56. data/app/models/cms/user.rb +1 -1
  57. data/app/models/cms/user_group_membership.rb +3 -0
  58. data/app/views/cms/attachments/_attachment.html.erb +14 -0
  59. data/app/views/cms/attachments/_attachment_table.html.erb +17 -0
  60. data/app/views/cms/attachments/_attachment_wrapper.html.erb +4 -0
  61. data/app/views/cms/blocks/index.html.erb +2 -3
  62. data/app/views/cms/blocks/show.html.erb +1 -1
  63. data/app/views/cms/dynamic_views/index.html.erb +1 -1
  64. data/app/views/cms/email_messages/index.html.erb +1 -1
  65. data/app/views/cms/file_blocks/_form.html.erb +1 -27
  66. data/app/views/cms/file_blocks/_section_selector.html.erb +13 -0
  67. data/app/views/cms/file_blocks/render.html.erb +3 -3
  68. data/app/views/cms/form_builder/_cms_attachment_manager.html.erb +26 -0
  69. data/app/views/cms/form_builder/_cms_file_field.html.erb +27 -35
  70. data/app/views/cms/groups/index.html.erb +1 -1
  71. data/app/views/cms/image_blocks/_form.html.erb +1 -27
  72. data/app/views/cms/image_blocks/render.html.erb +4 -1
  73. data/app/views/cms/page_routes/index.html.erb +3 -0
  74. data/app/views/cms/shared/error.xml.erb +8 -0
  75. data/app/views/cms/tags/render.html.erb +1 -1
  76. data/app/views/cms/toolbar/_mobile_toggle.html.erb +33 -0
  77. data/app/views/cms/users/index.html.erb +1 -1
  78. data/app/views/layouts/_page_toolbar.html.erb +2 -1
  79. data/bin/bcms +21 -26
  80. data/config/routes.rb +3 -2
  81. data/db/browsercms.seeds.rb +2 -1
  82. data/db/migrate/20111130221145_browsercms340.rb +5 -4
  83. data/db/migrate/20120329144406_browsercms350.rb +32 -0
  84. data/{test/dummy/db → db}/schema.rb +97 -128
  85. data/{performance_tuning_notes.md → doc/performance_tuning_notes.md} +0 -0
  86. data/doc/release_notes.md +74 -0
  87. data/lib/browsercms.rb +3 -0
  88. data/lib/cms/acts/content_block.rb +10 -2
  89. data/lib/cms/addressable.rb +8 -0
  90. data/lib/cms/attachments/attachment_serving.rb +59 -0
  91. data/lib/cms/attachments/configuration.rb +88 -0
  92. data/lib/cms/behaviors/attaching.rb +305 -136
  93. data/lib/cms/behaviors/connecting.rb +3 -4
  94. data/lib/cms/behaviors/dynamic_attributes.rb +121 -118
  95. data/lib/cms/behaviors/flush_cache_on_change.rb +1 -3
  96. data/lib/cms/behaviors/naming.rb +16 -0
  97. data/lib/cms/behaviors/pagination.rb +4 -1
  98. data/lib/cms/behaviors/publishing.rb +9 -3
  99. data/lib/cms/behaviors/searching.rb +3 -8
  100. data/lib/cms/behaviors/soft_deleting.rb +1 -0
  101. data/lib/cms/behaviors/taggable.rb +2 -0
  102. data/lib/cms/behaviors/versioning.rb +73 -120
  103. data/lib/cms/caching.rb +53 -11
  104. data/lib/cms/commands/actions.rb +19 -2
  105. data/lib/cms/configuration.rb +44 -0
  106. data/lib/cms/content_rendering_support.rb +9 -6
  107. data/lib/cms/default_accessible.rb +13 -0
  108. data/lib/cms/domain_support.rb +22 -0
  109. data/lib/cms/engine.rb +40 -19
  110. data/lib/cms/engine_helper.rb +54 -0
  111. data/lib/cms/extensions/active_record/connection_adapters/abstract/schema_statements.rb +14 -2
  112. data/lib/cms/mobile_aware.rb +67 -0
  113. data/lib/cms/route_extensions.rb +3 -0
  114. data/lib/cms/upgrades/v3_5_0.rb +155 -0
  115. data/lib/cms/version.rb +6 -1
  116. data/lib/generators/cms/content_block/content_block_generator.rb +14 -9
  117. data/lib/generators/cms/content_block/templates/_form.html.erb +17 -6
  118. data/lib/generators/cms/content_block/templates/render.html.erb +12 -5
  119. data/lib/generators/cms/template/template_generator.rb +11 -2
  120. data/lib/tasks/cms.rake +23 -0
  121. data/lib/templates/active_record/model/model.rb +6 -0
  122. metadata +127 -517
  123. data/.gitignore +0 -24
  124. data/.rvmrc +0 -2
  125. data/Gemfile +0 -29
  126. data/Gemfile.lock +0 -196
  127. data/Rakefile +0 -97
  128. data/app/assets/images/browsercms/.gitkeep +0 -0
  129. data/app/controllers/browsercms/application_controller.rb +0 -4
  130. data/browsercms.gemspec +0 -35
  131. data/config/cucumber.yml +0 -8
  132. data/config/database.jdbcmysql.yml +0 -30
  133. data/config/database.mysql.yml +0 -27
  134. data/config/database.postgres.yml +0 -25
  135. data/config/database.sqlite3.yml +0 -11
  136. data/config/environment.rb +0 -6
  137. data/config/initializers/query_reviewer_patch.rb +0 -12
  138. data/config/initializers/rack_1_2_1_patch.rb +0 -12
  139. data/config/locales/en.yml +0 -5
  140. data/features/acts_as_content_page.feature +0 -62
  141. data/features/add_content_to_pages.feature +0 -45
  142. data/features/caching.feature +0 -13
  143. data/features/ckeditor.feature +0 -11
  144. data/features/commands/confirm_aruba_works.feature +0 -24
  145. data/features/commands/generate_module.feature +0 -54
  146. data/features/commands/install_browsercms.feature +0 -21
  147. data/features/commands/new_demo_project.feature +0 -30
  148. data/features/commands/new_projects.feature +0 -50
  149. data/features/commands/upgrade_modules_to_3_4_0_from_3_1_x.feature +0 -19
  150. data/features/commands/upgrade_project_to_3_4_0_from_3_3_x.feature +0 -52
  151. data/features/commands/upgrading_modules.feature +0 -67
  152. data/features/content_blocks/manage_custom_blocks.feature +0 -67
  153. data/features/content_blocks/manage_html_blocks.feature +0 -48
  154. data/features/content_blocks/manage_image_blocks.feature +0 -41
  155. data/features/content_files.feature +0 -37
  156. data/features/content_pages.feature +0 -21
  157. data/features/generators/content_blocks_for_modules.feature +0 -58
  158. data/features/generators/content_blocks_for_projects.feature +0 -109
  159. data/features/install_content.feature +0 -25
  160. data/features/jquery-testplan.txt +0 -12
  161. data/features/manage_groups.feature +0 -33
  162. data/features/manage_page_routes.feature +0 -72
  163. data/features/manage_redirects.feature +0 -20
  164. data/features/manage_sections.feature +0 -12
  165. data/features/manage_tasks.feature +0 -25
  166. data/features/manage_users.feature +0 -38
  167. data/features/page_templates.feature +0 -49
  168. data/features/portlets/email_friend_portlet.feature +0 -29
  169. data/features/portlets/portlets.feature +0 -100
  170. data/features/portlets/tag_cloud_portlet.feature +0 -28
  171. data/features/sitemap/create_pages.feature +0 -15
  172. data/features/sitemap/manage_links.feature +0 -29
  173. data/features/sitemap/sitemap.feature +0 -18
  174. data/features/step_definitions/acts_as_content_page_steps.rb.rb +0 -3
  175. data/features/step_definitions/ckeditor_steps.rb +0 -13
  176. data/features/step_definitions/command_line_steps.rb +0 -212
  177. data/features/step_definitions/content_pages_steps.rb +0 -170
  178. data/features/step_definitions/data_steps.rb +0 -48
  179. data/features/step_definitions/edit_page_templates_steps.rb +0 -21
  180. data/features/step_definitions/html_blocks_steps.rb +0 -9
  181. data/features/step_definitions/install_content_steps.rb +0 -4
  182. data/features/step_definitions/manage_content_blocks_steps.rb +0 -26
  183. data/features/step_definitions/manage_image_blocks_steps.rb +0 -31
  184. data/features/step_definitions/manage_sections_steps.rb +0 -18
  185. data/features/step_definitions/manage_user_steps.rb +0 -22
  186. data/features/step_definitions/more_custom_block_steps.rb +0 -34
  187. data/features/step_definitions/page_route_steps.rb +0 -65
  188. data/features/step_definitions/page_template_steps.rb +0 -5
  189. data/features/step_definitions/permissions_steps.rb +0 -13
  190. data/features/step_definitions/portlets_steps.rb +0 -64
  191. data/features/step_definitions/redirect_steps.rb +0 -12
  192. data/features/step_definitions/sitemap_steps.rb +0 -18
  193. data/features/step_definitions/tag_cloud_steps.rb +0 -11
  194. data/features/step_definitions/task_steps.rb +0 -4
  195. data/features/step_definitions/taxonomy_steps.rb +0 -16
  196. data/features/step_definitions/upgrade_module_steps.rb +0 -76
  197. data/features/step_definitions/web_steps.rb +0 -211
  198. data/features/support/async_support.rb +0 -17
  199. data/features/support/command_line_helpers.rb +0 -63
  200. data/features/support/debug_formatter.rb +0 -7
  201. data/features/support/debugging.rb +0 -28
  202. data/features/support/env.rb +0 -73
  203. data/features/support/git_api.rb +0 -9
  204. data/features/support/open_on_first_failure.rb +0 -25
  205. data/features/support/paths.rb +0 -32
  206. data/features/support/rails_api.rb +0 -8
  207. data/features/support/selectors.rb +0 -39
  208. data/features/support/transforms.rb +0 -7
  209. data/features/taxonomy/add_content_with_category.feature +0 -30
  210. data/features/taxonomy/manage_categories.feature +0 -20
  211. data/features/taxonomy/manage_category_types.feature +0 -16
  212. data/lib/cms/init.rb +0 -105
  213. data/lib/tasks/data.rake +0 -43
  214. data/lib/tasks/db.rake +0 -82
  215. data/public/styled_file_field/index.html +0 -72
  216. data/script/cucumber +0 -10
  217. data/script/rails +0 -6
  218. data/test/console_helper.rb +0 -5
  219. data/test/custom_assertions.rb +0 -84
  220. data/test/dummy/Rakefile +0 -7
  221. data/test/dummy/app/assets/javascripts/application.js +0 -9
  222. data/test/dummy/app/assets/javascripts/content_page.js +0 -2
  223. data/test/dummy/app/assets/stylesheets/application.css +0 -7
  224. data/test/dummy/app/assets/stylesheets/content_page.css +0 -4
  225. data/test/dummy/app/controllers/application_controller.rb +0 -3
  226. data/test/dummy/app/controllers/cms/products_controller.rb +0 -2
  227. data/test/dummy/app/controllers/cms/sample_blocks_controller.rb +0 -3
  228. data/test/dummy/app/controllers/content_page_controller.rb +0 -13
  229. data/test/dummy/app/helpers/application_helper.rb +0 -2
  230. data/test/dummy/app/helpers/content_page_helper.rb +0 -2
  231. data/test/dummy/app/mailers/.gitkeep +0 -0
  232. data/test/dummy/app/models/.gitkeep +0 -0
  233. data/test/dummy/app/models/cms/sample_block.rb +0 -22
  234. data/test/dummy/app/models/product.rb +0 -5
  235. data/test/dummy/app/views/cms/products/_form.html.erb +0 -7
  236. data/test/dummy/app/views/cms/products/render.html.erb +0 -3
  237. data/test/dummy/app/views/content_page/custom_page.html.erb +0 -3
  238. data/test/dummy/app/views/content_page/index.html.erb +0 -2
  239. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  240. data/test/dummy/app/views/layouts/templates/default.html.erb +0 -17
  241. data/test/dummy/app/views/layouts/templates/subpage.html.erb +0 -16
  242. data/test/dummy/app/views/test_route/index.html.erb +0 -14
  243. data/test/dummy/config.ru +0 -4
  244. data/test/dummy/config/application.rb +0 -45
  245. data/test/dummy/config/boot.rb +0 -10
  246. data/test/dummy/config/database.yml +0 -27
  247. data/test/dummy/config/environment.rb +0 -5
  248. data/test/dummy/config/environments/development.rb +0 -32
  249. data/test/dummy/config/environments/production.rb +0 -60
  250. data/test/dummy/config/environments/test.rb +0 -46
  251. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  252. data/test/dummy/config/initializers/browsercms.rb +0 -7
  253. data/test/dummy/config/initializers/inflections.rb +0 -10
  254. data/test/dummy/config/initializers/mime_types.rb +0 -5
  255. data/test/dummy/config/initializers/quiet_sprocket_assets.rb +0 -13
  256. data/test/dummy/config/initializers/secret_token.rb +0 -7
  257. data/test/dummy/config/initializers/session_store.rb +0 -8
  258. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  259. data/test/dummy/config/locales/en.yml +0 -5
  260. data/test/dummy/config/routes.rb +0 -23
  261. data/test/dummy/db/migrate/20111228141250_create_products.rb +0 -16
  262. data/test/dummy/db/seeds.rb +0 -1
  263. data/test/dummy/lib/assets/.gitkeep +0 -0
  264. data/test/dummy/public/404.html +0 -26
  265. data/test/dummy/public/422.html +0 -26
  266. data/test/dummy/public/500.html +0 -26
  267. data/test/dummy/public/favicon.ico +0 -0
  268. data/test/dummy/script/rails +0 -6
  269. data/test/dummy/test/functional/content_page_controller_test.rb +0 -9
  270. data/test/dummy/test/unit/helpers/content_page_helper_test.rb +0 -4
  271. data/test/factories.rb +0 -235
  272. data/test/fixtures/multipart/foo.jpg +0 -0
  273. data/test/fixtures/multipart/sample_upload.txt +0 -1
  274. data/test/fixtures/multipart/second_upload.txt +0 -1
  275. data/test/fixtures/multipart/test.jpg +0 -0
  276. data/test/fixtures/multipart/version1.txt +0 -1
  277. data/test/fixtures/multipart/version2.txt +0 -1
  278. data/test/functional/cms/cache_controller_test.rb +0 -16
  279. data/test/functional/cms/categories_controller_test.rb +0 -28
  280. data/test/functional/cms/connectors_controller_test.rb +0 -64
  281. data/test/functional/cms/content_block_controller_test.rb +0 -127
  282. data/test/functional/cms/content_controller_test.rb +0 -351
  283. data/test/functional/cms/dashboard_controller_test.rb +0 -20
  284. data/test/functional/cms/file_blocks_controller_test.rb +0 -55
  285. data/test/functional/cms/home_controller_test.rb +0 -160
  286. data/test/functional/cms/html_blocks_controller_test.rb +0 -159
  287. data/test/functional/cms/image_blocks_controller_test.rb +0 -78
  288. data/test/functional/cms/links_controller_test.rb +0 -92
  289. data/test/functional/cms/log/test.log +0 -0
  290. data/test/functional/cms/pages_controller_test.rb +0 -233
  291. data/test/functional/cms/portlets_controller_test.rb +0 -57
  292. data/test/functional/cms/sections_controller_test.rb +0 -234
  293. data/test/functional/cms/sessions_controller_test.rb +0 -80
  294. data/test/functional/cms/tasks_controller_test.rb +0 -64
  295. data/test/functional/cms/toolbar_controller_test.rb +0 -76
  296. data/test/functional/cms/users_controller_test.rb +0 -218
  297. data/test/integration/cms/password_management_test.rb +0 -66
  298. data/test/integration/sitemap_performance_test.rb +0 -26
  299. data/test/mock_file.rb +0 -33
  300. data/test/performance/browsing_test.rb +0 -9
  301. data/test/support/engine_controller_hacks.rb +0 -34
  302. data/test/support/factory_helpers.rb +0 -57
  303. data/test/support/rails_3_1_routes_hack.rb +0 -70
  304. data/test/test_helper.rb +0 -199
  305. data/test/test_logging.rb +0 -67
  306. data/test/unit/active_record_callbacks.rb +0 -50
  307. data/test/unit/behaviors/attaching_test.rb +0 -370
  308. data/test/unit/behaviors/cms_user_test.rb +0 -67
  309. data/test/unit/behaviors/connectable_test.rb +0 -32
  310. data/test/unit/behaviors/connecting_test.rb +0 -56
  311. data/test/unit/behaviors/dynamic_attributes_test.rb +0 -74
  312. data/test/unit/behaviors/namespacing_test.rb +0 -76
  313. data/test/unit/behaviors/publishable_test.rb +0 -83
  314. data/test/unit/behaviors/rendering_test.rb +0 -68
  315. data/test/unit/behaviors/searching_test.rb +0 -102
  316. data/test/unit/behaviors/taggable_test.rb +0 -110
  317. data/test/unit/behaviors/userstamping_test.rb +0 -27
  318. data/test/unit/behaviors/versioning_test.rb +0 -102
  319. data/test/unit/extensions/active_record/base_test.rb +0 -25
  320. data/test/unit/extensions/hash_test.rb +0 -26
  321. data/test/unit/extensions/integer_test.rb +0 -10
  322. data/test/unit/extensions/string_test.rb +0 -14
  323. data/test/unit/factories_test.rb +0 -50
  324. data/test/unit/generators/install_generator_test.rb +0 -15
  325. data/test/unit/helpers/application_helper_test.rb +0 -104
  326. data/test/unit/helpers/date_picker_test.rb +0 -17
  327. data/test/unit/helpers/menu_helper_test.rb +0 -240
  328. data/test/unit/helpers/page_helper_test.rb +0 -69
  329. data/test/unit/helpers/path_helper_test.rb +0 -38
  330. data/test/unit/helpers/rendering_helper_test.rb +0 -8
  331. data/test/unit/lib/acts_as_content_page_test.rb +0 -72
  332. data/test/unit/lib/cms/authentication/controller_test.rb +0 -20
  333. data/test/unit/lib/cms/engine_helper_test.rb +0 -119
  334. data/test/unit/lib/cms/sitemap_test.rb +0 -210
  335. data/test/unit/lib/cms_domain_support_test.rb +0 -44
  336. data/test/unit/lib/command_line_test.rb +0 -70
  337. data/test/unit/lib/content_block_test.rb +0 -304
  338. data/test/unit/lib/content_rendering_support_test.rb +0 -40
  339. data/test/unit/lib/generators_test.rb +0 -40
  340. data/test/unit/lib/routes_test.rb +0 -98
  341. data/test/unit/mock_file_test.rb +0 -19
  342. data/test/unit/models/attachment_test.rb +0 -160
  343. data/test/unit/models/category_test.rb +0 -40
  344. data/test/unit/models/category_type_test.rb +0 -8
  345. data/test/unit/models/connector_test.rb +0 -152
  346. data/test/unit/models/content_type_group_test.rb +0 -26
  347. data/test/unit/models/content_type_test.rb +0 -177
  348. data/test/unit/models/dynamic_views_test.rb +0 -36
  349. data/test/unit/models/email_page_portlet_test.rb +0 -20
  350. data/test/unit/models/file_block_test.rb +0 -246
  351. data/test/unit/models/group_test.rb +0 -29
  352. data/test/unit/models/html_block_test.rb +0 -121
  353. data/test/unit/models/image_block_test.rb +0 -35
  354. data/test/unit/models/link_test.rb +0 -52
  355. data/test/unit/models/namespaces_test.rb +0 -57
  356. data/test/unit/models/page_partial_test.rb +0 -37
  357. data/test/unit/models/page_route_test.rb +0 -113
  358. data/test/unit/models/page_template_test.rb +0 -50
  359. data/test/unit/models/page_test.rb +0 -879
  360. data/test/unit/models/permission_test.rb +0 -10
  361. data/test/unit/models/portlet_test.rb +0 -99
  362. data/test/unit/models/sections_test.rb +0 -278
  363. data/test/unit/models/site_test.rb +0 -50
  364. data/test/unit/models/task_test.rb +0 -150
  365. data/test/unit/models/user_test.rb +0 -358
  366. data/test/unit/schema_statements_test.rb +0 -137
  367. data/todo_list.markdown +0 -50
@@ -67,7 +67,9 @@ class Cms::SectionsController < Cms::BaseController
67
67
  @move_to = Section.root.first
68
68
  end
69
69
  end
70
-
70
+
71
+ # Generates XML for Browsing files/pages/etc.
72
+ # @todo This MIGHT best live in the FCKeditor module, since it's XML format is highly coupled to that module's needs.
71
73
  def file_browser
72
74
  @section = Cms::Section.find_by_name_path(params[:CurrentFolder])
73
75
  if request.post? && params[:NewFile]
@@ -112,7 +114,7 @@ class Cms::SectionsController < Cms::BaseController
112
114
  else
113
115
  @section.pages
114
116
  end
115
- render 'cms/sections/file_browser.xml.builder', :layout => false
117
+ render 'cms/sections/file_browser', :layout => false, :format=>:xml
116
118
  end
117
119
 
118
120
  def public_groups
@@ -1,14 +1,18 @@
1
1
  module Cms
2
- class ToolbarController < Cms::BaseController
2
+ class ToolbarController < Cms::BaseController
3
3
 
4
- def index
5
- if params[:page_toolbar] != "0"
6
- @mode = params[:mode]
7
- @page_toolbar_enabled = true
4
+ layout "cms/toolbar"
5
+
6
+ helper MobileHelper
7
+
8
+ def index
9
+ if params[:page_toolbar] != "0"
10
+ @mode = params[:mode]
11
+ @page_toolbar_enabled = true
12
+ end
13
+ @page_version = params[:page_version]
14
+ @page = Page.find(params[:page_id]).as_of_version(params[:page_version]) if params[:page_id]
8
15
  end
9
- @page_version = params[:page_version]
10
- @page = Page.find(params[:page_id]).as_of_version(params[:page_version]) if params[:page_id]
11
- end
12
-
13
- end
16
+
17
+ end
14
18
  end
@@ -9,9 +9,9 @@ module Cms
9
9
  end
10
10
 
11
11
  def searchable_sections(selected = nil)
12
- root = Section.root.first
12
+ root = Section.root.first
13
13
  options = [['All sections', 'all'], [root.name, root.id]]
14
- root.master_section_list.each { |s| options << [s.full_path, s.id] }
14
+ root.master_section_list.each { |s| options << [s.full_path, s.id] }
15
15
  options_for_select(options, selected.to_i)
16
16
  end
17
17
 
@@ -24,7 +24,7 @@ module Cms
24
24
  text = select_tag(:version,
25
25
  options_for_select(page.versions.all(:order => "version desc").map { |r|
26
26
  ["v#{r.version}: #{r.version_comment} by #{r.updated_by.login} at #{time_on_date(r.updated_at)}", r.version]
27
- }, page.version),
27
+ }, page.version),
28
28
  :onchange => 'this.form.submit(); return false')
29
29
  text << javascript_tag("$('version').selectedIndex = 0") if page.live?
30
30
  text
@@ -54,7 +54,7 @@ module Cms
54
54
  #
55
55
  # @param [String] selector The CSS selector for the checkboxes that should be mass checked/unchecked.
56
56
  def check_uncheck_tag(selector)
57
- check_id = to_id(selector, "check")
57
+ check_id = to_id(selector, "check")
58
58
  uncheck_id = to_id(selector, "uncheck")
59
59
  content_for :html_head do
60
60
  html = <<HTML
@@ -71,7 +71,7 @@ HTML
71
71
  javascript_tag html
72
72
  end
73
73
 
74
- "#{link_to "Check All", '#', :id=>check_id}, #{link_to "Uncheck All", '#', :id=>uncheck_id}".html_safe
74
+ "#{link_to "Check All", '#', :id => check_id}, #{link_to "Uncheck All", '#', :id => uncheck_id}".html_safe
75
75
  end
76
76
 
77
77
  # @deprecated Use check_uncheck_tag instead. Retained for backwards compatibility w/ CMS implementations.
@@ -87,7 +87,7 @@ jQuery(function($) {
87
87
  HTML
88
88
  javascript_tag html
89
89
  end
90
- link_to name, '#', :id=>id
90
+ link_to name, '#', :id => id
91
91
  end
92
92
 
93
93
  # @deprecated Use check_uncheck_tag instead. Retained for backwards compatibility w/ CMS implementations.
@@ -103,7 +103,7 @@ jQuery(function($) {
103
103
  HTML
104
104
  javascript_tag html
105
105
  end
106
- link_to name, '#', :id=>id
106
+ link_to name, '#', :id => id
107
107
  end
108
108
 
109
109
  def span_tag(content)
@@ -117,7 +117,7 @@ HTML
117
117
  <div class="lt_button_content">
118
118
  <span>#{ content }</span>
119
119
  </div>
120
- #{image_tag "cms/lt_button_r.gif", :style=>"margin-right: 10px;"}
120
+ #{image_tag "cms/lt_button_r.gif", :style => "margin-right: 10px;"}
121
121
  </div>
122
122
  LBW
123
123
  button.html_safe
@@ -138,22 +138,26 @@ LBW
138
138
  # Fetches a list of categories for a cms_drop_down. Will prompt users to create Categories/Categories types if the proper ones don't exist.
139
139
  def categories_for(category_type_name, order="name")
140
140
  cat_type = CategoryType.named(category_type_name).first
141
- categories = cat_type ? cat_type.category_list(order) : [Category.new(:name=>"-- You must first create a 'Category Type' named '#{category_type_name}'")]
142
- categories.empty? ? [Category.new(:name=>"-- You must first create a Category with a Category Type of '#{category_type_name}'.")]: categories
141
+ categories = cat_type ? cat_type.category_list(order) : [Category.new(:name => "-- You must first create a 'Category Type' named '#{category_type_name}'")]
142
+ categories.empty? ? [Category.new(:name => "-- You must first create a Category with a Category Type of '#{category_type_name}'.")] : categories
143
143
  end
144
144
 
145
- def render_pagination(collection, collection_name, options={})
145
+ # Generates the HTML to render a paging control, if there is more than one page to be shown.
146
+ #
147
+ # @param [Array] collection List of content to be shown
148
+ # @param [Cms::ContentType] content_type The content type of the collection (used to generate links to Previous/Next)
149
+ # @param [Hash] options
150
+ def render_pagination(collection, content_type, options={})
146
151
  if collection.blank?
147
152
  content_tag(:div, "No Content", :class => "pagination")
148
153
  else
149
- collection_path = "#{collection_name}_path"
150
154
  render :partial => "cms/shared/pagination", :locals => {
151
- :collection => collection,
152
- :first_page_path => send(collection_path, {:page => 1}.merge(options)),
153
- :previous_page_path => send(collection_path, {:page => collection.previous_page ? collection.previous_page : 1}.merge(options)),
154
- :current_page_path => send(collection_path, options),
155
- :next_page_path => send(collection_path, {:page => collection.next_page ? collection.next_page : collection.current_page}.merge(options)),
156
- :last_page_path => send(collection_path, {:page => collection.total_pages}.merge(options))
155
+ :collection => collection,
156
+ :first_page_path => cms_connectable_path(content_type, {:page => 1}.merge(options)),
157
+ :previous_page_path => cms_connectable_path(content_type, {:page => collection.previous_page ? collection.previous_page : 1}.merge(options)),
158
+ :current_page_path => cms_connectable_path(content_type, options),
159
+ :next_page_path => cms_connectable_path(content_type, {:page => collection.next_page ? collection.next_page : collection.current_page}.merge(options)),
160
+ :last_page_path => cms_connectable_path(content_type, {:page => collection.total_pages}.merge(options))
157
161
  }
158
162
  end
159
163
  end
@@ -222,7 +226,7 @@ LBW
222
226
  #
223
227
  # @param [Path] The path or URL to link_to. Takes same types at url_for or link_to.
224
228
  def add_button(path, options={})
225
- classes = "button"
229
+ classes = "button"
226
230
  span_options = {:class => classes}
227
231
  link_to span_tag("&nbsp;Add&nbsp;".html_safe), path, span_options
228
232
  end
@@ -12,21 +12,21 @@ class Cms::FormBuilder < ActionView::Helpers::FormBuilder
12
12
  # * :width - The width for the select (defaults to 455px).
13
13
  #
14
14
  def drop_down(method, choices, options = {}, html_options = {})
15
- select_class = "#{@object_name}_#{method}"
16
- h_opts = add_tabindex!(@default_options.merge(html_options))
15
+ select_class = "#{@object_name}_#{method}"
16
+ h_opts = add_tabindex!(@default_options.merge(html_options))
17
17
  h_opts[:class] = select_class
18
18
 
19
- opts = objectify_options(options)
19
+ opts = objectify_options(options)
20
20
  set_default_value!(method, options)
21
21
  cms_options = options.extract_only!(:default_value, :width)
22
22
  render_cms_form_partial :fancy_drop_down,
23
23
  :object_name => @object_name, :method => method,
24
- :choices => choices, :options => opts,
24
+ :choices => choices, :options => opts,
25
25
  :cms_options => cms_options, :html_options => h_opts
26
26
  end
27
27
 
28
28
  def date_picker(method, options={})
29
- text_field(method, {:size => 10, :class => "date_picker", :value=>Cms::DatePicker.format_for_ui(@object.send(method))}.merge(options))
29
+ text_field(method, {:size => 10, :class => "date_picker", :value => Cms::DatePicker.format_for_ui(@object.send(method))}.merge(options))
30
30
  end
31
31
 
32
32
  def tag_list(options={})
@@ -51,13 +51,49 @@ class Cms::FormBuilder < ActionView::Helpers::FormBuilder
51
51
  class_eval src, __FILE__, __LINE__
52
52
  end
53
53
 
54
+ # Returns a label for a given field
55
+ # @param [Symbol] field Name of the field
56
+ # @param [String] label_value If nil, will use default logic for Rails::FormBuilder#label
57
+ def cms_label(field, label_value)
58
+ if label_value
59
+ label field, label_value
60
+ else
61
+ label field
62
+ end
63
+ end
64
+
65
+ # Returns a file upload input tag for a given block, along with label and instructions.
66
+ #
67
+ # @param [Symbol] method The name of the model this form upload is associated with
68
+ # @param [Hash] options
69
+ # @option options [String] :label (Data)
70
+ # @option options [String] :instructions (blank) Helpful tips for the person entering the field, appears blank if nothing is specified.
71
+ # @option options [Boolean] :edit_path (false) If true, render a text field to allow users to edit path for this file.
72
+ # @option options [Boolean] :edit_section (false) If true, render a select box which allows users to choose which section this attachment should be placed in.
73
+ def cms_file_field(method, options={})
74
+ @object.ensure_attachment_exists if @object.respond_to?(:ensure_attachment_exists)
75
+ render_form_field("file_field", method, options)
76
+ end
77
+
78
+ # Renders a multiple file uploader for attachments. Allows users to add as many attachments to this model as needed.
79
+ def cms_attachment_manager
80
+ defs = Cms::Attachment.definitions_for(object.class.name, :multiple)
81
+ names = defs.keys.sort
82
+ return if names.empty?
83
+
84
+ names.unshift "Select a type to upload a file" if names.size > 1
85
+ render_cms_form_partial :attachment_manager, :asset_definitions => defs, :asset_types => names
86
+ end
87
+
88
+ # @params html_options
89
+ # @options html_option [:class] - This will be overridden, so don't bother to set it
54
90
  def cms_drop_down(method, choices, options={}, html_options={})
55
91
  add_tabindex!(html_options)
56
92
  set_default_value!(method, options)
57
93
  cms_options = options.extract_only!(:label, :instructions, :default_value)
58
94
  render_cms_form_partial :drop_down,
59
95
  :object_name => @object_name, :method => method,
60
- :choices => choices, :options => options,
96
+ :choices => choices, :options => options,
61
97
  :cms_options => cms_options, :html_options => html_options
62
98
  end
63
99
 
@@ -86,20 +122,20 @@ class Cms::FormBuilder < ActionView::Helpers::FormBuilder
86
122
  set_default_value!(method, options)
87
123
  cms_options = options.extract_only!(:label, :instructions, :default_value)
88
124
  render_cms_form_partial :text_editor,
89
- :id => (options[:id] || "#{@object_name}_#{method}"),
125
+ :id => (options[:id] || "#{@object_name}_#{method}"),
90
126
  :editor_enabled => (cookies["editorEnabled"].blank? ? true : (cookies["editorEnabled"] == 'true' || cookies["editorEnabled"] == ['true'])),
91
- :object_name => @object_name, :method => method,
92
- :options => options, :cms_options => cms_options
127
+ :object_name => @object_name, :method => method,
128
+ :options => options, :cms_options => cms_options
93
129
  end
94
130
 
95
131
  # Renders instructions for a given field below the field itself. Instructions can be used to provide helpful
96
132
  # guidance to content editors including formatting help or just explaining what a field is for.
97
133
  #
98
- # Will not render if instructions are blank/nil.
134
+ # If instructions are blank/nil, then nothing will be shown.
99
135
  #
100
- # * instructions - The text of the instructions to show (Defaults to blank)
136
+ # @param [String] instructions (blank) The help text to show
101
137
  def cms_instructions(instructions)
102
- render_cms_form_partial :instructions, :instructions=>instructions
138
+ render_cms_form_partial :instructions, :instructions => instructions
103
139
  end
104
140
 
105
141
  # Renders a label and checkbox suitable for allow editors to update a boolean field.
@@ -115,7 +151,7 @@ class Cms::FormBuilder < ActionView::Helpers::FormBuilder
115
151
  add_tabindex!(options)
116
152
  set_default_value!(method, options)
117
153
  cms_options = options.extract_only!(:label, :instructions, :default_value)
118
- render_cms_form_partial "check_box", :method=>method, :options => options, :cms_options => cms_options
154
+ render_cms_form_partial "check_box", :method => method, :options => options, :cms_options => cms_options
119
155
  end
120
156
 
121
157
  #
@@ -139,10 +175,10 @@ class Cms::FormBuilder < ActionView::Helpers::FormBuilder
139
175
  set_default_value!(method, options)
140
176
  options[:default_handler] = "erb" unless options[:default_handler]
141
177
 
142
- cms_options = options.extract_only!(:label, :instructions)
178
+ cms_options = options.extract_only!(:label, :instructions)
143
179
  dropdown_options = options.extract_only!(:default_handler)
144
180
  add_tabindex!(options)
145
- render_cms_form_partial :template_editor, :method=>method, :dropdown_options=>dropdown_options, :options => options, :cms_options=>cms_options
181
+ render_cms_form_partial :template_editor, :method => method, :dropdown_options => dropdown_options, :options => options, :cms_options => cms_options
146
182
  end
147
183
  end
148
184
 
@@ -156,11 +192,23 @@ class Cms::FormBuilder < ActionView::Helpers::FormBuilder
156
192
  errors_list << @template.content_tag(:p, "There were problems with the following fields:")
157
193
  errors_list << @template.content_tag(:ul, object.errors.full_messages.map { |message| @template.content_tag(:li, message).html_safe }.join("\n").html_safe).html_safe
158
194
 
159
- @template.content_tag(:div, errors_list.html_safe, :class => "errorExplanation", :id=>"errorExplanation")
195
+ @template.content_tag(:div, errors_list.html_safe, :class => "errorExplanation", :id => "errorExplanation")
160
196
  end
161
197
 
162
198
  private
163
199
 
200
+ def render_form_field(form_control_name, method, options)
201
+ add_tabindex!(options)
202
+ set_default_value!(method, options)
203
+ cms_options = options.extract!(:label, :instructions, :default_value)
204
+ render_cms_form_partial form_control_name.to_sym,
205
+ :model_object => @object,
206
+ :object_name => @object_name,
207
+ :method => method,
208
+ :options => options,
209
+ :cms_options => cms_options
210
+ end
211
+
164
212
  def set_default_value!(method, options={})
165
213
  if options.has_key?(:default_value) && @object.send(method).blank?
166
214
  @object.send("#{method}=", options[:default_value])
@@ -182,8 +230,7 @@ class Cms::FormBuilder < ActionView::Helpers::FormBuilder
182
230
  end
183
231
 
184
232
  def render_cms_form_partial(field_type_name, locals)
185
- @template.render :partial => "cms/form_builder/cms_#{field_type_name}",
186
- :locals => {:f => self}.merge(locals)
233
+ @template.render :partial => "cms/form_builder/cms_#{field_type_name}", :locals => {:f => self}.merge(locals)
187
234
  end
188
235
 
189
236
  end
@@ -0,0 +1,19 @@
1
+ module Cms
2
+ module MobileHelper
3
+
4
+ def full_site_url
5
+ main_app.url_for(:host => Rails.configuration.cms.site_domain, :prefer_full_site => true)
6
+ end
7
+
8
+ def mobile_site_url
9
+ main_app.url_for(:host => Rails.configuration.cms.site_domain, :prefer_mobile_site => true)
10
+ end
11
+
12
+ # Determines if the mobile template exists for a given page.
13
+ # Used by view to show/hide the mobile toggle.
14
+ def mobile_template_exists?(page)
15
+ controller.template_exists?(page.layout_name, "layouts/mobile")
16
+ end
17
+ end
18
+
19
+ end
@@ -5,6 +5,30 @@ module Cms
5
5
  # From app, should be cms.xyz_path
6
6
  module PathHelper
7
7
 
8
+ # Returns the relative path to the given attachment.
9
+ # Content editors will see exact specific version path, while other users will see the 'public' url for the path.
10
+ def attachment_path_for(attachment)
11
+ return "" unless attachment
12
+ if current_user.able_to?(:edit_content)
13
+ attachment.attachment_version_path
14
+ else
15
+ attachment.url
16
+ end
17
+ end
18
+
19
+ # Returns a path to sort a table of Content Blocks by a given parameter. Retains other relevant parameters (like search criteria).
20
+ #
21
+ # @param [Cms::ContentType] content_type
22
+ # @param [String] column_to_sort The name of the column to sort on.
23
+ def cms_sortable_column_path(content_type, column_to_sort)
24
+ filtered_params = params.clone
25
+ filtered_params.delete(:action)
26
+ filtered_params.delete(:controller)
27
+ filtered_params.merge!(:order => determine_order(filtered_params[:order], column_to_sort))
28
+ cms_connectable_path(content_type.model_class, filtered_params)
29
+ end
30
+
31
+ # @deprecated Use cms_connectable_path instead.
8
32
  def cms_index_path_for(resource, options={})
9
33
  polymorphic_path(build_path_for(resource), options)
10
34
  end
@@ -23,6 +47,10 @@ module Cms
23
47
  send("new_#{resource_collection_name(resource).underscore.gsub('/', '_')}_url", options)
24
48
  end
25
49
 
50
+ # @param [Class, String] connectable The model class (i.e. HtmlBlock) or plural collection name (html_blocks) to link to
51
+ # @param [Hash] options Passed to polymorphic_path
52
+ #
53
+ # @return [String] path suitable to give to link_to
26
54
  def cms_connectable_path(connectable, options={})
27
55
  if Portlet === connectable
28
56
  cms.portlet_path(connectable)
@@ -74,11 +102,9 @@ module Cms
74
102
 
75
103
  private
76
104
 
105
+
77
106
  def build_path_for(model_or_class_or_content_type)
78
- path = []
79
- path << engine_for(model_or_class_or_content_type)
80
- path.concat path_elements_for(model_or_class_or_content_type)
81
- path
107
+ Cms::EngineAwarePathBuilder.new(model_or_class_or_content_type).build(self)
82
108
  end
83
109
 
84
110
  # Returns the name of the collection that this resource belongs to
@@ -4,8 +4,16 @@
4
4
  #
5
5
  module Cms
6
6
  module RenderingHelper
7
+
8
+ # Renders a table of attachments for a given content block.
9
+ # This is intended as a basic view of the content, and probably won't be suitable for blocks that need to be added directly to pages.
10
+ #
11
+ def attachment_viewer(content)
12
+ render :partial => 'cms/attachments/attachment_table', :locals => { :block => content, :can_delete => false }
13
+ end
14
+
7
15
  def render_connector_and_connectable(connector, connectable)
8
- logger.warn "Rendering #{connectable} "
16
+ logger.debug "Rendering #{connectable} "
9
17
  if logged_in? && @mode == "edit" && current_user.able_to_edit?(connector.page)
10
18
  render(:partial => 'cms/pages/edit_connector', :locals => { :connector => connector, :connectable => connectable})
11
19
  else
@@ -2,23 +2,23 @@ module Cms
2
2
  class AbstractFileBlock < ActiveRecord::Base
3
3
 
4
4
 
5
- set_table_name Namespacing.prefix("file_blocks")
5
+ self.table_name = Namespacing.prefix("file_blocks")
6
6
 
7
7
  validates_presence_of :name
8
8
 
9
9
  scope :by_section, lambda { |section| {
10
- :include => {:attachment => :section_node },
11
- :conditions => ["#{SectionNode.table_name}.ancestry = ?", section.node.ancestry_path] }
12
- }
10
+ :include => {:attachment => :section_node},
11
+ :conditions => ["#{SectionNode.table_name}.ancestry = ?", section.node.ancestry_path]}
12
+ }
13
13
 
14
14
  # Return the parent section for this block.
15
15
  # @return [Cms::Section]
16
16
  def parent
17
- attachment.parent
17
+ file.parent
18
18
  end
19
19
 
20
20
  def path
21
- attachment_file_path
21
+ file.url
22
22
  end
23
23
 
24
24
  def self.publishable?
@@ -1,150 +1,149 @@
1
- require 'digest/sha1'
2
- require 'fileutils'
3
-
4
1
  module Cms
5
2
  class Attachment < ActiveRecord::Base
6
3
 
7
- #----- Constants ----------------------------------------------------------------
8
- UNKNOWN_MIME_TYPE = 'application/octet-stream'
4
+ MULTIPLE = 'multiple'
9
5
 
10
- #----- Macros ----------------------------------------------------------------
11
- is_archivable
12
- is_publishable
13
- uses_soft_delete
14
- is_userstamped
15
- is_versioned
6
+ SANITIZATION_REGEXES = [[/\s/, '_'], [/[&+()]/, '-'], [/[=?!'"{}\[\]#<>%]/, '']]
7
+ #' this tic cleans up emacs ruby mode
16
8
 
17
- # Rails 3 uses a new ActionDispatch::Http::UploadedFile. This holds that during the file processing.
18
- attr_accessor :uploaded_file
9
+ self.table_name = :cms_attachments
19
10
 
20
- # This exists for backwards compatibility
21
- alias_method :temp_file, :uploaded_file
22
- alias_method :temp_file=, :uploaded_file=
11
+ cattr_accessor :definitions, :instance_writer => false
12
+ @@definitions = {}.with_indifferent_access
13
+ cattr_reader :configuration
14
+ attr_accessor :attachable_class
15
+ attr_accessible :attachable_class
23
16
 
24
- #----- Callbacks -------------------------------------------------------------
25
- before_validation :make_dirty_if_temp_file
26
- before_validation :prepend_file_path_with_slash
27
- before_validation :extract_file_extension_from_file_name
28
- before_validation :extract_file_type_from_temp_file
29
- before_validation :extract_file_size_from_temp_file
30
- before_validation :set_file_location
17
+ before_validation :set_cardinality
18
+ before_save :set_section, :sanitized_file_path_and_name
19
+ before_create :setup_attachment
31
20
 
32
- after_save :write_temp_file_to_storage_location
33
- after_save :clear_ivars
21
+ belongs_to :attachable, :polymorphic => true
34
22
 
23
+ include DefaultAccessible
24
+ attr_accessible :data, :attachable, :attachment_name
35
25
 
36
- #----- Associations ----------------------------------------------------------
26
+ validates :attachment_name, :attachable_type, :presence => true
37
27
 
38
28
  include Cms::Addressable
39
29
  include Cms::Addressable::DeprecatedPageAccessors
40
30
  has_one :section_node, :as => :node, :class_name => 'Cms::SectionNode'
41
31
  alias :node :section_node
42
32
 
43
- #----- Validations -----------------------------------------------------------
33
+ is_archivable; is_publishable; uses_soft_delete; is_userstamped; is_versioned
44
34
 
45
- validates_presence_of :temp_file, :message => "You must upload a file", :on => :create
46
- validates_presence_of :file_path
47
- validates_uniqueness_of :file_path
35
+ #TODO change this to a simple method
36
+ #def named(mid)
37
+ # find_all_by_name mid
38
+ # end
39
+ # ...or even get rid of it
40
+ scope :named, lambda { |name|
41
+ {:conditions => {:attachment_name => name.to_s}}
42
+ }
48
43
 
49
- #----- Virtual Attributes ----------------------------------------------------
44
+ scope :multiple, :conditions => {:cardinality => MULTIPLE}
50
45
 
51
- def section=(section)
52
- dirty! if self.section != section
53
- super(section)
54
- end
46
+ FILE_BLOCKS = "Cms::AbstractFileBlock"
47
+ validates_presence_of :data_file_path, :if => Proc.new { |a| a.attachable_type == FILE_BLOCKS }
48
+ validates_uniqueness_of :data_file_path, :message =>"must be unique. (Another file, image or page is already using '%{value}').", :if => Proc.new { |a| a.attachable_type == FILE_BLOCKS }
55
49
 
56
- #----- Callbacks Methods -----------------------------------------------------
50
+ class << self
57
51
 
58
- def make_dirty_if_temp_file
59
- dirty! if temp_file
60
- end
61
-
62
- def prepend_file_path_with_slash
63
- unless file_path.blank?
64
- self.file_path = "/#{file_path}" unless file_path =~ /^\//
52
+ # Makes file paths more URL friendly
53
+ def sanitize_file_path(file_path)
54
+ SANITIZATION_REGEXES.inject(file_path.to_s) do |s, (regex, replace)|
55
+ s.gsub(regex, replace)
56
+ end
65
57
  end
66
- end
67
58
 
68
- def extract_file_extension_from_file_name
69
- if file_name && file_name['.']
70
- self.file_extension = file_name.split('.').last.to_s.downcase
59
+ def definitions_for(klass, type)
60
+ definitions[klass].inject({}) { |d, (k, v)| d[k.capitalize] = v if v["type"] == type; d }
71
61
  end
72
- end
73
62
 
74
- def extract_file_type_from_temp_file
75
- unless temp_file.blank?
76
- self.file_type = temp_file.content_type
63
+ def configuration
64
+ @@configuration ||= Cms::Attachments.configuration
65
+ end
77
66
 
78
- # Some
79
- if self.file_type == nil
80
- self.file_type = UNKNOWN_MIME_TYPE
67
+ # Returns a Proc that can be used to dynamically determine styles based on the Cms::Attachment class
68
+ #
69
+ # Paperclip can handle a :styles parameter which responds to :call(Paperclip::Attachment)
70
+ def dynamically_return_styles
71
+ lambda do |paperclip_attachment|
72
+ cms_attachment = paperclip_attachment.instance
73
+
74
+ # Look up the style for the given block
75
+ if cms_attachment.has_assigned_content_type?
76
+ configuration_value(cms_attachment.content_block_class, cms_attachment.attachment_name, :styles)
77
+ else # New attachments that aren't associated with an Attaching type yet have no styles
78
+ {}
79
+ end
81
80
  end
82
81
  end
83
- end
84
82
 
85
- def extract_file_size_from_temp_file
86
- unless temp_file.blank?
87
- self.file_size = temp_file.size
83
+ def find_live_by_file_path(path)
84
+ Attachment.published.not_archived.find_by_data_file_path path
88
85
  end
89
- end
90
86
 
91
- # The file will be stored on disk at
92
- # Attachment.storage_location/year/month/day/sha1
93
- # The sha1 is a 40 character hash based on the original_filename
94
- # of the file uploaded and the current time
95
- def set_file_location
96
- unless temp_file.blank?
97
- sha1 = Digest::SHA1.hexdigest("#{temp_file.original_filename}#{Time.now.to_f}")
98
- self.file_location = "#{Time.now.strftime("%Y/%m/%d")}/#{sha1}"
99
- end
100
- end
101
87
 
102
- def write_temp_file_to_storage_location
103
- unless temp_file.blank?
104
- actual_temp_file = temp_file.tempfile
88
+ def configure_paperclip
89
+ # @todo This might be better done using subclasses of Attachment for each document instance.
90
+ # We could use single table inheritance to avoid needing to do meta configurations.
91
+ has_attached_file :data,
92
+ :url => configuration.url,
93
+ :path => configuration.path,
94
+ :styles => dynamically_return_styles,
105
95
 
106
- Rails.logger.warn "I want to write out #{temp_file.tempfile}"
107
- FileUtils.mkdir_p File.dirname(full_file_location)
108
- if actual_temp_file.path
109
- FileUtils.copy actual_temp_file.path, full_file_location
110
- else
111
- open(full_file_location, 'w') { |f| f << actual_temp_file.read }
112
- end
96
+ # Needed for versioning so that we keep all previous files.
97
+ :preserve_files => true,
98
+
99
+ #TODO: enable custom processors
100
+ :processors => configuration.processors,
101
+ :default_url => configuration.default_url,
102
+ :default_style => configuration.default_style,
103
+ :use_timestamp => configuration.use_timestamp,
104
+ :whiny => configuration.whiny,
105
+ :storage => rail_config(:storage),
106
+ :s3_credentials => rail_config(:s3_credentials),
107
+ :bucket => rail_config(:s3_bucket)
113
108
 
114
- if Cms.attachment_file_permission
115
- FileUtils.chmod Cms.attachment_file_permission, full_file_location
116
- end
117
109
  end
118
- end
119
110
 
120
- def clear_ivars
121
- @temp_file = nil
122
- @section = nil
123
- @section_id = nil
124
- end
111
+ # Looks up a value from Rails config
112
+ def rail_config(key)
113
+ Rails.configuration.cms.attachments[key]
114
+ end
125
115
 
126
- #----- Class Methods ---------------------------------------------------------
116
+ # Looks up the configuration value given:
117
+ # @param [Class] block_class The class of a block which has an attachment.
118
+ # @param [String] name_of_attachment The name of the attachment association (i.e. if was 'has_attachment :photos' then pass 'photo')
119
+ # @param [Symbol] key The key for the value to be fetched (i.e. :styles)
120
+ #
121
+ def configuration_value(block_class, name_of_attachment, key)
122
+ class_definitions = definitions[block_class]
123
+ if class_definitions == nil
124
+ raise "Couldn't find any definitions for '#{block_class}'."
125
+ end
126
+ attachment_definition = class_definitions[name_of_attachment]
127
+ if attachment_definition == nil
128
+ raise "Verify that '#{block_class}' defines an attachment named ':#{name_of_attachment}'."
129
+ end
130
+ attachment_definition[key] || configuration.send(key)
131
+ end
127
132
 
128
- def self.storage_location
129
- @storage_location ||= File.join(Rails.root, "/tmp/uploads")
130
133
  end
131
134
 
132
- def self.storage_location=(storage_location)
133
- @storage_location = storage_location
134
- end
135
135
 
136
- def self.find_live_by_file_path(file_path)
137
- Cms::Attachment.published.not_archived.first(:conditions => {:file_path => file_path})
136
+ def section=(section)
137
+ dirty! if self.section != section
138
+ super(section)
138
139
  end
139
140
 
140
- #----- Instance Methods ------------------------------------------------------
141
-
142
- def file_name
143
- file_path ? file_path.split('/').last : nil
141
+ def config_value_for(key)
142
+ self.class.configuration_value(content_block_class, attachment_name, key)
144
143
  end
145
144
 
146
- def name
147
- file_name
145
+ def content_block_class
146
+ attachable_class || attachable.try(:class).try(:name) || attachable_type
148
147
  end
149
148
 
150
149
  def icon
@@ -160,25 +159,115 @@ module Cms
160
159
  :xml => %w[xml],
161
160
  :zip => %w[zip rar tar gz tgz]
162
161
  }.each do |icon, extensions|
163
- return icon if extensions.include?(file_extension.to_s)
162
+ return icon if extensions.include?(data_file_extension)
164
163
  end
165
164
  :file
166
165
  end
167
166
 
167
+ # For authorized users, return the path to get the specific version of the file associated with this attachment.
168
+ # Guests should always get 'data_file_path' which is the public version of the asset.
169
+ def attachment_version_path
170
+ "/cms/attachments/#{id}?version=#{version}"
171
+ end
172
+
168
173
  def public?
169
174
  section ? section.public? : false
170
175
  end
171
176
 
172
- def full_file_location
173
- File.join(Cms::Attachment.storage_location, file_location)
177
+ def is_image?
178
+ %w[jpg gif png jpeg].include?(data_file_extension)
179
+ end
180
+
181
+ # Returns a Paperclip generated relative path to the file (with thumbnail sizing)
182
+ def url(style_name = configuration.default_style)
183
+ data.url(style_name)
184
+ end
185
+
186
+ # Returns the absolute file location of the underlying asset
187
+ def path(style_name = configuration.default_style)
188
+ data.path(style_name)
189
+ end
190
+
191
+ def original_filename
192
+ data_file_name
193
+ end
194
+
195
+ alias :file_name :original_filename
196
+
197
+ def size
198
+ data_file_size
199
+ end
200
+
201
+ def content_type
202
+ data_content_type
203
+ end
204
+
205
+ alias :file_type :content_type
206
+
207
+ # Returns the definitions for this particular attachment type.
208
+ # @return [Hash] Empty Hash if no definition have been defined for this attachment.
209
+ def config
210
+ content_defs = definitions[content_block_class] ? definitions[content_block_class] : {}
211
+ content_defs[attachment_name] ? content_defs[attachment_name] : {}
212
+ end
213
+
214
+ # Determines if this Attachment has access to configuration information yet. Until it is assigned to an Attaching object,
215
+ # it will lack style information.
216
+ def has_assigned_content_type?()
217
+ attachable_type && attachment_name
218
+ end
219
+
220
+ protected
221
+
222
+ private
223
+
224
+ def data_file_extension
225
+ data_file_name.split('.').last.downcase if data_file_name && data_file_name['.']
226
+ end
227
+
228
+ # Filter - Ensure that paths are going to URL friendly (and won't need encoding for special characters.')
229
+ def sanitized_file_path_and_name
230
+ if data_file_path
231
+ self.data_file_path = self.class.sanitize_file_path(data_file_path)
232
+ if !data_file_path.empty? && !data_file_path.starts_with?("/")
233
+ self.data_file_path = "/#{data_file_path}"
234
+ end
235
+ end
236
+
237
+ if data_file_name
238
+ self.data_file_name = self.class.sanitize_file_path(data_file_name)
239
+ end
240
+ end
241
+
242
+ def set_section
243
+ unless parent
244
+ self.parent = Section.root.first
245
+ end
246
+ end
247
+
248
+ def setup_attachment
249
+ data.instance_variable_set :@url, config_value_for(:url)
250
+ data.instance_variable_set :@path, config_value_for(:path)
251
+ data.instance_variable_set :@styles, config_value_for(:styles)
252
+ data.instance_variable_set :@normalized_styles, nil
253
+ data.send :post_process_styles
254
+ end
255
+
256
+ # Attachments should always be configured with a cardinality
257
+ def set_cardinality
258
+ unless cardinality
259
+ self.cardinality = config[:type].to_s
260
+ end
261
+
174
262
  end
175
263
 
176
264
  # Forces this record to be changed, even if nothing has changed
177
265
  # This is necessary if just the section.id has changed, for example
266
+ # test if this is necessary now that the attributes are in the
267
+ # model itself.
178
268
  def dirty!
179
269
  # Seems like a hack, is there a better way?
180
270
  self.updated_at = Time.now
181
271
  end
182
-
183
272
  end
184
- end
273
+ end