zena 1.0.0.rc2 → 1.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (274) hide show
  1. data/History.txt +23 -0
  2. data/README.rdoc +1 -1
  3. data/app/controllers/columns_controller.rb +3 -31
  4. data/app/controllers/comments_controller.rb +8 -3
  5. data/app/controllers/data_entries_controller.rb +1 -1
  6. data/app/controllers/documents_controller.rb +2 -2
  7. data/app/controllers/nodes_controller.rb +29 -12
  8. data/app/controllers/relations_controller.rb +2 -2
  9. data/app/controllers/sites_controller.rb +1 -1
  10. data/app/controllers/user_sessions_controller.rb +6 -3
  11. data/app/controllers/users_controller.rb +18 -16
  12. data/app/controllers/versions_controller.rb +20 -18
  13. data/app/controllers/virtual_classes_controller.rb +103 -17
  14. data/app/helpers/users_helper.rb +1 -1
  15. data/app/models/column.rb +19 -50
  16. data/app/models/comment.rb +2 -1
  17. data/app/models/node.rb +45 -22
  18. data/app/models/relation.rb +13 -0
  19. data/app/models/relation_proxy.rb +3 -2
  20. data/app/models/role.rb +213 -4
  21. data/app/models/site.rb +18 -11
  22. data/app/models/template.rb +37 -35
  23. data/app/models/version.rb +1 -1
  24. data/app/models/virtual_class.rb +154 -86
  25. data/app/views/columns/_li.html.erb +1 -1
  26. data/app/views/columns/index.html.erb +1 -9
  27. data/app/views/comments/index.rhtml +10 -8
  28. data/app/views/documents/_crop.rhtml +5 -6
  29. data/app/views/documents/crop_form.rjs +3 -2
  30. data/app/views/groups/index.rhtml +1 -1
  31. data/app/views/iformats/index.rhtml +1 -1
  32. data/app/views/nodes/_import_results.rhtml +1 -1
  33. data/app/views/nodes/_parent.rhtml +1 -2
  34. data/app/views/nodes/update.rjs +3 -4
  35. data/app/views/relations/index.erb +1 -1
  36. data/app/views/sites/index.erb +1 -1
  37. data/app/views/templates/drive_tabs/_drive.rhtml +0 -2
  38. data/app/views/templates/edit_tabs/_image.rhtml +1 -1
  39. data/app/views/templates/edit_tabs/_title.rhtml +0 -6
  40. data/app/views/users/index.rhtml +1 -1
  41. data/app/views/users/preferences.html.erb +2 -2
  42. data/app/views/versions/backup.rjs +1 -1
  43. data/app/views/versions/custom_tab.rhtml +9 -4
  44. data/app/views/versions/destroy.rjs +2 -2
  45. data/app/views/versions/update.rjs +2 -9
  46. data/app/views/virtual_classes/_form.erb +3 -2
  47. data/app/views/virtual_classes/import_prepare.html.erb +13 -0
  48. data/app/views/virtual_classes/index.erb +28 -8
  49. data/app/views/zafu/default/Node-+adminLayout.zafu +1 -13
  50. data/app/views/zafu/default/Node-+login.zafu +1 -0
  51. data/app/views/zafu/default/Node-+notFound.zafu +1 -1
  52. data/app/views/zafu/default/Node-+popupLayout.zafu +1 -2
  53. data/app/views/zafu/default/Node-+search.zafu +1 -1
  54. data/app/views/zafu/default/Node-admin.zafu +205 -0
  55. data/app/views/zafu/default/Node.zafu +11 -11
  56. data/bricks/captcha/lib/bricks/captcha.rb +3 -2
  57. data/bricks/mongrel/zena/init.rb +2 -1
  58. data/bricks/pdf/README +5 -5
  59. data/bricks/pdf/lib/bricks/pdf/engine/prince.rb +2 -2
  60. data/bricks/pdf/lib/bricks/pdf/engine/xhtml2pdf.rb +2 -2
  61. data/bricks/pdf/lib/bricks/pdf/install.rb +5 -5
  62. data/bricks/pdf/lib/bricks/pdf.rb +11 -11
  63. data/bricks/pdf/test/engines/test_prince.rb +4 -4
  64. data/bricks/pdf/test/engines/test_xhtml2pdf.rb +4 -4
  65. data/bricks/pdf/test/shoulda_macros/shoulda_pdf.rb +2 -2
  66. data/bricks/pdf/zena/init.rb +2 -2
  67. data/bricks/pdf/zena/tasks.rb +2 -2
  68. data/bricks/sphinx/lib/bricks/sphinx.rb +6 -2
  69. data/bricks/sphinx/zena/{sphinx.yml → sphinx.yml.erb} +2 -2
  70. data/bricks/sphinx/zena/tasks.rb +28 -2
  71. data/bricks/tags/lib/bricks/tags.rb +16 -1
  72. data/bricks/tags/zena/test/unit/tags_test.rb +15 -0
  73. data/bricks/tags/zena/test/zafu/tags.yml +5 -1
  74. data/bricks/worker/lib/bricks/worker.rb +39 -0
  75. data/bricks/worker/zena/deploy.rb +0 -2
  76. data/bricks/worker/zena/init.rb +1 -0
  77. data/bricks/worker/zena/test/sites/zena/delayed_jobs.yml +16 -0
  78. data/bricks/worker/zena/test/zafu/worker.yml +8 -0
  79. data/bricks/zena/zena/migrate/01_base.rb +36 -60
  80. data/bricks/zena/zena/migrate/02_zerox1_schema.rb +388 -0
  81. data/bricks/zena/zena/migrate/03_zerox1_data.rb +380 -0
  82. data/bricks/zena/zena/migrate/20110315161158_add_reverse_scope_to_roles.rb +9 -0
  83. data/config/database_example.yml +1 -1
  84. data/config/environment.rb +1 -1
  85. data/config/gems.yml +17 -14
  86. data/db/init/base/skins/default/Node-+index.zafu +8 -1
  87. data/db/init/base/skins/default/Node-+login.zafu +1 -0
  88. data/db/init/base/skins/default/Node-+popupLayout.zafu +1 -2
  89. data/db/init/base/skins/default/Node-+search.zafu +2 -2
  90. data/db/init/base/skins/default/Node.zafu +9 -9
  91. data/db/init/base/skins/default/{favicon.png → img/favicon.png} +0 -0
  92. data/db/init/base/skins/default/{style.css → img/style.css} +0 -0
  93. data/db/init/base/skins/default/img/translations.yml +11 -0
  94. data/db/init/base/skins/default/notes.zafu +7 -9
  95. data/doc/zafu_changes.yml +12 -0
  96. data/lib/bricks/loader.rb +38 -15
  97. data/lib/tasks/zena.rake +74 -24
  98. data/lib/zena/acts/enrollable.rb +4 -1
  99. data/lib/zena/acts/secure.rb +2 -48
  100. data/lib/zena/acts/serializable.rb +13 -1
  101. data/lib/zena/app.rb +9 -0
  102. data/lib/zena/code_syntax.rb +154 -151
  103. data/lib/zena/console.rb +141 -0
  104. data/lib/zena/controller/test_case.rb +1 -1
  105. data/lib/zena/db_helper/abstract_db.rb +17 -5
  106. data/lib/zena/db_helper/mysql.rb +14 -12
  107. data/lib/zena/db_helper/postgresql.rb +1 -2
  108. data/lib/zena/db_helper/sqlite3.rb +6 -6
  109. data/lib/zena/deploy/awstats.conf.rhtml +1 -1
  110. data/lib/zena/deploy/httpd.rhtml +6 -1
  111. data/lib/zena/deploy/vhost.rhtml +9 -1
  112. data/lib/zena/deploy.rb +12 -7
  113. data/lib/zena/foxy_parser.rb +3 -1
  114. data/lib/zena/info.rb +1 -1
  115. data/lib/zena/parser/zafu_tags.rb +1 -0
  116. data/lib/zena/parser/zazen_rules.rb +1 -1
  117. data/lib/zena/remote/node.rb +15 -3
  118. data/lib/zena/remote/serializable_array.rb +19 -0
  119. data/lib/zena/remote.rb +1 -0
  120. data/lib/zena/routes.rb +7 -2
  121. data/lib/zena/site_worker.rb +11 -1
  122. data/lib/zena/unit/test_case.rb +68 -0
  123. data/lib/zena/use/action.rb +6 -2
  124. data/lib/zena/use/ajax.rb +127 -53
  125. data/lib/zena/use/ancestry.rb +11 -8
  126. data/lib/zena/use/calendar.rb +265 -129
  127. data/lib/zena/use/conditional.rb +1 -1
  128. data/lib/zena/use/context.rb +5 -5
  129. data/lib/zena/use/dates.rb +172 -60
  130. data/lib/zena/use/display.rb +70 -39
  131. data/lib/zena/use/error_rendering.rb +1 -3
  132. data/lib/zena/use/field_index.rb +4 -1
  133. data/lib/zena/use/forms.rb +94 -72
  134. data/lib/zena/use/fulltext.rb +16 -24
  135. data/lib/zena/use/html_tags.rb +20 -12
  136. data/lib/zena/use/i18n.rb +37 -37
  137. data/lib/zena/use/image_builder.rb +8 -1
  138. data/lib/zena/use/ml_index.rb +16 -16
  139. data/lib/zena/use/prop_eval.rb +10 -5
  140. data/lib/zena/use/query_builder.rb +55 -23
  141. data/lib/zena/use/query_node.rb +51 -25
  142. data/lib/zena/use/refactor.rb +2 -28
  143. data/lib/zena/use/relations.rb +1 -1
  144. data/lib/zena/use/rendering.rb +29 -0
  145. data/lib/zena/use/scope_index.rb +75 -14
  146. data/lib/zena/use/search.rb +5 -10
  147. data/lib/zena/use/test_helper.rb +2 -2
  148. data/lib/zena/use/urls.rb +125 -104
  149. data/lib/zena/use/workflow.rb +2 -1
  150. data/lib/zena/use/zafu_attributes.rb +2 -2
  151. data/lib/zena/use/zafu_safe_definitions.rb +20 -0
  152. data/lib/zena/use/zafu_templates.rb +20 -6
  153. data/lib/zena/use/zazen.rb +31 -20
  154. data/lib/zena/view/test_case.rb +5 -0
  155. data/lib/zena/zafu_compiler.rb +24 -2
  156. data/lib/zena.rb +12 -6
  157. data/locale/de/LC_MESSAGES/zena.mo +0 -0
  158. data/locale/de/zena.po +1345 -1164
  159. data/locale/en/LC_MESSAGES/zena.mo +0 -0
  160. data/locale/en/zena.po +1275 -1129
  161. data/locale/fr/LC_MESSAGES/zena.mo +0 -0
  162. data/locale/fr/zena.mo +0 -0
  163. data/locale/fr/zena.po +1617 -1441
  164. data/locale/log.txt +9 -0
  165. data/locale/zena.pot +957 -748
  166. data/public/javascripts/prototype.js +1 -1
  167. data/public/javascripts/zena.js +99 -44
  168. data/public/stylesheets/admin.css +6 -4
  169. data/public/stylesheets/backend.css +71 -0
  170. data/public/stylesheets/calendar.css +24 -25
  171. data/public/stylesheets/code.css +11 -6
  172. data/public/stylesheets/comment.css +2 -1
  173. data/public/stylesheets/popup.css +7 -8
  174. data/test/custom_queries/complex.host.yml +15 -1
  175. data/test/fixtures/files/Node-test.zafu +29 -28
  176. data/test/fixtures/files/translations_de.yml +12 -1
  177. data/test/fixtures/files/translations_fr.yml +12 -1
  178. data/test/functional/comments_controller_test.rb +9 -0
  179. data/test/functional/iformats_controller_test.rb +1 -1
  180. data/test/functional/nodes_controller_test.rb +124 -35
  181. data/test/functional/users_controller_test.rb +132 -3
  182. data/test/functional/virtual_classes_controller_test.rb +75 -4
  183. data/test/integration/navigation_test.rb +51 -9
  184. data/test/integration/query_node/basic.yml +19 -7
  185. data/test/integration/query_node/complex.yml +1 -1
  186. data/test/integration/query_node/dates.yml +27 -1
  187. data/test/integration/query_node/filters.yml +1 -1
  188. data/test/integration/query_node/relations.yml +13 -4
  189. data/test/integration/query_node_test.rb +4 -0
  190. data/test/integration/xml_api_test.rb +6 -1
  191. data/test/integration/zafu_compiler/action.yml +3 -3
  192. data/test/integration/zafu_compiler/ajax.yml +103 -22
  193. data/test/integration/zafu_compiler/basic.yml +0 -52
  194. data/test/integration/zafu_compiler/calendar.yml +44 -20
  195. data/test/integration/zafu_compiler/comments.yml +53 -0
  196. data/test/integration/zafu_compiler/complex.yml +11 -11
  197. data/test/integration/zafu_compiler/complex_ok.yml +16 -3
  198. data/test/integration/zafu_compiler/conditional.yml +15 -5
  199. data/test/integration/zafu_compiler/context.yml +9 -0
  200. data/test/integration/zafu_compiler/dates.yml +43 -15
  201. data/test/integration/zafu_compiler/display.yml +60 -6
  202. data/test/integration/zafu_compiler/errors.yml +6 -2
  203. data/test/integration/zafu_compiler/forms.yml +45 -6
  204. data/test/integration/zafu_compiler/i18n.yml +8 -1
  205. data/test/integration/zafu_compiler/meta.yml +38 -0
  206. data/test/integration/zafu_compiler/query.yml +43 -4
  207. data/test/integration/zafu_compiler/relations.yml +26 -33
  208. data/test/integration/zafu_compiler/rubyless.yml +10 -0
  209. data/test/integration/zafu_compiler/safe_definitions.yml +21 -1
  210. data/test/integration/zafu_compiler/urls.yml +75 -5
  211. data/test/integration/zafu_compiler/version.yml +2 -2
  212. data/test/integration/zafu_compiler/zafu_attributes.yml +5 -1
  213. data/test/integration/zafu_compiler/zazen.yml +14 -6
  214. data/test/integration/zafu_compiler_test.rb +5 -1
  215. data/test/sites/complex/columns.yml +5 -0
  216. data/test/sites/complex/roles.yml +4 -0
  217. data/test/sites/zena/nodes.yml +13 -2
  218. data/test/sites/zena/roles.yml +13 -5
  219. data/test/sites/zena/versions.yml +27 -9
  220. data/test/unit/column_test.rb +51 -5
  221. data/test/unit/iformat_test.rb +2 -2
  222. data/test/unit/node_test.rb +29 -17
  223. data/test/unit/note_test.rb +1 -1
  224. data/test/unit/relation_proxy_test.rb +4 -5
  225. data/test/unit/relation_test.rb +16 -0
  226. data/test/unit/remote_test.rb +2 -2
  227. data/test/unit/role_test.rb +292 -4
  228. data/test/unit/site_test.rb +12 -0
  229. data/test/unit/template_test.rb +1 -1
  230. data/test/unit/text_document_test.rb +1 -1
  231. data/test/unit/virtual_class_test.rb +200 -83
  232. data/test/unit/zena/acts/enrollable_test.rb +26 -31
  233. data/test/unit/zena/use/calendar_test.rb +90 -37
  234. data/test/unit/zena/use/field_index_test.rb +28 -0
  235. data/test/unit/zena/use/html_tags_test.rb +7 -3
  236. data/test/unit/zena/use/ml_index_test.rb +2 -16
  237. data/test/unit/zena/use/nested_attributes_alias_view_test.rb +2 -2
  238. data/test/unit/zena/use/prop_eval_test.rb +50 -8
  239. data/test/unit/zena/use/query_node_test.rb +11 -0
  240. data/test/unit/zena/use/rendering_test.rb +72 -0
  241. data/test/unit/zena/use/scope_index_test.rb +37 -2
  242. data/test/unit/zena/use/urls_test.rb +10 -0
  243. data/test/unit/zena/use/zazen_test.rb +3 -3
  244. data/vendor/plugins/gettext_i18n_rails/Gemfile +11 -0
  245. data/vendor/plugins/gettext_i18n_rails/Gemfile.lock +92 -0
  246. data/vendor/plugins/gettext_i18n_rails/Rakefile +12 -17
  247. data/vendor/plugins/gettext_i18n_rails/Readme.md +215 -0
  248. data/vendor/plugins/gettext_i18n_rails/VERSION +1 -1
  249. data/vendor/plugins/gettext_i18n_rails/gettext_i18n_rails.gemspec +38 -34
  250. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/active_record.rb +1 -1
  251. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/backend.rb +30 -14
  252. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/haml_parser.rb +1 -1
  253. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/html_safe_translations.rb +29 -0
  254. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/i18n_hacks.rb +29 -1
  255. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/model_attributes_finder.rb +7 -1
  256. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/railtie.rb +10 -0
  257. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/ruby_gettext_extractor.rb +6 -2
  258. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/string_interpolate_fix.rb +20 -0
  259. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/tasks.rb +120 -0
  260. data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails.rb +10 -3
  261. data/vendor/plugins/gettext_i18n_rails/lib/tasks/gettext_rails_i18n.rake +1 -74
  262. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/active_record_spec.rb +51 -20
  263. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/backend_spec.rb +12 -7
  264. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/string_interpolate_fix_spec.rb +32 -0
  265. data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails_spec.rb +38 -1
  266. data/vendor/plugins/gettext_i18n_rails/spec/rails2/Gemfile +11 -0
  267. data/vendor/plugins/gettext_i18n_rails/spec/spec_helper.rb +1 -8
  268. data/zena.gemspec +2241 -2217
  269. metadata +123 -83
  270. data/.gitignore +0 -36
  271. data/app/views/nodes/_dates.rhtml +0 -13
  272. data/db/init/base/skins/default/Node-+adminLayout.zafu +0 -46
  273. data/db/init/base/skins/default/Node-tree.zafu +0 -19
  274. data/vendor/plugins/gettext_i18n_rails/README.markdown +0 -143
