zena 1.0.0.beta3 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (418) hide show
  1. data/History.txt +29 -0
  2. data/Rakefile +2 -0
  3. data/TODO_ZENA_1_0 +13 -23
  4. data/app/controllers/columns_controller.rb +1 -1
  5. data/app/controllers/comments_controller.rb +4 -3
  6. data/app/controllers/documents_controller.rb +8 -11
  7. data/app/controllers/nodes_controller.rb +39 -21
  8. data/app/controllers/users_controller.rb +8 -3
  9. data/app/controllers/versions_controller.rb +2 -2
  10. data/app/controllers/virtual_classes_controller.rb +17 -11
  11. data/app/helpers/documents_helper.rb +0 -3
  12. data/app/helpers/users_helper.rb +17 -0
  13. data/app/models/cache.rb +36 -31
  14. data/app/models/column.rb +48 -5
  15. data/app/models/comment.rb +14 -5
  16. data/app/models/data_entry.rb +2 -2
  17. data/app/models/document.rb +23 -33
  18. data/app/models/idx_nodes_datetime.rb +4 -0
  19. data/app/models/idx_nodes_float.rb +4 -0
  20. data/app/models/idx_project.rb +3 -0
  21. data/app/models/node.rb +372 -308
  22. data/app/models/page.rb +1 -31
  23. data/app/models/relation.rb +4 -4
  24. data/app/models/relation_proxy.rb +128 -17
  25. data/app/models/role.rb +27 -2
  26. data/app/models/site.rb +64 -56
  27. data/app/models/template.rb +11 -12
  28. data/app/models/text_document.rb +6 -7
  29. data/app/models/user.rb +95 -46
  30. data/app/models/version.rb +2 -2
  31. data/app/models/virtual_class.rb +418 -73
  32. data/app/views/columns/_form.html.erb +1 -1
  33. data/app/views/columns/_li.html.erb +1 -1
  34. data/app/views/comments/_form.rhtml +1 -1
  35. data/app/views/comments/_li.rhtml +1 -1
  36. data/app/views/comments/_li_simple.rhtml +1 -1
  37. data/app/views/groups/_form.rhtml +1 -1
  38. data/app/views/links/_li.rhtml +1 -1
  39. data/app/views/nodes/_groups.rhtml +1 -1
  40. data/app/views/nodes/_import_results.rhtml +1 -1
  41. data/app/views/nodes/_parent.rhtml +1 -1
  42. data/app/views/nodes/_results.rhtml +1 -1
  43. data/app/views/nodes/create.rjs +4 -2
  44. data/app/views/relations/_li.erb +2 -2
  45. data/app/views/templates/document_create_tabs/_file.rhtml +1 -1
  46. data/app/views/templates/document_create_tabs/_template.rhtml +2 -2
  47. data/app/views/templates/document_create_tabs/_text_document.rhtml +2 -2
  48. data/app/views/templates/edit_tabs/_help.rhtml +1 -1
  49. data/app/views/templates/edit_tabs/_title.rhtml +0 -3
  50. data/app/views/users/_form.rhtml +2 -6
  51. data/app/views/users/_li.rhtml +1 -3
  52. data/app/views/users/create.rjs +4 -4
  53. data/app/views/users/preferences.html.erb +1 -4
  54. data/app/views/versions/custom_tab.rhtml +5 -0
  55. data/app/views/virtual_classes/_form.erb +20 -10
  56. data/app/views/virtual_classes/_li.erb +21 -8
  57. data/app/views/zafu/default/Node-+search.zafu +1 -1
  58. data/app/views/zafu/default/Node.zafu +3 -3
  59. data/bricks/captcha/lib/bricks/captcha.rb +1 -1
  60. data/bricks/mongrel/zena/deploy.rb +14 -0
  61. data/bricks/{data2pdf → pdf}/.document +0 -0
  62. data/bricks/pdf/README +33 -0
  63. data/bricks/{data2pdf → pdf}/Rakefile +0 -0
  64. data/bricks/pdf/VERSION +1 -0
  65. data/bricks/pdf/lib/bricks/pdf.rb +110 -0
  66. data/bricks/pdf/lib/bricks/pdf/engine/prince.rb +38 -0
  67. data/bricks/pdf/lib/bricks/pdf/engine/xhtml2pdf.rb +9 -0
  68. data/bricks/pdf/lib/bricks/pdf/install.rb +121 -0
  69. data/bricks/pdf/test/engines/test_prince.rb +15 -0
  70. data/bricks/pdf/test/engines/test_xhtml2pdf.rb +15 -0
  71. data/bricks/{data2pdf → pdf}/test/fixtures/application.css +0 -0
  72. data/bricks/{data2pdf → pdf}/test/fixtures/contact.html +0 -0
  73. data/bricks/{data2pdf → pdf}/test/fixtures/pisa-default.css +0 -0
  74. data/bricks/{data2pdf → pdf}/test/fixtures/sheet1.css +0 -0
  75. data/bricks/{data2pdf → pdf}/test/fixtures/sheet2.css +0 -0
  76. data/bricks/{data2pdf → pdf}/test/fixtures/simple-html.html +0 -0
  77. data/bricks/{data2pdf → pdf}/test/fixtures/simple-text.txt +0 -0
  78. data/bricks/{data2pdf → pdf}/test/helper.rb +4 -5
  79. data/bricks/pdf/test/shoulda_macros/shoulda_pdf.rb +72 -0
  80. data/bricks/pdf/zena/init.rb +5 -0
  81. data/bricks/pdf/zena/tasks.rb +17 -0
  82. data/bricks/sphinx/lib/{use_sphinx.rb → bricks/sphinx.rb} +1 -1
  83. data/bricks/tags/zena/init.rb +2 -2
  84. data/bricks/tags/zena/test/zafu/tags.yml +4 -4
  85. data/bricks/zena/zena/migrate/01_base.rb +482 -0
  86. data/config/bricks.yml +22 -6
  87. data/config/gems.yml +8 -6
  88. data/db/20100628074512_zena0x_to1x.rb +6 -1
  89. data/db/fix/024_correct_vclass_kpath.rb +11 -0
  90. data/db/fix/025_move_tag_into_vclass.rb +13 -0
  91. data/db/{migrate → fix}/026_rename_templates.rb +0 -0
  92. data/db/{migrate → fix}/045_avoid_star_in_templates.rb +0 -0
  93. data/db/{migrate → fix}/046_fix_zazen_image_tag.rb +0 -0
  94. data/db/{migrate → fix}/047_change_default_link_id_to_zero.rb +1 -3
  95. data/db/{migrate → fix}/049_fix_publish_from_is_null.rb +0 -0
  96. data/db/{migrate → fix}/20090924141459_zafu_fix_sept09.rb +0 -0
  97. data/db/{migrate → fix}/20091013100351_rename_publish_group_to_drive_group.rb +1 -3
  98. data/db/{migrate → fix}/20091124161608_rebuild_fullpath.rb +0 -1
  99. data/db/{migrate → fix}/20100115134729_rebuild_fullpath_after_fix.rb +0 -0
  100. data/db/{migrate → fix}/20100526090140_renamed_contact_model_to_base_contact.rb +2 -4
  101. data/db/{migrate → fix/old_migrations}/001_create_base.rb +0 -1
  102. data/db/{migrate → fix/old_migrations}/002_add_time_zone_to_users.rb +0 -0
  103. data/db/{migrate → fix/old_migrations}/003_add_custom_base_flag.rb +0 -0
  104. data/db/{migrate → fix/old_migrations}/004_rename_template_skin.rb +0 -0
  105. data/db/{migrate → fix/old_migrations}/005_create_cached_pages.rb +0 -0
  106. data/db/{migrate → fix/old_migrations}/006_create_sites.rb +0 -0
  107. data/db/{migrate → fix/old_migrations}/007_replace_id_by_zip.rb +0 -0
  108. data/db/{migrate → fix/old_migrations}/008_user_status.rb +0 -0
  109. data/db/{migrate → fix/old_migrations}/009_fulltext.rb +0 -0
  110. data/db/fix/old_migrations/010_create_template_content.rb +17 -0
  111. data/db/{migrate → fix/old_migrations}/011_project_to_section.rb +0 -0
  112. data/db/{migrate → fix/old_migrations}/012_add_project_id.rb +0 -0
  113. data/db/{migrate → fix/old_migrations}/013_remove_defaults.rb +0 -0
  114. data/db/{migrate → fix/old_migrations}/014_add_sort_field.rb +0 -0
  115. data/db/{migrate → fix/old_migrations}/015_add_dyn_attributes.rb +0 -0
  116. data/db/{migrate → fix/old_migrations}/016_remove_translations.rb +0 -0
  117. data/db/{migrate → fix/old_migrations}/017_rename_authorize.rb +0 -0
  118. data/db/{migrate → fix/old_migrations}/018_add_auth_option.rb +0 -0
  119. data/db/{migrate → fix/old_migrations}/019_remove_user_status.rb +0 -0
  120. data/db/{migrate → fix/old_migrations}/020_create_participation.rb +0 -0
  121. data/db/{migrate → fix/old_migrations}/021_create_relations.rb +0 -0
  122. data/db/{migrate → fix/old_migrations}/022_create_virtual_classes.rb +0 -0
  123. data/db/{migrate → fix/old_migrations}/023_ip_on_anonymous_comment.rb +0 -0
  124. data/db/{migrate → fix/old_migrations}/027_add_country_to_contacts.rb +0 -0
  125. data/db/{migrate → fix/old_migrations}/028_change_size_of_conten_type_field.rb +0 -0
  126. data/db/{migrate → fix/old_migrations}/029_create_data_entries.rb +0 -0
  127. data/db/{migrate → fix/old_migrations}/030_redit_auto_publish_site_settings.rb +0 -0
  128. data/db/{migrate → fix/old_migrations}/031_create_iformats.rb +0 -0
  129. data/db/{migrate → fix/old_migrations}/032_caches_context_as_hash.rb +0 -0
  130. data/db/{migrate → fix/old_migrations}/033_documents_kpath_change.rb +0 -0
  131. data/db/{migrate → fix/old_migrations}/034_change_file_storage.rb +0 -0
  132. data/db/{migrate → fix/old_migrations}/035_add_status_to_link.rb +0 -0
  133. data/db/{migrate → fix/old_migrations}/036_add_flag_fields_on_nodes.rb +0 -0
  134. data/db/{migrate → fix/old_migrations}/037_add_auto_create_discussion_to_v_class.rb +0 -0
  135. data/db/{migrate → fix/old_migrations}/038_create_site_attributes.rb +0 -0
  136. data/db/{migrate → fix/old_migrations}/039_default_position.rb +0 -0
  137. data/db/{migrate → fix/old_migrations}/040_second_value_for_data_entry.rb +0 -0
  138. data/db/{migrate → fix/old_migrations}/041_add_attributes_to_v_class.rb +0 -0
  139. data/db/{migrate → fix/old_migrations}/042_fix_position_should_be_float.rb +0 -0
  140. data/db/{migrate → fix/old_migrations}/043_move_user_lang_into_participation.rb +0 -0
  141. data/db/{migrate → fix/old_migrations}/044_remove_monolingual_site_option.rb +0 -0
  142. data/db/{migrate → fix/old_migrations}/048_link_source_target_can_be_null.rb +0 -0
  143. data/db/{migrate → fix/old_migrations}/050_date_in_links.rb +0 -0
  144. data/db/{migrate → fix/old_migrations}/051_add_exif_tags_to_images.rb +0 -0
  145. data/db/{migrate → fix/old_migrations}/20090825201159_insert_zero_link.rb +0 -0
  146. data/db/{migrate → fix/old_migrations}/20090825201200_merge_bricks_migrations_with_std_migrations.rb +0 -0
  147. data/db/{migrate → fix/old_migrations}/20090927125912_allow_null_in_text_fields.rb +0 -0
  148. data/db/{migrate → fix/old_migrations}/20090928133440_no_more_private_nodes.rb +0 -0
  149. data/db/{migrate → fix/old_migrations}/20090928143754_version_status_change.rb +0 -0
  150. data/db/{migrate → fix/old_migrations}/20091001084025_change_status_values_for_comments.rb +0 -0
  151. data/db/{migrate → fix/old_migrations}/20091009084057_add_vhash_in_node.rb +0 -0
  152. data/db/{migrate → fix/old_migrations}/20091014130833_fix_template_title.rb +0 -0
  153. data/db/{migrate → fix/old_migrations}/20091014183726_merge_participation_into_users.rb +0 -0
  154. data/db/{migrate → fix/old_migrations}/20091018200734_add_popup_info_to_image_format.rb +0 -0
  155. data/db/{migrate → fix/old_migrations}/20091026161708_add_persistence_token.rb +0 -0
  156. data/db/{migrate → fix/old_migrations}/20091101184952_add_session_table.rb +0 -0
  157. data/db/{migrate → fix/old_migrations}/20091123175137_add_single_access_token.rb +0 -0
  158. data/db/{migrate → fix/old_migrations}/20100125062254_add_dynamo_to_version.rb +0 -0
  159. data/db/{migrate → fix/old_migrations}/20100201133242_remove_default_status_on_version.rb +0 -0
  160. data/db/{migrate → fix/old_migrations}/20100208194210_create_attachments.rb +0 -0
  161. data/db/{migrate → fix/old_migrations}/20100210112319_change_dynamo_to_property.rb +0 -0
  162. data/db/{migrate → fix/old_migrations}/20100320145726_transform_template_contents_into_index.rb +0 -0
  163. data/db/{migrate → fix/old_migrations}/20100328125634_change_skin_name_to_id.rb +0 -0
  164. data/db/{migrate → fix/old_migrations}/20100417061257_add_properties_to_sites.rb +0 -0
  165. data/db/{migrate → fix/old_migrations}/20100419163149_rename_name_to_node_name.rb +0 -0
  166. data/db/{migrate → fix/old_migrations}/20100422091606_change_v_class_table_into_roles.rb +0 -0
  167. data/db/{migrate → fix/old_migrations}/20100422094048_node_habtm_roles.rb +0 -0
  168. data/db/{migrate → fix/old_migrations}/20100422115935_create_columns.rb +0 -0
  169. data/db/{migrate → fix/old_migrations}/20100513181529_add_site_id_to_columns.rb +0 -0
  170. data/db/{migrate → fix/old_migrations}/20100519091711_add_index_definition_to_columns.rb +0 -0
  171. data/db/{migrate → fix/old_migrations}/20100519091940_create_idx_nodes_string.rb +0 -0
  172. data/db/{migrate → fix/old_migrations}/20100519232432_create_idx_nodes_ml_string.rb +0 -0
  173. data/db/{migrate → fix/old_migrations}/20100525113858_add_porperties_to_users.rb +0 -0
  174. data/db/{migrate → fix/old_migrations}/20100527130937_change_column_index_to_string.rb +0 -0
  175. data/db/{migrate → fix/old_migrations}/20100531135128_add_fulltext_builder_fields.rb +0 -0
  176. data/db/{migrate → fix/old_migrations}/20100915062903_add_api_group_id_to_site.rb +0 -0
  177. data/db/fix/old_migrations/20100923154807_remove_base_contact.rb +84 -0
  178. data/db/fix/old_migrations/20100926192223_remove_su_user.rb +8 -0
  179. data/db/fix/old_migrations/20100927141658_add_eval_attributes_to_v_class.rb +12 -0
  180. data/db/fix/old_migrations/20100928185257_add_obvious_idx.rb +52 -0
  181. data/db/fix/old_migrations/20100929143111_remove_node_name.rb +11 -0
  182. data/db/fix/old_migrations/20101006090454_store_properties_in_long_text.rb +9 -0
  183. data/db/fix/old_migrations/20101014185753_remove_user_prototype_id.rb +9 -0
  184. data/db/fix/old_migrations/20101101084318_create_scope_index.rb +35 -0
  185. data/db/fix/old_migrations/20101109074232_create_idx_nodes_tables.rb +65 -0
  186. data/db/fix/old_migrations/20101110184235_add_role_update_to_site.rb +9 -0
  187. data/db/fix/old_migrations/20101116103920_change_scope_index.rb +31 -0
  188. data/db/fix/old_migrations/20101123125822_add_integer_idx.rb +17 -0
  189. data/db/fix/old_migrations/20101130134522_add_index_field.rb +13 -0
  190. data/db/fix/old_migrations/20101213133816_add_group_to_relation.rb +9 -0
  191. data/db/init/base/help.fr.zml +1 -1
  192. data/db/init/base/skins/default.zml +0 -1
  193. data/db/init/base/skins/default/Node-+search.zafu +1 -1
  194. data/db/init/base/skins/default/Node-tree.zafu +3 -3
  195. data/db/init/base/skins/default/Node.zafu +3 -3
  196. data/lib/bricks/loader.rb +4 -1
  197. data/lib/bricks/requirements_validation.rb +11 -6
  198. data/lib/log_recorder/lib/log_recorder.rb +2 -2
  199. data/lib/tasks/zena.rake +25 -15
  200. data/lib/zena.rb +42 -9
  201. data/lib/zena/acts/enrollable.rb +81 -99
  202. data/lib/zena/acts/secure.rb +27 -23
  203. data/lib/zena/acts/secure_node.rb +10 -55
  204. data/lib/zena/acts/serializable.rb +9 -10
  205. data/lib/zena/app.rb +0 -2
  206. data/lib/zena/code_syntax.rb +1 -1
  207. data/lib/zena/controller/test_case.rb +0 -5
  208. data/lib/zena/core_ext/string.rb +48 -20
  209. data/lib/zena/db.rb +10 -442
  210. data/lib/zena/db_helper/abstract_db.rb +184 -0
  211. data/lib/zena/db_helper/mysql.rb +150 -0
  212. data/lib/zena/db_helper/postgresql.rb +79 -0
  213. data/lib/zena/db_helper/sqlite3.rb +135 -0
  214. data/lib/zena/deploy.rb +4 -1
  215. data/lib/zena/deploy/httpd.rhtml +3 -3
  216. data/lib/zena/deploy/vhost.rhtml +1 -1
  217. data/lib/zena/foxy_parser.rb +37 -18
  218. data/lib/zena/info.rb +3 -13
  219. data/lib/zena/migrator.rb +0 -1
  220. data/lib/zena/parser/zafu_rules.rb +9 -4
  221. data/lib/zena/parser/zazen_rules.rb +5 -5
  222. data/lib/zena/parser/zena_rules.rb +1 -1
  223. data/lib/zena/remote/interface.rb +1 -1
  224. data/lib/zena/site_worker.rb +3 -3
  225. data/lib/zena/test_controller.rb +10 -10
  226. data/lib/zena/use/action.rb +66 -6
  227. data/lib/zena/use/ajax.rb +39 -13
  228. data/lib/zena/use/ancestry.rb +210 -0
  229. data/lib/zena/use/authlogic.rb +30 -1
  230. data/lib/zena/use/calendar.rb +158 -0
  231. data/lib/zena/use/conditional.rb +3 -2
  232. data/lib/zena/use/context.rb +42 -12
  233. data/lib/zena/use/dates.rb +15 -14
  234. data/lib/zena/use/display.rb +54 -7
  235. data/lib/zena/use/error_rendering.rb +1 -0
  236. data/lib/zena/use/field_index.rb +20 -0
  237. data/lib/zena/use/fixtures.rb +12 -9
  238. data/lib/zena/use/forms.rb +230 -106
  239. data/lib/zena/use/fulltext.rb +28 -14
  240. data/lib/zena/use/html_tags.rb +1 -24
  241. data/lib/zena/use/i18n.rb +69 -14
  242. data/lib/zena/use/kpath.rb +60 -0
  243. data/lib/zena/use/ml_index.rb +6 -4
  244. data/lib/zena/use/node_context.rb +63 -0
  245. data/lib/zena/use/prop_eval.rb +90 -0
  246. data/lib/zena/use/query_builder.rb +159 -29
  247. data/lib/zena/use/query_comment.rb +1 -1
  248. data/lib/zena/use/query_node.rb +147 -56
  249. data/lib/zena/use/recursion.rb +2 -2
  250. data/lib/zena/use/relations.rb +31 -19
  251. data/lib/zena/use/rendering.rb +111 -121
  252. data/lib/zena/use/scope_index.rb +230 -0
  253. data/lib/zena/use/search.rb +7 -7
  254. data/lib/zena/use/urls.rb +87 -25
  255. data/lib/zena/use/version_hash.rb +113 -113
  256. data/lib/zena/use/workflow.rb +5 -1
  257. data/lib/zena/use/zafu_attributes.rb +11 -14
  258. data/lib/zena/use/zafu_eval.rb +1 -1
  259. data/lib/zena/use/zafu_safe_definitions.rb +91 -9
  260. data/lib/zena/use/zafu_templates.rb +146 -102
  261. data/lib/zena/use/zazen.rb +5 -4
  262. data/lib/zena/zafu_compiler.rb +1 -0
  263. data/locale/en/LC_MESSAGES/zena.mo +0 -0
  264. data/locale/en/zena.po +0 -1
  265. data/locale/fr/LC_MESSAGES/zena.mo +0 -0
  266. data/locale/fr/zena.mo +0 -0
  267. data/locale/fr/zena.po +4 -4
  268. data/misc/zena +35 -0
  269. data/misc/zena_init +41 -0
  270. data/public/images/ext/{basecontact.png → contact.png} +0 -0
  271. data/public/javascripts/zena.js +35 -7
  272. data/public/stylesheets/admin.css +5 -2
  273. data/public/stylesheets/default.css +2 -1
  274. data/public/stylesheets/popup.css +1 -1
  275. data/public/stylesheets/zena.css +2 -2
  276. data/test/custom_queries/complex.host.yml +12 -5
  277. data/test/fixtures/files/Node-test.zafu +3 -3
  278. data/test/fixtures/files/translations_fr.yml +4 -2
  279. data/test/functional/documents_controller_test.rb +31 -0
  280. data/test/functional/nodes_controller_commit_test.rb +1 -5
  281. data/test/functional/nodes_controller_test.rb +92 -12
  282. data/test/functional/user_sessions_controller_test.rb +2 -2
  283. data/test/functional/users_controller_test.rb +31 -29
  284. data/test/functional/versions_controller_test.rb +2 -2
  285. data/test/functional/virtual_classes_controller_test.rb +2 -2
  286. data/test/integration/multiple_hosts_test.rb +19 -8
  287. data/test/integration/navigation_test.rb +91 -12
  288. data/test/integration/query_node/basic.yml +40 -37
  289. data/test/integration/query_node/complex.yml +23 -18
  290. data/test/integration/query_node/dates.yml +3 -3
  291. data/test/integration/query_node/errors.yml +7 -1
  292. data/test/integration/query_node/filters.yml +41 -35
  293. data/test/integration/query_node/idx_fields.yml +11 -0
  294. data/test/integration/query_node/idx_key_value.yml +77 -0
  295. data/test/integration/query_node/idx_scope.yml +33 -0
  296. data/test/integration/query_node/relations.yml +13 -13
  297. data/test/integration/query_node_test.rb +6 -10
  298. data/test/integration/zafu_compiler/action.yml +19 -6
  299. data/test/integration/zafu_compiler/ajax.yml +111 -51
  300. data/test/integration/zafu_compiler/apphelper.yml +1 -1
  301. data/test/integration/zafu_compiler/asset.yml +1 -1
  302. data/test/integration/zafu_compiler/basic.yml +42 -52
  303. data/test/integration/zafu_compiler/calendar.yml +3 -3
  304. data/test/integration/zafu_compiler/complex.yml +16 -16
  305. data/test/integration/zafu_compiler/complex_ok.yml +2 -2
  306. data/test/integration/zafu_compiler/conditional.yml +42 -33
  307. data/test/integration/zafu_compiler/data.yml +3 -3
  308. data/test/integration/zafu_compiler/dates.yml +25 -10
  309. data/test/integration/zafu_compiler/display.yml +49 -12
  310. data/test/integration/zafu_compiler/errors.yml +26 -6
  311. data/test/integration/zafu_compiler/eval.yml +4 -4
  312. data/test/integration/zafu_compiler/forms.yml +89 -15
  313. data/test/integration/zafu_compiler/i18n.yml +23 -18
  314. data/test/integration/zafu_compiler/idx_scope.yml +7 -0
  315. data/test/integration/zafu_compiler/later.yml +10 -16
  316. data/test/integration/zafu_compiler/off/off.yml +2 -2
  317. data/test/integration/zafu_compiler/query.yml +207 -0
  318. data/test/integration/zafu_compiler/recursion.yml +2 -2
  319. data/test/integration/zafu_compiler/relations.yml +144 -168
  320. data/test/integration/zafu_compiler/roles.yml +86 -10
  321. data/test/integration/zafu_compiler/rubyless.yml +49 -6
  322. data/test/integration/zafu_compiler/safe_definitions.yml +35 -6
  323. data/test/integration/zafu_compiler/search.yml +1 -1
  324. data/test/integration/zafu_compiler/security.yml +37 -0
  325. data/test/integration/zafu_compiler/urls.yml +50 -40
  326. data/test/integration/zafu_compiler/user.yml +21 -6
  327. data/test/integration/zafu_compiler/version.yml +6 -6
  328. data/test/integration/zafu_compiler/zafu_attributes.yml +43 -34
  329. data/test/integration/zafu_compiler/zazen.yml +10 -10
  330. data/test/integration/zafu_compiler_test.rb +19 -13
  331. data/test/sites/complex/nodes.yml +0 -2
  332. data/test/sites/complex/roles.yml +9 -1
  333. data/test/sites/complex/sites.yml +0 -1
  334. data/test/sites/complex/users.yml +2 -5
  335. data/test/sites/ocean/nodes.yml +2 -5
  336. data/test/sites/ocean/roles.yml +8 -0
  337. data/test/sites/ocean/sites.yml +0 -1
  338. data/test/sites/ocean/users.yml +0 -13
  339. data/test/sites/zena/columns.yml +27 -5
  340. data/test/sites/zena/idx_projects.yml +5 -0
  341. data/test/sites/zena/nodes.yml +8 -32
  342. data/test/sites/zena/relations.yml +5 -0
  343. data/test/sites/zena/roles.yml +25 -3
  344. data/test/sites/zena/sites.yml +2 -2
  345. data/test/sites/zena/users.yml +1 -21
  346. data/test/sites/zena/versions.yml +35 -12
  347. data/test/test_helper.rb +7 -0
  348. data/test/unit/after_commit_test.rb +7 -7
  349. data/test/unit/cache_test.rb +32 -0
  350. data/test/unit/cached_page_test.rb +1 -1
  351. data/test/unit/column_test.rb +31 -7
  352. data/test/unit/comment_test.rb +2 -2
  353. data/test/unit/core_ext_test.rb +38 -7
  354. data/test/unit/document_test.rb +14 -42
  355. data/test/unit/node_test.rb +311 -324
  356. data/test/unit/note_test.rb +23 -31
  357. data/test/unit/page_test.rb +16 -58
  358. data/test/unit/project_test.rb +2 -2
  359. data/test/unit/relation_proxy_test.rb +148 -21
  360. data/test/unit/relation_test.rb +23 -3
  361. data/test/unit/remote_test.rb +15 -9
  362. data/test/unit/role_test.rb +9 -0
  363. data/test/unit/site_test.rb +49 -47
  364. data/test/unit/skin_test.rb +16 -0
  365. data/test/unit/template_test.rb +60 -69
  366. data/test/unit/text_document_test.rb +15 -14
  367. data/test/unit/user_test.rb +101 -41
  368. data/test/unit/version_test.rb +4 -4
  369. data/test/unit/virtual_class_test.rb +577 -36
  370. data/test/unit/workflow_test.rb +58 -21
  371. data/test/unit/zena/acts/enrollable_test.rb +36 -127
  372. data/test/unit/zena/acts/secure_test.rb +6 -22
  373. data/test/unit/zena/acts/serializable_test.rb +18 -0
  374. data/test/unit/zena/db_test.rb +14 -14
  375. data/test/unit/zena/parser/zafu.yml +5 -3
  376. data/test/unit/zena/use/ancestry_test.rb +198 -0
  377. data/test/unit/zena/use/calendar_test.rb +8 -8
  378. data/test/unit/zena/use/dates_test.rb +2 -0
  379. data/test/unit/zena/use/fulltext_test.rb +9 -1
  380. data/test/unit/zena/use/html_tags_test.rb +2 -16
  381. data/test/unit/zena/use/i18n_test.rb +2 -2
  382. data/test/unit/zena/use/kpath_test.rb +13 -0
  383. data/test/unit/zena/use/ml_index_test.rb +60 -12
  384. data/test/unit/zena/use/prop_eval_test.rb +170 -0
  385. data/test/unit/zena/use/query_node_test.rb +9 -2
  386. data/test/unit/zena/use/rendering_test.rb +98 -1
  387. data/test/unit/zena/use/scope_index_test.rb +464 -0
  388. data/test/unit/zena/use/urls_test.rb +23 -13
  389. data/test/unit/zena/use/version_hash_test.rb +2 -2
  390. data/test/unit/zena/use/zafu_template_test.rb +21 -8
  391. data/test/unit/zena/use/zazen_test.rb +47 -47
  392. data/zena.gemspec +177 -143
  393. metadata +222 -141
  394. data/app/models/base_contact.rb +0 -79
  395. data/app/models/book.rb +0 -242
  396. data/app/models/contact_content.rb +0 -70
  397. data/app/models/contact_version.rb +0 -40
  398. data/app/models/reference.rb +0 -18
  399. data/app/views/templates/edit_tabs/_basecontact.rhtml +0 -8
  400. data/bricks/data2pdf/README +0 -19
  401. data/bricks/data2pdf/VERSION +0 -1
  402. data/bricks/data2pdf/lib/data2pdf.rb +0 -60
  403. data/bricks/data2pdf/lib/engines/prince.rb +0 -39
  404. data/bricks/data2pdf/lib/engines/xhtml2pdf.rb +0 -41
  405. data/bricks/data2pdf/lib/install.rb +0 -111
  406. data/bricks/data2pdf/test/engines/test_prince.rb +0 -14
  407. data/bricks/data2pdf/test/engines/test_xhtml2pdf.rb +0 -14
  408. data/bricks/data2pdf/test/shoulda_macros/shoulda_data2pdf.rb +0 -91
  409. data/bricks/data2pdf/test/unit/test_rendering.rb +0 -37
  410. data/config/routes.rb +0 -3
  411. data/db/migrate/010_create_template_content.rb +0 -17
  412. data/db/migrate/024_correct_vclass_kpath.rb +0 -13
  413. data/db/migrate/025_move_tag_into_vclass.rb +0 -15
  414. data/lib/version_off.rb +0 -323
  415. data/lib/zena/use/node_name.rb +0 -94
  416. data/test/integration/query_node/properties.yml +0 -41
  417. data/test/unit/base_contact_test.rb +0 -242
  418. data/test/unit/node_name_test.rb +0 -137
