zena 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (1826) hide show
  1. data/History.txt +18 -0
  2. data/README.txt +133 -0
  3. data/app/controllers/application_controller.rb +3 -0
  4. data/app/controllers/comments_controller.rb +141 -0
  5. data/app/controllers/data_entries_controller.rb +81 -0
  6. data/app/controllers/discussions_controller.rb +48 -0
  7. data/app/controllers/documents_controller.rb +136 -0
  8. data/app/controllers/groups_controller.rb +99 -0
  9. data/app/controllers/iformats_controller.rb +78 -0
  10. data/app/controllers/links_controller.rb +98 -0
  11. data/app/controllers/nodes_controller.rb +497 -0
  12. data/app/controllers/preferences_controller.rb +52 -0
  13. data/app/controllers/relations_controller.rb +95 -0
  14. data/app/controllers/sessions_controller.rb +41 -0
  15. data/app/controllers/sites_controller.rb +112 -0
  16. data/app/controllers/users_controller.rb +139 -0
  17. data/app/controllers/versions_controller.rb +268 -0
  18. data/app/controllers/virtual_classes_controller.rb +95 -0
  19. data/app/helpers/application_helper.rb +4 -0
  20. data/app/helpers/documents_helper.rb +13 -0
  21. data/app/helpers/nodes_helper.rb +20 -0
  22. data/app/helpers/versions_helper.rb +18 -0
  23. data/app/models/book.rb +242 -0
  24. data/app/models/cache.rb +52 -0
  25. data/app/models/cached_page.rb +134 -0
  26. data/app/models/comment.rb +125 -0
  27. data/app/models/contact.rb +32 -0
  28. data/app/models/contact_content.rb +70 -0
  29. data/app/models/contact_version.rb +40 -0
  30. data/app/models/data_entry.rb +162 -0
  31. data/app/models/discussion.rb +65 -0
  32. data/app/models/document.rb +146 -0
  33. data/app/models/document_content.rb +186 -0
  34. data/app/models/document_version.rb +13 -0
  35. data/app/models/dyn_attribute.rb +4 -0
  36. data/app/models/group.rb +142 -0
  37. data/app/models/iformat.rb +146 -0
  38. data/app/models/image.rb +96 -0
  39. data/app/models/image_content.rb +189 -0
  40. data/app/models/image_version.rb +21 -0
  41. data/app/models/link.rb +121 -0
  42. data/app/models/node.rb +1752 -0
  43. data/app/models/note.rb +58 -0
  44. data/app/models/page.rb +53 -0
  45. data/app/models/project.rb +10 -0
  46. data/app/models/reference.rb +18 -0
  47. data/app/models/relation.rb +18 -0
  48. data/app/models/relation_proxy.rb +379 -0
  49. data/app/models/section.rb +5 -0
  50. data/app/models/site.rb +355 -0
  51. data/app/models/skin.rb +20 -0
  52. data/app/models/template.rb +134 -0
  53. data/app/models/template_content.rb +112 -0
  54. data/app/models/template_version.rb +37 -0
  55. data/app/models/text_document.rb +162 -0
  56. data/app/models/text_document_content.rb +46 -0
  57. data/app/models/text_document_version.rb +21 -0
  58. data/app/models/user.rb +412 -0
  59. data/app/models/version.rb +328 -0
  60. data/app/models/virtual_class.rb +134 -0
  61. data/app/models/zip.rb +6 -0
  62. data/app/views/comments/_add.rhtml +6 -0
  63. data/app/views/comments/_bin.rhtml +5 -0
  64. data/app/views/comments/_form.rhtml +26 -0
  65. data/app/views/comments/_li.rhtml +13 -0
  66. data/app/views/comments/_li_simple.rhtml +3 -0
  67. data/app/views/comments/_list.rhtml +13 -0
  68. data/app/views/comments/create.rjs +32 -0
  69. data/app/views/comments/edit.rjs +2 -0
  70. data/app/views/comments/empty_bin.rjs +1 -0
  71. data/app/views/comments/index.rhtml +12 -0
  72. data/app/views/comments/publish.rjs +7 -0
  73. data/app/views/comments/remove.rjs +9 -0
  74. data/app/views/comments/reply_to.rjs +2 -0
  75. data/app/views/comments/update.rjs +1 -0
  76. data/app/views/data_entries/_li.html.erb +9 -0
  77. data/app/views/data_entries/create.rjs +1 -0
  78. data/app/views/data_entries/destroy.rjs +1 -0
  79. data/app/views/data_entries/edit.rjs +1 -0
  80. data/app/views/data_entries/index.html.erb +5 -0
  81. data/app/views/data_entries/show.html.erb +5 -0
  82. data/app/views/data_entries/show.rjs +1 -0
  83. data/app/views/data_entries/update.rjs +1 -0
  84. data/app/views/discussions/_add.rhtml +6 -0
  85. data/app/views/discussions/_form.rhtml +21 -0
  86. data/app/views/discussions/_li.rhtml +9 -0
  87. data/app/views/discussions/_list.rhtml +4 -0
  88. data/app/views/discussions/create.rjs +10 -0
  89. data/app/views/discussions/remove.rjs +7 -0
  90. data/app/views/discussions/show.rjs +1 -0
  91. data/app/views/discussions/update.rjs +2 -0
  92. data/app/views/documents/_crop.rhtml +10 -0
  93. data/app/views/documents/crop_form.rjs +4 -0
  94. data/app/views/documents/new.rhtml +18 -0
  95. data/app/views/documents/show.rhtml +17 -0
  96. data/app/views/groups/_add.rhtml +6 -0
  97. data/app/views/groups/_form.rhtml +44 -0
  98. data/app/views/groups/_li.rhtml +13 -0
  99. data/app/views/groups/create.rjs +8 -0
  100. data/app/views/groups/destroy.rjs +2 -0
  101. data/app/views/groups/edit.html.erb +5 -0
  102. data/app/views/groups/index.rhtml +6 -0
  103. data/app/views/groups/show.html.erb +5 -0
  104. data/app/views/groups/show.rjs +1 -0
  105. data/app/views/iformats/_add.rhtml +6 -0
  106. data/app/views/iformats/_form.rhtml +29 -0
  107. data/app/views/iformats/_li.rhtml +15 -0
  108. data/app/views/iformats/create.rjs +8 -0
  109. data/app/views/iformats/destroy.rjs +11 -0
  110. data/app/views/iformats/edit.html.erb +5 -0
  111. data/app/views/iformats/index.rhtml +7 -0
  112. data/app/views/iformats/show.html.erb +5 -0
  113. data/app/views/iformats/show.rjs +1 -0
  114. data/app/views/iformats/update.rjs +5 -0
  115. data/app/views/image/_title.rhtml +8 -0
  116. data/app/views/links/_add.rhtml +6 -0
  117. data/app/views/links/_form.rhtml +34 -0
  118. data/app/views/links/_li.rhtml +7 -0
  119. data/app/views/links/_list.rhtml +9 -0
  120. data/app/views/links/create.rjs +5 -0
  121. data/app/views/links/destroy.rjs +11 -0
  122. data/app/views/links/show.rjs +5 -0
  123. data/app/views/nodes/404.html +15 -0
  124. data/app/views/nodes/500.html +15 -0
  125. data/app/views/nodes/_dates.rhtml +13 -0
  126. data/app/views/nodes/_edit_attribute.rhtml +32 -0
  127. data/app/views/nodes/_gallery.rhtml +16 -0
  128. data/app/views/nodes/_groups.rhtml +25 -0
  129. data/app/views/nodes/_import_results.rhtml +20 -0
  130. data/app/views/nodes/_list_nodes.rhtml +9 -0
  131. data/app/views/nodes/_parent.rhtml +15 -0
  132. data/app/views/nodes/_position.rhtml +22 -0
  133. data/app/views/nodes/_results.rhtml +29 -0
  134. data/app/views/nodes/_show_attr.rhtml +6 -0
  135. data/app/views/nodes/_table.rhtml +14 -0
  136. data/app/views/nodes/clear_order.rjs +7 -0
  137. data/app/views/nodes/create.rjs +17 -0
  138. data/app/views/nodes/drive.rjs +2 -0
  139. data/app/views/nodes/drop.rjs +1 -0
  140. data/app/views/nodes/edit.html.erb +17 -0
  141. data/app/views/nodes/edit.rjs +7 -0
  142. data/app/views/nodes/import.rhtml +10 -0
  143. data/app/views/nodes/save_text.rjs +13 -0
  144. data/app/views/nodes/search.rjs +3 -0
  145. data/app/views/nodes/show.rjs +1 -0
  146. data/app/views/nodes/table_update.rjs +8 -0
  147. data/app/views/nodes/update.rjs +29 -0
  148. data/app/views/nodes/zafu.rjs +1 -0
  149. data/app/views/relations/_add.erb +6 -0
  150. data/app/views/relations/_form.erb +43 -0
  151. data/app/views/relations/_li.erb +16 -0
  152. data/app/views/relations/create.rjs +8 -0
  153. data/app/views/relations/destroy.rjs +6 -0
  154. data/app/views/relations/edit.erb +2 -0
  155. data/app/views/relations/index.erb +6 -0
  156. data/app/views/relations/new.erb +2 -0
  157. data/app/views/relations/show.rjs +1 -0
  158. data/app/views/relations/update.rjs +5 -0
  159. data/app/views/search/_form.rhtml +13 -0
  160. data/app/views/sites/_form.erb +37 -0
  161. data/app/views/sites/_li.erb +13 -0
  162. data/app/views/sites/clear_cache.rjs +2 -0
  163. data/app/views/sites/edit.erb +2 -0
  164. data/app/views/sites/index.erb +6 -0
  165. data/app/views/sites/show.rjs +1 -0
  166. data/app/views/sites/update.rjs +5 -0
  167. data/app/views/sites/zena_up.html.erb +11 -0
  168. data/app/views/templates/defaults/+adminLayout.zafu +69 -0
  169. data/app/views/templates/defaults/+login.zafu +32 -0
  170. data/app/views/templates/document_create_tabs/_file.rhtml +13 -0
  171. data/app/views/templates/document_create_tabs/_import.rhtml +9 -0
  172. data/app/views/templates/document_create_tabs/_template.rhtml +22 -0
  173. data/app/views/templates/document_create_tabs/_text_doc.rhtml +14 -0
  174. data/app/views/templates/drive_tabs/_drive.rhtml +11 -0
  175. data/app/views/templates/drive_tabs/_help.rhtml +0 -0
  176. data/app/views/templates/drive_tabs/_links.rhtml +8 -0
  177. data/app/views/templates/edit_tabs/_contact.rhtml +8 -0
  178. data/app/views/templates/edit_tabs/_custom.rhtml +6 -0
  179. data/app/views/templates/edit_tabs/_document.rhtml +8 -0
  180. data/app/views/templates/edit_tabs/_help.rhtml +7 -0
  181. data/app/views/templates/edit_tabs/_image.rhtml +19 -0
  182. data/app/views/templates/edit_tabs/_template.rhtml +8 -0
  183. data/app/views/templates/edit_tabs/_text.rhtml +1 -0
  184. data/app/views/templates/edit_tabs/_textdocument.rhtml +16 -0
  185. data/app/views/templates/edit_tabs/_title.rhtml +27 -0
  186. data/app/views/users/_add.rhtml +6 -0
  187. data/app/views/users/_form.rhtml +49 -0
  188. data/app/views/users/_li.rhtml +18 -0
  189. data/app/views/users/change_info.rjs +7 -0
  190. data/app/views/users/change_password.rjs +7 -0
  191. data/app/views/users/create.rjs +8 -0
  192. data/app/views/users/index.rhtml +7 -0
  193. data/app/views/users/preferences.html.erb +40 -0
  194. data/app/views/users/show.rjs +1 -0
  195. data/app/views/users/update.rjs +16 -0
  196. data/app/views/versions/_li.rhtml +3 -0
  197. data/app/views/versions/_list.rhtml +5 -0
  198. data/app/views/versions/_tr.rhtml +10 -0
  199. data/app/views/versions/backup.rjs +16 -0
  200. data/app/views/versions/css_preview.rjs +2 -0
  201. data/app/views/versions/destroy.rjs +6 -0
  202. data/app/views/versions/diff.rjs +3 -0
  203. data/app/views/versions/edit.rhtml +55 -0
  204. data/app/views/versions/preview.rjs +9 -0
  205. data/app/views/versions/show.rjs +5 -0
  206. data/app/views/versions/update.rjs +9 -0
  207. data/app/views/virtual_classes/_add.erb +6 -0
  208. data/app/views/virtual_classes/_form.erb +30 -0
  209. data/app/views/virtual_classes/_li.erb +12 -0
  210. data/app/views/virtual_classes/create.rjs +8 -0
  211. data/app/views/virtual_classes/destroy.rjs +6 -0
  212. data/app/views/virtual_classes/index.erb +7 -0
  213. data/app/views/virtual_classes/new.erb +2 -0
  214. data/app/views/virtual_classes/show.rjs +1 -0
  215. data/app/views/virtual_classes/update.rjs +5 -0
  216. data/bin/zena +5 -0
  217. data/bricks/captcha/MIT-LICENSE +19 -0
  218. data/bricks/captcha/README +11 -0
  219. data/bricks/captcha/patch/application_controller.rb +10 -0
  220. data/bricks/captcha/patch/application_helper.rb +32 -0
  221. data/bricks/captcha/patch/site.rb +2 -0
  222. data/bricks/captcha/zafu/captcha.rb +29 -0
  223. data/bricks/math/patch/application_helper.rb +95 -0
  224. data/bricks/tags/README +31 -0
  225. data/bricks/tags/lib/has_tags.rb +164 -0
  226. data/bricks/tags/patch/node.rb +15 -0
  227. data/bricks/tags/test/sites/zena/links.yml +11 -0
  228. data/bricks/tags/test/unit/tags_test.rb +103 -0
  229. data/bricks/tags/test/zafu/tags.yml +28 -0
  230. data/bricks/toto.zip +0 -0
  231. data/config/awstats.conf.rhtml +1497 -0
  232. data/config/boot.rb +109 -0
  233. data/config/database.rhtml +25 -0
  234. data/config/database.yml +40 -0
  235. data/config/database_example.yml +27 -0
  236. data/config/deploy.rb +382 -0
  237. data/config/deploy_config_example.rb +7 -0
  238. data/config/environment.rb +13 -0
  239. data/config/environments/development.rb +21 -0
  240. data/config/environments/production.rb +27 -0
  241. data/config/environments/test.rb +22 -0
  242. data/config/gems.yml +46 -0
  243. data/config/httpd.rhtml +18 -0
  244. data/config/initializers/mime_types.rb +10 -0
  245. data/config/initializers/zena.rb +1 -0
  246. data/config/locales/de.yml +120 -0
  247. data/config/locales/fr-CH.yml +123 -0
  248. data/config/locales/fr.yml +123 -0
  249. data/config/mongrel_upload_progress.conf +7 -0
  250. data/config/routes.rb +3 -0
  251. data/config/start.html +44 -0
  252. data/config/stats.vhost.rhtml +40 -0
  253. data/config/vhost.rhtml +84 -0
  254. data/config/vhost_www.rhtml +10 -0
  255. data/config/zena.rb +39 -0
  256. data/db/init/base/help.en.zml +94 -0
  257. data/db/init/base/help.fr.zml +88 -0
  258. data/db/init/base/skins.zml +3 -0
  259. data/db/init/base/skins/default.zml +10 -0
  260. data/db/init/base/skins/default/Node-+adminLayout.zafu +45 -0
  261. data/db/init/base/skins/default/Node-+index.zafu +1 -0
  262. data/db/init/base/skins/default/Node-+login.zafu +25 -0
  263. data/db/init/base/skins/default/Node-+notFound.zafu +14 -0
  264. data/db/init/base/skins/default/Node-+popupLayout.zafu +39 -0
  265. data/db/init/base/skins/default/Node-+search.zafu +20 -0
  266. data/db/init/base/skins/default/Node-tree.zafu +19 -0
  267. data/db/init/base/skins/default/Node.zafu +95 -0
  268. data/db/init/base/skins/default/Project.zafu +8 -0
  269. data/db/init/base/skins/default/favicon.png +0 -0
  270. data/db/init/base/skins/default/notes.zafu +22 -0
  271. data/db/init/base/skins/default/style.css +80 -0
  272. data/db/migrate/001_create_base.rb +156 -0
  273. data/db/migrate/002_add_time_zone_to_users.rb +9 -0
  274. data/db/migrate/003_add_custom_base_flag.rb +11 -0
  275. data/db/migrate/004_rename_template_skin.rb +9 -0
  276. data/db/migrate/005_create_cached_pages.rb +20 -0
  277. data/db/migrate/006_create_sites.rb +60 -0
  278. data/db/migrate/007_replace_id_by_zip.rb +17 -0
  279. data/db/migrate/008_user_status.rb +10 -0
  280. data/db/migrate/009_fulltext.rb +13 -0
  281. data/db/migrate/010_create_template_content.rb +17 -0
  282. data/db/migrate/011_project_to_section.rb +9 -0
  283. data/db/migrate/012_add_project_id.rb +12 -0
  284. data/db/migrate/013_remove_defaults.rb +29 -0
  285. data/db/migrate/014_add_sort_field.rb +10 -0
  286. data/db/migrate/015_add_dyn_attributes.rb +18 -0
  287. data/db/migrate/016_remove_translations.rb +20 -0
  288. data/db/migrate/017_rename_authorize.rb +9 -0
  289. data/db/migrate/018_add_auth_option.rb +9 -0
  290. data/db/migrate/019_remove_user_status.rb +25 -0
  291. data/db/migrate/020_create_participation.rb +30 -0
  292. data/db/migrate/021_create_relations.rb +23 -0
  293. data/db/migrate/022_create_virtual_classes.rb +20 -0
  294. data/db/migrate/023_ip_on_anonymous_comment.rb +9 -0
  295. data/db/migrate/024_correct_vclass_kpath.rb +11 -0
  296. data/db/migrate/025_move_tag_into_vclass.rb +13 -0
  297. data/db/migrate/026_rename_templates.rb +47 -0
  298. data/db/migrate/027_add_country_to_contacts.rb +9 -0
  299. data/db/migrate/028_change_size_of_conten_type_field.rb +9 -0
  300. data/db/migrate/029_create_data_entries.rb +21 -0
  301. data/db/migrate/030_redit_auto_publish_site_settings.rb +13 -0
  302. data/db/migrate/031_create_iformats.rb +21 -0
  303. data/db/migrate/032_caches_context_as_hash.rb +10 -0
  304. data/db/migrate/033_documents_kpath_change.rb +17 -0
  305. data/db/migrate/034_change_file_storage.rb +38 -0
  306. data/db/migrate/035_add_status_to_link.rb +13 -0
  307. data/db/migrate/036_add_flag_fields_on_nodes.rb +11 -0
  308. data/db/migrate/037_add_auto_create_discussion_to_v_class.rb +11 -0
  309. data/db/migrate/038_create_site_attributes.rb +15 -0
  310. data/db/migrate/039_default_position.rb +10 -0
  311. data/db/migrate/040_second_value_for_data_entry.rb +11 -0
  312. data/db/migrate/041_add_attributes_to_v_class.rb +9 -0
  313. data/db/migrate/042_fix_position_should_be_float.rb +8 -0
  314. data/db/migrate/043_move_user_lang_into_participation.rb +15 -0
  315. data/db/migrate/044_remove_monolingual_site_option.rb +9 -0
  316. data/db/migrate/045_avoid_star_in_templates.rb +13 -0
  317. data/db/migrate/046_fix_zazen_image_tag.rb +47 -0
  318. data/db/migrate/047_change_default_link_id_to_zero.rb +12 -0
  319. data/db/migrate/048_link_source_target_can_be_null.rb +11 -0
  320. data/db/migrate/049_fix_publish_from_is_null.rb +9 -0
  321. data/db/migrate/050_date_in_links.rb +9 -0
  322. data/db/migrate/051_add_exif_tags_to_images.rb +9 -0
  323. data/db/migrate/20090825201159_insert_zero_link.rb +8 -0
  324. data/db/migrate/20090825201200_merge_bricks_migrations_with_std_migrations.rb +19 -0
  325. data/db/migrate/20090924141459_zafu_fix_sept09.rb +19 -0
  326. data/db/migrate/20090927125912_allow_null_in_text_fields.rb +17 -0
  327. data/db/migrate/20090928133440_no_more_private_nodes.rb +25 -0
  328. data/db/migrate/20090928143754_version_status_change.rb +24 -0
  329. data/db/migrate/20091001084025_change_status_values_for_comments.rb +22 -0
  330. data/db/migrate/20091009084057_add_vhash_in_node.rb +13 -0
  331. data/db/migrate/20091013100351_rename_publish_group_to_drive_group.rb +12 -0
  332. data/db/migrate/20091014130833_fix_template_title.rb +16 -0
  333. data/db/migrate/20091014183726_merge_participation_into_users.rb +21 -0
  334. data/db/production.sqlite3 +0 -0
  335. data/db/schema.rb +281 -0
  336. data/lib/base_additions.rb +7 -0
  337. data/lib/bricks/patcher.rb +68 -0
  338. data/lib/comment_query.rb +92 -0
  339. data/lib/core_ext/date_time.rb +5 -0
  340. data/lib/core_ext/dir.rb +12 -0
  341. data/lib/core_ext/fixnum.rb +20 -0
  342. data/lib/core_ext/string.rb +74 -0
  343. data/lib/exif_data.rb +54 -0
  344. data/lib/fix_rails_layouts.rb +9 -0
  345. data/lib/gettext_strings.rb +160 -0
  346. data/lib/image_builder.rb +325 -0
  347. data/lib/log_recorder/lib/log_recorder.rb +138 -0
  348. data/lib/log_recorder/test/log_recorder_test.rb +0 -0
  349. data/lib/parser.rb +1 -0
  350. data/lib/tasks/capistrano.rake +99 -0
  351. data/lib/tasks/zena.rake +358 -0
  352. data/lib/tasks/zena.rb +2 -0
  353. data/lib/upload_progress_server.rb +24 -0
  354. data/lib/webdav_adapter.rb +172 -0
  355. data/lib/zafu_parser.rb +3 -0
  356. data/lib/zazen_parser.rb +1 -0
  357. data/lib/zena.rb +398 -0
  358. data/lib/zena/acts/multiversion.rb +755 -0
  359. data/lib/zena/acts/secure.rb +774 -0
  360. data/lib/zena/app.rb +39 -0
  361. data/lib/zena/code_syntax.rb +275 -0
  362. data/lib/zena/controller/test_case.rb +32 -0
  363. data/lib/zena/db.rb +252 -0
  364. data/lib/zena/fix/mysql_connection.rb +17 -0
  365. data/lib/zena/foxy_parser.rb +845 -0
  366. data/lib/zena/migrator.rb +109 -0
  367. data/lib/zena/parser.rb +601 -0
  368. data/lib/zena/parser/zafu_rules.rb +232 -0
  369. data/lib/zena/parser/zafu_tags.rb +197 -0
  370. data/lib/zena/parser/zazen_rules.rb +427 -0
  371. data/lib/zena/parser/zazen_tags.rb +44 -0
  372. data/lib/zena/parser/zena_rules.rb +29 -0
  373. data/lib/zena/parser/zena_tags.rb +3559 -0
  374. data/lib/zena/root.rb +3 -0
  375. data/lib/zena/routes.rb +73 -0
  376. data/lib/zena/test_controller.rb +74 -0
  377. data/lib/zena/unit/test_case.rb +24 -0
  378. data/lib/zena/use/ajax.rb +119 -0
  379. data/lib/zena/use/authentification.rb +120 -0
  380. data/lib/zena/use/calendar.rb +130 -0
  381. data/lib/zena/use/custom_queries/complex.host.yml +173 -0
  382. data/lib/zena/use/dates.rb +230 -0
  383. data/lib/zena/use/dyn_attributes.rb +256 -0
  384. data/lib/zena/use/error_rendering.rb +52 -0
  385. data/lib/zena/use/fixtures.rb +133 -0
  386. data/lib/zena/use/grid.rb +148 -0
  387. data/lib/zena/use/html_tags.rb +603 -0
  388. data/lib/zena/use/i18n.rb +247 -0
  389. data/lib/zena/use/nested_attributes_alias.rb +201 -0
  390. data/lib/zena/use/node_query_finders.rb +491 -0
  391. data/lib/zena/use/refactor.rb +231 -0
  392. data/lib/zena/use/relations.rb +360 -0
  393. data/lib/zena/use/rendering.rb +248 -0
  394. data/lib/zena/use/test_helper.rb +151 -0
  395. data/lib/zena/use/urls.rb +180 -0
  396. data/lib/zena/use/zafu.rb +549 -0
  397. data/lib/zena/use/zazen.rb +230 -0
  398. data/lib/zena/view/test_case.rb +23 -0
  399. data/locale/en/LC_MESSAGES/zena.mo +0 -0
  400. data/locale/en/zena.po +2116 -0
  401. data/locale/fr/LC_MESSAGES/zena.mo +0 -0
  402. data/locale/fr/zena.po +2172 -0
  403. data/locale/zena.pot +1915 -0
  404. data/public/calendar/calendar-brown.css +225 -0
  405. data/public/calendar/calendar-setup.js +153 -0
  406. data/public/calendar/calendar.js +1817 -0
  407. data/public/calendar/iconCalendar.gif +0 -0
  408. data/public/calendar/lang/calendar-en-utf8.js +128 -0
  409. data/public/calendar/lang/calendar-fr-utf8.js +120 -0
  410. data/public/calendar/lang/lang.zip +0 -0
  411. data/public/dispatch.cgi +10 -0
  412. data/public/dispatch.fcgi +24 -0
  413. data/public/dispatch.rb +10 -0
  414. data/public/favicon.ico +0 -0
  415. data/public/images/accept.png +0 -0
  416. data/public/images/action.png +0 -0
  417. data/public/images/add.png +0 -0
  418. data/public/images/ajax-loader.gif +0 -0
  419. data/public/images/anchor.png +0 -0
  420. data/public/images/application.png +0 -0
  421. data/public/images/application_add.png +0 -0
  422. data/public/images/application_cascade.png +0 -0
  423. data/public/images/application_delete.png +0 -0
  424. data/public/images/application_double.png +0 -0
  425. data/public/images/application_edit.png +0 -0
  426. data/public/images/application_error.png +0 -0
  427. data/public/images/application_form.png +0 -0
  428. data/public/images/application_form_add.png +0 -0
  429. data/public/images/application_form_delete.png +0 -0
  430. data/public/images/application_form_edit.png +0 -0
  431. data/public/images/application_form_magnify.png +0 -0
  432. data/public/images/application_get.png +0 -0
  433. data/public/images/application_go.png +0 -0
  434. data/public/images/application_home.png +0 -0
  435. data/public/images/application_key.png +0 -0
  436. data/public/images/application_lightning.png +0 -0
  437. data/public/images/application_link.png +0 -0
  438. data/public/images/application_osx.png +0 -0
  439. data/public/images/application_osx_terminal.png +0 -0
  440. data/public/images/application_put.png +0 -0
  441. data/public/images/application_side_boxes.png +0 -0
  442. data/public/images/application_side_contract.png +0 -0
  443. data/public/images/application_side_expand.png +0 -0
  444. data/public/images/application_side_list.png +0 -0
  445. data/public/images/application_side_tree.png +0 -0
  446. data/public/images/application_split.png +0 -0
  447. data/public/images/application_tile_horizontal.png +0 -0
  448. data/public/images/application_tile_vertical.png +0 -0
  449. data/public/images/application_view_columns.png +0 -0
  450. data/public/images/application_view_detail.png +0 -0
  451. data/public/images/application_view_gallery.png +0 -0
  452. data/public/images/application_view_icons.png +0 -0
  453. data/public/images/application_view_list.png +0 -0
  454. data/public/images/application_view_tile.png +0 -0
  455. data/public/images/application_xp.png +0 -0
  456. data/public/images/application_xp_terminal.png +0 -0
  457. data/public/images/arrow_branch.png +0 -0
  458. data/public/images/arrow_divide.png +0 -0
  459. data/public/images/arrow_down.png +0 -0
  460. data/public/images/arrow_in.png +0 -0
  461. data/public/images/arrow_inout.png +0 -0
  462. data/public/images/arrow_join.png +0 -0
  463. data/public/images/arrow_left.png +0 -0
  464. data/public/images/arrow_merge.png +0 -0
  465. data/public/images/arrow_out.png +0 -0
  466. data/public/images/arrow_redo.png +0 -0
  467. data/public/images/arrow_refresh.png +0 -0
  468. data/public/images/arrow_refresh_small.png +0 -0
  469. data/public/images/arrow_right.png +0 -0
  470. data/public/images/arrow_rotate_anticlockwise.png +0 -0
  471. data/public/images/arrow_rotate_clockwise.png +0 -0
  472. data/public/images/arrow_switch.png +0 -0
  473. data/public/images/arrow_turn_left.png +0 -0
  474. data/public/images/arrow_turn_right.png +0 -0
  475. data/public/images/arrow_undo.png +0 -0
  476. data/public/images/arrow_up.png +0 -0
  477. data/public/images/asterisk_orange.png +0 -0
  478. data/public/images/asterisk_yellow.png +0 -0
  479. data/public/images/attach.png +0 -0
  480. data/public/images/award_star_add.png +0 -0
  481. data/public/images/award_star_bronze_1.png +0 -0
  482. data/public/images/award_star_bronze_2.png +0 -0
  483. data/public/images/award_star_bronze_3.png +0 -0
  484. data/public/images/award_star_delete.png +0 -0
  485. data/public/images/award_star_gold_1.png +0 -0
  486. data/public/images/award_star_gold_2.png +0 -0
  487. data/public/images/award_star_gold_3.png +0 -0
  488. data/public/images/award_star_silver_1.png +0 -0
  489. data/public/images/award_star_silver_2.png +0 -0
  490. data/public/images/award_star_silver_3.png +0 -0
  491. data/public/images/basket.png +0 -0
  492. data/public/images/basket_add.png +0 -0
  493. data/public/images/basket_delete.png +0 -0
  494. data/public/images/basket_edit.png +0 -0
  495. data/public/images/basket_error.png +0 -0
  496. data/public/images/basket_go.png +0 -0
  497. data/public/images/basket_put.png +0 -0
  498. data/public/images/basket_remove.png +0 -0
  499. data/public/images/bell.png +0 -0
  500. data/public/images/bell_add.png +0 -0
  501. data/public/images/bell_delete.png +0 -0
  502. data/public/images/bell_error.png +0 -0
  503. data/public/images/bell_go.png +0 -0
  504. data/public/images/bell_link.png +0 -0
  505. data/public/images/bin.png +0 -0
  506. data/public/images/bin_closed.png +0 -0
  507. data/public/images/bin_empty.gif +0 -0
  508. data/public/images/bin_empty.png +0 -0
  509. data/public/images/bin_full.gif +0 -0
  510. data/public/images/bomb.png +0 -0
  511. data/public/images/book.png +0 -0
  512. data/public/images/book_add.png +0 -0
  513. data/public/images/book_addresses.png +0 -0
  514. data/public/images/book_delete.png +0 -0
  515. data/public/images/book_edit.png +0 -0
  516. data/public/images/book_error.png +0 -0
  517. data/public/images/book_go.png +0 -0
  518. data/public/images/book_key.png +0 -0
  519. data/public/images/book_link.png +0 -0
  520. data/public/images/book_next.png +0 -0
  521. data/public/images/book_open.png +0 -0
  522. data/public/images/book_previous.png +0 -0
  523. data/public/images/box.png +0 -0
  524. data/public/images/brick.png +0 -0
  525. data/public/images/brick_add.png +0 -0
  526. data/public/images/brick_delete.png +0 -0
  527. data/public/images/brick_edit.png +0 -0
  528. data/public/images/brick_error.png +0 -0
  529. data/public/images/brick_go.png +0 -0
  530. data/public/images/brick_link.png +0 -0
  531. data/public/images/bricks.png +0 -0
  532. data/public/images/briefcase.png +0 -0
  533. data/public/images/bug.png +0 -0
  534. data/public/images/bug_add.png +0 -0
  535. data/public/images/bug_delete.png +0 -0
  536. data/public/images/bug_edit.png +0 -0
  537. data/public/images/bug_error.png +0 -0
  538. data/public/images/bug_go.png +0 -0
  539. data/public/images/bug_link.png +0 -0
  540. data/public/images/building.png +0 -0
  541. data/public/images/building_add.png +0 -0
  542. data/public/images/building_delete.png +0 -0
  543. data/public/images/building_edit.png +0 -0
  544. data/public/images/building_error.png +0 -0
  545. data/public/images/building_go.png +0 -0
  546. data/public/images/building_key.png +0 -0
  547. data/public/images/building_link.png +0 -0
  548. data/public/images/bullet_add.png +0 -0
  549. data/public/images/bullet_arrow_bottom.png +0 -0
  550. data/public/images/bullet_arrow_down.png +0 -0
  551. data/public/images/bullet_arrow_top.png +0 -0
  552. data/public/images/bullet_arrow_up.png +0 -0
  553. data/public/images/bullet_black.png +0 -0
  554. data/public/images/bullet_blue.png +0 -0
  555. data/public/images/bullet_delete.png +0 -0
  556. data/public/images/bullet_disk.png +0 -0
  557. data/public/images/bullet_error.png +0 -0
  558. data/public/images/bullet_feed.png +0 -0
  559. data/public/images/bullet_go.png +0 -0
  560. data/public/images/bullet_green.png +0 -0
  561. data/public/images/bullet_key.png +0 -0
  562. data/public/images/bullet_orange.png +0 -0
  563. data/public/images/bullet_picture.png +0 -0
  564. data/public/images/bullet_pink.png +0 -0
  565. data/public/images/bullet_purple.png +0 -0
  566. data/public/images/bullet_red.png +0 -0
  567. data/public/images/bullet_star.png +0 -0
  568. data/public/images/bullet_toggle_minus.png +0 -0
  569. data/public/images/bullet_toggle_plus.png +0 -0
  570. data/public/images/bullet_white.png +0 -0
  571. data/public/images/bullet_wrench.png +0 -0
  572. data/public/images/bullet_yellow.png +0 -0
  573. data/public/images/cake.png +0 -0
  574. data/public/images/calculator.png +0 -0
  575. data/public/images/calculator_add.png +0 -0
  576. data/public/images/calculator_delete.png +0 -0
  577. data/public/images/calculator_edit.png +0 -0
  578. data/public/images/calculator_error.png +0 -0
  579. data/public/images/calculator_link.png +0 -0
  580. data/public/images/calendar.png +0 -0
  581. data/public/images/calendar_add.png +0 -0
  582. data/public/images/calendar_delete.png +0 -0
  583. data/public/images/calendar_edit.png +0 -0
  584. data/public/images/calendar_link.png +0 -0
  585. data/public/images/calendar_view_day.png +0 -0
  586. data/public/images/calendar_view_month.png +0 -0
  587. data/public/images/calendar_view_week.png +0 -0
  588. data/public/images/camera.png +0 -0
  589. data/public/images/camera_add.png +0 -0
  590. data/public/images/camera_delete.png +0 -0
  591. data/public/images/camera_edit.png +0 -0
  592. data/public/images/camera_error.png +0 -0
  593. data/public/images/camera_go.png +0 -0
  594. data/public/images/camera_link.png +0 -0
  595. data/public/images/camera_small.png +0 -0
  596. data/public/images/cancel.png +0 -0
  597. data/public/images/car.png +0 -0
  598. data/public/images/car_add.png +0 -0
  599. data/public/images/car_delete.png +0 -0
  600. data/public/images/cart.png +0 -0
  601. data/public/images/cart_add.png +0 -0
  602. data/public/images/cart_delete.png +0 -0
  603. data/public/images/cart_edit.png +0 -0
  604. data/public/images/cart_error.png +0 -0
  605. data/public/images/cart_go.png +0 -0
  606. data/public/images/cart_put.png +0 -0
  607. data/public/images/cart_remove.png +0 -0
  608. data/public/images/cd.png +0 -0
  609. data/public/images/cd_add.png +0 -0
  610. data/public/images/cd_burn.png +0 -0
  611. data/public/images/cd_delete.png +0 -0
  612. data/public/images/cd_edit.png +0 -0
  613. data/public/images/cd_eject.png +0 -0
  614. data/public/images/cd_go.png +0 -0
  615. data/public/images/chart_bar.png +0 -0
  616. data/public/images/chart_bar_add.png +0 -0
  617. data/public/images/chart_bar_delete.png +0 -0
  618. data/public/images/chart_bar_edit.png +0 -0
  619. data/public/images/chart_bar_error.png +0 -0
  620. data/public/images/chart_bar_link.png +0 -0
  621. data/public/images/chart_curve.png +0 -0
  622. data/public/images/chart_curve_add.png +0 -0
  623. data/public/images/chart_curve_delete.png +0 -0
  624. data/public/images/chart_curve_edit.png +0 -0
  625. data/public/images/chart_curve_error.png +0 -0
  626. data/public/images/chart_curve_go.png +0 -0
  627. data/public/images/chart_curve_link.png +0 -0
  628. data/public/images/chart_line.png +0 -0
  629. data/public/images/chart_line_add.png +0 -0
  630. data/public/images/chart_line_delete.png +0 -0
  631. data/public/images/chart_line_edit.png +0 -0
  632. data/public/images/chart_line_error.png +0 -0
  633. data/public/images/chart_line_link.png +0 -0
  634. data/public/images/chart_organisation.png +0 -0
  635. data/public/images/chart_organisation_add.png +0 -0
  636. data/public/images/chart_organisation_delete.png +0 -0
  637. data/public/images/chart_pie.png +0 -0
  638. data/public/images/chart_pie_add.png +0 -0
  639. data/public/images/chart_pie_delete.png +0 -0
  640. data/public/images/chart_pie_edit.png +0 -0
  641. data/public/images/chart_pie_error.png +0 -0
  642. data/public/images/chart_pie_link.png +0 -0
  643. data/public/images/clock.png +0 -0
  644. data/public/images/clock_add.png +0 -0
  645. data/public/images/clock_delete.png +0 -0
  646. data/public/images/clock_edit.png +0 -0
  647. data/public/images/clock_error.png +0 -0
  648. data/public/images/clock_go.png +0 -0
  649. data/public/images/clock_link.png +0 -0
  650. data/public/images/clock_pause.png +0 -0
  651. data/public/images/clock_play.png +0 -0
  652. data/public/images/clock_red.png +0 -0
  653. data/public/images/clock_stop.png +0 -0
  654. data/public/images/cog.png +0 -0
  655. data/public/images/cog_add.png +0 -0
  656. data/public/images/cog_delete.png +0 -0
  657. data/public/images/cog_edit.png +0 -0
  658. data/public/images/cog_error.png +0 -0
  659. data/public/images/cog_go.png +0 -0
  660. data/public/images/coins.png +0 -0
  661. data/public/images/coins_add.png +0 -0
  662. data/public/images/coins_delete.png +0 -0
  663. data/public/images/collection.png +0 -0
  664. data/public/images/color_swatch.png +0 -0
  665. data/public/images/color_wheel.png +0 -0
  666. data/public/images/column_add.png +0 -0
  667. data/public/images/column_delete.png +0 -0
  668. data/public/images/comment.png +0 -0
  669. data/public/images/comment_add.png +0 -0
  670. data/public/images/comment_delete.png +0 -0
  671. data/public/images/comment_edit.png +0 -0
  672. data/public/images/comments.png +0 -0
  673. data/public/images/comments_add.png +0 -0
  674. data/public/images/comments_delete.png +0 -0
  675. data/public/images/comments_red.png +0 -0
  676. data/public/images/compress.png +0 -0
  677. data/public/images/computer.png +0 -0
  678. data/public/images/computer_add.png +0 -0
  679. data/public/images/computer_delete.png +0 -0
  680. data/public/images/computer_edit.png +0 -0
  681. data/public/images/computer_error.png +0 -0
  682. data/public/images/computer_go.png +0 -0
  683. data/public/images/computer_key.png +0 -0
  684. data/public/images/computer_link.png +0 -0
  685. data/public/images/connect.png +0 -0
  686. data/public/images/contrast.png +0 -0
  687. data/public/images/contrast_decrease.png +0 -0
  688. data/public/images/contrast_high.png +0 -0
  689. data/public/images/contrast_increase.png +0 -0
  690. data/public/images/contrast_low.png +0 -0
  691. data/public/images/control_eject.png +0 -0
  692. data/public/images/control_eject_blue.png +0 -0
  693. data/public/images/control_end.png +0 -0
  694. data/public/images/control_end_blue.png +0 -0
  695. data/public/images/control_equalizer.png +0 -0
  696. data/public/images/control_equalizer_blue.png +0 -0
  697. data/public/images/control_fastforward.png +0 -0
  698. data/public/images/control_fastforward_blue.png +0 -0
  699. data/public/images/control_pause.png +0 -0
  700. data/public/images/control_pause_blue.png +0 -0
  701. data/public/images/control_play.png +0 -0
  702. data/public/images/control_play_blue.png +0 -0
  703. data/public/images/control_repeat.png +0 -0
  704. data/public/images/control_repeat_blue.png +0 -0
  705. data/public/images/control_rewind.png +0 -0
  706. data/public/images/control_rewind_blue.png +0 -0
  707. data/public/images/control_start.png +0 -0
  708. data/public/images/control_start_blue.png +0 -0
  709. data/public/images/control_stop.png +0 -0
  710. data/public/images/control_stop_blue.png +0 -0
  711. data/public/images/controller.png +0 -0
  712. data/public/images/controller_add.png +0 -0
  713. data/public/images/controller_delete.png +0 -0
  714. data/public/images/controller_error.png +0 -0
  715. data/public/images/creditcards.png +0 -0
  716. data/public/images/cross.png +0 -0
  717. data/public/images/css.png +0 -0
  718. data/public/images/css_add.png +0 -0
  719. data/public/images/css_delete.png +0 -0
  720. data/public/images/css_go.png +0 -0
  721. data/public/images/css_valid.png +0 -0
  722. data/public/images/cup.png +0 -0
  723. data/public/images/cup_add.png +0 -0
  724. data/public/images/cup_delete.png +0 -0
  725. data/public/images/cup_edit.png +0 -0
  726. data/public/images/cup_error.png +0 -0
  727. data/public/images/cup_go.png +0 -0
  728. data/public/images/cup_key.png +0 -0
  729. data/public/images/cup_link.png +0 -0
  730. data/public/images/cursor.png +0 -0
  731. data/public/images/cut.png +0 -0
  732. data/public/images/cut_red.png +0 -0
  733. data/public/images/database.png +0 -0
  734. data/public/images/database_add.png +0 -0
  735. data/public/images/database_connect.png +0 -0
  736. data/public/images/database_delete.png +0 -0
  737. data/public/images/database_edit.png +0 -0
  738. data/public/images/database_error.png +0 -0
  739. data/public/images/database_gear.png +0 -0
  740. data/public/images/database_go.png +0 -0
  741. data/public/images/database_key.png +0 -0
  742. data/public/images/database_lightning.png +0 -0
  743. data/public/images/database_link.png +0 -0
  744. data/public/images/database_refresh.png +0 -0
  745. data/public/images/database_save.png +0 -0
  746. data/public/images/database_table.png +0 -0
  747. data/public/images/date.png +0 -0
  748. data/public/images/date_add.png +0 -0
  749. data/public/images/date_delete.png +0 -0
  750. data/public/images/date_edit.png +0 -0
  751. data/public/images/date_error.png +0 -0
  752. data/public/images/date_go.png +0 -0
  753. data/public/images/date_link.png +0 -0
  754. data/public/images/date_magnify.png +0 -0
  755. data/public/images/date_next.png +0 -0
  756. data/public/images/date_previous.png +0 -0
  757. data/public/images/delete.png +0 -0
  758. data/public/images/disconnect.png +0 -0
  759. data/public/images/disk.png +0 -0
  760. data/public/images/disk_multiple.png +0 -0
  761. data/public/images/door.png +0 -0
  762. data/public/images/door_in.png +0 -0
  763. data/public/images/door_open.png +0 -0
  764. data/public/images/door_out.png +0 -0
  765. data/public/images/drink.png +0 -0
  766. data/public/images/drink_empty.png +0 -0
  767. data/public/images/drive.png +0 -0
  768. data/public/images/drive_add.png +0 -0
  769. data/public/images/drive_burn.png +0 -0
  770. data/public/images/drive_cd.png +0 -0
  771. data/public/images/drive_cd_empty.png +0 -0
  772. data/public/images/drive_delete.png +0 -0
  773. data/public/images/drive_disk.png +0 -0
  774. data/public/images/drive_edit.png +0 -0
  775. data/public/images/drive_error.png +0 -0
  776. data/public/images/drive_go.png +0 -0
  777. data/public/images/drive_key.png +0 -0
  778. data/public/images/drive_link.png +0 -0
  779. data/public/images/drive_magnify.png +0 -0
  780. data/public/images/drive_network.png +0 -0
  781. data/public/images/drive_rename.png +0 -0
  782. data/public/images/drive_user.png +0 -0
  783. data/public/images/drive_web.png +0 -0
  784. data/public/images/dvd.png +0 -0
  785. data/public/images/dvd_add.png +0 -0
  786. data/public/images/dvd_delete.png +0 -0
  787. data/public/images/dvd_edit.png +0 -0
  788. data/public/images/dvd_error.png +0 -0
  789. data/public/images/dvd_go.png +0 -0
  790. data/public/images/dvd_key.png +0 -0
  791. data/public/images/dvd_link.png +0 -0
  792. data/public/images/email.png +0 -0
  793. data/public/images/email_add.png +0 -0
  794. data/public/images/email_attach.png +0 -0
  795. data/public/images/email_delete.png +0 -0
  796. data/public/images/email_edit.png +0 -0
  797. data/public/images/email_error.png +0 -0
  798. data/public/images/email_go.png +0 -0
  799. data/public/images/email_link.png +0 -0
  800. data/public/images/email_open.png +0 -0
  801. data/public/images/email_open_image.png +0 -0
  802. data/public/images/emoticon_evilgrin.png +0 -0
  803. data/public/images/emoticon_grin.png +0 -0
  804. data/public/images/emoticon_happy.png +0 -0
  805. data/public/images/emoticon_smile.png +0 -0
  806. data/public/images/emoticon_surprised.png +0 -0
  807. data/public/images/emoticon_tongue.png +0 -0
  808. data/public/images/emoticon_unhappy.png +0 -0
  809. data/public/images/emoticon_waii.png +0 -0
  810. data/public/images/emoticon_wink.png +0 -0
  811. data/public/images/error.png +0 -0
  812. data/public/images/error_add.png +0 -0
  813. data/public/images/error_delete.png +0 -0
  814. data/public/images/error_go.png +0 -0
  815. data/public/images/exclamation.png +0 -0
  816. data/public/images/ext/contact.png +0 -0
  817. data/public/images/ext/contact_pv.png +0 -0
  818. data/public/images/ext/doc.png +0 -0
  819. data/public/images/ext/doc_tiny.png +0 -0
  820. data/public/images/ext/jpg.png +0 -0
  821. data/public/images/ext/jpg_tiny.png +0 -0
  822. data/public/images/ext/other.png +0 -0
  823. data/public/images/ext/other_pv.png +0 -0
  824. data/public/images/ext/other_tiny.png +0 -0
  825. data/public/images/ext/page.png +0 -0
  826. data/public/images/ext/page_pv.png +0 -0
  827. data/public/images/ext/page_tiny.png +0 -0
  828. data/public/images/ext/pdf.png +0 -0
  829. data/public/images/ext/pdf_pv.png +0 -0
  830. data/public/images/ext/pdf_tiny.png +0 -0
  831. data/public/images/ext/png.png +0 -0
  832. data/public/images/ext/png_tiny.png +0 -0
  833. data/public/images/ext/post.png +0 -0
  834. data/public/images/ext/post_pv.png +0 -0
  835. data/public/images/ext/post_tiny.png +0 -0
  836. data/public/images/ext/project.png +0 -0
  837. data/public/images/ext/project_pv.png +0 -0
  838. data/public/images/ext/project_tiny.png +0 -0
  839. data/public/images/ext/rtf.png +0 -0
  840. data/public/images/ext/rtf_tiny.png +0 -0
  841. data/public/images/ext/tag.png +0 -0
  842. data/public/images/ext/tag_pv.png +0 -0
  843. data/public/images/ext/xls.png +0 -0
  844. data/public/images/ext/xls_tiny.png +0 -0
  845. data/public/images/ext/zip.png +0 -0
  846. data/public/images/ext/zip_pv.png +0 -0
  847. data/public/images/ext/zip_tiny.png +0 -0
  848. data/public/images/eye.png +0 -0
  849. data/public/images/feed.png +0 -0
  850. data/public/images/feed_add.png +0 -0
  851. data/public/images/feed_delete.png +0 -0
  852. data/public/images/feed_disk.png +0 -0
  853. data/public/images/feed_edit.png +0 -0
  854. data/public/images/feed_error.png +0 -0
  855. data/public/images/feed_go.png +0 -0
  856. data/public/images/feed_key.png +0 -0
  857. data/public/images/feed_link.png +0 -0
  858. data/public/images/feed_magnify.png +0 -0
  859. data/public/images/female.png +0 -0
  860. data/public/images/film.png +0 -0
  861. data/public/images/film_add.png +0 -0
  862. data/public/images/film_delete.png +0 -0
  863. data/public/images/film_edit.png +0 -0
  864. data/public/images/film_error.png +0 -0
  865. data/public/images/film_go.png +0 -0
  866. data/public/images/film_key.png +0 -0
  867. data/public/images/film_link.png +0 -0
  868. data/public/images/film_save.png +0 -0
  869. data/public/images/find.png +0 -0
  870. data/public/images/flag_blue.png +0 -0
  871. data/public/images/flag_green.png +0 -0
  872. data/public/images/flag_orange.png +0 -0
  873. data/public/images/flag_pink.png +0 -0
  874. data/public/images/flag_purple.png +0 -0
  875. data/public/images/flag_red.png +0 -0
  876. data/public/images/flag_yellow.png +0 -0
  877. data/public/images/folder.png +0 -0
  878. data/public/images/folder_add.png +0 -0
  879. data/public/images/folder_bell.png +0 -0
  880. data/public/images/folder_brick.png +0 -0
  881. data/public/images/folder_bug.png +0 -0
  882. data/public/images/folder_camera.png +0 -0
  883. data/public/images/folder_database.png +0 -0
  884. data/public/images/folder_delete.png +0 -0
  885. data/public/images/folder_edit.png +0 -0
  886. data/public/images/folder_error.png +0 -0
  887. data/public/images/folder_explore.png +0 -0
  888. data/public/images/folder_feed.png +0 -0
  889. data/public/images/folder_find.png +0 -0
  890. data/public/images/folder_go.png +0 -0
  891. data/public/images/folder_heart.png +0 -0
  892. data/public/images/folder_image.png +0 -0
  893. data/public/images/folder_key.png +0 -0
  894. data/public/images/folder_lightbulb.png +0 -0
  895. data/public/images/folder_link.png +0 -0
  896. data/public/images/folder_magnify.png +0 -0
  897. data/public/images/folder_page.png +0 -0
  898. data/public/images/folder_page_white.png +0 -0
  899. data/public/images/folder_palette.png +0 -0
  900. data/public/images/folder_picture.png +0 -0
  901. data/public/images/folder_star.png +0 -0
  902. data/public/images/folder_table.png +0 -0
  903. data/public/images/folder_user.png +0 -0
  904. data/public/images/folder_wrench.png +0 -0
  905. data/public/images/font.png +0 -0
  906. data/public/images/font_add.png +0 -0
  907. data/public/images/font_delete.png +0 -0
  908. data/public/images/font_go.png +0 -0
  909. data/public/images/group.png +0 -0
  910. data/public/images/group_add.png +0 -0
  911. data/public/images/group_admin.png +0 -0
  912. data/public/images/group_delete.png +0 -0
  913. data/public/images/group_edit.png +0 -0
  914. data/public/images/group_error.png +0 -0
  915. data/public/images/group_gear.png +0 -0
  916. data/public/images/group_go.png +0 -0
  917. data/public/images/group_key.png +0 -0
  918. data/public/images/group_link.png +0 -0
  919. data/public/images/group_pub.png +0 -0
  920. data/public/images/group_site.png +0 -0
  921. data/public/images/heart.png +0 -0
  922. data/public/images/heart_add.png +0 -0
  923. data/public/images/heart_delete.png +0 -0
  924. data/public/images/help.png +0 -0
  925. data/public/images/home.png +0 -0
  926. data/public/images/hourglass.png +0 -0
  927. data/public/images/hourglass_add.png +0 -0
  928. data/public/images/hourglass_delete.png +0 -0
  929. data/public/images/hourglass_go.png +0 -0
  930. data/public/images/hourglass_link.png +0 -0
  931. data/public/images/house.png +0 -0
  932. data/public/images/house_go.png +0 -0
  933. data/public/images/house_link.png +0 -0
  934. data/public/images/html.png +0 -0
  935. data/public/images/html_add.png +0 -0
  936. data/public/images/html_delete.png +0 -0
  937. data/public/images/html_go.png +0 -0
  938. data/public/images/html_valid.png +0 -0
  939. data/public/images/image.png +0 -0
  940. data/public/images/image_add.png +0 -0
  941. data/public/images/image_delete.png +0 -0
  942. data/public/images/image_edit.png +0 -0
  943. data/public/images/image_link.png +0 -0
  944. data/public/images/images.png +0 -0
  945. data/public/images/img_not_found.png +0 -0
  946. data/public/images/information.png +0 -0
  947. data/public/images/ipod.png +0 -0
  948. data/public/images/ipod_cast.png +0 -0
  949. data/public/images/ipod_cast_add.png +0 -0
  950. data/public/images/ipod_cast_delete.png +0 -0
  951. data/public/images/ipod_sound.png +0 -0
  952. data/public/images/joystick.png +0 -0
  953. data/public/images/joystick_add.png +0 -0
  954. data/public/images/joystick_delete.png +0 -0
  955. data/public/images/joystick_error.png +0 -0
  956. data/public/images/key.png +0 -0
  957. data/public/images/key_add.png +0 -0
  958. data/public/images/key_delete.png +0 -0
  959. data/public/images/key_go.png +0 -0
  960. data/public/images/keyboard.png +0 -0
  961. data/public/images/keyboard_add.png +0 -0
  962. data/public/images/keyboard_delete.png +0 -0
  963. data/public/images/keyboard_magnify.png +0 -0
  964. data/public/images/latex_error.png +0 -0
  965. data/public/images/layers.png +0 -0
  966. data/public/images/layout.png +0 -0
  967. data/public/images/layout_add.png +0 -0
  968. data/public/images/layout_content.png +0 -0
  969. data/public/images/layout_delete.png +0 -0
  970. data/public/images/layout_edit.png +0 -0
  971. data/public/images/layout_error.png +0 -0
  972. data/public/images/layout_header.png +0 -0
  973. data/public/images/layout_link.png +0 -0
  974. data/public/images/layout_sidebar.png +0 -0
  975. data/public/images/lightbulb.png +0 -0
  976. data/public/images/lightbulb_add.png +0 -0
  977. data/public/images/lightbulb_delete.png +0 -0
  978. data/public/images/lightbulb_off.png +0 -0
  979. data/public/images/lightning.png +0 -0
  980. data/public/images/lightning_add.png +0 -0
  981. data/public/images/lightning_delete.png +0 -0
  982. data/public/images/lightning_go.png +0 -0
  983. data/public/images/link.png +0 -0
  984. data/public/images/link_add.png +0 -0
  985. data/public/images/link_break.png +0 -0
  986. data/public/images/link_delete.png +0 -0
  987. data/public/images/link_edit.png +0 -0
  988. data/public/images/link_error.png +0 -0
  989. data/public/images/link_go.png +0 -0
  990. data/public/images/lock.png +0 -0
  991. data/public/images/lock_add.png +0 -0
  992. data/public/images/lock_break.png +0 -0
  993. data/public/images/lock_delete.png +0 -0
  994. data/public/images/lock_edit.png +0 -0
  995. data/public/images/lock_go.png +0 -0
  996. data/public/images/lock_open.png +0 -0
  997. data/public/images/lorry.png +0 -0
  998. data/public/images/lorry_add.png +0 -0
  999. data/public/images/lorry_delete.png +0 -0
  1000. data/public/images/lorry_error.png +0 -0
  1001. data/public/images/lorry_flatbed.png +0 -0
  1002. data/public/images/lorry_go.png +0 -0
  1003. data/public/images/lorry_link.png +0 -0
  1004. data/public/images/magifier_zoom_out.png +0 -0
  1005. data/public/images/magnifier.png +0 -0
  1006. data/public/images/magnifier_zoom_in.png +0 -0
  1007. data/public/images/male.png +0 -0
  1008. data/public/images/map.png +0 -0
  1009. data/public/images/map_add.png +0 -0
  1010. data/public/images/map_delete.png +0 -0
  1011. data/public/images/map_edit.png +0 -0
  1012. data/public/images/map_go.png +0 -0
  1013. data/public/images/map_magnify.png +0 -0
  1014. data/public/images/medal_bronze_1.png +0 -0
  1015. data/public/images/medal_bronze_2.png +0 -0
  1016. data/public/images/medal_bronze_3.png +0 -0
  1017. data/public/images/medal_bronze_add.png +0 -0
  1018. data/public/images/medal_bronze_delete.png +0 -0
  1019. data/public/images/medal_gold_1.png +0 -0
  1020. data/public/images/medal_gold_2.png +0 -0
  1021. data/public/images/medal_gold_3.png +0 -0
  1022. data/public/images/medal_gold_add.png +0 -0
  1023. data/public/images/medal_gold_delete.png +0 -0
  1024. data/public/images/medal_silver_1.png +0 -0
  1025. data/public/images/medal_silver_2.png +0 -0
  1026. data/public/images/medal_silver_3.png +0 -0
  1027. data/public/images/medal_silver_add.png +0 -0
  1028. data/public/images/medal_silver_delete.png +0 -0
  1029. data/public/images/money.png +0 -0
  1030. data/public/images/money_add.png +0 -0
  1031. data/public/images/money_delete.png +0 -0
  1032. data/public/images/money_dollar.png +0 -0
  1033. data/public/images/money_euro.png +0 -0
  1034. data/public/images/money_pound.png +0 -0
  1035. data/public/images/money_yen.png +0 -0
  1036. data/public/images/monitor.png +0 -0
  1037. data/public/images/monitor_add.png +0 -0
  1038. data/public/images/monitor_delete.png +0 -0
  1039. data/public/images/monitor_edit.png +0 -0
  1040. data/public/images/monitor_error.png +0 -0
  1041. data/public/images/monitor_go.png +0 -0
  1042. data/public/images/monitor_lightning.png +0 -0
  1043. data/public/images/monitor_link.png +0 -0
  1044. data/public/images/mouse.png +0 -0
  1045. data/public/images/mouse_add.png +0 -0
  1046. data/public/images/mouse_delete.png +0 -0
  1047. data/public/images/mouse_error.png +0 -0
  1048. data/public/images/music.png +0 -0
  1049. data/public/images/new.png +0 -0
  1050. data/public/images/newspaper.png +0 -0
  1051. data/public/images/newspaper_add.png +0 -0
  1052. data/public/images/newspaper_delete.png +0 -0
  1053. data/public/images/newspaper_go.png +0 -0
  1054. data/public/images/newspaper_link.png +0 -0
  1055. data/public/images/note.png +0 -0
  1056. data/public/images/note_add.png +0 -0
  1057. data/public/images/note_delete.png +0 -0
  1058. data/public/images/note_edit.png +0 -0
  1059. data/public/images/note_error.png +0 -0
  1060. data/public/images/note_go.png +0 -0
  1061. data/public/images/overlays.png +0 -0
  1062. data/public/images/package.png +0 -0
  1063. data/public/images/package_add.png +0 -0
  1064. data/public/images/package_delete.png +0 -0
  1065. data/public/images/package_go.png +0 -0
  1066. data/public/images/package_green.png +0 -0
  1067. data/public/images/package_link.png +0 -0
  1068. data/public/images/page.png +0 -0
  1069. data/public/images/page_add.png +0 -0
  1070. data/public/images/page_attach.png +0 -0
  1071. data/public/images/page_code.png +0 -0
  1072. data/public/images/page_copy.png +0 -0
  1073. data/public/images/page_delete.png +0 -0
  1074. data/public/images/page_edit.png +0 -0
  1075. data/public/images/page_error.png +0 -0
  1076. data/public/images/page_excel.png +0 -0
  1077. data/public/images/page_find.png +0 -0
  1078. data/public/images/page_gear.png +0 -0
  1079. data/public/images/page_go.png +0 -0
  1080. data/public/images/page_green.png +0 -0
  1081. data/public/images/page_key.png +0 -0
  1082. data/public/images/page_lightning.png +0 -0
  1083. data/public/images/page_link.png +0 -0
  1084. data/public/images/page_paintbrush.png +0 -0
  1085. data/public/images/page_paste.png +0 -0
  1086. data/public/images/page_red.png +0 -0
  1087. data/public/images/page_refresh.png +0 -0
  1088. data/public/images/page_save.png +0 -0
  1089. data/public/images/page_white.png +0 -0
  1090. data/public/images/page_white_acrobat.png +0 -0
  1091. data/public/images/page_white_actionscript.png +0 -0
  1092. data/public/images/page_white_add.png +0 -0
  1093. data/public/images/page_white_c.png +0 -0
  1094. data/public/images/page_white_camera.png +0 -0
  1095. data/public/images/page_white_cd.png +0 -0
  1096. data/public/images/page_white_code.png +0 -0
  1097. data/public/images/page_white_code_red.png +0 -0
  1098. data/public/images/page_white_coldfusion.png +0 -0
  1099. data/public/images/page_white_compressed.png +0 -0
  1100. data/public/images/page_white_copy.png +0 -0
  1101. data/public/images/page_white_cplusplus.png +0 -0
  1102. data/public/images/page_white_csharp.png +0 -0
  1103. data/public/images/page_white_cup.png +0 -0
  1104. data/public/images/page_white_database.png +0 -0
  1105. data/public/images/page_white_delete.png +0 -0
  1106. data/public/images/page_white_dvd.png +0 -0
  1107. data/public/images/page_white_edit.png +0 -0
  1108. data/public/images/page_white_error.png +0 -0
  1109. data/public/images/page_white_excel.png +0 -0
  1110. data/public/images/page_white_find.png +0 -0
  1111. data/public/images/page_white_flash.png +0 -0
  1112. data/public/images/page_white_freehand.png +0 -0
  1113. data/public/images/page_white_gear.png +0 -0
  1114. data/public/images/page_white_get.png +0 -0
  1115. data/public/images/page_white_go.png +0 -0
  1116. data/public/images/page_white_h.png +0 -0
  1117. data/public/images/page_white_horizontal.png +0 -0
  1118. data/public/images/page_white_key.png +0 -0
  1119. data/public/images/page_white_lightning.png +0 -0
  1120. data/public/images/page_white_link.png +0 -0
  1121. data/public/images/page_white_magnify.png +0 -0
  1122. data/public/images/page_white_medal.png +0 -0
  1123. data/public/images/page_white_office.png +0 -0
  1124. data/public/images/page_white_paint.png +0 -0
  1125. data/public/images/page_white_paintbrush.png +0 -0
  1126. data/public/images/page_white_paste.png +0 -0
  1127. data/public/images/page_white_php.png +0 -0
  1128. data/public/images/page_white_picture.png +0 -0
  1129. data/public/images/page_white_powerpoint.png +0 -0
  1130. data/public/images/page_white_put.png +0 -0
  1131. data/public/images/page_white_ruby.png +0 -0
  1132. data/public/images/page_white_stack.png +0 -0
  1133. data/public/images/page_white_star.png +0 -0
  1134. data/public/images/page_white_swoosh.png +0 -0
  1135. data/public/images/page_white_text.png +0 -0
  1136. data/public/images/page_white_text_width.png +0 -0
  1137. data/public/images/page_white_tux.png +0 -0
  1138. data/public/images/page_white_vector.png +0 -0
  1139. data/public/images/page_white_visualstudio.png +0 -0
  1140. data/public/images/page_white_width.png +0 -0
  1141. data/public/images/page_white_word.png +0 -0
  1142. data/public/images/page_white_world.png +0 -0
  1143. data/public/images/page_white_wrench.png +0 -0
  1144. data/public/images/page_white_zip.png +0 -0
  1145. data/public/images/page_word.png +0 -0
  1146. data/public/images/page_world.png +0 -0
  1147. data/public/images/paintbrush.png +0 -0
  1148. data/public/images/paintcan.png +0 -0
  1149. data/public/images/palette.png +0 -0
  1150. data/public/images/paste_plain.png +0 -0
  1151. data/public/images/paste_word.png +0 -0
  1152. data/public/images/pencil.png +0 -0
  1153. data/public/images/pencil_add.png +0 -0
  1154. data/public/images/pencil_delete.png +0 -0
  1155. data/public/images/pencil_go.png +0 -0
  1156. data/public/images/phone.png +0 -0
  1157. data/public/images/phone_add.png +0 -0
  1158. data/public/images/phone_delete.png +0 -0
  1159. data/public/images/phone_sound.png +0 -0
  1160. data/public/images/photo.png +0 -0
  1161. data/public/images/photo_add.png +0 -0
  1162. data/public/images/photo_blue.png +0 -0
  1163. data/public/images/photo_delete.png +0 -0
  1164. data/public/images/photo_grey.png +0 -0
  1165. data/public/images/photo_link.png +0 -0
  1166. data/public/images/photos.png +0 -0
  1167. data/public/images/picture.png +0 -0
  1168. data/public/images/picture_add.png +0 -0
  1169. data/public/images/picture_delete.png +0 -0
  1170. data/public/images/picture_edit.png +0 -0
  1171. data/public/images/picture_empty.png +0 -0
  1172. data/public/images/picture_error.png +0 -0
  1173. data/public/images/picture_go.png +0 -0
  1174. data/public/images/picture_key.png +0 -0
  1175. data/public/images/picture_link.png +0 -0
  1176. data/public/images/picture_save.png +0 -0
  1177. data/public/images/pictures.png +0 -0
  1178. data/public/images/pilcrow.png +0 -0
  1179. data/public/images/pill.png +0 -0
  1180. data/public/images/pill_add.png +0 -0
  1181. data/public/images/pill_delete.png +0 -0
  1182. data/public/images/pill_go.png +0 -0
  1183. data/public/images/plugin.png +0 -0
  1184. data/public/images/plugin_add.png +0 -0
  1185. data/public/images/plugin_delete.png +0 -0
  1186. data/public/images/plugin_disabled.png +0 -0
  1187. data/public/images/plugin_edit.png +0 -0
  1188. data/public/images/plugin_error.png +0 -0
  1189. data/public/images/plugin_go.png +0 -0
  1190. data/public/images/plugin_link.png +0 -0
  1191. data/public/images/printer.png +0 -0
  1192. data/public/images/printer_add.png +0 -0
  1193. data/public/images/printer_delete.png +0 -0
  1194. data/public/images/printer_empty.png +0 -0
  1195. data/public/images/printer_error.png +0 -0
  1196. data/public/images/project.png +0 -0
  1197. data/public/images/rails.png +0 -0
  1198. data/public/images/rainbow.png +0 -0
  1199. data/public/images/report.png +0 -0
  1200. data/public/images/report_add.png +0 -0
  1201. data/public/images/report_delete.png +0 -0
  1202. data/public/images/report_disk.png +0 -0
  1203. data/public/images/report_edit.png +0 -0
  1204. data/public/images/report_go.png +0 -0
  1205. data/public/images/report_key.png +0 -0
  1206. data/public/images/report_link.png +0 -0
  1207. data/public/images/report_magnify.png +0 -0
  1208. data/public/images/report_picture.png +0 -0
  1209. data/public/images/report_user.png +0 -0
  1210. data/public/images/report_word.png +0 -0
  1211. data/public/images/resultset_first.png +0 -0
  1212. data/public/images/resultset_last.png +0 -0
  1213. data/public/images/resultset_next.png +0 -0
  1214. data/public/images/resultset_previous.png +0 -0
  1215. data/public/images/rosette.png +0 -0
  1216. data/public/images/row_add.png +0 -0
  1217. data/public/images/row_delete.png +0 -0
  1218. data/public/images/rss.png +0 -0
  1219. data/public/images/rss_add.png +0 -0
  1220. data/public/images/rss_delete.png +0 -0
  1221. data/public/images/rss_go.png +0 -0
  1222. data/public/images/rss_valid.png +0 -0
  1223. data/public/images/ruby.png +0 -0
  1224. data/public/images/ruby_add.png +0 -0
  1225. data/public/images/ruby_delete.png +0 -0
  1226. data/public/images/ruby_gear.png +0 -0
  1227. data/public/images/ruby_get.png +0 -0
  1228. data/public/images/ruby_go.png +0 -0
  1229. data/public/images/ruby_key.png +0 -0
  1230. data/public/images/ruby_link.png +0 -0
  1231. data/public/images/ruby_put.png +0 -0
  1232. data/public/images/script.png +0 -0
  1233. data/public/images/script_add.png +0 -0
  1234. data/public/images/script_code.png +0 -0
  1235. data/public/images/script_code_red.png +0 -0
  1236. data/public/images/script_delete.png +0 -0
  1237. data/public/images/script_edit.png +0 -0
  1238. data/public/images/script_error.png +0 -0
  1239. data/public/images/script_gear.png +0 -0
  1240. data/public/images/script_go.png +0 -0
  1241. data/public/images/script_key.png +0 -0
  1242. data/public/images/script_lightning.png +0 -0
  1243. data/public/images/script_link.png +0 -0
  1244. data/public/images/script_palette.png +0 -0
  1245. data/public/images/script_save.png +0 -0
  1246. data/public/images/server.png +0 -0
  1247. data/public/images/server_add.png +0 -0
  1248. data/public/images/server_chart.png +0 -0
  1249. data/public/images/server_compressed.png +0 -0
  1250. data/public/images/server_connect.png +0 -0
  1251. data/public/images/server_database.png +0 -0
  1252. data/public/images/server_delete.png +0 -0
  1253. data/public/images/server_edit.png +0 -0
  1254. data/public/images/server_error.png +0 -0
  1255. data/public/images/server_go.png +0 -0
  1256. data/public/images/server_key.png +0 -0
  1257. data/public/images/server_lightning.png +0 -0
  1258. data/public/images/server_link.png +0 -0
  1259. data/public/images/server_uncompressed.png +0 -0
  1260. data/public/images/shading.png +0 -0
  1261. data/public/images/shape_align_bottom.png +0 -0
  1262. data/public/images/shape_align_center.png +0 -0
  1263. data/public/images/shape_align_left.png +0 -0
  1264. data/public/images/shape_align_middle.png +0 -0
  1265. data/public/images/shape_align_right.png +0 -0
  1266. data/public/images/shape_align_top.png +0 -0
  1267. data/public/images/shape_flip_horizontal.png +0 -0
  1268. data/public/images/shape_flip_vertical.png +0 -0
  1269. data/public/images/shape_group.png +0 -0
  1270. data/public/images/shape_handles.png +0 -0
  1271. data/public/images/shape_move_back.png +0 -0
  1272. data/public/images/shape_move_backwards.png +0 -0
  1273. data/public/images/shape_move_forwards.png +0 -0
  1274. data/public/images/shape_move_front.png +0 -0
  1275. data/public/images/shape_rotate_anticlockwise.png +0 -0
  1276. data/public/images/shape_rotate_clockwise.png +0 -0
  1277. data/public/images/shape_square.png +0 -0
  1278. data/public/images/shape_square_add.png +0 -0
  1279. data/public/images/shape_square_delete.png +0 -0
  1280. data/public/images/shape_square_edit.png +0 -0
  1281. data/public/images/shape_square_error.png +0 -0
  1282. data/public/images/shape_square_go.png +0 -0
  1283. data/public/images/shape_square_key.png +0 -0
  1284. data/public/images/shape_square_link.png +0 -0
  1285. data/public/images/shape_ungroup.png +0 -0
  1286. data/public/images/shield.png +0 -0
  1287. data/public/images/shield_add.png +0 -0
  1288. data/public/images/shield_delete.png +0 -0
  1289. data/public/images/shield_go.png +0 -0
  1290. data/public/images/silk.html +1495 -0
  1291. data/public/images/sitemap.png +0 -0
  1292. data/public/images/sitemap_color.png +0 -0
  1293. data/public/images/sound.png +0 -0
  1294. data/public/images/sound_add.png +0 -0
  1295. data/public/images/sound_delete.png +0 -0
  1296. data/public/images/sound_low.png +0 -0
  1297. data/public/images/sound_mute.png +0 -0
  1298. data/public/images/sound_none.png +0 -0
  1299. data/public/images/spellcheck.png +0 -0
  1300. data/public/images/sport_8ball.png +0 -0
  1301. data/public/images/sport_basketball.png +0 -0
  1302. data/public/images/sport_football.png +0 -0
  1303. data/public/images/sport_golf.png +0 -0
  1304. data/public/images/sport_raquet.png +0 -0
  1305. data/public/images/sport_shuttlecock.png +0 -0
  1306. data/public/images/sport_soccer.png +0 -0
  1307. data/public/images/sport_tennis.png +0 -0
  1308. data/public/images/star.png +0 -0
  1309. data/public/images/status_away.png +0 -0
  1310. data/public/images/status_busy.png +0 -0
  1311. data/public/images/status_offline.png +0 -0
  1312. data/public/images/status_online.png +0 -0
  1313. data/public/images/stop.png +0 -0
  1314. data/public/images/style.png +0 -0
  1315. data/public/images/style_add.png +0 -0
  1316. data/public/images/style_delete.png +0 -0
  1317. data/public/images/style_edit.png +0 -0
  1318. data/public/images/style_go.png +0 -0
  1319. data/public/images/sum.png +0 -0
  1320. data/public/images/swf/xspf/Main.as +55 -0
  1321. data/public/images/swf/xspf/com/zuardi/musicplayer/MusicButton.as +557 -0
  1322. data/public/images/swf/xspf/com/zuardi/musicplayer/MusicPlayer.as +118 -0
  1323. data/public/images/swf/xspf/com/zuardi/musicplayer/Playlist.as +127 -0
  1324. data/public/images/swf/xspf/com/zuardi/musicplayer/ProgressiveSlider.as +66 -0
  1325. data/public/images/swf/xspf/license.txt +10 -0
  1326. data/public/images/swf/xspf/musicplayer.swf +0 -0
  1327. data/public/images/swf/xspf/musicplayer_f6.swf +0 -0
  1328. data/public/images/swf/xspf/musicplayerbtn.fla +0 -0
  1329. data/public/images/swf/xspf/parameters.as +39 -0
  1330. data/public/images/tab.png +0 -0
  1331. data/public/images/tab_add.png +0 -0
  1332. data/public/images/tab_delete.png +0 -0
  1333. data/public/images/tab_edit.png +0 -0
  1334. data/public/images/tab_go.png +0 -0
  1335. data/public/images/table.png +0 -0
  1336. data/public/images/table_add.png +0 -0
  1337. data/public/images/table_delete.png +0 -0
  1338. data/public/images/table_edit.png +0 -0
  1339. data/public/images/table_error.png +0 -0
  1340. data/public/images/table_gear.png +0 -0
  1341. data/public/images/table_go.png +0 -0
  1342. data/public/images/table_key.png +0 -0
  1343. data/public/images/table_lightning.png +0 -0
  1344. data/public/images/table_link.png +0 -0
  1345. data/public/images/table_multiple.png +0 -0
  1346. data/public/images/table_refresh.png +0 -0
  1347. data/public/images/table_relationship.png +0 -0
  1348. data/public/images/table_row_delete.png +0 -0
  1349. data/public/images/table_row_insert.png +0 -0
  1350. data/public/images/table_save.png +0 -0
  1351. data/public/images/table_sort.png +0 -0
  1352. data/public/images/tag.png +0 -0
  1353. data/public/images/tag_blue.png +0 -0
  1354. data/public/images/tag_blue_add.png +0 -0
  1355. data/public/images/tag_blue_delete.png +0 -0
  1356. data/public/images/tag_blue_edit.png +0 -0
  1357. data/public/images/tag_green.png +0 -0
  1358. data/public/images/tag_orange.png +0 -0
  1359. data/public/images/tag_pink.png +0 -0
  1360. data/public/images/tag_purple.png +0 -0
  1361. data/public/images/tag_red.png +0 -0
  1362. data/public/images/tag_yellow.png +0 -0
  1363. data/public/images/target.png +0 -0
  1364. data/public/images/telephone.png +0 -0
  1365. data/public/images/telephone_add.png +0 -0
  1366. data/public/images/telephone_delete.png +0 -0
  1367. data/public/images/telephone_edit.png +0 -0
  1368. data/public/images/telephone_error.png +0 -0
  1369. data/public/images/telephone_go.png +0 -0
  1370. data/public/images/telephone_key.png +0 -0
  1371. data/public/images/telephone_link.png +0 -0
  1372. data/public/images/television.png +0 -0
  1373. data/public/images/television_add.png +0 -0
  1374. data/public/images/television_delete.png +0 -0
  1375. data/public/images/text_align_center.png +0 -0
  1376. data/public/images/text_align_justify.png +0 -0
  1377. data/public/images/text_align_left.png +0 -0
  1378. data/public/images/text_align_right.png +0 -0
  1379. data/public/images/text_allcaps.png +0 -0
  1380. data/public/images/text_bold.png +0 -0
  1381. data/public/images/text_columns.png +0 -0
  1382. data/public/images/text_dropcaps.png +0 -0
  1383. data/public/images/text_heading_1.png +0 -0
  1384. data/public/images/text_heading_2.png +0 -0
  1385. data/public/images/text_heading_3.png +0 -0
  1386. data/public/images/text_heading_4.png +0 -0
  1387. data/public/images/text_heading_5.png +0 -0
  1388. data/public/images/text_heading_6.png +0 -0
  1389. data/public/images/text_horizontalrule.png +0 -0
  1390. data/public/images/text_indent.png +0 -0
  1391. data/public/images/text_indent_remove.png +0 -0
  1392. data/public/images/text_italic.png +0 -0
  1393. data/public/images/text_kerning.png +0 -0
  1394. data/public/images/text_letter_omega.png +0 -0
  1395. data/public/images/text_letterspacing.png +0 -0
  1396. data/public/images/text_linespacing.png +0 -0
  1397. data/public/images/text_list_bullets.png +0 -0
  1398. data/public/images/text_list_numbers.png +0 -0
  1399. data/public/images/text_lowercase.png +0 -0
  1400. data/public/images/text_padding_bottom.png +0 -0
  1401. data/public/images/text_padding_left.png +0 -0
  1402. data/public/images/text_padding_right.png +0 -0
  1403. data/public/images/text_padding_top.png +0 -0
  1404. data/public/images/text_replace.png +0 -0
  1405. data/public/images/text_signature.png +0 -0
  1406. data/public/images/text_smallcaps.png +0 -0
  1407. data/public/images/text_strikethrough.png +0 -0
  1408. data/public/images/text_subscript.png +0 -0
  1409. data/public/images/text_superscript.png +0 -0
  1410. data/public/images/text_underline.png +0 -0
  1411. data/public/images/text_uppercase.png +0 -0
  1412. data/public/images/textfield.png +0 -0
  1413. data/public/images/textfield_add.png +0 -0
  1414. data/public/images/textfield_delete.png +0 -0
  1415. data/public/images/textfield_key.png +0 -0
  1416. data/public/images/textfield_rename.png +0 -0
  1417. data/public/images/thumb_down.png +0 -0
  1418. data/public/images/thumb_up.png +0 -0
  1419. data/public/images/tick.png +0 -0
  1420. data/public/images/time.png +0 -0
  1421. data/public/images/time_add.png +0 -0
  1422. data/public/images/time_delete.png +0 -0
  1423. data/public/images/time_go.png +0 -0
  1424. data/public/images/timeline_marker.png +0 -0
  1425. data/public/images/transmit.png +0 -0
  1426. data/public/images/transmit_add.png +0 -0
  1427. data/public/images/transmit_blue.png +0 -0
  1428. data/public/images/transmit_delete.png +0 -0
  1429. data/public/images/transmit_edit.png +0 -0
  1430. data/public/images/transmit_error.png +0 -0
  1431. data/public/images/transmit_go.png +0 -0
  1432. data/public/images/tux.png +0 -0
  1433. data/public/images/user.png +0 -0
  1434. data/public/images/user_add.png +0 -0
  1435. data/public/images/user_admin.png +0 -0
  1436. data/public/images/user_comment.png +0 -0
  1437. data/public/images/user_delete.png +0 -0
  1438. data/public/images/user_edit.png +0 -0
  1439. data/public/images/user_female.png +0 -0
  1440. data/public/images/user_go.png +0 -0
  1441. data/public/images/user_gray.png +0 -0
  1442. data/public/images/user_green.png +0 -0
  1443. data/public/images/user_orange.png +0 -0
  1444. data/public/images/user_pub.png +0 -0
  1445. data/public/images/user_red.png +0 -0
  1446. data/public/images/user_su.png +0 -0
  1447. data/public/images/user_suit.png +0 -0
  1448. data/public/images/validate.png +0 -0
  1449. data/public/images/valider.png +0 -0
  1450. data/public/images/vcard.png +0 -0
  1451. data/public/images/vcard_add.png +0 -0
  1452. data/public/images/vcard_delete.png +0 -0
  1453. data/public/images/vcard_edit.png +0 -0
  1454. data/public/images/vector.png +0 -0
  1455. data/public/images/vector_add.png +0 -0
  1456. data/public/images/vector_delete.png +0 -0
  1457. data/public/images/wand.png +0 -0
  1458. data/public/images/weather_clouds.png +0 -0
  1459. data/public/images/weather_cloudy.png +0 -0
  1460. data/public/images/weather_lightning.png +0 -0
  1461. data/public/images/weather_rain.png +0 -0
  1462. data/public/images/weather_snow.png +0 -0
  1463. data/public/images/weather_sun.png +0 -0
  1464. data/public/images/webcam.png +0 -0
  1465. data/public/images/webcam_add.png +0 -0
  1466. data/public/images/webcam_delete.png +0 -0
  1467. data/public/images/webcam_error.png +0 -0
  1468. data/public/images/world.png +0 -0
  1469. data/public/images/world_add.png +0 -0
  1470. data/public/images/world_delete.png +0 -0
  1471. data/public/images/world_edit.png +0 -0
  1472. data/public/images/world_go.png +0 -0
  1473. data/public/images/world_link.png +0 -0
  1474. data/public/images/wrench.png +0 -0
  1475. data/public/images/wrench_orange.png +0 -0
  1476. data/public/images/xhtml.png +0 -0
  1477. data/public/images/xhtml_add.png +0 -0
  1478. data/public/images/xhtml_delete.png +0 -0
  1479. data/public/images/xhtml_go.png +0 -0
  1480. data/public/images/xhtml_valid.png +0 -0
  1481. data/public/images/zoom.png +0 -0
  1482. data/public/images/zoom_in.png +0 -0
  1483. data/public/images/zoom_out.png +0 -0
  1484. data/public/img/logo.png +0 -0
  1485. data/public/javascripts/application.js +2 -0
  1486. data/public/javascripts/builder.js +136 -0
  1487. data/public/javascripts/controls.js +965 -0
  1488. data/public/javascripts/dragdrop.js +975 -0
  1489. data/public/javascripts/effects.js +1130 -0
  1490. data/public/javascripts/prototype.js +4320 -0
  1491. data/public/javascripts/scriptaculous.js +60 -0
  1492. data/public/javascripts/slider.js +275 -0
  1493. data/public/javascripts/sound.js +55 -0
  1494. data/public/javascripts/tablekit.js +965 -0
  1495. data/public/javascripts/unittest.js +568 -0
  1496. data/public/javascripts/upload-progress.js +133 -0
  1497. data/public/javascripts/zena.js +501 -0
  1498. data/public/robots.txt +1 -0
  1499. data/public/stylesheets/admin.css +77 -0
  1500. data/public/stylesheets/calendar.css +55 -0
  1501. data/public/stylesheets/code.css +67 -0
  1502. data/public/stylesheets/comment.css +43 -0
  1503. data/public/stylesheets/csshover2.htc +121 -0
  1504. data/public/stylesheets/default.css +85 -0
  1505. data/public/stylesheets/popup.css +200 -0
  1506. data/public/stylesheets/reset.css +33 -0
  1507. data/public/stylesheets/search.css +19 -0
  1508. data/public/stylesheets/upload-progress.css +4 -0
  1509. data/public/stylesheets/wiki.css +100 -0
  1510. data/public/stylesheets/zen.css +230 -0
  1511. data/public/stylesheets/zena.css +78 -0
  1512. data/rails/init.rb +2 -0
  1513. data/tasks/ann.rake +80 -0
  1514. data/tasks/bones.rake +20 -0
  1515. data/tasks/gem.rake +201 -0
  1516. data/tasks/git.rake +40 -0
  1517. data/tasks/notes.rake +27 -0
  1518. data/tasks/post_load.rake +34 -0
  1519. data/tasks/rdoc.rake +51 -0
  1520. data/tasks/rubyforge.rake +55 -0
  1521. data/tasks/setup.rb +292 -0
  1522. data/tasks/spec.rake +54 -0
  1523. data/tasks/svn.rake +47 -0
  1524. data/tasks/test.rake +40 -0
  1525. data/tasks/zentest.rake +36 -0
  1526. data/test/fixtures/comments.yml +126 -0
  1527. data/test/fixtures/contact_contents.yml +132 -0
  1528. data/test/fixtures/data_entries.yml +65 -0
  1529. data/test/fixtures/discussions.yml +48 -0
  1530. data/test/fixtures/document_contents.yml +108 -0
  1531. data/test/fixtures/dyn_attributes.yml +66 -0
  1532. data/test/fixtures/files/Node-test.zafu +307 -0
  1533. data/test/fixtures/files/bird.jpg +0 -0
  1534. data/test/fixtures/files/bomb.png +0 -0
  1535. data/test/fixtures/files/exif_sample.jpg +0 -0
  1536. data/test/fixtures/files/flower.jpg +0 -0
  1537. data/test/fixtures/files/forest.pdf +0 -0
  1538. data/test/fixtures/files/import.tgz +0 -0
  1539. data/test/fixtures/files/jet_30.zip +0 -0
  1540. data/test/fixtures/files/lake.jpg +0 -0
  1541. data/test/fixtures/files/letter.zip +0 -0
  1542. data/test/fixtures/files/other.txt +1 -0
  1543. data/test/fixtures/files/simple.zml.gz +0 -0
  1544. data/test/fixtures/files/some.txt +1 -0
  1545. data/test/fixtures/files/translations_de.yml +4 -0
  1546. data/test/fixtures/files/translations_fr.yml +4 -0
  1547. data/test/fixtures/files/tree.jpg +0 -0
  1548. data/test/fixtures/files/water.pdf +0 -0
  1549. data/test/fixtures/groups.yml +86 -0
  1550. data/test/fixtures/groups_users.yml +81 -0
  1551. data/test/fixtures/iformats.yml +28 -0
  1552. data/test/fixtures/import/photos.en.zml +11 -0
  1553. data/test/fixtures/import/photos/bird.jpg +0 -0
  1554. data/test/fixtures/import/photos/bird.jpg.en.zml +1 -0
  1555. data/test/fixtures/import/photos/bird.jpg.fr.zml +1 -0
  1556. data/test/fixtures/import/photos/document.yml.en +4 -0
  1557. data/test/fixtures/import/photos/document.yml.fr +4 -0
  1558. data/test/fixtures/import/simple.zml +8 -0
  1559. data/test/fixtures/links.yml +313 -0
  1560. data/test/fixtures/nodes.yml +2592 -0
  1561. data/test/fixtures/relations.yml +126 -0
  1562. data/test/fixtures/sites.yml +58 -0
  1563. data/test/fixtures/template_contents.yml +172 -0
  1564. data/test/fixtures/users.yml +167 -0
  1565. data/test/fixtures/versions.yml +1909 -0
  1566. data/test/fixtures/virtual_classes.yml +87 -0
  1567. data/test/fixtures/zips.yml +15 -0
  1568. data/test/functional/application_controller_test.rb +136 -0
  1569. data/test/functional/calendar_controller_test.rb +25 -0
  1570. data/test/functional/comments_controller_test.rb +59 -0
  1571. data/test/functional/data_entries_controller_test.rb +22 -0
  1572. data/test/functional/discussion_controller_test.rb +20 -0
  1573. data/test/functional/documents_controller_test.rb +155 -0
  1574. data/test/functional/groups_controller_test.rb +109 -0
  1575. data/test/functional/iformats_controller_test.rb +115 -0
  1576. data/test/functional/links_controller_test.rb +26 -0
  1577. data/test/functional/nodes_controller_test.rb +448 -0
  1578. data/test/functional/note_controller_test.rb +53 -0
  1579. data/test/functional/preferences_controller_test.rb +11 -0
  1580. data/test/functional/relations_controller_test.rb +55 -0
  1581. data/test/functional/search_controller_test.rb +41 -0
  1582. data/test/functional/sessions_controller_test.rb +73 -0
  1583. data/test/functional/sites_controller_test.rb +102 -0
  1584. data/test/functional/users_controller_test.rb +28 -0
  1585. data/test/functional/versions_controller_test.rb +99 -0
  1586. data/test/functional/virtual_classes_controller_test.rb +62 -0
  1587. data/test/helpers/node_query/basic.yml +149 -0
  1588. data/test/helpers/node_query/comments.yml +18 -0
  1589. data/test/helpers/node_query/complex.yml +98 -0
  1590. data/test/helpers/node_query/filters.yml +105 -0
  1591. data/test/helpers/node_query/relations.yml +43 -0
  1592. data/test/helpers/node_query_test.rb +117 -0
  1593. data/test/integration/multiple_hosts_test.rb +98 -0
  1594. data/test/integration/multiversion_test.rb +164 -0
  1595. data/test/integration/navigation_test.rb +283 -0
  1596. data/test/sites/README +2 -0
  1597. data/test/sites/complex/complex.png +0 -0
  1598. data/test/sites/complex/groups.yml +9 -0
  1599. data/test/sites/complex/links.yml +75 -0
  1600. data/test/sites/complex/nodes.yml +253 -0
  1601. data/test/sites/complex/relations.yml +11 -0
  1602. data/test/sites/complex/sites.yml +13 -0
  1603. data/test/sites/complex/users.yml +20 -0
  1604. data/test/sites/complex/versions.yml +1 -0
  1605. data/test/sites/complex/virtual_classes.yml +19 -0
  1606. data/test/sites/ocean/contact_contents.yml +19 -0
  1607. data/test/sites/ocean/groups.yml +9 -0
  1608. data/test/sites/ocean/iformats.yml +7 -0
  1609. data/test/sites/ocean/nodes.yml +36 -0
  1610. data/test/sites/ocean/sites.yml +14 -0
  1611. data/test/sites/ocean/template_contents.yml +8 -0
  1612. data/test/sites/ocean/users.yml +33 -0
  1613. data/test/sites/ocean/versions.yml +48 -0
  1614. data/test/sites/zena/comments.yml +82 -0
  1615. data/test/sites/zena/contact_contents.yml +55 -0
  1616. data/test/sites/zena/data_entries.yml +42 -0
  1617. data/test/sites/zena/discussions.yml +30 -0
  1618. data/test/sites/zena/document_contents.yml +76 -0
  1619. data/test/sites/zena/dyn_attributes.yml +43 -0
  1620. data/test/sites/zena/groups.yml +11 -0
  1621. data/test/sites/zena/iformats.yml +6 -0
  1622. data/test/sites/zena/links.yml +49 -0
  1623. data/test/sites/zena/nodes.yml +338 -0
  1624. data/test/sites/zena/relations.yml +66 -0
  1625. data/test/sites/zena/sites.yml +13 -0
  1626. data/test/sites/zena/template_contents.yml +103 -0
  1627. data/test/sites/zena/users.yml +48 -0
  1628. data/test/sites/zena/versions.yml +558 -0
  1629. data/test/sites/zena/virtual_classes.yml +23 -0
  1630. data/test/test_helper.rb +62 -0
  1631. data/test/test_zena.rb +138 -0
  1632. data/test/unit/cache_test.rb +62 -0
  1633. data/test/unit/cached_page_test.rb +165 -0
  1634. data/test/unit/comment_test.rb +185 -0
  1635. data/test/unit/contact_content_test.rb +33 -0
  1636. data/test/unit/contact_test.rb +39 -0
  1637. data/test/unit/contact_version_test.rb +48 -0
  1638. data/test/unit/core_ext_test.rb +48 -0
  1639. data/test/unit/data_entry_test.rb +92 -0
  1640. data/test/unit/discussion_test.rb +59 -0
  1641. data/test/unit/document_content_test.rb +110 -0
  1642. data/test/unit/document_test.rb +234 -0
  1643. data/test/unit/document_version_test.rb +11 -0
  1644. data/test/unit/dyn_attributes_test.rb +229 -0
  1645. data/test/unit/exif_data_test.rb +66 -0
  1646. data/test/unit/group_test.rb +142 -0
  1647. data/test/unit/iformat_test.rb +190 -0
  1648. data/test/unit/image_builder_test.rb +214 -0
  1649. data/test/unit/image_content_test.rb +154 -0
  1650. data/test/unit/image_test.rb +311 -0
  1651. data/test/unit/image_version_test.rb +18 -0
  1652. data/test/unit/letter_test.rb +9 -0
  1653. data/test/unit/link_test.rb +32 -0
  1654. data/test/unit/multiversion_test.rb +1008 -0
  1655. data/test/unit/node_test.rb +1578 -0
  1656. data/test/unit/note_test.rb +85 -0
  1657. data/test/unit/page_test.rb +79 -0
  1658. data/test/unit/project_test.rb +32 -0
  1659. data/test/unit/reference_test.rb +9 -0
  1660. data/test/unit/relation_proxy_test.rb +409 -0
  1661. data/test/unit/relation_test.rb +48 -0
  1662. data/test/unit/section_test.rb +32 -0
  1663. data/test/unit/secure_test.rb +939 -0
  1664. data/test/unit/site_test.rb +236 -0
  1665. data/test/unit/skin_test.rb +18 -0
  1666. data/test/unit/template_content_test.rb +9 -0
  1667. data/test/unit/template_test.rb +357 -0
  1668. data/test/unit/template_version_test.rb +7 -0
  1669. data/test/unit/text_document_content_test.rb +8 -0
  1670. data/test/unit/text_document_test.rb +139 -0
  1671. data/test/unit/text_document_version_test.rb +37 -0
  1672. data/test/unit/user_test.rb +295 -0
  1673. data/test/unit/version_test.rb +312 -0
  1674. data/test/unit/virtual_class_test.rb +242 -0
  1675. data/test/unit/zena/db_test.rb +94 -0
  1676. data/test/unit/zena/parser/latex.yml +14 -0
  1677. data/test/unit/zena/parser/zafu.yml +391 -0
  1678. data/test/unit/zena/parser/zafu_asset.yml +43 -0
  1679. data/test/unit/zena/parser/zafu_insight.yml +3 -0
  1680. data/test/unit/zena/parser/zazen.yml +211 -0
  1681. data/test/unit/zena/parser_test.rb +184 -0
  1682. data/test/unit/zena/unit/test_case_test.rb +12 -0
  1683. data/test/unit/zena/use/calendar_test.rb +49 -0
  1684. data/test/unit/zena/use/dates_model_methods_test.rb +41 -0
  1685. data/test/unit/zena/use/dates_string_methods_test.rb +94 -0
  1686. data/test/unit/zena/use/dates_view_methods_test.rb +158 -0
  1687. data/test/unit/zena/use/html_tags_test.rb +244 -0
  1688. data/test/unit/zena/use/i18n_test.rb +34 -0
  1689. data/test/unit/zena/use/nested_attributes_alias_model_test.rb +104 -0
  1690. data/test/unit/zena/use/nested_attributes_alias_view_test.rb +99 -0
  1691. data/test/unit/zena/use/refactor_test.rb +52 -0
  1692. data/test/unit/zena/use/rendering_test.rb +23 -0
  1693. data/test/unit/zena/use/urls_test.rb +119 -0
  1694. data/test/unit/zena/use/zafu_test.rb +21 -0
  1695. data/test/unit/zena/use/zazen_test.rb +230 -0
  1696. data/test/unit/zena/zena_tags/ajax.yml +233 -0
  1697. data/test/unit/zena/zena_tags/apphelper.yml +85 -0
  1698. data/test/unit/zena/zena_tags/basic.yml +1295 -0
  1699. data/test/unit/zena/zena_tags/complex.yml +249 -0
  1700. data/test/unit/zena/zena_tags/data.yml +73 -0
  1701. data/test/unit/zena/zena_tags/errors.yml +71 -0
  1702. data/test/unit/zena/zena_tags/eval.yml +51 -0
  1703. data/test/unit/zena/zena_tags/relations.yml +411 -0
  1704. data/test/unit/zena/zena_tags/zazen.yml +84 -0
  1705. data/test/unit/zena/zena_tags_test.rb +235 -0
  1706. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run 2.tmCommand +24 -0
  1707. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run Context.tmCommand +58 -0
  1708. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run Focused Should.tmCommand +88 -0
  1709. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run.tmCommand +27 -0
  1710. data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/YAML to Shoulda.tmCommand +23 -0
  1711. data/vendor/TextMate/Ruby Shoulda.tmbundle/Preferences/Symbol List: Context.tmPreferences +19 -0
  1712. data/vendor/TextMate/Ruby Shoulda.tmbundle/Preferences/Symbol List: Should.tmPreferences +19 -0
  1713. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory attributes for.tmSnippet +16 -0
  1714. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory build.tmSnippet +16 -0
  1715. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory.tmSnippet +16 -0
  1716. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_define with class.tmSnippet +18 -0
  1717. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_define.tmSnippet +18 -0
  1718. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_next.tmSnippet +16 -0
  1719. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_sequence.tmSnippet +18 -0
  1720. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_bad_value.tmSnippet +16 -0
  1721. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_contains.tmSnippet +16 -0
  1722. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_does_not_contain.tmSnippet +16 -0
  1723. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_good_value.tmSnippet +16 -0
  1724. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_same_elements.tmSnippet +16 -0
  1725. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_save.tmSnippet +16 -0
  1726. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_sent_email.tmSnippet +18 -0
  1727. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_valid.tmSnippet +16 -0
  1728. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/association.tmSnippet +17 -0
  1729. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/attribute.tmSnippet +17 -0
  1730. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/before_should block.tmSnippet +18 -0
  1731. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block get.tmSnippet +22 -0
  1732. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block post.tmSnippet +23 -0
  1733. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block with setup.tmSnippet +25 -0
  1734. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/setup.tmSnippet +18 -0
  1735. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should block with before proc.tmSnippet +18 -0
  1736. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should block.tmSnippet +18 -0
  1737. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_allow_values_for.tmSnippet +16 -0
  1738. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_assign_to.tmSnippet +16 -0
  1739. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_be_restful denied.tmSnippet +20 -0
  1740. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_be_restful.tmSnippet +20 -0
  1741. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_belong_to.tmSnippet +16 -0
  1742. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_change by.tmSnippet +16 -0
  1743. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_change from to.tmSnippet +16 -0
  1744. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_at_least.tmSnippet +16 -0
  1745. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_in_range.tmSnippet +16 -0
  1746. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_is.tmSnippet +16 -0
  1747. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_value_in_range.tmSnippet +16 -0
  1748. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_eventually.tmSnippet +18 -0
  1749. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_filter_params.tmSnippet +16 -0
  1750. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_and_belong_to_many.tmSnippet +16 -0
  1751. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_class_methods.tmSnippet +16 -0
  1752. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_db_column.tmSnippet +16 -0
  1753. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_db_columns.tmSnippet +16 -0
  1754. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_index.tmSnippet +16 -0
  1755. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_indices.tmSnippet +16 -0
  1756. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_instance_methods.tmSnippet +16 -0
  1757. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_many.tmSnippet +16 -0
  1758. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_named_scope.tmSnippet +16 -0
  1759. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_one.tmSnippet +16 -0
  1760. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_readonly_attributes.tmSnippet +16 -0
  1761. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_allow_mass_assignment_of.tmSnippet +16 -0
  1762. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_allow_values_for.tmSnippet +16 -0
  1763. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_assign_to.tmSnippet +16 -0
  1764. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_change.tmSnippet +16 -0
  1765. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_set_the_flash.tmSnippet +16 -0
  1766. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_redirect_to.tmSnippet +16 -0
  1767. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_a_form.tmSnippet +16 -0
  1768. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_template.tmSnippet +16 -0
  1769. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_with_layout.tmSnippet +16 -0
  1770. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_without_layout.tmSnippet +16 -0
  1771. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_respond_with.tmSnippet +16 -0
  1772. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_respond_with_content_type.tmSnippet +16 -0
  1773. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_return_from_session.tmSnippet +16 -0
  1774. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_route.tmSnippet +16 -0
  1775. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_set_the_flash_to.tmSnippet +16 -0
  1776. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_acceptance_of.tmSnippet +16 -0
  1777. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_numericality_of.tmSnippet +16 -0
  1778. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_presence_of.tmSnippet +16 -0
  1779. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_uniqueness_of with scope.tmSnippet +16 -0
  1780. data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_uniqueness_of.tmSnippet +16 -0
  1781. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/catch_exception.rb +39 -0
  1782. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/run_script.rb +104 -0
  1783. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/stdin_dialog.rb +14 -0
  1784. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/test.rb +17 -0
  1785. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/todo.txt +13 -0
  1786. data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/bin/yaml_to_shoulda.rb +25 -0
  1787. data/vendor/TextMate/Ruby Shoulda.tmbundle/Syntaxes/Ruby on Rails (Shoulda).tmLanguage +166 -0
  1788. data/vendor/TextMate/Ruby Shoulda.tmbundle/info.plist +304 -0
  1789. data/vendor/TextMate/Zena.tmbundle/Commands/Run all yaml tests.tmCommand +37 -0
  1790. data/vendor/TextMate/Zena.tmbundle/Commands/Run focused yaml test.tmCommand +53 -0
  1791. data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/run_script.rb +74 -0
  1792. data/vendor/TextMate/Zena.tmbundle/info.plist +15 -0
  1793. data/vendor/apache_upload/mod_upload_progress.c +813 -0
  1794. data/vendor/bricks/20070122-172926.txt +282 -0
  1795. data/vendor/plugins/ar_mysql_full_text/README +15 -0
  1796. data/vendor/plugins/ar_mysql_full_text/init.rb +1 -0
  1797. data/vendor/plugins/ar_mysql_full_text/lib/ar_mysql_full_text.rb +69 -0
  1798. data/vendor/plugins/gettext_i18n_rails/README.markdown +139 -0
  1799. data/vendor/plugins/gettext_i18n_rails/Rakefile +6 -0
  1800. data/vendor/plugins/gettext_i18n_rails/init.rb +10 -0
  1801. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails.rb +21 -0
  1802. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/action_controller.rb +6 -0
  1803. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/active_record.rb +17 -0
  1804. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/backend.rb +47 -0
  1805. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/haml_parser.rb +43 -0
  1806. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/i18n_hacks.rb +10 -0
  1807. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/model_attributes_finder.rb +46 -0
  1808. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/ruby_gettext_extractor.rb +136 -0
  1809. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/action_controller_spec.rb +36 -0
  1810. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/active_record_spec.rb +50 -0
  1811. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/backend_spec.rb +41 -0
  1812. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails_spec.rb +43 -0
  1813. data/vendor/plugins/gettext_i18n_rails/spec/spec_helper.rb +15 -0
  1814. data/vendor/plugins/gettext_i18n_rails/tasks/gettext_rails_i18n.rake +73 -0
  1815. data/vendor/plugins/responds_to_parent/MIT-LICENSE +20 -0
  1816. data/vendor/plugins/responds_to_parent/README +42 -0
  1817. data/vendor/plugins/responds_to_parent/Rakefile +22 -0
  1818. data/vendor/plugins/responds_to_parent/init.rb +1 -0
  1819. data/vendor/plugins/responds_to_parent/lib/responds_to_parent.rb +46 -0
  1820. data/vendor/plugins/responds_to_parent/test/responds_to_parent_test.rb +115 -0
  1821. data/vendor/plugins/rjs-assertions/MIT-LICENSE +20 -0
  1822. data/vendor/plugins/rjs-assertions/README +64 -0
  1823. data/vendor/plugins/rjs-assertions/init.rb +1 -0
  1824. data/vendor/plugins/rjs-assertions/lib/rjs-assertions.rb +99 -0
  1825. data/vendor/rails_patches/support_for_inverse_relationships_on_active_record_objects.diff +739 -0
  1826. metadata +2075 -0