@@ -1,7 +1,7 @@
1
1
  # zena apache2 vhost for <%= config[:host] %>
2
2
  # automatically generated file
3
3
 
4
- <VirtualHost *>
4
+ <VirtualHost *<%= config[:ssl] ? ':443' : '' %>>
5
5
  ServerName <%= config[:host] %>
6
6
 
7
7
  DocumentRoot <%= config[:sites_root] %>/<%= config[:host] %>/public
@@ -95,4 +95,12 @@
95
95
  LogFormat '"%r" %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate
96
96
  CustomLog <%= config[:sites_root] %>/<%= config[:host] %>/log/deflate.log deflate
97
97
  <% end %>
98
+
99
+ <% if config[:ssl] %>
100
+ SSLEngine on
101
+ SSLCertificateFile /etc/ssl/<%= config[:host] %>.crt
102
+ SSLCertificateKeyFile /etc/ssl/<%= config[:host] %>.key
103
+ SSLCACertificateFile /etc/ssl/<%= config[:ssl_pem] %>
104
+ SSLVerifyClient None
105
+ <% end %>
98
106
  </VirtualHost>
data/lib/zena/deploy.rb CHANGED
@@ -149,7 +149,7 @@ Capistrano::Configuration.instance(:must_exist).load do
149
149
  #========================== MANAGE HOST =========================#