data/app/models/page.rb CHANGED
@@ -1,35 +1,5 @@
1
1
  =begin rdoc
2
- === subclasses
3
-
4
- Section:: used to group pages together with a same 'section_id'
5
- Tag:: used to create collections of items.
6
- Document:: contains data from uploaded files.
7
- Image:: subclass of Document, contains image data that can be resized/viewed in the browser.
8
- TextDocument:: subclass of Document, used by documents that can be edited online (scripts, text).
9
- Template:: subclass of TextDocument. Contains the zafu code to make the look and feel of the site.
10
- Skin:: subclass of Template. Contains other templates.
2
+ The Page class is just used to group Section and Project in a common ancestor.
11
3
  =end
12
4
  class Page < Node
13
-
14
- private
15
-
16
- def validate_node
17
- super
18
-
19
- # we are in a scope, we cannot just use the normal validates_...
20
- # FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
21
- test_same_name = nil
22
- if node_name_changed? || parent_id_changed? || kpath_changed?
23
- Node.send(:with_exclusive_scope) do
24
- if new_record?
25
- cond = ["node_name = ? AND parent_id = ? AND kpath LIKE 'NP%'", self[:node_name], self[:parent_id]]
26
- else
27
- cond = ["node_name = ? AND parent_id = ? AND kpath LIKE 'NP%' AND id != ? ", self[:node_name], self[:parent_id], self[:id]]
28
- end
29
- test_same_name = Node.find(:all, :conditions => cond)
30
- end
31
- errors.add("node_name", "has already been taken") unless test_same_name == []
32
- end
33
- end
34
-
35
5
  end