@@ -0,0 +1,121 @@
1
+ class Link < ActiveRecord::Base
2
+ include RubyLess::SafeClass
3
+ safe_attribute :status, :comment, :date
4
+
5
+ attr_reader :relation
6
+ attr_accessor :start, :side
7
+
8
+ class << self
9
+ def find_through(node, link_id)
10
+ return nil unless link = Link.find(:first, :conditions => ['(source_id = ? OR target_id = ?) AND id = ?', node[:id], node[:id], link_id])
11
+ link.start = node
12
+ node.link = link
13
+ link
14
+ end
15
+ end
16
+
17
+ # TODO: is this used ?
18
+ def update_attributes_with_transformations(attrs)
19
+ return false unless @node
20
+
21
+ if attrs['role']
22
+ # TODO: destroy this link and create a new one ?
23
+ end
24
+
25
+ rel = @node.relation_proxy_from_link(self)
26
+ rel.other_link = self
27
+
28
+ Zena::Use::Relations::LINK_ATTRIBUTES.each do |k|
29
+ k = k.to_s # TODO: use only strings or symbols but avoid this mess
30
+ rel.send("other_#{k}=", attrs[k]) if attrs.has_key?(k)
31
+ self[k] = attrs[k]
32
+ end
33
+
34
+ if other_id = attrs['other_id'] || attrs['other_zip']
35
+ other_id = secure(Node) { Node.translate_pseudo_id(other_id, :id, @node) }
36
+ rel.other_id = other_id
37
+ if @side == :source
38
+ self[:target_id] = other_id
39
+ @target = nil
40
+ else
41
+ self[:source_id] = other_id
42
+ @source = nil
43
+ end
44
+ end
45
+
46
+ @node.save
47
+ @node.link = self
48
+ @errors = @node.errors
49
+ return errors.empty?
50
+ end
51
+
52
+ def target
53
+ @target ||= begin
54
+ node = secure!(Node) { Node.find(target_id) }
55
+ node.link = self
56
+ node
57
+ end
58
+ end
59
+
60
+ def source
61
+ @source ||= begin
62
+ node = secure!(Node) { Node.find(source_id) }
63
+ node.link = self
64
+ node
65
+ end
66
+ end
67
+
68
+ def start=(node)
69
+ @node = node
70
+ if @node[:id] == self[:source_id]
71
+ @side = :source
72
+ @source = @node
73
+ else
74
+ @side = :target
75
+ @target = @node
76
+ end
77
+ end
78
+
79
+ def other
80
+ @side == :source ? target : source
81
+ end
82
+
83
+ def this
84
+ @side == :source ? source : target
85
+ end
86
+
87
+ def other_zip
88
+ other[:zip]
89
+ end
90
+
91
+ def this_zip
92
+ this[:zip]
93
+ end
94
+
95
+ def zip
96
+ self[:id]
97
+ end
98
+
99
+ def can_write?
100
+ this.can_write?
101
+ end
102
+
103
+ def relation_proxy(node=nil)
104
+ return @relation_proxy if defined?(@relation_proxy)
105
+ rel = RelationProxy.find(self[:relation_id])
106
+ @node = node if node
107
+ if @node
108
+ if self[:source_id] == @node[:id]
109
+ rel.side = :source
110
+ else
111
+ rel.side = :target
112
+ end
113
+ rel.start = @node
114
+ end
115
+ @relation_proxy = rel
116
+ end
117
+
118
+ def role
119
+ relation_proxy.other_role
120
+ end
121
+ end
@@ -0,0 +1,1752 @@
1
+ =begin rdoc
2
+ A Node is the root class of all elements in the zena application. Class inheritance diagram:
3
+
4
+
5
+ FIXME: some parts are not correct (Partial, Task, Request, Milestone). Either correct this tree or add these classes.
6
+ Node (manages access and publication cycle)
7
+ |
8
+ +-- Page (web pages)
9
+ | |
10
+ | +--- Project (has it's own project_id. Can contain notes, collaborators, etc)
11
+ | |
12
+ | +--- Section (has it's own section_id = group of pages)
13
+ | |
14
+ | +--- Skin (theme: contains css, templates, etc)
15
+ |
16
+ +--- Document
17
+ | |
18
+ | +--- Image
19
+ | |
20
+ | +--- TextDocument (for css, scripts)
21
+ | |
22
+ | +--- Partial (uses the zafu templating language)
23
+ | |
24
+ | +--- Template (entry for rendering)
25
+ |
26
+ +-- Note (date related information, event)
27
+ | |
28
+ | +--- Post (blog entry)
29
+ | |
30
+ | +--- Task
31
+ | | |
32
+ | | +--- Letter
33
+ | | |
34
+ | | +--- Request
35
+ | | |
36
+ | | +--- Bug
37
+ | |
38
+ | +--- Milestone
39
+ |
40
+ +-- Reference
41
+ |
42
+ +-- Contact (address, name, phone)
43
+
44
+ === Node, Version and Content
45
+
46
+ The +nodes+ table only holds columns to secure the access. This table does not hold every possible data for every sub-class of Node. The text data is stored into the +versions+ table and any other specific content goes in its own table (+document_contents+ for example). This is an example of how an Image is stored :
47
+
48
+ Node o----------- Version o--------- Content
49
+ dgroup_id title width
50
+ wgroup_id text height
51
+ user_id summary content_type
52
+ ... ... ...
53
+
54
+ === Acessing version and content data
55
+
56
+ To ease the work to set/retrieve the data from the version and or content, we use some special notation. This notation abstracts this Node/Version/Content structure so you can use a version's attribute as if it was in the node directly.
57
+
58
+ TODO: DOC removed (was out of sync)
59
+
60
+ === Dynamic attributes
61
+
62
+ The Version class uses dynamic attributes. These let you add any attribute you like to the versions (see DynAttribute for details). These attributes can be accessed by using the +d_+ prefix :
63
+
64
+ @node.d_whatever ===> @node.version.dyn[:whatever]
65
+
66
+ === Attributes
67
+
68
+ Each node uses the following basic attributes:
69
+
70
+ Base attributes:
71
+
72
+ zip:: unique id (incremented in each site's scope).
73
+ name:: used to build the node's url when 'custom_base' is set. Used for document names.
74
+ site_id:: site to which this node belongs to.
75
+ parent_id:: parent node (every node except root is inserted in a unique place through this attribute).
76
+ user_id:: owner of the node.
77
+ ref_lang:: original node language.
78
+ created_at:: creation date.
79
+ updated_at:: modification date.
80
+ custom_base:: boolean value. When set to true, the node's url becomes it's fullpath. All it descendants will use this node's fullpath as their base url. See below for an example.
81
+ inherit:: inheritance mode (0=custom, 1=inherit, -1=private).
82
+
83
+ Attributes inherited from the parent:
84
+ section_id:: reference project (cannot be overwritten even if inheritance mode is custom).
85
+ rgroup_id:: id of the readers group.
86
+ wgroup_id:: id of the writers group.
87
+ dgroup_id:: id of the publishers group.
88
+ skin:: name of theSkin to use when rendering the pate ('theme').
89
+
90
+ Attributes used internally:
91
+ publish_from:: earliest publication date from all published versions.
92
+ kpath:: inheritance hierarchy. For example an Image has 'NPDI' (Node, Page, Document, Image), a Letter would have 'NNTL' (Node, Note, Task. Letter). This is used to optimize sql queries.
93
+ fullpath:: cached full path made of ancestors' names (<gdparent name>/<parent name>/<self name>).
94
+ basepath:: cached base path (the base path is used to build the url depending on the 'custom_base' flag).
95
+
96
+ === Node url
97
+ A node's url is made of it's class and +zip+. For the examples below, this is our site tree:
98
+ root
99
+ |
100
+ +--- projects (Page)
101
+ |
102
+ +--- worldTour (Project)
103
+ | |
104
+ | +--- photos (Page)
105
+ |
106
+ +--- music (Project)
107
+
108
+ The worldTour project's url would look like:
109
+ /en/project21.html
110
+
111
+ The 'photos' url would be:
112
+ /en/page23.html
113
+
114
+ When custom base is set (only for descendants of Page), worldTour url becomes its fullpath:
115
+ /en/projects/worldTour
116
+
117
+ and the 'photos' url is now in the worldTour project's basepath:
118
+ /en/projects/worldTour/page23.html
119
+
120
+ Setting 'custom_base' on a node should be done with caution as the node's zip is on longer in the url and when you move the node around, there is no way to find the new location from the old url. Custom_base should therefore only be used for nodes that are not going to move.
121
+ =end
122
+ class Node < ActiveRecord::Base
123
+
124
+ include RubyLess::SafeClass
125
+ safe_attribute :created_at, :updated_at, :event_at, :log_at, :publish_from, :basepath, :inherit
126
+
127
+ # we use safe_method because the columns can be null, but the values are never null
128
+ safe_method :name => String, :kpath => String, :user_zip => Number, :parent_zip => Number,
129
+ :project_zip => Number, :section_zip => Number, :skin => String, :ref_lang => String,
130
+ :fullpath => String, :rootpath => String, :position => Number, :rgroup_id => Number,
131
+ :wgroup_id => Number, :dgroup_id => Number, :custom_base => Boolean, :klass => String,
132
+ :score => Number, :comments_count => Number,
133
+ :custom_a => Number, :custom_b => Number,
134
+ :m_text => String, :m_title => String, :m_author => String,
135
+ :zip => Number
136
+ # FIXME: remove 'zip' and use :id => {:class => Number, :method => 'zip'}
137
+ # same with parent_zip, section_zip, etc...
138
+
139
+ #attr_accessible :version_content
140
+ has_many :discussions, :dependent => :destroy
141
+ has_many :links
142
+ has_and_belongs_to_many :cached_pages
143
+ belongs_to :virtual_class, :foreign_key => 'vclass_id'
144
+ belongs_to :site
145
+ before_validation :node_before_validation # run our 'before_validation' after 'secure'
146
+ validates_presence_of :name
147
+ validate :validate_node
148
+ before_create :node_before_create
149
+ before_save :change_klass
150
+ after_save :spread_project_and_section
151
+ after_save :clear_children_fullpath
152
+ after_create :node_after_create
153
+ attr_protected :site_id, :zip, :id, :section_id, :project_id, :publish_from
154
+ attr_protected :site_id
155
+
156
+ include Zena::Use::Dates::ModelMethods
157
+ parse_date_attribute :event_at, :log_at
158
+
159
+ include Zena::Use::NestedAttributesAlias::ModelMethods
160
+ nested_attributes_alias %r{^v_(\w+)} => ['version']
161
+ nested_attributes_alias %r{^c_(\w+)} => ['version', 'content']
162
+ nested_attributes_alias %r{^d_(\w+)} => ['version', 'dyn']
163
+
164
+ zafu_context :author => "Contact", :parent => "Node",
165
+ :project => "Project", :section => "Section",
166
+ :real_project => "Project", :real_section => "Section",
167
+ :user => "User",
168
+ :version => "Version", :comments => ["Comment"],
169
+ :data => {:node_class => ["DataEntry"], :data_root => 'node_a'},
170
+ :data_a => {:node_class => ["DataEntry"], :data_root => 'node_a'},
171
+ :data_b => {:node_class => ["DataEntry"], :data_root => 'node_b'},
172
+ :data_c => {:node_class => ["DataEntry"], :data_root => 'node_c'},
173
+ :data_d => {:node_class => ["DataEntry"], :data_root => 'node_d'}
174
+
175
+ extend Zena::Acts::SecureNode
176
+ extend Zena::Acts::Multiversion
177
+ include Zena::Use::Relations::ModelMethods
178
+
179
+ acts_as_secure_node
180
+ acts_as_multiversioned
181
+ use_node_query
182
+
183
+ @@native_node_classes = {'N' => self}
184
+ @@unhandled_children = []
185
+ class << self
186
+
187
+ # needed for compatibility with virtual classes
188
+ alias create_instance create
189
+ alias new_instance new
190
+
191
+ def inherited(child)
192
+ super
193
+ @@unhandled_children << child
194
+ end
195
+
196
+ # Return the list of (kpath,subclasses) for the current class.
197
+ def native_classes
198
+ # this is to make sure subclasses are loaded before the first call
199
+ [Note,Page,Project,Section,Reference,Contact,Document,Image,TextDocument,Skin,Template]
200
+ while child = @@unhandled_children.pop
201
+ @@native_node_classes[child.kpath] = child
202
+ end
203
+ @@native_node_classes.reject{|kpath,klass| !(kpath =~ /^#{self.kpath}/) }
204
+ end
205
+
206
+ # check inheritance chain through kpath
207
+ def kpath_match?(kpath)
208
+ self.kpath =~ /^#{kpath}/
209
+ end
210
+
211
+ # Class list to which this class can change to
212
+ def change_to_classes_for_form
213
+ classes_for_form(:class => 'Node', :without => 'Document, Contact')
214
+ end
215
+
216
+ # List of classes that a node can change to.
217
+ def allowed_change_to_classes
218
+ change_to_classes_for_form.map {|k,v| v}
219
+ end
220
+
221
+ # FIXME: how to make sure all sub-classes of Node are loaded before this is called ?
222
+ def classes_for_form(opts={})
223
+ if klass = opts.delete(:class)
224
+ if klass = get_class(klass)
225
+ klass.classes_for_form(opts)
226
+ else
227
+ return ['', ''] # bad class
228
+ end
229
+ else
230
+ all_classes(opts).map{|a,b| [a[0..-1].sub(/^#{self.kpath}/,'').gsub(/./,'  ') + b.to_s, b.to_s] } # white spaces are insecable spaces (not ' ')
231
+ end
232
+ end
233
+
234
+ # FIXME: how to make sure all sub-classes of Node are loaded before this is called ?
235
+ def kpaths_for_form(opts={})
236
+ all_classes(opts).map{|a,b| [a[1..-1].gsub(/./,'  ') + b.to_s, a.to_s] } # white spaces are insecable spaces (not ' ')
237
+ end
238
+
239
+ def all_classes(opts={})
240
+ virtual_classes = VirtualClass.find(:all, :conditions => ["site_id = ? AND create_group_id IN (?) AND kpath LIKE '#{self.kpath}%'", current_site[:id], visitor.group_ids])
241
+ classes = (virtual_classes.map{|r| [r.kpath, r.name]} + native_classes.to_a).sort{|a,b| a[0] <=> b[0]}
242
+ if opts[:without]
243
+ reject_kpath = opts[:without].split(',').map(&:strip).map {|name| Node.get_class(name) }.compact.map { |kla| kla.kpath }.join('|')
244
+ classes.reject! {|k,c| k =~ /^#{reject_kpath}/ }
245
+ end
246
+ classes
247
+ end
248
+
249
+ # Return class or virtual class from name.
250
+ def get_class(rel, opts={})
251
+ class_name = rel.singularize.camelize # mushroom_types ==> MushroomType
252
+ begin
253
+ klass = Module.const_get(class_name)
254
+ raise NameError unless klass.ancestors.include?(Node)
255
+ rescue NameError
256
+ # find the virtual class
257
+ if opts[:create]
258
+ klass = VirtualClass.find(:first, :conditions=>["site_id = ? AND create_group_id IN (?) AND name = ?",current_site[:id], visitor.group_ids, class_name])
259
+ else
260
+ klass = VirtualClass.find(:first, :conditions=>["site_id = ? AND name = ?",current_site[:id], class_name])
261
+ end
262
+ end
263
+ klass
264
+ end
265
+
266
+ # Return a new object of the class name or nil if the class name does not exist.
267
+ def new_from_class(rel)
268
+ if k = get_class(rel, :create => true)
269
+ k.new
270
+ else
271
+ nil
272
+ end
273
+ end
274
+
275
+ def get_class_from_kpath(kp)
276
+ native_classes[kp] || VirtualClass.find(:first, :conditions=>["site_id = ? AND kpath = ?",current_site[:id], kp])
277
+ end
278
+
279
+ # Find a node's attribute based on a pseudo (id or path). Used by zazen to create a link for ""::art or "":(people/ant) for example.
280
+ def translate_pseudo_id(id, sym = :id, base_node = nil)
281
+ if id.to_s =~ /\A(-?)(\d+)\Z/
282
+ # zip
283
+ # FIXME: this is not secure
284
+ res = Zena::Db.fetch_row("SELECT #{sym} FROM nodes WHERE site_id = #{current_site[:id]} AND zip = '#{$2}'")
285
+ res ? ($1.blank? ? res.to_i : -res.to_i) : nil
286
+ elsif node = find_node_by_pseudo(id,base_node)
287
+ node[sym]
288
+ else
289
+ nil
290
+ end
291
+ end
292
+
293
+ # Find a node based on a query shortcut. Used by zazen to create a link for ""::art for example.
294
+ def find_node_by_pseudo(id, base_node = nil)
295
+ raise Zena::AccessViolation if self.scoped_methods == []
296
+ str = id.to_s
297
+ if str =~ /\A\d+\Z/
298
+ # zip
299
+ find_by_zip(str)
300
+ elsif str =~ /\A:?([0-9a-zA-Z ]+)(\+*)\Z/
301
+ offset = $2.to_s.size
302
+ find(:first, Node.match_query($1.gsub('-',' '), :offset => offset))
303
+ elsif path = str[/\A\(([^\)]*)\)\Z/,1]
304
+ if path[0..0] == '/'
305
+ find_by_path(path[1..-1])
306
+ elsif base_node
307
+ find_by_path(path.abs_path(base_node.fullpath))
308
+ else
309
+ # do not use (path) pseudo when there is no base_node (during create_or_update_node for example).
310
+ # FIXME: path pseudo is needed for links... and it should be done here (egg and hen problem)
311
+ nil
312
+ end
313
+ end
314
+ end
315
+
316
+ # def attr_public?(attribute)
317
+ # if attribute.to_s =~ /(.*)_zips?$/
318
+ # return true if self.ancestors.include?(Node) && RelationProxy.find_by_role($1.singularize)
319
+ # end
320
+ # super
321
+ # end
322
+
323
+ def create_or_update_node(new_attributes)
324
+ attributes = transform_attributes(new_attributes)
325
+ unless attributes['name'] && attributes['parent_id']
326
+ node = Node.new
327
+ node.errors.add('name', "can't be blank") unless attributes['name']
328
+ node.errors.add('parent_id', "can't be blank") unless attributes['parent_id']
329
+ return node
330
+ end
331
+
332
+ begin
333
+ klass = Node.get_class(attributes['klass'] || 'Node')
334
+ klass = klass.real_class if klass.kind_of?(VirtualClass)
335
+ rescue NameError
336
+ klass = Node
337
+ end
338
+
339
+ # FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
340
+ node = klass.send(:with_exclusive_scope) do
341
+ klass.find(:first, :conditions => ['site_id = ? AND name = ? AND parent_id = ?',
342
+ current_site[:id], attributes['name'].url_name, attributes['parent_id']])
343
+ end
344
+
345
+ if node
346
+ visitor.visit(node) # secure
347
+ # TODO: class ignored (could be used to transform from one class to another...)
348
+ attributes.delete('class')
349
+ attributes.delete('klass')
350
+ updated_date = node.updated_at
351
+ node.update_attributes(attributes)
352
+
353
+ if updated_date != node.updated_at
354
+ node[:create_or_update] = 'updated'
355
+ else
356
+ node[:create_or_update] = 'same'
357
+ end
358
+ else
359
+ node = create_node(new_attributes)
360
+ node[:create_or_update] = 'new'
361
+ end
362
+
363
+ node
364
+ end
365
+
366
+ # TODO: cleanup and rename with something indicating the attrs cleanup that this method does.
367
+ def create_node(new_attributes)
368
+ attributes = transform_attributes(new_attributes)
369
+
370
+ # the way this works here and in do_update_attributes is not good
371
+ publish_after_save = (attributes.delete('v_status').to_i == Zena::Status[:pub])
372
+
373
+ # TODO: replace this hack with a proper class method 'secure' behaving like the
374
+ # instance method. It would get the visitor and scope from the same hack below.
375
+ scope = self.scoped_methods[0] || {}
376
+
377
+ klass_name = attributes.delete('class') || attributes.delete('klass') || 'Page'
378
+ unless klass = get_class(klass_name, :create => true)
379
+ node = Node.new
380
+ node.instance_eval { @attributes = attributes }
381
+ node.errors.add('klass', 'invalid')
382
+ # This is to show the klass in the form seizure
383
+ node.instance_variable_set(:@klass, klass_name.to_s)
384
+ def node.klass; @klass; end
385
+ return node
386
+ end
387
+
388
+ node = if klass != self
389
+ # FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
390
+ klass.send(:with_exclusive_scope, scope) { klass.create_instance(attributes) }
391
+ else
392
+ self.create_instance(attributes)
393
+ end
394
+
395
+ node.publish if publish_after_save
396
+ node
397
+ end
398
+
399
+ # Create new nodes from the data in a folder or archive.
400
+ def create_nodes_from_folder(opts)
401
+ # TODO: all this method needs cleaning, it's a mess.
402
+ return [] unless (opts[:folder] || opts[:archive]) && (opts[:parent] || opts[:parent_id])
403
+ scope = self.scoped_methods[0] || {}
404
+ parent_id = opts[:parent_id] || opts[:parent][:id]
405
+ folder = opts[:folder]
406
+ defaults = (opts[:defaults] || {}).stringify_keys
407
+ klass = opts[:klass] || "Page"
408
+ res = {}
409
+
410
+ # create from archive
411
+ unless folder
412
+ archive = opts[:archive]
413
+ n = 0
414
+ while true
415
+ folder = File.join(RAILS_ROOT, 'tmp', sprintf('%s.%d.%d', 'import', $$, n))
416
+ break unless File.exists?(folder)
417
+ end
418
+
419
+ begin
420
+ FileUtils::mkpath(folder)
421
+
422
+ if archive.kind_of?(StringIO)
423
+ filename = archive.original_filename
424
+ tempf = Tempfile.new(archive.original_filename)
425
+ File.open(tempf.path, 'wb') { |f| f.syswrite(archive.read) }
426
+ archive = tempf
427
+ else
428
+ filename = archive.original_filename
429
+ end
430
+
431
+ # extract file in this temporary folder.
432
+ # FIXME: is there a security risk here ?
433
+ if filename =~ /\.tgz$/
434
+ `tar -C '#{folder}' -xz < '#{archive.path}'`
435
+ elsif filename =~ /\.tar$/
436
+ `tar -C '#{folder}' -x < '#{archive.path}'`
437
+ elsif filename =~ /\.zip$/
438
+ `unzip -d '#{folder}' '#{archive.path}'`
439
+ elsif filename =~ /(.*)(\.gz|\.z)$/
440
+ `gzip -d '#{archive.path}' -c > '#{folder}/#{$1.gsub("'",'')}'`
441
+ else
442
+ # FIXME: send errors back
443
+ puts "BAD #{archive.inspect}"
444
+ end
445
+ res = create_nodes_from_folder(:folder => folder, :parent_id => parent_id, :defaults => defaults, :klass => klass)
446
+ ensure
447
+ FileUtils::rmtree(folder)
448
+ end
449
+ return res
450
+ end
451
+
452
+ entries = Dir.entries(folder).reject { |f| f =~ /^([\._~]|[^\w])/ }.sort
453
+ index = 0
454
+
455
+ while entries[index]
456
+ type = current_obj = sub_folder = document_path = nil
457
+ versions = []
458
+ filename = entries[index]
459
+
460
+ path = File.join(folder, filename)
461
+
462
+ if File.stat(path).directory?
463
+ type = :folder
464
+ name = filename
465
+ sub_folder = path
466
+ attrs = defaults.dup
467
+ elsif filename =~ /^(.+?)(\.\w\w|)(\.\d+|)\.zml$/ # bird.jpg.en.zml
468
+ # node content in yaml
469
+ type = :node
470
+ name = "#{$1}#{$4}"
471
+ lang = $2.blank? ? nil : $2[1..-1]
472
+
473
+ # no need for base_node (this is done after all with parse_assets in the controller)
474
+ attrs = defaults.merge(get_attributes_from_yaml(path))
475
+ attrs['name'] = name
476
+ attrs['v_lang'] = lang || attrs['v_lang'] || visitor.lang
477
+ versions << attrs
478
+ elsif filename =~ /^((.+?)\.(.+?))(\.\w\w|)(\.\d+|)$/ # bird.jpg.en
479
+ type = :document
480
+ name = $1
481
+ attrs = defaults.dup
482
+ lang = $4.blank? ? nil : $4[1..-1]
483
+ attrs['v_lang'] = lang || attrs['v_lang'] || visitor.lang
484
+ attrs['c_ext'] = $3
485
+ document_path = path
486
+ end
487
+
488
+ index += 1
489
+ while entries[index] =~ /^#{name}(\.\w\w|)(\.\d+|)\.zml$/ # bird.jpg.en.zml
490
+ lang = $1.blank? ? visitor.lang : $1[1..-1]
491
+ path = File.join(folder,entries[index])
492
+
493
+ # we have a zml file. Create a version with this file
494
+ # no need for base_node (this is done after all with parse_assets in the controller)
495
+ attrs = defaults.merge(get_attributes_from_yaml(path))
496
+ attrs['name'] = name
497
+ attrs['v_lang'] ||= lang
498
+ versions << attrs
499
+
500
+ index += 1
501
+ end
502
+
503
+ if versions.empty?
504
+ if type == :folder
505
+ # minimal node for a folder
506
+ attrs['name'] = name
507
+ attrs['v_lang'] ||= lang
508
+ attrs['class'] = klass
509
+ versions << attrs
510
+ elsif type == :document
511
+ # minimal node for a document
512
+ attrs['name'] = name
513
+ attrs['v_lang'] ||= lang
514
+ versions << attrs
515
+ end
516
+ end
517
+
518
+ new_object = false
519
+ versions.each do |attrs|
520
+ # FIXME: same lang: remove before update current_obj.remove if current_obj.v_lang == attrs['v_lang'] && current_obj.v_status != Zena::Status[:red]
521
+ # FIXME: current_obj.publish if attrs['v_status'].to_i == Zena::Status[:pub]
522
+ if type == :document
523
+ attrs['name' ] = attrs['name'].split('.')[0..-2].join('.')
524
+ if document_path
525
+ attrs['c_ext'] ||= document_path.split('.').last
526
+ # file
527
+ insert_zafu_headings = false
528
+ if opts[:parent_class] == 'Skin' && ['html','xhtml'].include?(attrs['c_ext']) && attrs['name'] == 'index'
529
+ attrs['c_ext'] = 'zafu'
530
+ attrs['name'] = 'Node'
531
+ insert_zafu_headings = true
532
+ end
533
+
534
+ ctype = EXT_TO_TYPE[attrs['c_ext']]
535
+ ctype = ctype ? ctype[0] : "application/octet-stream"
536
+ attrs['c_content_type'] = ctype
537
+
538
+
539
+ File.open(document_path) do |file|
540
+ (class << file; self; end;).class_eval do
541
+ alias local_path path if defined?(:path)
542
+ alias o_read read
543
+ define_method(:original_filename) { filename }
544
+ define_method(:content_type) { ctype }
545
+ define_method(:read) do
546
+ if insert_zafu_headings
547
+ o_read.sub(%r{</head>}," <r:stylesheets/>\n <r:javascripts/>\n <r:uses_datebox/>\n</head>")
548
+ else
549
+ o_read
550
+ end
551
+ end
552
+ end
553
+ current_obj = create_or_update_node(attrs.merge(:c_file => file, :klass => 'Document', :_parent_id => parent_id))
554
+ end
555
+ document_path = nil
556
+ else
557
+ current_obj = create_or_update_node(attrs.merge(:_parent_id => parent_id, :klass => 'Document'))
558
+ end
559
+ else
560
+ # :folder, :node
561
+ current_obj = create_or_update_node(attrs.merge(:_parent_id => parent_id))
562
+ end
563
+ new_object = new_object || current_obj.instance_variable_get(:@new_record_before_save)
564
+ end
565
+ current_obj.instance_variable_set(:@new_record_before_save, new_object)
566
+
567
+ current_obj.instance_variable_set(:@versions_count, versions.size)
568
+ res[current_obj[:id].to_i] = current_obj
569
+
570
+ res.merge!(create_nodes_from_folder(:folder => sub_folder, :parent_id => current_obj[:id], :defaults => defaults, :parent_class => opts[:klass])) if sub_folder && !current_obj.new_record?
571
+ end
572
+ res
573
+ end
574
+
575
+ def find_by_zip(zip)
576
+ node = find(:first, :conditions=>"zip = #{zip.to_i}")
577
+ raise ActiveRecord::RecordNotFound unless node
578
+ node
579
+ end
580
+
581
+ # Find a node by it's full path. Cache 'fullpath' if found.
582
+ def find_by_path(path)
583
+ return nil unless scope = scoped_methods[0]
584
+ return nil unless scope[:find] # not secured find. refuse.
585
+ node = self.find_by_fullpath(path)
586
+ if node.nil?
587
+ path = path.split('/')
588
+ last = path.pop
589
+ # FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
590
+ Node.send(:with_exclusive_scope) do
591
+ node = Node.find(current_site[:root_id])
592
+ path.each do |p|
593
+ raise ActiveRecord::RecordNotFound unless node = Node.find_by_name_and_parent_id(p, node[:id])
594
+ end
595
+ end
596
+ raise ActiveRecord::RecordNotFound unless node = self.find_by_name_and_parent_id(last, node[:id])
597
+ path << last
598
+ node.fullpath = path.join('/')
599
+ # bypass callbacks here
600
+ Node.connection.execute "UPDATE #{Node.table_name} SET fullpath='#{path.join('/').gsub("'",'"')}' WHERE id='#{node[:id]}'"
601
+ end
602
+ node
603
+ end
604
+
605
+ # Paginate found results. Returns [previous_page, collection, next_page]. You can specify page and items per page in the query hash :
606
+ # :page => 1, :per_page => 20. This should be wrapped into a secure scope.
607
+ def find_with_pagination(count, opts)
608
+ previous_page, collection, next_page, count_all = nil, [], nil, nil
609
+ per_page = (opts.delete(:per_page) || 20).to_i
610
+ page = opts.delete(:page) || 1
611
+ page = page > 0 ? page.to_i : 1
612
+ offset = (page - 1) * per_page
613
+
614
+ if opts[:group]
615
+ count_select = "DISTINCT #{opts[:group]}"
616
+ else
617
+ count_select = opts.delete(:count) || 'nodes.id'
618
+ end
619
+
620
+ # FIXME: why do we need 'exclusive scope' here ?
621
+ with_exclusive_scope(self.scoped_methods[0] || {}) do
622
+ count_all = count(opts.merge( :select => count_select, :order => nil, :group => nil ))
623
+ if count_all > offset
624
+ collection = find(count, opts.merge(:offset => offset, :limit => per_page))
625
+ if count_all > (offset + per_page)
626
+ next_page = page + 1
627
+ end
628
+ previous_page = page > 1 ? (page - 1) : nil
629
+ else
630
+ # offset too big, previous page = last page
631
+ previous_page = page > 1 ? ((count_all + per_page - 1) / per_page) : nil
632
+ end
633
+ end
634
+ [previous_page, collection, next_page, count_all]
635
+ end
636
+
637
+ # Return a hash to do a fulltext query.
638
+ def match_query(query, opts={})
639
+ node = opts.delete(:node)
640
+ if query == '.' && node
641
+ return opts.merge(
642
+ :conditions => ["parent_id = ?",node[:id]],
643
+ :order => 'name ASC' )
644
+ elsif !query.blank?
645
+ if Zena::Db.adapter == 'mysql' && RAILS_ENV != 'test'
646
+ match = sanitize_sql(["MATCH (vs.title,vs.text,vs.summary) AGAINST (?) OR nodes.name LIKE ?", query, "#{opts[:name_query] || query.url_name}%"])
647
+ select = sanitize_sql(["nodes.*, MATCH (vs.title,vs.text,vs.summary) AGAINST (?) + (5 * (nodes.name LIKE ?)) AS score", query, "#{query}%"])
648
+ else
649
+ match = sanitize_sql(["nodes.name LIKE ?", "#{query}%"])
650
+ select = "nodes.*, #{match} AS score"
651
+ end
652
+
653
+ return opts.merge(
654
+ :select => select,
655
+ :joins => "INNER JOIN versions AS vs ON vs.node_id = nodes.id AND vs.status >= #{Zena::Status[:pub]}",
656
+ :conditions => match,
657
+ :group => "nodes.id",
658
+ :order => "score DESC, zip ASC")
659
+ else
660
+ # error
661
+ return opts.merge(:conditions => '0')
662
+ end
663
+ end
664
+
665
+ # FIXME: Where is this used ?
666
+ def class_for_relation(rel)
667
+ case rel
668
+ when 'author'
669
+ User
670
+ when 'traductions'
671
+ Version
672
+ when 'versions'
673
+ Version
674
+ else
675
+ Node
676
+ end
677
+ end
678
+
679
+ def plural_relation?(rel)
680
+ rel = rel.split(/\s/).first
681
+ if ['root', 'parent', 'self', 'children', 'documents_only', 'all_pages'].include?(rel) || Node.get_class(rel)
682
+ rel.pluralize == rel
683
+ elsif rel =~ /\A\d+\Z/
684
+ false
685
+ else
686
+ relation = RelationProxy.find_by_role(rel.singularize)
687
+ return rel =~ /s$/ unless relation
688
+ relation.target_role == rel.singularize ? !relation.target_unique : !relation.source_unique
689
+ end
690
+ end
691
+
692
+ # Translate attributes from the visitor's reference to the application.
693
+ # This method translates dates, zazen shortcuts and zips and returns a stringified hash.
694
+ def transform_attributes(new_attributes, base_node = nil)
695
+ res = {}
696
+ res['parent_id'] = new_attributes[:_parent_id] if new_attributes[:_parent_id] # real id set inside zena.
697
+
698
+ attributes = new_attributes.stringify_keys
699
+
700
+ if attributes['copy'] || attributes['copy_id']
701
+ copy_node = attributes.delete('copy')
702
+ copy_node ||= Node.find_by_zip(attributes.delete('copy_id'))
703
+ attributes = copy_node.replace_attributes_in_values(attributes)
704
+ end
705
+
706
+ if !res['parent_id'] && p = attributes['parent_id']
707
+ res['parent_id'] = Node.translate_pseudo_id(p, :id, base_node) || p
708
+ end
709
+
710
+ attributes.keys.each do |key|
711
+ next if ['_parent_id', 'parent_id'].include?(key)
712
+
713
+ if ['rgroup_id', 'wgroup_id', 'dgroup_id'].include?(key)
714
+ res[key] = Group.translate_pseudo_id(attributes[key], :id) || attributes[key]
715
+ elsif ['rgroup', 'wgroup', 'dgroup'].include?(key)
716
+ res["#{key}_id"] = Group.translate_pseudo_id(attributes[key], :id) || attributes[key]
717
+ elsif ['user_id'].include?(key)
718
+ res[key] = User.translate_pseudo_id(attributes[key], :id) || attributes[key]
719
+ elsif ['date'].include?(key)
720
+ # FIXME: this is a temporary hack because date in links do not support timezones/formats properly
721
+ if attributes[key].kind_of?(Time)
722
+ res[key] = attributes[key]
723
+ elsif attributes[key]
724
+ # parse date
725
+ res[key] = attributes[key].to_utc("%Y-%m-%d %H:%M:%S")
726
+ end
727
+ elsif key =~ /^(\w+)_id$/
728
+ if key[0..1] == 'd_'
729
+ res[key] = Node.translate_pseudo_id(attributes[key], :zip, base_node) || attributes[key]
730
+ else
731
+ res[key] = Node.translate_pseudo_id(attributes[key], :id, base_node) || attributes[key]
732
+ end
733
+ elsif key =~ /^(\w+)_ids$/
734
+ # Id list. Bad ids are removed.
735
+ values = attributes[key].kind_of?(Array) ? attributes[key] : attributes[key].split(',')
736
+ if key[0..1] == 'd_'
737
+ values.map! {|v| Node.translate_pseudo_id(v, :zip, base_node) }
738
+ else
739
+ values.map! {|v| Node.translate_pseudo_id(v, :id, base_node) }
740
+ end
741
+ res[key] = values.compact
742
+ elsif key == 'file'
743
+ unless attributes[key].blank?
744
+ res[key] = attributes[key]
745
+ end
746
+ elsif attributes[key].kind_of?(Hash)
747
+ res[key] = transform_attributes(attributes[key], base_node)
748
+ else
749
+ # translate zazen
750
+ value = attributes[key]
751
+ if value.kind_of?(String)
752
+ # FIXME: ignore if 'v_text' of a TextDocument...
753
+ res[key] = ZazenParser.new(value,:helper=>self).render(:translate_ids=>:zip, :node=>base_node)
754
+ else
755
+ res[key] = value
756
+ end
757
+ end
758
+ end
759
+
760
+ res
761
+ end
762
+
763
+ def get_attributes_from_yaml(filepath, base_node = nil)
764
+ attributes = YAML::load( File.read( filepath ) )
765
+ attributes.delete(:_parent_id)
766
+ transform_attributes(attributes, base_node)
767
+ end
768
+
769
+ def safe_method_type(signature)
770
+ if signature.size > 1
771
+ RubyLess::SafeClass.safe_method_type_for(self, signature)
772
+ else
773
+ method = signature.first
774
+ # if model_names = nested_model_names_for_alias(method)
775
+ # # ...
776
+ # end
777
+ case method[0..1]
778
+ when 'v_'
779
+ method = method[2..-1]
780
+ if type = version_class.safe_method_type([method])
781
+ type.merge(:method => "version.#{type[:method]}")
782
+ else
783
+ # might be readable by sub-classes
784
+ # what is the expected return type ?
785
+ {:method => "version.safe_read(#{method.inspect})", :nil => true, :class => String}
786
+ end
787
+ when 'c_'
788
+ method = method[2..-1]
789
+ klass = version_class.content_class
790
+ if klass && type = klass.safe_method_type([method])
791
+ type.merge(:method => "version.content.#{type[:method]}")
792
+ else
793
+ {:method => "version.safe_content_read(#{method.inspect})", :nil => true, :class => String}
794
+ end
795
+ when 'd_'
796
+ {:method => "version.dyn[#{method[2..-1].inspect}]", :nil => true, :class => String}
797
+ else
798
+ if method =~ /^(.+)_((id|zip|status|comment)(s?))\Z/ && !instance_methods.include?(method)
799
+ {:method => "rel[#{$1.inspect}].try(:other_#{$2})", :nil => true, :class => ($4.blank? ? Number : [Number])}
800
+ else
801
+ RubyLess::SafeClass.safe_method_type_for(self, signature)
802
+ end
803
+ end
804
+ end
805
+ end
806
+
807
+ # Return a safe string to access node attributes in compiled templates and compiled sql.
808
+ def zafu_attribute(node, attribute)
809
+ if node.kind_of?(String)
810
+ raise Exception.new("You should use safe_method_type...")
811
+ else
812
+ node.safe_read(attribute)
813
+ end
814
+ end
815
+
816
+
817
+ def auto_create_discussion
818
+ false
819
+ end
820
+ end
821
+
822
+ # TODO: remove when :inverse_of works.
823
+ def versions_with_secure(*args)
824
+ proxy = versions_without_secure(*args)
825
+ if frozen?
826
+ proxy = []
827
+ elsif proxy.loaded?
828
+ proxy.each do |v|
829
+ v.node = self
830
+ end
831
+ end
832
+ proxy
833
+ end
834
+ alias_method_chain :versions, :secure
835
+
836
+ # Additional security so that unsecure finders explode when trying to update/save or follow relations.
837
+ def visitor
838
+ return @visitor if @visitor
839
+ # We need to be more tolerant during object creation since 'v_foo' can be
840
+ # set before 'visitor' and we need visitor.lang when creating versions.
841
+ return Thread.current.visitor if new_record?
842
+ raise Zena::RecordNotSecured.new("Visitor not set, record not secured.")
843
+ end
844
+
845
+ # Return an attribute if it is safe (RubyLess allowed). Return nil otherwise.
846
+ # This is mostly used when the zafu compiler cannot decide whether a method is safe or not at compile time.
847
+ def safe_read(attribute)
848
+ case attribute[0..1]
849
+ when 'v_'
850
+ version.safe_read(attribute[2..-1])
851
+ when 'c_'
852
+ version.safe_content_read(attribute[2..-1])
853
+ when 'd_'
854
+ version.dyn[attribute[2..-1]]
855
+ else
856
+ if @attributes.has_key?(attribute) &&
857
+ !self.class.column_names.include?(attribute) &&
858
+ !methods.include?(attribute) &&
859
+ !self.class.safe_method_type([attribute])
860
+ # db fetch only: select 'created_at AS age' ----> 'age' can be read
861
+ @attributes[attribute]
862
+ else
863
+ super
864
+ end
865
+ end
866
+ end
867
+
868
+ # check inheritance chain through kpath
869
+ def kpath_match?(kpath)
870
+ vclass.kpath =~ /^#{kpath}/
871
+ end
872
+
873
+ # virtual class
874
+ def vclass
875
+ virtual_class || self.class
876
+ end
877
+
878
+ def klass
879
+ @new_klass || @set_klass || vclass.to_s
880
+ end
881
+
882
+ def dyn_attribute_keys
883
+ (version.dyn.keys + (virtual_class ? virtual_class.dyn_keys.to_s.split(',').map(&:strip) : [])).uniq.sort
884
+ end
885
+
886
+ def klass=(str)
887
+ return if str == klass
888
+ @new_klass = str
889
+ end
890
+
891
+ # include virtual classes to check inheritance chain
892
+ def vkind_of?(klass)
893
+ if self.class.ancestors.map{|k| k.to_s}.include?(klass)
894
+ true
895
+ elsif virt = VirtualClass.find(:first, :conditions=>["site_id = ? AND name = ?",current_site[:id], klass])
896
+ kpath_match?(virt.kpath)
897
+ end
898
+ end
899
+
900
+ # Update a node's attributes, transforming the attributes first from the visitor's context to Node context.
901
+ def update_attributes_with_transformation(new_attributes)
902
+ update_attributes(secure(Node) {Node.transform_attributes(new_attributes, self)})
903
+ end
904
+
905
+ # Replace [id], [v_title], etc in attributes values
906
+ def replace_attributes_in_values(hash)
907
+ hash.each do |k,v|
908
+ v.gsub!(/\[([^\]]+)\]/) do
909
+ attribute = $1
910
+ real_attribute = attribute =~ /\Ad_/ ? attribute : attribute.gsub(/\A(|[\w_]+)id(s?)\Z/, '\1zip\2')
911
+ Node.zafu_attribute(self, real_attribute)
912
+ end
913
+ end
914
+ end
915
+
916
+
917
+ # Parse text content and replace all relative urls ('../projects/art') by ids ('34')
918
+ def parse_assets(text, helper, key)
919
+ # helper is used in textdocuments
920
+ ZazenParser.new(text,:helper=>helper).render(:translate_ids => :zip, :node => self)
921
+ end
922
+
923
+ # Parse text and replace ids '!30!' by their pseudo path '!(img/bird)!'
924
+ def unparse_assets(text, helper, key)
925
+ ZazenParser.new(text,:helper=>helper).render(:translate_ids => :relative_path, :node=>self)
926
+ end
927
+
928
+ # Return the list of ancestors (without self): [root, obj, obj]
929
+ # ancestors to which the visitor has no access are removed from the list
930
+ def ancestors(start=[])
931
+ raise Zena::InvalidRecord, "Infinit loop in 'ancestors' (#{start.inspect} --> #{self[:id]})" if start.include?(self[:id])
932
+ start += [self[:id]]
933
+ if self[:id] == current_site[:root_id]
934
+ []
935
+ elsif self[:parent_id].nil?
936
+ []
937
+ else
938
+ parent = @parent || Node.find(self[:parent_id])
939
+ parent.visitor = visitor
940
+ if parent.can_read?
941
+ parent.ancestors(start) + [parent]
942
+ else
943
+ parent.ancestors(start)
944
+ end
945
+ end
946
+ end
947
+
948
+
949
+ # Return the same basepath as the parent. Is overwriten by 'Page' class.
950
+ def basepath(rebuild=false, update= true)
951
+ if !self[:basepath] || rebuild
952
+ if self[:parent_id]
953
+ parent = parent(false)
954
+ path = parent ? parent.basepath(rebuild) : ''
955
+ else
956
+ path = ''
957
+ end
958
+ self.connection.execute "UPDATE #{self.class.table_name} SET basepath='#{path}' WHERE id='#{self[:id]}'" if path != self[:basepath] && update
959
+ self[:basepath] = path
960
+ end
961
+ self[:basepath]
962
+ end
963
+
964
+ # Return the full path as an array if it is cached or build it when asked for.
965
+ def fullpath(rebuild=false, update = true, loop_ids = [])
966
+ return "" if loop_ids.include?(self.id)
967
+ loop_ids << self.id
968
+ if !self[:fullpath] || rebuild
969
+ if parent = parent(false)
970
+ path = parent.fullpath(rebuild,true,loop_ids).split('/') + [name.gsub("'",'')]
971
+ else
972
+ path = []
973
+ end
974
+ path = path.join('/')
975
+ self.connection.execute "UPDATE #{self.class.table_name} SET fullpath='#{path}' WHERE id='#{self[:id]}'" if path != self[:fullpath] && update
976
+ self[:fullpath] = path
977
+ end
978
+ self[:fullpath]
979
+ end
980
+
981
+ # Same as fullpath, but the path includes the root node.
982
+ def rootpath
983
+ current_site.name + (fullpath != "" ? "/#{fullpath}" : "")
984
+ end
985
+
986
+ alias path rootpath
987
+
988
+ # Return an array with the node name and the last two parents' names.
989
+ def short_path
990
+ path = self.rootpath.split('/')
991
+ if path.size > 2
992
+ ['..'] + path[-2..-1]
993
+ else
994
+ path
995
+ end
996
+ end
997
+
998
+ def pseudo_id(root_node, sym)
999
+ case sym
1000
+ when :zip
1001
+ self.zip
1002
+ when :relative_path
1003
+ full = self.fullpath
1004
+ root = root_node ? root_node.fullpath : ''
1005
+ "(#{full.rel_path(root)})"
1006
+ end
1007
+ end
1008
+
1009
+ # Return save path for an asset (element produced by text like a png file from LateX)
1010
+ def asset_path(asset_filename)
1011
+ # It would be nice to move this outside 'self[:id]' so that the same asset can
1012
+ # be used by many pages... But then, how do we expire unused assets ?
1013
+ "#{SITES_ROOT}#{site.data_path}/asset/#{self[:id]}/#{asset_filename}"
1014
+ end
1015
+
1016
+ # Used by zafu to find the search score
1017
+ # def score
1018
+ # self[:score]
1019
+ # end
1020
+
1021
+ def all_relations
1022
+ @all_relations ||= self.vclass.all_relations(self)
1023
+ end
1024
+
1025
+ # Find parent
1026
+ def parent(is_secure = true)
1027
+ # make sure the cache is in sync with 'parent_id' (used during validation)
1028
+ if self[:parent_id].nil?
1029
+ nil
1030
+ elsif is_secure
1031
+ # cache parent result (done through secure query)
1032
+ return @parent if @parent && @parent[:id] == self[:parent_id]
1033
+ @parent = secure(Node) { Node.find(self[:parent_id]) }
1034
+ else
1035
+ # not secured (inside an exclusive scope)
1036
+ return @parent_insecure if @parent_insecure && @parent_insecure[:id] == self[:parent_id]
1037
+ @parent_insecure = secure(Node, :secure => false) { Node.find(self[:parent_id]) }
1038
+ end
1039
+ end
1040
+
1041
+ # Return self if the current node is a section else find section.
1042
+ def section
1043
+ self.kind_of?(Section) ? self : real_section
1044
+ end
1045
+
1046
+ # Find real section
1047
+ def real_section(is_secure = true)
1048
+ return self if self[:parent_id].nil? # root
1049
+ # we cannot use Section to find because the root node behaves like a Section but is a Project.
1050
+ if is_secure
1051
+ secure(Node) { Node.find(self[:section_id]) }
1052
+ else
1053
+ secure(Node, :secure => false) { Node.find(self[:section_id]) }
1054
+ end
1055
+ end
1056
+
1057
+ # Return self if the current node is a project else find project.
1058
+ def project
1059
+ self.kind_of?(Project) ? self : real_project
1060
+ end
1061
+
1062
+ # Find real project (Project's project if node is a Project)
1063
+ def real_project(is_secure = true)
1064
+ return self if self[:parent_id].nil?
1065
+ if is_secure
1066
+ secure(Project) { Project.find(self[:project_id]) }
1067
+ else
1068
+ secure(Node, :secure => false) { Project.find(self[:project_id]) }
1069
+ end
1070
+ end
1071
+
1072
+ # Create a child and let him inherit from rwp groups and section_id
1073
+ def new_child(opts={})
1074
+ klass = opts.delete(:class) || Page
1075
+ c = klass.new(opts)
1076
+ c.parent_id = self[:id]
1077
+ c.instance_variable_set(:@parent, self)
1078
+
1079
+ c.visitor = visitor
1080
+
1081
+ c.inherit = 1
1082
+ c.rgroup_id = self.rgroup_id
1083
+ c.wgroup_id = self.wgroup_id
1084
+ c.dgroup_id = self.dgroup_id
1085
+
1086
+ c.section_id = self.get_section_id
1087
+ c.project_id = self.get_project_id
1088
+ c
1089
+ end
1090
+
1091
+ # ACCESSORS
1092
+ def author
1093
+ user.contact
1094
+ end
1095
+
1096
+ # Find icon through a relation named 'icon' or use first image child
1097
+ def icon
1098
+ return nil if new_record?
1099
+ return @icon if defined? @icon
1100
+ query = Node.build_find(:first, ['icon group by id,l_id order by l_id desc, position asc, name asc', 'image'], :node_name => 'self')
1101
+ sql_str, uses_node_name = query.to_s, query.uses_node_name
1102
+ @icon = sql_str ? do_find(:first, eval(sql_str), :ignore_source => !uses_node_name) : nil
1103
+ end
1104
+
1105
+ alias o_user user
1106
+
1107
+ def user
1108
+ secure!(User) { o_user }
1109
+ end
1110
+
1111
+ # Find all data entries linked to the current node
1112
+ def data
1113
+ list = DataEntry.find(:all, :conditions => "node_a_id = #{id} OR node_b_id = #{id} OR node_c_id = #{id} OR node_d_id = #{id}", :order => 'date ASC,created_at ASC')
1114
+ list == [] ? nil : list
1115
+ end
1116
+
1117
+ if Node.connection.tables.include?('data_entries')
1118
+ # We need this guard during initial migration (Node loaded before data entries table is created).
1119
+ # FIXME: remove in [1.1] when we 'squash' all migrations
1120
+
1121
+ DataEntry::NodeLinkSymbols.each do |sym|
1122
+ # Find data entries through a specific slot (node_a, node_b). "data_entries_a" finds all data entries link through 'node_a_id'.
1123
+ class_eval "def #{sym.to_s.gsub('node', 'data')}
1124
+ return nil if new_record?
1125
+ list = DataEntry.find(:all, :conditions=>\"#{sym}_id = '\#{self[:id]}'\")
1126
+ list == [] ? nil : list
1127
+ end"
1128
+ end
1129
+ end
1130
+
1131
+ def ext
1132
+ (name && name != '' && name =~ /\./ ) ? name.split('.').last : ''
1133
+ end
1134
+
1135
+ # set name: remove all accents and camelize
1136
+ def name=(str)
1137
+ return unless str && str != ""
1138
+ self[:name] = str.url_name
1139
+ end
1140
+
1141
+ # Return current discussion id (used by query_builder)
1142
+ def get_discussion_id
1143
+ (discussion && !discussion.new_record?) ? discussion[:id] : '0'
1144
+ end
1145
+
1146
+ # Return self[:id] if the node is a kind of Section. Return section_id otherwise.
1147
+ def get_section_id
1148
+ # root node is it's own section and project
1149
+ self[:parent_id].nil? ? self[:id] : self[:section_id]
1150
+ end
1151
+
1152
+ # Return self[:id] if the node is a kind of Project. Return project_id otherwise.
1153
+ def get_project_id
1154
+ # root node is it's own section and project
1155
+ self[:parent_id].nil? ? self[:id] : self[:project_id]
1156
+ end
1157
+
1158
+ # Id to zip mapping for parent_id. Used by zafu and forms.
1159
+ def parent_zip
1160
+ parent ? parent[:zip] : nil
1161
+ end
1162
+
1163
+ # Id to zip mapping for section_id. Used by zafu and forms.
1164
+ def section_zip
1165
+ section[:zip]
1166
+ end
1167
+
1168
+ # Id to zip mapping for project_id. Used by zafu and forms.
1169
+ def project_zip
1170
+ project[:zip]
1171
+ end
1172
+
1173
+ # Id to zip mapping for user_id. Used by zafu and forms.
1174
+ def user_zip; self[:user_id]; end
1175
+
1176
+ # transform to another class
1177
+ # def vclass=(new_class)
1178
+ # if new_class.kind_of?(String)
1179
+ # klass = Module.const_get(new_class)
1180
+ # else
1181
+ # klass = new_class
1182
+ # end
1183
+ # raise NameError if !klass.ancestors.include?(Node) || klass.version_class != self.class.content_class
1184
+ #
1185
+ #
1186
+ #
1187
+ # rescue NameError
1188
+ # errors.add('klass', 'invalid')
1189
+ # end
1190
+
1191
+ # transform an Node into another Object. This is a two step operation :
1192
+ # 1. create a new object with the attributes from the old one
1193
+ # 2. move old object out of the way (setting parent_id and section_id to -1)
1194
+ # 3. try to save new object
1195
+ # 4. delete old and set new object id to old
1196
+ # THIS IS DANGEROUS !! NEEDS TESTING
1197
+ # def change_to(klass)
1198
+ # return nil if self[:id] == current_site[:root_id]
1199
+ # # ==> Check for class specific information (file to remove, participations, tags, etc) ... should we leave these things and
1200
+ # # not care ?
1201
+ # # ==> When changing into something else : update version type and data !!!
1202
+ # my_id = self[:id].to_i
1203
+ # my_parent = self[:parent_id].to_i
1204
+ # my_project = self[:section_id].to_i
1205
+ # connection = self.class.connection
1206
+ # # 1. create a new object with the attributes from the old one
1207
+ # new_obj = secure!(klass) { klass.new(self.attributes) }
1208
+ # # 2. move old object out of the way (setting parent_id and section_id to -1)
1209
+ # self.class.connection.execute "UPDATE #{self.class.table_name} SET parent_id='0', section_id='0' WHERE id=#{my_id}"
1210
+ # # 3. try to save new object
1211
+ # if new_obj.save
1212
+ # tmp_id = new_obj[:id]
1213
+ # # 4. delete old and set new object id to old. Delete tmp Version.
1214
+ # self.class.connection.execute "DELETE FROM #{self.class.table_name} WHERE id=#{my_id}"
1215
+ # self.class.connection.execute "DELETE FROM #{Version.table_name} WHERE node_id=#{tmp_id}"
1216
+ # self.class.connection.execute "UPDATE #{self.class.table_name} SET id='#{my_id}' WHERE id=#{tmp_id}"
1217
+ # self.class.connection.execute "UPDATE #{self.class.table_name} SET section_id=id WHERE id=#{my_id}" if new_obj.kind_of?(Section)
1218
+ # self.class.logger.info "[#{self[:id]}] #{self.class} --> #{klass}"
1219
+ # if new_obj.kind_of?(Section)
1220
+ # # update section_id for children
1221
+ # sync_section(my_id)
1222
+ # elsif self.kind_of?(Section)
1223
+ # # update section_id for children
1224
+ # sync_section(parent[:section_id])
1225
+ # end
1226
+ # secure ( klass ) { klass.find(my_id) }
1227
+ # else
1228
+ # # set object back
1229
+ # self.class.connection.execute "UPDATE #{self.class.table_name} SET parent_id='#{my_parent}', section_id='#{my_project}' WHERE id=#{my_id}"
1230
+ # self
1231
+ # end
1232
+ # end
1233
+
1234
+ # Find the discussion for the current context (v_status and v_lang). This automatically creates a new #Discussion if there is
1235
+ # no closed or open discussion for the current lang and Node#can_auto_create_discussion? is true
1236
+ def discussion
1237
+ return @discussion if defined?(@discussion)
1238
+
1239
+ @discussion = Discussion.find(:first, :conditions=>[ "node_id = ? AND inside = ? AND lang = ?",
1240
+ self[:id], v_status != Zena::Status[:pub], v_lang ], :order=>'id DESC') ||
1241
+ if can_auto_create_discussion?
1242
+ Discussion.new(:node_id=>self[:id], :lang=>v_lang, :inside=>(v_status != Zena::Status[:pub]))
1243
+ else
1244
+ nil
1245
+ end
1246
+ end
1247
+
1248
+ # Automatically create a discussion if any of the following conditions are met:
1249
+ # - there already exists an +outside+, +open+ discussion for another language
1250
+ # - the node is not published (creates an internal discussion)
1251
+ # - the user has drive access to the node
1252
+ def can_auto_create_discussion?
1253
+ can_drive? ||
1254
+ (v_status != Zena::Status[:pub]) ||
1255
+ Discussion.find(:first, :conditions=>[ "node_id = ? AND inside = ? AND open = ?",
1256
+ self[:id], false, true ])
1257
+ end
1258
+
1259
+ # FIXME: use nested_attributes_alias and try to use native Rails to create the comment
1260
+ # comment_attributes=, ...
1261
+ def m_text; ''; end
1262
+ def m_title; ''; end
1263
+ def m_author; ''; end
1264
+
1265
+ def m_text=(str)
1266
+ @add_comment ||= {}
1267
+ @add_comment[:text] = str
1268
+ end
1269
+
1270
+ def m_title=(str)
1271
+ @add_comment ||= {}
1272
+ @add_comment[:title] = str
1273
+ end
1274
+
1275
+ def m_author=(str)
1276
+ @add_comment ||= {}
1277
+ @add_comment[:author] = str
1278
+ end
1279
+
1280
+ # Comments for the current context. Returns nil when there is no discussion.
1281
+ def comments
1282
+ if discussion
1283
+ res = discussion.comments(:with_prop=>can_drive?)
1284
+ res == [] ? nil : res
1285
+ else
1286
+ nil
1287
+ end
1288
+ end
1289
+
1290
+ # TODO: remove, replace by relation proxy: proxy.count...
1291
+ def comments_count
1292
+ if discussion
1293
+ discussion.comments_count(:with_prop=>can_drive?)
1294
+ else
1295
+ 0
1296
+ end
1297
+ end
1298
+
1299
+ # Return true if it is allowed to add comments to the node in the current context
1300
+ def can_comment?
1301
+ visitor.commentator? && discussion && discussion.open?
1302
+ end
1303
+
1304
+ # TODO: test
1305
+ def sweep_cache
1306
+ return if current_site.being_created?
1307
+ # zafu 'erb' rendering cache expire
1308
+ # TODO: expire only 'dev' rendering if version is a redaction
1309
+ CachedPage.expire_with(self) if self.kind_of?(Template)
1310
+
1311
+ # Clear element cache
1312
+ Cache.sweep(:visitor_id=>self[:user_id], :visitor_groups=>[rgroup_id, wgroup_id, dgroup_id], :kpath=>self.vclass.kpath)
1313
+
1314
+ # Clear full result cache
1315
+
1316
+ # we want to be sure to find the project and parent, even if the visitor does not have an
1317
+ # access to these elements.
1318
+ # FIXME: use self + modified relations instead of parent/project
1319
+ [self, self.real_project(false), self.real_section(false), self.parent(false)].compact.uniq.each do |obj|
1320
+ # destroy all pages in project, parent and section !
1321
+ CachedPage.expire_with(obj)
1322
+ # this destroys less cache but might miss things like 'changes in project' that are displayed on every page.
1323
+ # CachedPage.expire_with(self, [self[:project_id], self[:section_id], self[:parent_id]].compact.uniq)
1324
+ end
1325
+
1326
+ # clear assets
1327
+ FileUtils::rmtree(asset_path(''))
1328
+ end
1329
+
1330
+ # Include data entry verification in multiversion's empty? method.
1331
+ def empty?
1332
+ return true if new_record?
1333
+ super && 0 == self.class.count_by_sql("SELECT COUNT(*) FROM #{DataEntry.table_name} WHERE node_a_id = #{id} OR node_b_id = #{id} OR node_c_id = #{id} OR node_d_id = #{id}")
1334
+ end
1335
+
1336
+ # create a 'tgz' archive with node content and children, returning temporary file path
1337
+ def archive
1338
+ n = 0
1339
+ while true
1340
+ folder_path = File.join(RAILS_ROOT, 'tmp', sprintf('%s.%d.%d', 'archive', $$, n))
1341
+ break unless File.exists?(folder_path)
1342
+ end
1343
+
1344
+ begin
1345
+ FileUtils::mkpath(folder_path)
1346
+ export_to_folder(folder_path)
1347
+ tempf = Tempfile.new(name)
1348
+ `cd #{folder_path}; tar czf #{tempf.path} *`
1349
+ ensure
1350
+ FileUtils::rmtree(folder_path)
1351
+ end
1352
+ tempf
1353
+ end
1354
+
1355
+ # export node content and children into a folder
1356
+ def export_to_folder(path)
1357
+ children = secure(Node) { Node.find(:all, :conditions=>['parent_id = ?', self[:id] ]) }
1358
+
1359
+ if kind_of?(Document) && version.title == name && (kind_of?(TextDocument) || version.text.blank? || version.text == "!#{zip}!")
1360
+ # skip zml
1361
+ # TODO: this should better check that version content is really useless
1362
+ elsif version.title == name && version.text.blank? && klass == 'Page' && children
1363
+ # skip zml
1364
+ else
1365
+ File.open(File.join(path, name + '.zml'), 'wb') do |f|
1366
+ f.puts self.to_yaml
1367
+ end
1368
+ end
1369
+
1370
+ if kind_of?(Document)
1371
+ data = kind_of?(TextDocument) ? StringIO.new(version.text) : version.content.file
1372
+ File.open(File.join(path, filename), 'wb') { |f| f.syswrite(data.read) }
1373
+ end
1374
+
1375
+ if children
1376
+ content_folder = File.join(path,name)
1377
+ FileUtils::mkpath(content_folder)
1378
+ children.each do |child|
1379
+ child.export_to_folder(content_folder)
1380
+ end
1381
+ end
1382
+ end
1383
+
1384
+ # export node as a hash
1385
+ def to_yaml
1386
+ hash = {}
1387
+ export_keys[:zazen].each do |k, v|
1388
+ hash[k] = unparse_assets(v, self, k)
1389
+ end
1390
+
1391
+ export_keys[:dates].each do |k, v|
1392
+ hash[k] = visitor.tz.utc_to_local(v).strftime("%Y-%m-%d %H:%M:%S")
1393
+ end
1394
+
1395
+ hash.merge!('class' => self.klass)
1396
+ hash.to_yaml
1397
+ end
1398
+
1399
+ # List of attribute keys to export in a zml file.
1400
+ def export_keys
1401
+ {
1402
+ :zazen => version.export_keys[:zazen],
1403
+ :dates => version.export_keys[:dates],
1404
+ }
1405
+ end
1406
+
1407
+ # List of attribute keys to transform (change references, etc).
1408
+ def parse_keys
1409
+ export_keys[:zazen].keys
1410
+ end
1411
+
1412
+ # This is needed during 'unparse_assets' when the node is it's own helper
1413
+ def find_node_by_pseudo(string, base_node = nil)
1414
+ secure(Node) { Node.find_node_by_pseudo(string, base_node || self) }
1415
+ end
1416
+
1417
+ protected
1418
+
1419
+ # after node is saved, make sure it's children have the correct section set
1420
+ def spread_project_and_section
1421
+ if @spread_section_id || @spread_project_id
1422
+ # update children
1423
+ sync_section_and_project(@spread_section_id, @spread_project_id)
1424
+ remove_instance_variable :@spread_section_id if @spread_section_id
1425
+ remove_instance_variable :@spread_project_id if @spread_project_id
1426
+ end
1427
+ end
1428
+
1429
+ # node [change project and section]
1430
+ # |
1431
+ # +-- node [set project] [set section]
1432
+ # |
1433
+ # +-- section 4 [set project] [ keep ]
1434
+ # | |
1435
+ # | +-- node [set project] [ keep ]
1436
+ # | |
1437
+ # | +-- project [ keep ] [ keep ] => skip
1438
+ # |
1439
+ # +-- page [set project] [set section]
1440
+ # |
1441
+ # +-- project [ keep ] [set section]
1442
+ # |
1443
+ # +-- node [ keep ] [set section]
1444
+ # |
1445
+ # +-- section [ keep ] [ keep ] => skip
1446
+ def sync_section_and_project(section_id, project_id)
1447
+
1448
+ # If this code is optimized, do not forget to sweep_cache for each modified child.
1449
+ all_children.each do |child|
1450
+ if child.kind_of?(Section) # [keep section] [set project]
1451
+ next unless project_id # => skip
1452
+ # needed when doing 'sweep_cache'.
1453
+ visitor.visit(child)
1454
+
1455
+ child[:project_id] = project_id # [set project]
1456
+ child.save_with_validation(false)
1457
+ child.sync_section_and_project( nil , project_id)
1458
+
1459
+ elsif child.kind_of?(Project) # [set section] [keep project]
1460
+ next unless section_id # => skip
1461
+ # needed when doing 'sweep_cache'.
1462
+ visitor.visit(child)
1463
+
1464
+ child[:section_id] = section_id # [set section]
1465
+ child.save_with_validation(false)
1466
+ child.sync_section_and_project(section_id, nil )
1467
+ else # [set section] [set project]
1468
+ # needed when doing 'sweep_cache'.
1469
+ visitor.visit(child)
1470
+
1471
+ child[:section_id] = section_id if section_id #[set section]
1472
+ child[:project_id] = project_id if project_id # [set project]
1473
+ child.save_with_validation(false)
1474
+ child.sync_section_and_project(section_id, project_id)
1475
+ end
1476
+ end
1477
+ end
1478
+
1479
+ private
1480
+ def node_before_validation
1481
+ self[:kpath] = self.vclass.kpath
1482
+
1483
+ self.name ||= (version.title || '').url_name
1484
+
1485
+ if ref_lang == version.lang &&
1486
+ ((full_drive? && version.status == Zena::Status[:pub]) ||
1487
+ (can_drive? && vhash['r'][ref_lang].nil?))
1488
+ if name_changed? && !name.blank?
1489
+ version.title = self.name.gsub(/([A-Z])/) { " #{$1.downcase}" }
1490
+ elsif !version.title.blank?
1491
+ self.name = version.title.url_name
1492
+ end
1493
+ end
1494
+
1495
+ unless name.blank?
1496
+ # update cached fullpath
1497
+ if new_record? || name_changed? || parent_id_changed?
1498
+ self[:fullpath] = self.fullpath(true,false)
1499
+ elsif !new_record? && custom_base_changed?
1500
+ self[:basepath] = self.basepath(true,false)
1501
+ end
1502
+ if !new_record? && fullpath_changed?
1503
+ # FIXME: update children's cached fullpaths
1504
+ @clear_children_fullpath = true
1505
+ end
1506
+ end
1507
+
1508
+ # make sure section is the same as the parent
1509
+ if self[:parent_id].nil?
1510
+ # root node
1511
+ self[:section_id] = self[:id]
1512
+ self[:project_id] = self[:id]
1513
+ elsif parent
1514
+ self[:section_id] = ref.get_section_id
1515
+ self[:project_id] = ref.get_project_id
1516
+ else
1517
+ # bad parent will be caught later.
1518
+ end
1519
+
1520
+ if !new_record? && self[:parent_id]
1521
+ # node updated and it is not the root node
1522
+ if !kind_of?(Section) && section_id_changed?
1523
+ @spread_section_id = self[:section_id]
1524
+ end
1525
+ if !kind_of?(Project) && project_id_changed?
1526
+ @spread_project_id = self[:project_id]
1527
+ end
1528
+ end
1529
+
1530
+ # set position
1531
+ if klass != 'Node'
1532
+ # 'Node' does not have a position scope (need two first letters of kpath)
1533
+ if new_record?
1534
+ if self[:position].to_f == 0
1535
+ pos = Zena::Db.fetch_row("SELECT `position` FROM #{Node.table_name} WHERE parent_id = #{Node.connection.quote(self[:parent_id])} AND kpath like #{Node.connection.quote("#{self.class.kpath[0..1]}%")} ORDER BY position DESC LIMIT 1").to_f
1536
+ self[:position] = pos > 0 ? pos + 1.0 : 0.0
1537
+ end
1538
+ elsif parent_id_changed?
1539
+ # moved, update position
1540
+ pos = Zena::Db.fetch_row("SELECT `position` FROM #{Node.table_name} WHERE parent_id = #{Node.connection.quote(self[:parent_id])} AND kpath like #{Node.connection.quote("#{self.class.kpath[0..1]}%")} ORDER BY position DESC LIMIT 1").to_f
1541
+ self[:position] = pos > 0 ? pos + 1.0 : 0.0
1542
+ end
1543
+ end
1544
+
1545
+ end
1546
+
1547
+ # Make sure the node is complete before creating it (check parent and project references)
1548
+ def validate_node
1549
+ # when creating root node, self[:id] and :root_id are both nil, so it works.
1550
+ if parent_id_changed? && self[:id] == current_site[:root_id]
1551
+ errors.add("parent_id", "root should not have a parent") unless self[:parent_id].blank?
1552
+ end
1553
+
1554
+ errors.add(:base, 'You do not have the rights to post comments.') if @add_comment && !can_comment?
1555
+
1556
+ if @new_klass
1557
+ if !can_drive? || !self[:parent_id]
1558
+ errors.add('klass', 'You do not have the rights to do this.')
1559
+ else
1560
+ errors.add('klass', 'invalid') if !self.class.allowed_change_to_classes.include?(@new_klass)
1561
+ end
1562
+ end
1563
+ end
1564
+
1565
+ # Called before destroy. An node must be empty to be destroyed
1566
+ def secure_on_destroy
1567
+ return false unless super
1568
+ # expire cache
1569
+ # TODO: test, use observer instead...
1570
+ CachedPage.expire_with(self)
1571
+ true
1572
+ end
1573
+
1574
+ # Get unique zip in the current site's scope
1575
+ def node_before_create
1576
+ self[:zip] = Zena::Db.next_zip(self[:site_id])
1577
+ end
1578
+
1579
+ # Create an 'outside' discussion if the virtual class has auto_create_discussion set
1580
+ def node_after_create
1581
+ if vclass.auto_create_discussion
1582
+ Discussion.create(:node_id=>self[:id], :lang=>v_lang, :inside => false)
1583
+ end
1584
+ end
1585
+
1586
+ # Called after a node is 'unpublished'
1587
+ def after_unpublish
1588
+ if !self[:publish_from] && !@new_record_before_save
1589
+ # not published any more. 'unpublish' documents
1590
+ sync_documents(:unpublish)
1591
+ else
1592
+ true
1593
+ end
1594
+ end
1595
+
1596
+ def after_redit
1597
+ return true if @new_record_before_save
1598
+ sync_documents(:redit)
1599
+ end
1600
+
1601
+ # Called after a node is 'removed'
1602
+ def after_remove
1603
+ return true if @new_record_before_save
1604
+ sync_documents(:remove)
1605
+ end
1606
+
1607
+ # Called after a node is 'proposed'
1608
+ def after_propose
1609
+ return true if @new_record_before_save
1610
+ sync_documents(:propose)
1611
+ end
1612
+
1613
+ # Called after a node is 'refused'
1614
+ def after_refuse
1615
+ return true if @new_record_before_save
1616
+ sync_documents(:refuse)
1617
+ end
1618
+
1619
+ # Called after a node is published
1620
+ def after_publish
1621
+ return true if @new_record_before_save
1622
+ sync_documents(:publish)
1623
+ end
1624
+
1625
+ # Publish, refuse, propose the Documents of a redaction
1626
+ def sync_documents(action)
1627
+ allOK = true
1628
+ documents = secure_drive(Document) { Document.find(:all, :conditions=>"parent_id = #{self[:id]}") } || []
1629
+ case action
1630
+ when :propose
1631
+ documents.each do |doc|
1632
+ if doc.can_propose?
1633
+ allOK = doc.propose(Zena::Status[:prop_with]) && allOK
1634
+ end
1635
+ end
1636
+ when :unpublish
1637
+ # FIXME: use a 'before_unpublish' callback to make sure all sub-nodes can be unpublished...
1638
+ documents.each do |doc|
1639
+ unless doc.unpublish
1640
+ doc.errors.each do |k, v|
1641
+ errors.add('document', "#{k} #{v}")
1642
+ end
1643
+ allOK = false
1644
+ end
1645
+ end
1646
+ else
1647
+ documents.each do |doc|
1648
+ if doc.can_apply?(action)
1649
+ allOK = doc.apply(action) && allOK
1650
+ end
1651
+ end
1652
+ end
1653
+ allOK
1654
+ end
1655
+
1656
+ # Whenever something changed (publication/proposition/redaction/link/...)
1657
+ def after_all
1658
+ sweep_cache
1659
+ if @add_comment
1660
+ # add comment
1661
+ @discussion ||= self.discussion
1662
+ @discussion.save if @discussion.new_record?
1663
+ @add_comment[:author_name] = nil unless visitor.is_anon? # only anonymous user should set 'author_name'
1664
+ @add_comment[:discussion_id] = @discussion[:id]
1665
+ @add_comment[:user_id] = visitor[:id]
1666
+
1667
+ @comment = secure!(Comment) { Comment.create(@add_comment) }
1668
+
1669
+ remove_instance_variable(:@add_comment)
1670
+ end
1671
+ remove_instance_variable(:@discussion) if defined?(@discussion) # force reload
1672
+
1673
+ true
1674
+ end
1675
+
1676
+ def change_klass
1677
+
1678
+ if @new_klass && !new_record?
1679
+ old_kpath = self.kpath
1680
+
1681
+ klass = Node.get_class(@new_klass)
1682
+ if klass.kind_of?(VirtualClass)
1683
+ self[:vclass_id] = klass.kind_of?(VirtualClass) ? klass[:id] : nil
1684
+ self[:type] = klass.real_class.to_s
1685
+ else
1686
+ self[:vclass_id] = klass.kind_of?(VirtualClass) ? klass[:id] : nil
1687
+ self[:type] = klass.to_s
1688
+ end
1689
+ self[:kpath] = klass.kpath
1690
+
1691
+ if old_kpath[/^NPS/] && !self[:kpath][/^NPS/]
1692
+ @spread_section_id = self[:section_id]
1693
+ elsif !old_kpath[/^NPS/] && self[:kpath][/^NPS/]
1694
+ @spread_section_id = self[:id]
1695
+ end
1696
+
1697
+ if old_kpath[/^NPP/] && !self[:kpath][/^NPP/]
1698
+ @spread_project_id = self[:project_id]
1699
+ elsif !old_kpath[/^NPP/] && self[:kpath][/^NPP/]
1700
+ @spread_project_id = self[:id]
1701
+ end
1702
+
1703
+ @set_klass = @new_klass
1704
+ remove_instance_variable(:@new_klass)
1705
+ end
1706
+
1707
+ true
1708
+ end
1709
+
1710
+ # Find all children, whatever visitor is here (used to check if the node can be destroyed or to update section_id)
1711
+ def all_children
1712
+ # FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
1713
+ Node.send(:with_exclusive_scope) do
1714
+ Node.find(:all, :conditions=>['parent_id = ?', self[:id] ])
1715
+ end
1716
+ end
1717
+
1718
+ def clear_children_fullpath(i = self[:id])
1719
+ return true unless @clear_children_fullpath
1720
+ base_class.connection.execute "UPDATE nodes SET fullpath = NULL WHERE #{ref_field(false)}='#{i}'"
1721
+ ids = nil
1722
+ # FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
1723
+ base_class.send(:with_exclusive_scope) do
1724
+ ids = Zena::Db.fetch_ids("SELECT id FROM #{base_class.table_name} WHERE #{ref_field(true)} = '#{i.to_i}' AND inherit='1'")
1725
+ end
1726
+
1727
+ ids.each { |i| clear_children_fullpath(i) }
1728
+ true
1729
+ end
1730
+
1731
+ # Base class
1732
+ def base_class
1733
+ Node
1734
+ end
1735
+
1736
+ # Reference class
1737
+ def ref_class
1738
+ Node
1739
+ end
1740
+
1741
+ # return the id of the reference
1742
+ def ref_field(for_heirs=false)
1743
+ if !for_heirs && (self[:id] == current_site[:root_id])
1744
+ :id # root is it's own reference
1745
+ else
1746
+ :parent_id
1747
+ end
1748
+ end
1749
+
1750
+ end
1751
+
1752
+ Bricks::Patcher.apply_patches