150
150
  desc "create a new site [-s host='...' -s pass='...' -s lang='...']"
151
151
  task :mksite, :roles => :app do
152
- run "#{in_current} rake zena:mksite HOST='#{self[:host]}' PASSWORD='#{self[:pass]}' RAILS_ENV='production' LANG='#{self[:lang] || 'en'}'"
152
+ run "#{in_current} rake zena:mksite HOST='#{self[:host]}' PASSWORD='#{self[:pass]}' RAILS_ENV='production' HOST_LANG='#{self[:lang] || 'en'}'"
153
153
  create_vhost
154
154
  create_awstats
155
155
  logrotate
@@ -307,12 +307,17 @@ Capistrano::Configuration.instance(:must_exist).load do
307
307
  end
308
308
 
309
309
  run "test -e /etc/apache2/sites-enabled/000-default && a2dissite default || echo 'default already disabled'"
310
- run "test -e /etc/apache2/mods-enabled/rewrite.load || a2enmod rewrite"
311
- run "test -e /etc/apache2/mods-enabled/deflate.load || a2enmod deflate"
312
- run "test -e /etc/apache2/mods-enabled/proxy_balancer.load || a2enmod proxy_balancer"
313
- run "test -e /etc/apache2/mods-enabled/proxy.load || a2enmod proxy"
314
- run "test -e /etc/apache2/mods-enabled/proxy_http.load || a2enmod proxy_http"
315
- run "test -e /etc/apache2/mods-enabled/expires.load || a2enmod expires"
310
+
311
+ modules = %w{rewrite deflate proxy_balancer proxy proxy_http expires}
312
+ if self[:ssl]
313
+ modules << 'ssl'
314
+ # Default in debian: no need to change ports.
315
+ # /etc/apache2/ports.conf:
316
+ # Listen 443
317
+ end
318
+ modules.each do |mod|
319
+ run "test -e /etc/apache2/mods-enabled/#{mod}.load || a2enmod #{mod}"
320
+ end
316
321
  run "/etc/init.d/apache2 force-reload"