@@ -31,25 +31,25 @@ class Relation < ActiveRecord::Base
31
31
  end
32
32
 
33
33
  if self[:source_role].blank?
34
- if klass = Node.get_class_from_kpath(source_kpath)
34
+ if klass = VirtualClass.find_by_kpath(source_kpath)
35
35
  self.source_role = klass.to_s.underscore
36
36
  else
37
37
  klass = nil
38
38
  end
39
39
  else
40
- klass = Node.get_class_from_kpath(source_kpath)
40
+ klass = VirtualClass.find_by_kpath(source_kpath)
41
41
  end
42
42
 
43
43
  errors.add(:source_kpath, 'invalid (could not find class)') unless klass
44
44
 
45
45
  if self[:target_role].blank?
46
- if klass = Node.get_class_from_kpath(target_kpath)
46
+ if klass = VirtualClass.find_by_kpath(target_kpath)
47
47
  self.target_role = klass.to_s.underscore
48
48
  else
49
49
  klass = nil
50
50
  end
51
51
  else
52
- klass = Node.get_class_from_kpath(target_kpath)
52
+ klass = VirtualClass.find_by_kpath(target_kpath)
53
53
  end
54
54
 
55
55
  errors.add(:target_kpath, 'invalid (could not find class)') unless klass
@@ -1,5 +1,9 @@
1
1
  class RelationProxy < Relation