317
322
  end
318
323
 
@@ -411,7 +411,7 @@ module Zena
411
411
  records = [
412
412
  { 'id' => Zena::FoxyParser::id(site, "#{name}_#{node['v_lang'] || node['ref_lang']}"),
413
413
  'publish_from' => node['v_publish_from'],
414
- 'status' => Zena::Status[node['v_status'].to_sym],
414
+ 'status' => Zena::Status[(node['v_status'] || 'pub').to_sym],
415
415
  'lang' => node['v_lang'] || node['ref_lang']
416
416
  }
417
417
  ]
@@ -602,6 +602,7 @@ module Zena
602
602
  version['lang'] ||= node['ref_lang']
603
603
  version['user_id'] ||= Zena::FoxyParser::multi_site_id(node['user'])
604
604
  if prop = version.delete('prop')
605
+ version['idx_text_high'] = prop['title']
605
606
  version['properties'] = make_prop(prop) unless prop.blank?
606
607
  end
607
608
 
@@ -642,6 +643,7 @@ module Zena
642
643
  version['prop']['title'] ||= version['node']
643
644
 
644
645
  if prop = version.delete('prop')
646
+ version['idx_text_high'] = prop['title']
645
647
  version['properties'] = make_prop(prop) unless prop.blank?
646
648
  end
647
649
 
data/lib/zena/info.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Zena
2
- VERSION = '1.0.0.rc2'
2
+ VERSION = '1.0.0.rc3'
3
3
  ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
4
4
  end
@@ -1,3 +1,4 @@
1
+ # This should be removed (it is used by zazen but I do not know why)
1
2
  module Zena
2
3
  module Parser
3
4
  module ZafuTags
@@ -203,7 +203,7 @@ module Zena
203
203
  store "\"#{title}\":#{id}"
204
204
  else
205
205
  id = "#{node.zip}#{mode_format}"
206
- if format == '.data'
206
+ if format == '.data' && node.kind_of?(Document)
207
207
  title = "#{node.fullpath_as_title.join('/')}#{mode}.#{node.ext}#{dash}"
208
208
  else
209
209
  title = "#{node.fullpath_as_title.join('/')}#{mode_format}"
@@ -13,7 +13,10 @@ module Zena
13
13
  def attributes=(new_attributes)
14
14
  raise Exception.new("Invalid attributes. Expecting a hash, found #{new_attributes.inspect}") unless new_attributes.kind_of?(Hash)
15
15
  new_attributes.stringify_keys.each do |key, value|
16
- if value.kind_of?(Array)
16
+ writer = "#{key}=".to_sym
17
+ if self.respond_to?(writer)
18
+ self.send(writer, value)
19
+ elsif value.kind_of?(Array)
17
20
  # setting multiple ids
18
21
  key = "#{key}_ids" unless key =~ /_ids$/
19
22
  @attributes[key] = value.map do |elem|
@@ -34,6 +37,10 @@ module Zena
34
37
  end
35
38
  end
36
39
 
40
+ def tag_names=(list)
41
+ @attributes['tag_names'] = SerializableArray.new('tag_names', 'tag', list)
42
+ end
43
+
37
44
  def id
38
45
  @attributes['id']
39
46
  end
@@ -48,8 +55,13 @@ module Zena
48
55
  @attributes[key] = elem.id
49
56
  elsif elem.kind_of?(Array)
50
57
  key = "#{key}_ids" unless key =~ /_ids?$/
51
- @attributes[key] = elem.map do |value|
52
- value.kind_of?(Remote::Node) ? value.id : value
58
+ if elem == []
59
+ # Fix for strange handling of empty array by to_xml and such.
60
+ @attributes[key] = nil
61
+ else
62
+ @attributes[key] = elem.map do |value|
63
+ value.kind_of?(Remote::Node) ? value.id : value
64
+ end
53
65
  end
54
66
  else
55
67
  @attributes[$1] = elem
@@ -0,0 +1,19 @@
1
+ module Zena
2
+ module Remote
3
+ class SerializableArray < Array
4
+ def initialize(name, elem_name, elements)
5
+ @name, @elem_name = name, elem_name
6
+ replace(elements)
7
+ end
8
+
9
+ def to_xml(opts)
10
+ builder = opts[:builder]
11
+ builder.tag!(@name, :type => :array) do
12
+ each do |elem|
13
+ builder.tag!(@elem_name, elem.to_s, :type => :string)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end # Remote
19
+ end # Zena
data/lib/zena/remote.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'active_support'
2
2
  require 'zena/remote/interface'
3
3
  require 'zena/remote/klass'
4
+ require 'zena/remote/serializable_array'
4
5
  require 'zena/remote/node'
5
6
  require 'zena/remote/connection'
6
7
 
data/lib/zena/routes.rb CHANGED
@@ -56,8 +56,13 @@ module Zena
56
56
  :member => { :crop_form => :get }
57
57
 
58
58
  resources :relations
59
- resources :virtual_classes, :collection => {:import => :post}
60
- resources :columns, :collection => {:import => :post}
59
+ resources :virtual_classes, :collection => {
60
+ :import_prepare => :post,
61
+ :import => :post,
62
+ :export => :get,
63
+ }
64
+
65
+ resources :columns
61
66
 
62
67
  resources :sites,
63
68
  :member => { :clear_cache => :post }
@@ -19,7 +19,7 @@ module Zena
19
19
  def perform(site = nil)
20
20
  if site.nil?
21
21
  site ||= Site.find(site_id)
22
- Thread.current[:visitor] = site.anon
22
+ Thread.current[:visitor] = site.any_admin
23
23
  end
24
24
 
25
25
  if nodes = get_nodes
@@ -44,5 +44,15 @@ module Zena
44
44
  def page_count
45
45
  (Node.count(:conditions => ['site_id = ?', site_id]) / CHUNK_SIZE) + 1
46
46
  end
47
+
48
+ # Return a textual description of the operation.
49
+ def info
50
+ if site_id == current_site.id
51
+ "#{action}, #{_('page')} #{page}/#{page_count}"
52
+ else
53
+ # Do not show jobs from other sites
54
+ "-"
55
+ end
56
+ end
47
57
  end
48
58
  end # Zena
@@ -17,6 +17,74 @@ module Zena
17
17
  # Ignore since we include helpers in the TestCase itself
18
18
  end
19
19
 