2
- attr_accessor :side, :link_errors, :start, :other_link, :last_target
2
+ include RubyLess
3
+
4
+ safe_method :name => {:class => String, :method => 'other_role'}
5
+
6
+ attr_accessor :side, :link_errors, :start, :other_link, :last_target, :add_links
3
7
  LINK_ATTRIBUTES = Zena::Use::Relations::LINK_ATTRIBUTES
4
8
  LINK_ATTRIBUTES_SQL = LINK_ATTRIBUTES.map {|sym| connection.quote_column_name(sym)}.join(',')
5
9
  LINK_SELECT = "nodes.*,links.id AS link_id,#{LINK_ATTRIBUTES.map {|l| "links.#{l} AS l_#{l}"}.join(',')}"
@@ -33,7 +37,7 @@ class RelationProxy < Relation
33
37
  def get_proxy(node, role)
34
38
  # TODO: use find_by_role(role, node.kpath) when all tests are clear
35
39
  rel = find_by_role(role)
36
- if rel && (node.new_record? || node.vclass.kpath =~ /\A#{rel.this_kpath}/)
40
+ if rel && (node.new_record? || node.kpath =~ /\A#{rel.this_kpath}/)
37
41
  rel.start = node
38
42
  rel
39
43
  else
@@ -82,11 +86,13 @@ class RelationProxy < Relation
82
86
  end
83
87
 
84
88
  def other_zips
89
+ return nil unless @start[:id]
85
90
  return @other_zips if defined?(@other_zips)
86
91
  @other_zips = @records ? @records.map { |r| r.zip} : Zena::Db.fetch_ids("SELECT zip FROM nodes INNER JOIN links ON nodes.id=links.#{other_side} AND links.relation_id = #{self[:id]} AND links.#{link_side} = #{@start[:id]} WHERE #{secure_scope('nodes')} GROUP BY nodes.zip", 'zip')
87
92
  end
88
93
 
89
94
  def records(opts = {})
95
+ return nil unless @start[:id]
90
96
  return @records if defined?(@records)
91
97
  options = {
92
98
  :select => "nodes.*, #{LINK_SELECT}",
@@ -114,12 +120,30 @@ class RelationProxy < Relation
114
120
  end
115
121
 
116
122
  # Get class of other element (used by QueryNode to properly set resulting class).
117
- def other_klass
118
- Node.get_class_from_kpath(@side == :source ? self[:target_kpath] : self[:source_kpath])
123
+ def other_vclass
124
+ VirtualClass.find_by_kpath(@side == :source ? self[:target_kpath] : self[:source_kpath])
125
+ end
126
+
127
+ # set from query builder
128
+ def qb=(qb)
129
+ if qb.blank?
130
+ self.other_id = []
131
+ else
132
+ query = @start.class.build_query(:all, qb,
133
+ :node_name => '@start',
134
+ :main_class => @start.virtual_class,
135
+ :rubyless_helper => @start.virtual_class,
136
+ :default => {:order => 'id asc'}
137
+ )
138
+ self.other_id = secure(Node) {Node.find_by_sql(eval(query.to_s))} || []
139
+ end
140
+ rescue ::QueryBuilder::Error => err
141
+ attributes_to_update[:errors] = {'base' => err.message}
119
142
  end
120
143
 
121
144
  # set
122
145
  def other_id=(v)
146
+ attributes_to_update[:errors] = {}
123
147
  if !v.kind_of?(Array) && v.to_i < 0
124
148
  # removing a link
125
149
  # TODO: support Array
@@ -128,8 +152,62 @@ class RelationProxy < Relation
128
152
  else
129
153
  # ignore
130
154
  end
155
+ elsif v.kind_of?(Array)
156
+ if v.first.kind_of?(Node)
157
+ node_by_id = attributes_to_update[:nodes] = {}
158
+ v.each do |r|
159
+ node_by_id[r.id.to_i] = r
160
+ end
161
+ attributes_to_update[:id] = v.map{|r| r.id.to_i}
162
+ else
163
+ attributes_to_update[:id] = v.map(&:to_i)
164
+ end
165
+ else
166
+ attributes_to_update[:id] = v.blank? ? nil : v.to_i
167
+ end
168
+ end
169
+
170
+ # set
171
+ def other_zip=(zip_values)
172
+ # Translate ids and then set
173
+ errors = attributes_to_update[:errors] = {}
174
+ id_to_zip = attributes_to_update[:id_to_zip] = {}
175
+
176
+ if zip_values.kind_of?(Array)
177
+ attributes_to_update[:id] = []
178
+ zip_values.each do |zip|
179
+ if id = secure(Node) { Node.translate_pseudo_id(zip, :id, @start) }
180
+ # ok
181
+ id_to_zip[id] = zip
182
+ attributes_to_update[:id] << id
183
+ else
184
+ # error
185
+ errors[zip] = _('could not be found')
186
+ end
187
+ end
188
+ elsif zip_values.blank?
189
+ # remove all
190
+ attributes_to_update[:id] = nil
131
191
  else
132
- attributes_to_update[:id] = v.kind_of?(Array) ? v.uniq.compact.map {|v| v.to_i} : (v.blank? ? nil : v.to_i)
192
+ if id = secure(Node) { Node.translate_pseudo_id(zip_values, :id, @start) }
193
+ if id < 0
194
+ # removing a link
195
+ # TODO: support Array
196
+ if link = other_links.select { |l| l[other_side] == -id }.first
197
+ remove_link(link)
198
+ else
199
+ # ignore
200
+ end
201
+ else
202
+ id_to_zip[id] = zip_values
203
+ attributes_to_update[:id] = id
204
+ end
205
+ else
206
+ # error
207
+ # do not try to add
208
+ attributes_to_update[:id] = :ignore
209
+ errors[zip_values] = _('could not be found')
210
+ end
133
211
  end
134
212
  end
135
213
 
@@ -137,6 +215,10 @@ class RelationProxy < Relation
137
215
  self.other_id = v
138
216
  end
139
217
 
218
+ def other_zips=(v)
219
+ self.other_zip = v
220
+ end
221
+
140
222
  def remove_link(link)
141
223
  @links_to_delete ||= []
142
224
  @links_to_delete << link
@@ -167,7 +249,7 @@ class RelationProxy < Relation
167
249
  def attributes_to_update_valid?
168
250
  return true unless @attributes_to_update || @links_to_delete
169
251
 
170
- @link_errors = []
252
+ @link_errors = {}
171
253
  @add_links = []
172
254
  @del_links = []
173
255
  @update_links = []
@@ -179,7 +261,7 @@ class RelationProxy < Relation
179
261
  else
180
262
 
181
263
  # check if we have an update/create
182
- unless @attributes_to_update.has_key?(:id)
264
+ unless @attributes_to_update.has_key?(:id) # set during other_id=
183
265
  # try to find current id/ids
184
266
  if @other_link
185
267
  @attributes_to_update[:id] = @other_link[other_side]
@@ -192,25 +274,28 @@ class RelationProxy < Relation
192
274
  elsif @attributes_to_update.keys == [:id]
193
275
  # ignore (set icon_id = nil when already == nil)
194
276
  else
195
- @link_errors << "invalid target"
277
+ @link_errors['update'] = _('missing target')
196
278
  end
197
279
  else
198
280
  # error: cannot set other attributes (status/comment) on multiple nodes
199
- @link_errors << "invalid target"
281
+ @link_errors['update'] = _('cannot update multiple targets')
200
282
  end
201
283
  end
202
284
 
203
285
  if @attributes_to_update[:id].kind_of?(Array)
204
286
  if unique?
205
- @link_errors << "Cannot set multiple targets on #{as_unique? ? 'one' : 'many'}-to-one relation '#{this_role}'."
287
+ # TODO: translate
288
+ @link_errors['arity'] = "Cannot set multiple targets on #{as_unique? ? 'one' : 'many'}-to-one relation '#{this_role}'."
206
289
  elsif (@attributes_to_update.keys & LINK_ATTRIBUTES) != []
207
290
  keys = @attributes_to_update.keys
208
291
  keys.delete(:id)
209
- @link_errors << "Cannot set attributes #{keys.join(', ')} on multiple targets."
292
+ # TODO: translate
293
+ @link_errors['arity'] = "Cannot set attributes #{keys.join(', ')} on multiple targets."
210
294
  end
211
295
  end
212
296
 
213
- return false if @link_errors != []
297
+ return false if @link_errors != {}
298
+ @link_errors = @attributes_to_update[:errors] || {}
214
299
 
215
300
  # 1. find what changed
216
301
  if @attributes_to_update[:id].kind_of?(Array)
@@ -262,6 +347,8 @@ class RelationProxy < Relation
262
347
  end
263
348
  end
264
349
  end
350
+ elsif @attributes_to_update[:id] == :ignore
351
+ # bad id set, just used for error reporting
265
352
  else
266
353
  # add
267
354
  @add_links << @attributes_to_update
@@ -270,10 +357,14 @@ class RelationProxy < Relation
270
357
  end
271
358
  end
272
359
 
360
+ id_to_zip = attributes_to_update[:id_to_zip] || {}
361
+
273
362
  # 2. can write in new target ? (and remove targets previous link)
274
363
  @add_links.each do |hash|
275
364
  # last_target is used by "linked_node" from Node to get hold of the last linked node
276
365
  if @last_target = find_target(hash[:id])
366
+ # store remote node so that we can use in index rebuild (scope_index)
367
+ hash[:node] = @last_target
277
368
  # make sure we can overwrite previous link if as_unique
278
369
  if as_unique?
279
370
  if previous_link = Link.find(:first, :conditions => ["relation_id = ? AND #{other_side} = ?", self[:id], @last_target[:id]])
@@ -281,19 +372,35 @@ class RelationProxy < Relation
281
372
  end
282
373
  end
283
374
  else
284
- @link_errors << 'invalid target'
375
+ if zip = id_to_zip[hash[:id]]
376
+ key = zip
377
+ elsif node = secure(Node) { Node.find_by_id(hash[:id]) }
378
+ key = node.zip
379
+ else
380
+ key = 'id'
381
+ end
382
+
383
+ @link_errors[key] = _('invalid target')
285
384
  end
286
385
  end
287
386
 
288
387
  # 1. can remove old link ?
289
388
  @del_links.each do |link|
290
389
  unless find_node(link[other_side], unique?)
291
- @link_errors << 'cannot remove link'
390
+ if zip = id_to_zip[link[other_side]]
391
+ key = zip
392
+ elsif node = secure(Node) { Node.find_by_id(hash[:id]) }
393
+ key = node.zip
394
+ else
395
+ key = 'id'
396
+ end
397
+
398
+ @link_errors[key] = _('cannot remove link')
292
399
  end
293
400
  end
294
401
 
295
402
  @update_links.compact!
296
- return @link_errors == []
403
+ return @link_errors == {}
297
404
  end
298
405
 
299
406
  # Return updated link if changed or nil when nothing changed
@@ -364,12 +471,16 @@ class RelationProxy < Relation
364
471
 
365
472
  def find_target(obj_id)
366
473
  if as_unique?
367
- secure_drive(relation_class) { relation_class.find(:first, :conditions=>['id = ? AND kpath LIKE ?', obj_id, "#{other_kpath}%"]) }
474
+ cache[obj_id] ||= secure_drive(relation_class) { relation_class.find(:first, :conditions=>['id = ? AND kpath LIKE ?', obj_id, "#{other_kpath}%"]) }
368
475
  else
369
- secure_write(relation_class) { relation_class.find(:first, :conditions=>['id = ? AND kpath LIKE ?', obj_id, "#{other_kpath}%"]) }
476
+ cache[obj_id] ||= secure_write(relation_class) { relation_class.find(:first, :conditions=>['id = ? AND kpath LIKE ?', obj_id, "#{other_kpath}%"]) }
370
477
  end
371
478
  end
372
479
 
480
+ def cache
481
+ @cache ||= attributes_to_update[:nodes] || {}
482
+ end
483
+
373
484
  def attributes_to_update
374
485
  @attributes_to_update ||= {}
375
486
  end
data/app/models/role.rb CHANGED
@@ -1,22 +1,38 @@
1
1
  require 'property/stored_role'
2
2
 
3
3
  class Role < ActiveRecord::Base
4
+ # We define 'klass' in the Role used by the real classes so that property methods can be
5
+ # defined.
6
+ attr_accessor :klass
7
+
8
+ # Only store partial class name in 'type' field (not ::Role)
9
+ self.store_full_sti_class = false
10
+
4
11
  include Property::StoredRole
5
12
  has_many :stored_columns, :class_name => 'Column', :dependent => :destroy
6
13
  has_and_belongs_to_many :nodes
7
14
 
8
15
  before_validation :set_defaults
9
16
  validate :check_can_save
17
+ attr_accessible :name, :superclass, :icon
18
+
19
+ after_save :expire_vclass_cache
20
+ after_destroy :expire_vclass_cache
10
21
 
11
22
  include RubyLess
12
- safe_method :columns => {:class => ['Column'], :method => 'columns.values', :nil => false}
23
+ # Columns defined in the role.
24
+ safe_method :columns => {:class => ['Column'], :method => 'defined_safe_columns'}
25
+
13
26
  safe_method :name => String
14
27
 
28
+ # We use property to store index information, default values and such
29
+ include Property
30
+
15
31
  def superclass
16
32
  if new_record?
17
33
  Node
18
34
  else
19
- Node.get_class_from_kpath(kpath)
35
+ VirtualClass.find_by_kpath(kpath)
20
36
  end
21
37
  end
22
38
 
@@ -28,13 +44,22 @@ class Role < ActiveRecord::Base
28
44
  end
29
45
  end
30
46
 
47
+ # By default, all defined columns are safe (see )
48
+ def defined_safe_columns
49
+ @safe_column ||= defined_columns.values.sort {|a,b| a.name <=> b.name}
50
+ end
31
51
 
32
52
  private
33
53
  def set_defaults
54
+ self[:type] = self.class.to_s
34
55
  self.site_id = visitor.site.id
35
56
  end
36
57
 
37
58
  def check_can_save
38
59
  errors.add('base', 'You do not have the rights to change roles.') unless visitor.is_admin?
39
60
  end
61
+
62
+ def expire_vclass_cache
63
+ VirtualClass.expire_cache!
64
+ end
40
65
  end
data/app/models/site.rb CHANGED
@@ -7,7 +7,6 @@ The #Site model holds configuration information for a site:
7
7
 
8
8
  +host+:: Unique host name. (teti.ch, zenadmin.org, dev.example.org, ...)
9
9
  +root_id+:: Site root node id. This is the only node in the site without a parent.
10
- +su_id+:: Super User id. This user has extended priviledges on the site. It should only be used in case of emergency.
11
10
  +anon_id+:: Anonymous user id. This user is the 'public' user of the site. Even if +authorize+ is set to true, this user is needed to configure the defaults for all newly created users.
12
11
  +public_group_id+:: Id of the 'public' group. Every user of the site (with 'anonymous user') belongs to this group.
13
12
  +site_group_id+:: Id of the 'site' group. Every user except anonymous are part of this group. This group can be seen as the 'logged in users' group.
@@ -69,24 +68,22 @@ class Site < ActiveRecord::Base
69
68
  # =========== CREATE zip counter ==========================
70
69
  connection.execute "INSERT INTO zips (site_id, zip) VALUES (#{site[:id]},0)"
71
70
 
72
- # =========== CREATE Super User ===========================
73
- # create su user
74
- su = User.new_no_defaults( :login => host, :password => su_password,
75
- :first_name => "Super", :name => "User", :lang => site.default_lang, :status => User::Status[:su])
76
- su.site = site
71
+ # =========== CREATE Admin User ===========================
77
72
 
78
- Thread.current[:visitor] = su
73
+ # create admin user
74
+ admin_user = User.new_no_defaults( :login => 'admin', :password => su_password,
75
+ :lang => site.default_lang, :status => User::Status[:admin])
76
+ admin_user.site = site
77
+
78
+ Thread.current[:visitor] = admin_user
79
79
 
80
- unless su.save
80
+ unless admin_user.save
81
81
  # rollback
82
82
  Site.connection.execute "DELETE FROM #{Site.table_name} WHERE id = #{site.id}"
83
83
  Site.connection.execute "DELETE FROM zips WHERE site_id = #{site.id}"
84
- raise Exception.new("Could not create super user for site [#{host}] (site#{site[:id]})\n#{su.errors.map{|k,v| "[#{k}] #{v}"}.join("\n")}")
84
+ raise Exception.new("Could not create admin user for site [#{host}] (site#{site[:id]})\n#{admin_user.errors.map{|k,v| "[#{k}] #{v}"}.join("\n")}")
85
85
  end
86
86
 
87
- site[:su_id] = su[:id]
88
-
89
-
90
87
  # =========== CREATE PUBLIC, ADMIN, SITE GROUPS ===========
91
88
  # create public group
92
89
  pub = site.send(:secure,Group) { Group.create(:name => 'public') }
@@ -96,6 +93,9 @@ class Site < ActiveRecord::Base
96
93
  admin = site.send(:secure,Group) { Group.create( :name => 'admin') }
97
94
  raise Exception.new("Could not create admin group for site [#{host}] (site#{site[:id]})\n#{admin.errors.map{|k,v| "[#{k}] #{v}"}.join("\n")}") if admin.new_record?
98
95
 
96
+ # add admin to the 'admin group'
97
+ admin.users << admin_user
98
+
99
99
  # create site group
100
100
  sgroup = site.send(:secure,Group) { Group.create( :name => 'site') }
101
101
  raise Exception.new("Could not create site group for site [#{host}] (site#{site[:id]})\n#{sgroup.errors.map{|k,v| "[#{k}] #{v}"}.join("\n")}") if sgroup.new_record?
@@ -104,39 +104,27 @@ class Site < ActiveRecord::Base
104
104
  site.site_group_id = sgroup[:id]
105
105
  site.groups << pub << sgroup << admin
106
106
 
107
- # =========== CREATE Anonymous, admin =====================
107
+ # Reload group_ids in admin
108
+ admin_user.instance_variable_set(:@group_ids, nil)
109
+
110
+ # =========== CREATE Anonymous User =====================
108
111
  # create anon user
109
- # FIXME: make sure user_id = admin user
110
112
 
111
- anon = site.send(:secure, User) {User.new_no_defaults( :login => nil, :password => nil,
112
- :first_name => "Anonymous", :name => "User", :lang => site.default_lang, :status => User::Status[:moderated])}
113
+ anon = site.send(:secure, User) do
114
+ User.new_no_defaults( :login => nil, :password => nil,
115
+ :lang => site.default_lang, :status => User::Status[:moderated])
116
+ end
113
117
 
114
118
  anon.site = site
115
119
  raise Exception.new("Could not create anonymous user for site [#{host}] (site#{site[:id]})\n#{anon.errors.map{|k,v| "[#{k}] #{v}"}.join("\n")}") unless anon.save
116
120
  site[:anon_id] = anon[:id]
117
121
 
118
- # create admin user
119
- admin_user = site.send(:secure,User) { User.new_no_defaults( :login => 'admin', :password => su_password,
120
- :first_name => "Admin", :name => "User", :lang => site.default_lang, :status => User::Status[:admin]) }
121
- admin_user.site = site
122
- raise Exception.new("Could not create admin user for site [#{host}] (site#{site[:id]})\n#{admin_user.errors.map{|k,v| "[#{k}] #{v}"}.join("\n")}") unless admin_user.save
123
- class << admin_user
124
- # until participation is created
125
- def status; User::Status[:admin]; end
126
- def lang; site.default_lang; end
127
- end
128
- # add admin to the 'admin group'
129
- admin.users << admin_user
130
-
131
122
  # =========== CREATE ROOT NODE ============================
132
- # reload admin so all groups are set
133
-
134
- #admin_user = site.send(:secure, User) { User.find(admin_user[:id]) }
135
123
 
136
- # make admin the current visitor
137
- Thread.current[:visitor] = admin_user
124
+ root = site.send(:secure,Project) do
125
+ Project.create( :title => site.name, :rgroup_id => pub[:id], :wgroup_id => sgroup[:id], :dgroup_id => admin[:id], :title => site.name, :v_status => Zena::Status[:pub])
126
+ end
138
127
 
139
- root = site.send(:secure,Project) { Project.create( :node_name => site.name, :rgroup_id => pub[:id], :wgroup_id => sgroup[:id], :dgroup_id => admin[:id], :title => site.name, :v_status => Zena::Status[:pub]) }
140
128
  raise Exception.new("Could not create root node for site [#{host}] (site#{site[:id]})\n#{root.errors.map{|k,v| "[#{k}] #{v}"}.join("\n")}") if root.new_record?
141
129
 
142
130
  Node.connection.execute "UPDATE nodes SET section_id = id, project_id = id WHERE id = '#{root[:id]}'"
@@ -150,16 +138,17 @@ class Site < ActiveRecord::Base
150
138
  raise Exception.new("Could not save site definition for site [#{host}] (site#{site[:id]})\n#{site.errors.map{|k,v| "[#{k}] #{v}"}.join("\n")}") unless site.save
151
139
 
152
140
  # =========== CREATE CONTACT PAGES ==============
153
- [su, admin_user, anon].each do |user|
154
- user.send(:create_contact)
141
+ {admin_user => 'Admin User', anon => 'Anonymous User'}.each do |user, title|
142
+ # forces @node creation
143
+ user.node_attributes = {'title' => title, 'parent_id' => root[:id] }
144
+ user.send(:create_node)
155
145
  user.save
156
146
  end
157
147
 
158
148
  # =========== LOAD INITIAL DATA (default skin) =============
159
149
 
160
- nodes = site.send(:secure,Node) { Node.create_nodes_from_folder(:folder => File.join(Zena::ROOT, 'db', 'init', 'base'), :parent_id => root[:id], :defaults => { :v_status => Zena::Status[:pub], :rgroup_id => pub[:id], :wgroup_id => sgroup[:id], :dgroup_id => admin[:id] } ) }.values
161
-
162
- # == set skin name to 'default' for all elements in the site == #
150
+ nodes = site.send(:secure, Node) { Node.create_nodes_from_folder(:folder => File.join(Zena::ROOT, 'db', 'init', 'base'), :parent_id => root[:id], :defaults => { :v_status => Zena::Status[:pub], :rgroup_id => pub[:id], :wgroup_id => sgroup[:id], :dgroup_id => admin[:id] } ) }.values
151
+ # == set skin id to 'default' for all elements in the site == #
163
152
  skin = nodes.detect {|n| n.kind_of?(Skin) }
164
153
  Node.connection.execute "UPDATE nodes SET skin_id = '#{skin.id}' WHERE site_id = '#{site[:id]}'"
165
154
 
@@ -184,6 +173,10 @@ class Site < ActiveRecord::Base
184
173
  end
185
174
  end
186
175
 
176
+ property.string 'usr_prototype_attributes'
177
+
178
+ Site.attributes_for_form[:text] << 'usr_prototype_attributes'
179
+
187
180
  # Return path for static/cached content served by proxy: RAILS_ROOT/sites/_host_/public
188
181
  # If you need to serve from another directory, we do not store the path into the sites table
189
182
  # for security reasons. The easiest way around this limitation is to symlink the 'public' directory.
@@ -208,12 +201,6 @@ class Site < ActiveRecord::Base
208
201
  @anon ||= User.find_by_id_and_site_id(self[:anon_id], self.id)
209
202
  end
210
203
 
211
- # Return the super user. This user has extended priviledges on the data (has access to private other's data).
212
- # This is an emergency user.
213
- def su
214
- @su ||= User.find_by_id_and_site_id(self[:su_id], self.id)
215
- end
216
-
217
204
  # TODO: test
218
205
  def root_node
219
206
  secure(Node) { Node.find(self[:root_id]) }
@@ -221,17 +208,17 @@ class Site < ActiveRecord::Base
221
208
 
222
209
  # Return the public group: the one in which every visitor belongs.
223
210
  def public_group
224
- @public_group ||= Group.find(self[:public_group_id])
211
+ @public_group ||= secure(Group) { Group.find(self[:public_group_id]) }
225
212
  end
226
213
 
227
214
  # Return the site group: the one in which every visitor except 'anonymous' belongs (= all logged in users).
228
215
  def site_group
229
- @site_group ||= Group.find(self[:site_group_id])
216
+ @site_group ||= secure(Group) { Group.find(self[:site_group_id]) }
230
217
  end
231
218
 
232
219
  # Return the API group: the one in which API visitors must be to use the API.
233
220
  def api_group
234
- @api_group ||= Group.find_by_id(self[:api_group_id])
221
+ @api_group ||= secure(Group) { Group.find_by_id(self[:api_group_id]) }
235
222
  end
236
223
 
237
224
  # Return true if the given user is an administrator for this site.
@@ -241,7 +228,7 @@ class Site < ActiveRecord::Base
241
228
 
242
229
  # Return the ids of the administrators of the current site.
243
230
  def admin_user_ids
244
- # TODO: admin_user_ids could be cached in the 'site' record.
231
+ # TODO: PERFORMANCE admin_user_ids could be cached in the 'site' record.
245
232
  @admin_user_ids ||= secure!(User) { User.find(:all, :conditions => "status >= #{User::Status[:admin]}") }.map {|r| r[:id]}
246
233
  end
247
234
 
@@ -277,7 +264,7 @@ class Site < ActiveRecord::Base
277
264
 
278
265
  # ids of the users that cannot be removed
279
266
  def protected_user_ids
280
- [anon_id, su_id]
267
+ [anon_id, visitor.id] # cannot remove self
281
268
  end
282
269
 
283
270
  # Return an array with the languages for the site.
@@ -304,6 +291,24 @@ class Site < ActiveRecord::Base
304
291
  end
305
292
  end
306
293
 
294
+ def iformats_updated!
295
+ Site.connection.execute "UPDATE sites SET formats_updated_at = (SELECT updated_at FROM iformats WHERE site_id = #{self[:id]} ORDER BY iformats.updated_at DESC LIMIT 1) WHERE id = #{self[:id]}"
296
+ if $iformats
297
+ $iformats[self[:id]] = @iformats = nil
298
+ end
299
+ end
300
+
301
+ def virtual_classes
302
+ @iformats ||= begin
303
+ $iformats ||= {} # mem cache
304
+ site_formats = $iformats[self[:id]]
305
+ if !site_formats || self[:formats_updated_at] != site_formats[:updated_at]
306
+ site_formats = $iformats[self[:id]] = Iformat.formats_for_site(self[:id]) # reload
307
+ end
308
+ site_formats
309
+ end
310
+ end
311
+
307
312
  def iformats_updated!
308
313
  Site.connection.execute "UPDATE sites SET formats_updated_at = (SELECT updated_at FROM iformats WHERE site_id = #{self[:id]} ORDER BY iformats.updated_at DESC LIMIT 1) WHERE id = #{self[:id]}"
309
314
  if $iformats
@@ -353,17 +358,20 @@ class Site < ActiveRecord::Base
353
358
  true
354
359
  end
355
360
 
356
- # TODO: replace fullpath defined from names by '/zip/zip/zip'
357
- def rebuild_fullpath(parent_id = nil, parent_fullpath = "", parent_basepath = "")
361
+ # Recreates the fullpath ('/zip/zip/zip').
362
+ # TODO: find a way to use SiteWorker (need to remove get_nodes)
363
+ def rebuild_fullpath(parent_id = nil, parent_fullpath = "", parent_basepath = "", start=[])
364
+ raise Zena::InvalidRecord, "Infinit loop in 'ancestors' (#{start.inspect} --> #{parent_id})" if start.include?(parent_id)
365
+ start += [parent_id]
358
366
  i = 0
359
367
  batch_size = 100
360
368
  children = []
361
369
  while true
362
- rec = Zena::Db.fetch_attributes(['id', 'fullpath', 'basepath', 'custom_base', 'node_name'], 'nodes', "parent_id #{parent_id ? "= #{parent_id}" : "IS NULL"} AND site_id = #{self.id} ORDER BY id ASC LIMIT #{batch_size} OFFSET #{i * batch_size}")
370
+ rec = Zena::Db.fetch_attributes(['id', 'fullpath', 'basepath', 'custom_base', 'zip'], 'nodes', "parent_id #{parent_id ? "= #{parent_id}" : "IS NULL"} AND site_id = #{self.id} ORDER BY id ASC LIMIT #{batch_size} OFFSET #{i * batch_size}")
363
371
  break if rec.empty?
364
372
  rec.each do |rec|
365
373
  if parent_id
366
- rec['fullpath'] = parent_fullpath == '' ? rec['node_name'] : "#{parent_fullpath}/#{rec['node_name']}"
374
+ rec['fullpath'] = parent_fullpath == '' ? rec['zip'] : "#{parent_fullpath}/#{rec['zip']}"
367
375
  else
368
376
  # root node
369
377
  rec['fullpath'] = ''
@@ -376,7 +384,7 @@ class Site < ActiveRecord::Base
376
384
  end
377
385
 
378
386
  id = rec.delete('id')
379
- children << [id, rec['fullpath'], rec['basepath']]
387
+ children << [id, rec['fullpath'], rec['basepath'], start]
380
388
  Zena::Db.execute "UPDATE nodes SET #{rec.map {|k,v| "#{Zena::Db.connection.quote_column_name(k)}=#{Zena::Db.quote(v)}"}.join(', ')} WHERE id = #{id}"
381
389
  end
382
390
  # 50 more