20
+ # Specific helpers to validate model relations and queries with SQLiss
21
+ def main_date
22
+ raise "The test uses 'validate_query' without defining @main_date" unless @main_date
23
+ return @main_date.strftime("'%Y-%m-%d'")
24
+ end
25
+
26
+ # Test a query (useful with complex custom queries). Usage:
27
+ #
28
+ # validate_query "emp_comp_dates where log_at is not null", [
29
+ # { :title => 'Creativity',
30
+ # :priority => '5',
31
+ # :log_at => '2010-06-01',
32
+ # :event_at => '2011-06-01',
33
+ # },
34
+ # { :title => 'Leadership',
35
+ # :priority => '5',
36
+ # :log_at => '2003-01-01',
37
+ # :event_at => nil, # forever
38
+ # },
39
+ # ]
40
+ #
41
+ def validate_query(query, expected_list)
42
+ list = subject.find(:all, query.gsub('&lt;', '<').gsub('&gt;', '>'), :errors => true)
43
+ if expected_list.nil? || expected_list.empty?
44
+ assert_equal nil, list
45
+ elsif expected_list.first.kind_of?(String)
46
+ assert_equal expected_list, list.map(&:title)
47
+ elsif list.nil?
48
+ assert_equal expected_list, list
49
+ elsif list.kind_of?(::QueryBuilder::Error)
50
+ assert_equal expected_list, list.to_s
51
+ else
52
+ proto = expected_list.first.keys
53
+ sz = [expected_list.size, list.size].max
54
+
55
+ (0..(sz-1)).to_a.each do |i|
56
+ record = list[i]
57
+ expected = expected_list[i]
58
+ if not record
59
+ assert_equal expected[:title], nil
60
+ elsif not expected
61
+ assert_equal nil, map_to_proto(proto, record)
62
+ else
63
+ if expected[:title] != record.title
64
+ assert_equal expected[:title], map_to_proto(proto, record)
65
+ else
66
+ expected.keys.each do |key|
67
+ value = format_date(record[key] || record.send(key))
68
+ assert_equal expected[key], value, "(#{record.title} #{key} expected to be #{expected[key].inspect} but was #{value.inspect}"
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ private
77
+ def format_date(date)
78
+ if date.respond_to?(:strftime)
79
+ date.strftime('%Y-%m-%d')
80
+ else
81
+ date
82
+ end
83
+ end
84
+
85
+ def map_to_proto(proto, record)
86
+ Hash[*proto.map{|k| [k, format_date(record[k] || record.send(k))]}.flatten]
87
+ end
20
88
  end
21
89
  end
22
90
  end
@@ -27,12 +27,16 @@ module Zena
27
27
  tag = "<a href='#{url}' target='_blank' title='#{title}' onclick=\"Zena.open_window('#{url}', '#{id}', event);return false;\">"
28
28
  else
29
29
  query = query.empty? ? '' : "?#{query.join('&')}"
30
- tag = "<a href='/nodes/#{node_zip}/versions/0/#{action}#{query}' onclick='Zena.put(this);return false;' title ='#{title}'>"
30
+ tag = "<a href='/nodes/#{node_zip}/versions/0/#{action}#{query}' onclick='Zena.m(this, \"put\");return false;' title ='#{title}'>"
31
31
  end
32
32
  "#{tag}#{text}</a>"
33
33
  end
34
34
  end
35
35
 
36
+ module ControllerMethods
37
+ include Common
38
+ end
39
+
36
40
  module ViewMethods
37
41
  include Common
38
42
  include RubyLess
@@ -270,7 +274,6 @@ class #{node.klass}: #{Array(node.klass).first.columns.keys.join(', ')}
270
274
  end
271
275
  elsif block = (ancestor('block') || ancestor('each'))
272
276
  # ancestor: ok
273
- block = self
274
277
  elsif parent && block = parent.descendant('block')
275
278
  # sibling: ok
276
279
  upd_both = ''
@@ -285,6 +288,7 @@ class #{node.klass}: #{Array(node.klass).first.columns.keys.join(', ')}
285
288
  out make_link(:update => block, :action => 'update', :query_params => query_params, :method => :put)
286
289
  end
287
290
  end # ZafuMethods
291
+
288
292
  end # Action
289
293
  end # Use
290
294
  end # Zena
data/lib/zena/use/ajax.rb CHANGED
@@ -2,24 +2,29 @@ module Zena
2
2
  module Use
3
3
  module Ajax
4
4
  module ViewMethods
5
+ include RubyLess
6
+ safe_method :ajax? => {:class => Boolean, :method => 'params[:s]'}
7
+
5
8
  # Return the DOM id for a node. We had to name this method 'ndom_id' because we want
6
9
  # to avoid the clash with Rails' dom_id method.
7
10
  def ndom_id(node)
8
- if node.new_record?
9
- "#{params[:dom_id]}_form"
10
- elsif params[:action] == 'create' && !params[:udom_id]
11
- "#{params[:dom_id]}_#{node.zip}"
12
- else
13
- @dom_id || params[:udom_id] || params[:dom_id]
11
+ if node.kind_of?(Node)
12
+ if node.new_record?
13
+ return "#{params[:dom_id]}_form"
14
+ elsif params[:action] == 'create' && !params[:udom_id]
15
+ return "#{params[:dom_id]}_#{node.zip}"
16
+ end
14
17
  end
18
+
19
+ @dom_id || params[:udom_id] || params[:dom_id]
15
20
  end
16
21
 
17
22
  # RJS to update a page after create/update/destroy
18
23
  def update_page_content(page, obj)
19
24
  unless params[:dom_id]
20
25
  # simply reply with failure or success
21
- if !@node.errors.empty?
22
- page << "alert(#{@node.errors.first.join(': ')});"
26
+ if !obj.errors.empty?
27
+ page << "alert(#{obj.errors.first.join(': ')});"
23
28
  page << "return false;" # How to avoid 'onSuccess' ?
24
29
  elsif params[:udom_id] == '_page'
25
30
  # reload page
@@ -30,8 +35,8 @@ module Zena
30
35
  return
31
36
  end
32
37
 
33
- if params[:t_id] && @node.errors.empty?
34
- @node = secure(Node) { Node.find_by_zip(params[:t_id])}
38
+ if params[:t_id] && obj.errors.empty?
39
+ obj = secure(Node) { Node.find_by_zip(params[:t_id])}
35
40
  end
36
41
 
37
42
  base_class = obj.kind_of?(Node) ? Node : obj.class
@@ -84,14 +89,13 @@ module Zena
84
89
  case params[:action]
85
90
  when 'edit'
86
91
  page.replace params[:dom_id], :file => template_path_from_template_url + ".erb"
87
- puts "$('#{params[:dom_id]}_form_t').focusFirstElement();"
88
92
  page << "$('#{params[:dom_id]}_form_t').focusFirstElement();"
89
93
  when 'create'
90
94
  pos = params[:position] || :before
91
95
  ref = params[:reference] || "#{params[:dom_id]}_add"
92
96
  page.insert_html pos.to_sym, ref, :file => template_path_from_template_url + ".erb"
93
97
  if obj.kind_of?(Node)
94
- @node = @node.parent.new_child(:class => @node.class)
98
+ @node = obj.parent.new_child(:class => obj.class)
95
99
  else
96
100
  instance_variable_set("@#{base_class.to_s.underscore}", obj.clone)
97
101
  end
@@ -115,7 +119,11 @@ module Zena
115
119
  end
116
120
  page.replace params[:dom_id], :file => template_path_from_template_url + ".erb"
117
121
  else
118
- page.replace params[:dom_id], :file => template_path_from_template_url + ".erb"
122
+ if position = params[:insert]
123
+ page.call 'Zena.insert_inner', params[:dom_id], position, render(:file => template_path_from_template_url + ".erb")
124
+ else
125
+ page.replace params[:dom_id], :file => template_path_from_template_url + ".erb"
126
+ end
119
127
  end
120
128
  end
121
129
  page << render_js(false)
@@ -179,43 +187,46 @@ module Zena
179
187
 
180
188
  module ZafuMethods
181
189
  def self.included(base)
182
- # TODO: move process_drag, process_toggle in 'before_wrap' callback so that 'node' properly set.
190
+ # TODO: move process_toggle in 'before_wrap' callback so that 'node' is properly set.
183
191
  base.before_process :process_drag, :process_toggle
184
192
  base.before_wrap :wrap_with_drag
185
193
  end
186
194
 
187
- def wrap_with_drag(text)
188
- if @wrap_with_drag
189
- @wrap_with_drag.wrap(text)
190
- else
191
- text
192
- end
195
+ def process_drag
196
+ @drag_param = @params.delete(:draggable)
193
197
  end
194
198
 
195
199
  # Force an id on the current tag and record the DOM_ID to make the element draggable.
196
- def process_drag
197
- return unless drag = @params.delete(:draggable)
200
+ def wrap_with_drag(text)
201
+ # do not render drag in make_form
202
+ return text unless @drag_param && !@context[:make_form]
203
+ drag = @drag_param
198
204
 
199
- if @markup.params[:id]
200
- # we do not mess with it
201
- markup = @wrap_with_drag = Zafu::Markup.new('span')
205
+ if @markup.params[:id] || (@markup.done && @method == 'link') # hack to rewrap link...
206
+ # we do not mess with the original but use our own markup
207
+ markup = @wrap_markup = Zafu::Markup.new('span')
202
208
  else
203
209
  markup = @markup
204
210
  end
205
211
 
206
212
  markup.tag ||= 'div'
207
213
 
208
- node = pre_filter_node
209
-
210
214
  if @name.blank?
211
215
  # make sure we have a scope
212
- set_dom_prefix(node)
216
+ node.dom_prefix = dom_name
213
217
  end
214
218
 
215
- # We do not want to use the same id as the 'each' loop but we also want to
216
- # avoid changing the node context
217
- @drag_prefix ||= root.get_unique_name('drag', true).gsub(/[^\d\w\/]/,'_')
218
- markup.set_id(node.dom_id(:dom_prefix => @drag_prefix))
219
+ if erb_dom_id = markup.dyn_params[:id]
220
+ # id set, get erb id
221
+ else
222
+ # We do not want to use the same id as the 'each' loop but we also want to
223
+ # avoid changing the node context
224
+ @drag_prefix ||= root.get_unique_name('drag', true).gsub(/[^\d\w\/]/,'_')
225
+ erb_dom_id = node.dom_id(:dom_prefix => @drag_prefix)
226
+ markup.set_id(erb_dom_id)
227
+ end
228
+
229
+ dom_id = erb_dom_id[/<%=\s*(.*?)\s*%>/,1]
219
230
 
220
231
  markup.append_param(:class, 'drag')
221
232
 
@@ -234,7 +245,13 @@ module Zena
234
245
  js_options << (%w{true false}.include?(revert) ? revert : revert.inspect)
235
246
  end
236
247
 
237
- markup.pre_wrap[:drag] = "#{handle}<% add_drag_id(\"#{node.dom_id(:dom_prefix => @drag_prefix, :erb => false)}\", #{js_options.join(', ').inspect}) %>"
248
+ markup.pre_wrap[:drag] = "#{handle}<% add_drag_id(#{dom_id}, #{js_options.join(', ').inspect}) %>"
249
+
250
+ if @markup == markup
251
+ text
252
+ else
253
+ markup.wrap(text)
254
+ end
238
255
  end
239
256
 
240
257
  # Display an input field to filter a remote block
@@ -243,13 +260,24 @@ module Zena
243
260
  return unless block = find_target(upd)
244
261
  else
245
262
  return parser_error("missing 'block' in same parent") unless parent && block = parent.descendant('block')
263
+ if block.name.blank?
264
+ block.name ||= unique_name
265
+ end
266
+ upd = block.name
246
267
  end
247
268
 
248
269
  return parser_error("cannot use 's' as key (used by start_node)") if @params[:key] == 's'
249
270
 
271
+ # Move up in case we are in a list.
272
+ if self.node.list_context?
273
+ node = self.node.up(Node)
274
+ else
275
+ node = self.node
276
+ end
277
+ node.dom_prefix = dom_name
250
278
  dom_id = node.dom_id(:erb => false)
251
279
 
252
- out %Q{<%= form_remote_tag(:url => zafu_node_path(#{node}.zip), :method => :get, :html => {:id => \"#{dom_id}_f\"}) %>
280
+ out %Q{<%= form_remote_tag(:url => zafu_node_path(#{node}), :method => :get, :html => {:id => \"#{dom_id}_f\"}) %>
253
281
  <div class='hidden'>
254
282
  <input type='hidden' name='t_url' value='#{template_url(upd)}'/>
255
283
  <input type='hidden' name='dom_id' value='#{upd}'/>
@@ -271,25 +299,22 @@ module Zena
271
299
  def r_drop
272
300
  if parent.method == 'each' && @method == parent.single_child_method
273
301
  # We reuse the 'each' block.
274
- markup = parent.markup
275
- # Make sure the parent has a proper dom_prefix.
276
- parent.set_dom_prefix
302
+ target = parent
277
303
  else
278
- set_dom_prefix
279
- markup = @markup
304
+ node.dom_prefix = dom_name
305
+ target = self
280
306
  end
281
307
 
308
+ # Make sure the target has a proper dom_prefix.
309
+ # FIXME: Test without, not sure this is needed anymore
310
+ #target.node.dom_prefix = target.dom_name
311
+
312
+ node = target.node
313
+ markup = target.markup
314
+
282
315
  markup.tag ||= 'div'
283
316
 
284
- # This dom_id detection code is crap but it fixes the drop in each bug.
285
- if dom_id = markup.dyn_params[:id]
286
- if dom_id =~ /<%= %Q\{(.*)\} %>/
287
- dom_id = $1
288
- end
289
- else
290
- dom_id = node.dom_id(:list => false, :erb => false)
291
- markup.set_id(node.dom_id(:list => false))
292
- end
317
+ dom_id, dom_prefix = get_dom_id(target)
293
318
 
294
319
  markup.append_param(:class, 'drop') unless markup.params[:class] =~ /drop/
295
320
 
@@ -300,11 +325,11 @@ module Zena
300
325
  end
301
326
 
302
327
  if role = @params.delete(:set) || @params.delete(:add)
303
- @params["node[#{role}_id]"] = '\#{id}'
328
+ @params["node[#{role}_id]"] = '\\#{id}'
304
329
  end
305
330
 
306
- query_params << ", :url => #{make_href(self.name, :action => 'drop')}"
307
- markup.pre_wrap[:drop] = "<% add_drop_id(\"#{dom_id}\"#{query_params}) %>"
331
+ query_params << ", :url => #{make_href(target, :action => 'drop')}"
332
+ markup.pre_wrap[:drop] = "<% add_drop_id(#{dom_id}#{query_params}) %>"
308
333
  r_block
309
334
  end
310
335
 
@@ -316,7 +341,7 @@ module Zena
316
341
  finder = RubyLess.translate(self, finder)
317
342
  return parser_error("Invalid class 'for' parameter: #{finder.klass}") unless finder.klass <= Node
318
343
 
319
- set_dom_prefix
344
+ node.dom_prefix = dom_name
320
345
  dom_id = node.dom_id(:erb => false)
321
346
  markup.set_id(node.dom_id)
322
347
  markup.append_param(:class, 'toggle')
@@ -342,7 +367,7 @@ module Zena
342
367
  if dom_id = @markup.params[:id]
343
368
  # we do not mess with it
344
369
  else
345
- set_dom_prefix
370
+ node.dom_prefix = dom_name
346
371
  markup.set_id(node.dom_id)
347
372
  dom_id = node.dom_id(:erb => false)
348
373
  end
@@ -403,6 +428,22 @@ module Zena
403
428
  #end
404
429
  end
405
430
 
431
+ # Add some js at end of document/partial
432
+ def r_js
433
+ if @blocks.detect {|b| !b.kind_of?(String)}
434
+ out "<% js_data << capture do %>"
435
+ out expand_with
436
+ out "<% end %>"
437
+ else
438
+ txt = @blocks.join('')
439
+ out "<% js_data << #{txt.inspect} %>"
440
+ end
441
+ end
442
+
443
+ def r_ajax?
444
+ r_if(RubyLess.translate(self, 'ajax?'))
445
+ end
446
+
406
447
  protected
407
448
 
408
449
  def need_ajax?(each_block)
@@ -413,6 +454,39 @@ module Zena
413
454
  each_block.descendant('unlink')
414
455
  end
415
456
 
457
+ # Returns ruby for dom_id.
458
+ #
459
+ # FIXME: HACK
460
+ # This dom_id detection code is crap but it fixes the drop in each bug.
461
+ def get_dom_id(target)
462
+ if dom_id = target.markup.dyn_params[:id] || target.markup.params[:id]
463
+ if dom_id =~ /^<%=\s+(.*?)\s+%>$/
464
+ dom_id = $1
465
+ else
466
+ dom_id = "%Q{#{dom_id}}"
467
+ end
468
+
469
+ elsif target.context
470
+ # @context set, so node is available
471
+ dom_id = "%Q{#{target.node.dom_id(
472
+ :list => target.method == 'each',
473
+ :erb => false
474
+ )}}"
475
+
476
+ target.markup.set_id(node.dom_id(
477
+ :list => target.method == 'each'
478
+ ))
479
+ else
480
+ # Has not been rendered yet, does not have a dom_prefix set.
481
+ dom_id = "%Q{#{target.dom_name}}"
482
+
483
+ target.markup.set_id(node.dom_id(
484
+ :list => target.method == 'each'
485
+ ))
486
+ end
487
+
488
+ return [dom_id, target.context ? target.node.dom_prefix : target.dom_name]
489
+ end
416
490
  end
417
491
  end # Ajax
418
492
  end # Use