zena 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. data/History.txt +38 -1
  2. data/app/controllers/documents_controller.rb +7 -5
  3. data/app/controllers/nodes_controller.rb +47 -6
  4. data/app/controllers/user_sessions_controller.rb +12 -3
  5. data/app/controllers/virtual_classes_controller.rb +8 -2
  6. data/app/models/acl.rb +5 -2
  7. data/app/models/cached_page.rb +5 -5
  8. data/app/models/column.rb +27 -4
  9. data/app/models/group.rb +1 -1
  10. data/app/models/node.rb +106 -24
  11. data/app/models/note.rb +2 -1
  12. data/app/models/relation.rb +9 -4
  13. data/app/models/relation_proxy.rb +2 -2
  14. data/app/models/role.rb +12 -5
  15. data/app/models/site.rb +10 -9
  16. data/app/models/skin.rb +8 -0
  17. data/app/models/string_hash.rb +65 -0
  18. data/app/models/text_document.rb +1 -1
  19. data/app/models/user.rb +2 -0
  20. data/app/models/virtual_class.rb +43 -10
  21. data/app/views/comments/create.rjs +1 -32
  22. data/app/views/comments/edit.rjs +1 -1
  23. data/app/views/comments/update.rjs +1 -1
  24. data/app/views/documents/show.rhtml +1 -1
  25. data/app/views/groups/_form.rhtml +7 -0
  26. data/app/views/groups/_li.rhtml +1 -1
  27. data/app/views/nodes/500.html +2 -1
  28. data/app/views/nodes/destroy.rjs +2 -0
  29. data/app/views/sites/jobs.erb +2 -3
  30. data/app/views/templates/document_create_tabs/_file.rhtml +1 -1
  31. data/app/views/templates/document_create_tabs/_import.rhtml +4 -1
  32. data/app/views/templates/document_create_tabs/_template.rhtml +3 -0
  33. data/app/views/templates/document_create_tabs/_text_document.rhtml +3 -0
  34. data/app/views/versions/custom_tab.rhtml +1 -1
  35. data/app/views/versions/edit.rhtml +1 -1
  36. data/bricks/acls/lib/bricks/acls.rb +3 -3
  37. data/bricks/acls/zena/test/unit/acl_test.rb +15 -0
  38. data/bricks/fs_skin/lib/bricks/fs_skin.rb +190 -0
  39. data/bricks/fs_skin/zena/init.rb +1 -0
  40. data/bricks/fs_skin/zena/migrate/20110702010330_add_fs_skin_to_idx_templates.rb +12 -0
  41. data/bricks/{static → fs_skin}/zena/skins/blog/Image-edit.zafu +0 -0
  42. data/bricks/{static → fs_skin}/zena/skins/blog/Image.zafu +0 -0
  43. data/bricks/{static → fs_skin}/zena/skins/blog/Node-+index.zafu +0 -0
  44. data/bricks/{static → fs_skin}/zena/skins/blog/Node-+notFound.zafu +0 -0
  45. data/bricks/{static → fs_skin}/zena/skins/blog/Node-+search.zafu +0 -0
  46. data/bricks/{static → fs_skin}/zena/skins/blog/Node.zafu +1 -1
  47. data/bricks/{static → fs_skin}/zena/skins/blog/Post.zafu +0 -0
  48. data/bricks/{static → fs_skin}/zena/skins/blog/Project--kml.zafu +0 -0
  49. data/bricks/{static → fs_skin}/zena/skins/blog/Project.zafu +0 -0
  50. data/bricks/{static → fs_skin}/zena/skins/blog/comments.zafu +0 -0
  51. data/bricks/{static → fs_skin}/zena/skins/blog/dict.yml +0 -0
  52. data/bricks/{static → fs_skin}/zena/skins/blog/img/dateBg.jpg +0 -0
  53. data/bricks/{static → fs_skin}/zena/skins/blog/img/header.png +0 -0
  54. data/bricks/{static → fs_skin}/zena/skins/blog/img/mapPin.png +0 -0
  55. data/bricks/{static → fs_skin}/zena/skins/blog/img/menu.gif +0 -0
  56. data/bricks/{static → fs_skin}/zena/skins/blog/img/menuover.gif +0 -0
  57. data/bricks/{static → fs_skin}/zena/skins/blog/img/style.css +0 -0
  58. data/bricks/fs_skin/zena/tasks.rb +26 -0
  59. data/bricks/{static/zena/test/integration/static_integration_test.rb → fs_skin/zena/test/integration/fs_skin_integration_test.rb} +6 -6
  60. data/bricks/fs_skin/zena/test/unit/fs_skin_test.rb +33 -0
  61. data/bricks/grid/lib/bricks/grid.rb +4 -3
  62. data/bricks/tags/lib/bricks/tags.rb +1 -7
  63. data/bricks/zena/zena/migrate/20120605091558_add_ssl_login_to_site.rb +7 -0
  64. data/bricks/zena/zena/migrate/20120630123551_add_auto_publish_to_group.rb +9 -0
  65. data/config/bricks.yml +3 -3
  66. data/config/gems.yml +2 -3
  67. data/lib/tasks/zena.rake +7 -3
  68. data/lib/zafu.rb +7 -0
  69. data/lib/zafu/all.rb +21 -0
  70. data/lib/zafu/compiler.rb +7 -0
  71. data/lib/zafu/controller_methods.rb +58 -0
  72. data/lib/zafu/handler.rb +57 -0
  73. data/lib/zafu/info.rb +4 -0
  74. data/lib/zafu/markup.rb +309 -0
  75. data/lib/zafu/mock_helper.rb +42 -0
  76. data/lib/zafu/node_context.rb +203 -0
  77. data/lib/zafu/ordered_hash.rb +53 -0
  78. data/lib/zafu/parser.rb +676 -0
  79. data/lib/zafu/parsing_rules.rb +382 -0
  80. data/lib/zafu/process/ajax.rb +530 -0
  81. data/lib/zafu/process/conditional.rb +92 -0
  82. data/lib/zafu/process/context.rb +186 -0
  83. data/lib/zafu/process/forms.rb +143 -0
  84. data/lib/zafu/process/html.rb +186 -0
  85. data/lib/zafu/process/ruby_less_processing.rb +321 -0
  86. data/lib/zafu/security.rb +15 -0
  87. data/lib/zafu/template.rb +25 -0
  88. data/lib/zafu/test_helper.rb +19 -0
  89. data/lib/zafu/view_methods.rb +6 -0
  90. data/lib/zena.rb +1 -1
  91. data/lib/zena/acts/enrollable.rb +1 -1
  92. data/lib/zena/app.rb +4 -17
  93. data/lib/zena/console.rb +18 -1
  94. data/lib/zena/core_ext/file_utils.rb +13 -1
  95. data/lib/zena/core_ext/fixnum.rb +4 -0
  96. data/lib/zena/core_ext/float.rb +7 -0
  97. data/lib/zena/deploy.rb +4 -2
  98. data/lib/zena/deploy/app_init.rhtml +2 -1
  99. data/lib/zena/deploy/database.rhtml +1 -1
  100. data/lib/zena/info.rb +1 -1
  101. data/lib/zena/parser/zazen_rules.rb +4 -4
  102. data/lib/zena/routes.rb +1 -1
  103. data/lib/zena/test_controller.rb +1 -1
  104. data/lib/zena/use.rb +14 -1
  105. data/lib/zena/use/action.rb +4 -2
  106. data/lib/zena/use/ajax.rb +86 -38
  107. data/lib/zena/use/authlogic.rb +16 -1
  108. data/lib/zena/use/calendar.rb +37 -17
  109. data/lib/zena/use/conditional.rb +2 -2
  110. data/lib/zena/use/context.rb +30 -9
  111. data/lib/zena/use/dates.rb +39 -3
  112. data/lib/zena/use/display.rb +6 -19
  113. data/lib/zena/use/forms.rb +100 -79
  114. data/lib/zena/use/i18n.rb +40 -16
  115. data/lib/zena/use/query_builder.rb +0 -6
  116. data/lib/zena/use/query_node.rb +17 -4
  117. data/lib/zena/use/relations.rb +1 -3
  118. data/lib/zena/use/rendering.rb +10 -8
  119. data/lib/zena/use/scope_index.rb +5 -1
  120. data/lib/zena/use/search.rb +2 -1
  121. data/lib/zena/use/urls.rb +82 -77
  122. data/lib/zena/use/workflow.rb +12 -4
  123. data/lib/zena/use/zafu_safe_definitions.rb +37 -9
  124. data/lib/zena/use/zafu_templates.rb +49 -20
  125. data/lib/zena/use/zazen.rb +6 -2
  126. data/locale/it/LC_MESSAGES/zena.mo +0 -0
  127. data/locale/it/zena.mo +0 -0
  128. data/locale/it/zena.po +1982 -0
  129. data/public/images/arrow_back.png +0 -0
  130. data/public/images/remove_tag.png +0 -0
  131. data/public/javascripts/grid.js +800 -199
  132. data/public/javascripts/window.js +1 -1
  133. data/public/javascripts/zena.js +130 -21
  134. data/public/stylesheets/grid.css +11 -2
  135. data/public/stylesheets/zena.css +2 -1
  136. data/test/custom_queries/complex.host.yml +5 -0
  137. data/test/fixtures/files/TestNode.zafu +36 -0
  138. data/test/functional/nodes_controller_test.rb +18 -1
  139. data/test/integration/zafu_compiler/action.yml +2 -2
  140. data/test/integration/zafu_compiler/ajax.yml +44 -26
  141. data/test/integration/zafu_compiler/asset.yml +12 -2
  142. data/test/integration/zafu_compiler/basic.yml +0 -16
  143. data/test/integration/zafu_compiler/calendar.yml +6 -6
  144. data/test/integration/zafu_compiler/complex_ok.yml +23 -1
  145. data/test/integration/zafu_compiler/conditional.yml +5 -5
  146. data/test/integration/zafu_compiler/context.yml +6 -5
  147. data/test/integration/zafu_compiler/dates.yml +23 -2
  148. data/test/integration/zafu_compiler/display.yml +46 -2
  149. data/test/integration/zafu_compiler/errors.yml +2 -2
  150. data/test/integration/zafu_compiler/eval.yml +35 -7
  151. data/test/integration/zafu_compiler/forms.yml +47 -13
  152. data/test/integration/zafu_compiler/i18n.yml +2 -2
  153. data/test/integration/zafu_compiler/meta.yml +35 -1
  154. data/test/integration/zafu_compiler/query.yml +23 -4
  155. data/test/integration/zafu_compiler/relations.yml +10 -6
  156. data/test/integration/zafu_compiler/roles.yml +4 -4
  157. data/test/integration/zafu_compiler/rubyless.yml +11 -1
  158. data/test/integration/zafu_compiler/safe_definitions.yml +23 -5
  159. data/test/integration/zafu_compiler/security.yml +10 -6
  160. data/test/integration/zafu_compiler/urls.yml +23 -6
  161. data/test/integration/zafu_compiler/zafu_attributes.yml +1 -1
  162. data/test/integration/zafu_compiler/zazen.yml +14 -0
  163. data/test/selenium/Add/add3.rsel +8 -8
  164. data/test/selenium/Destroy/0setup.rsel +12 -0
  165. data/test/selenium/Destroy/destroy1.rsel +16 -0
  166. data/test/selenium/Edit/edit2.rsel +9 -9
  167. data/test/selenium/Edit/edit5.rsel +9 -9
  168. data/test/selenium/Edit/edit6.rsel +9 -9
  169. data/test/selenium/Form/form4.rsel +17 -0
  170. data/test/selenium/Toggle/toggle1.rsel +2 -0
  171. data/test/selenium/Toggle/toggle2.rsel +18 -0
  172. data/test/sites/zena/columns.yml +3 -0
  173. data/test/sites/zena/versions.yml +7 -0
  174. data/test/unit/cached_page_test.rb +13 -13
  175. data/test/unit/column_test.rb +26 -0
  176. data/test/unit/node_test.rb +16 -1
  177. data/test/unit/project_test.rb +6 -1
  178. data/test/unit/relation_test.rb +1 -1
  179. data/test/unit/role_test.rb +1 -1
  180. data/test/unit/string_hash_test.rb +30 -0
  181. data/test/unit/virtual_class_test.rb +31 -17
  182. data/test/unit/zafu_markup_test.rb +414 -0
  183. data/test/unit/zafu_node_context_test.rb +375 -0
  184. data/test/unit/zafu_ordered_hash_test.rb +69 -0
  185. data/test/unit/zena/acts/enrollable_test.rb +1 -1
  186. data/test/unit/zena/parser/zafu_asset.yml +0 -10
  187. data/test/unit/zena/parser/zazen.yml +1 -1
  188. data/test/unit/zena/parser_test.rb +1 -72
  189. data/test/unit/zena/use/dates_test.rb +1 -1
  190. data/test/unit/zena/use/rendering_test.rb +24 -7
  191. data/test/unit/zena/use/scope_index_test.rb +17 -0
  192. data/test/unit/zena/use/zazen_test.rb +2 -1
  193. data/zena.gemspec +71 -37
  194. metadata +104 -83
  195. data/app/views/nodes/destroy.erb +0 -0
  196. data/bricks/static/lib/bricks/static.rb +0 -151
  197. data/bricks/static/zena/init.rb +0 -1
  198. data/bricks/static/zena/migrate/20110702010330_add_static_to_idx_templates.rb +0 -12
  199. data/bricks/static/zena/test/unit/static_test.rb +0 -33
  200. data/lib/zena/parser/zafu_rules.rb +0 -244
  201. data/lib/zena/parser/zafu_tags.rb +0 -198
  202. data/lib/zena/parser/zena_rules.rb +0 -23
@@ -1,4 +1,41 @@
1
- == 1.2.0 2012-05-01
1
+ == 1.2.2 2012-08-30
2
+
3
+ * Major changes
4
+ * Basic zjs to batch create/update nodes (with grid.js).
5
+ * Zafu is not a separate gem anymore.
6
+ * Added simple support for JS Tags (used to define grid colums).
7
+ * Enabled rebuilding of templates on partial query.
8
+ * Enabled 'hash' property type.
9
+ * Enabled javascript on toggle.
10
+ * Enabled "fs_skin" brick to use zafu stored in brick file system.
11
+ * No need to use '>' or '<' in html params. \' escape works. Yeah !!
12
+ * Enabled "static" assets with symlink to skins in fs_skin bricks (/static/[brick]-[skin]/xxx.css => bricks/[brick]/skins/[skin]/static/xxx.css)
13
+ * No more strict scoping: "set" variables are rewritten if type matches.
14
+ * Added support for new in rubyless (Post.new, Post.new(:title => 'foo')).
15
+ * Added support for type in custom queries and SQLiss select "nodes select created_at as ti:time"
16
+
17
+ * Minor changes
18
+ * Fixed label traduction for param.
19
+ * Enable ajax response on Node destroy (use dummy update parameter).
20
+ * Added 'sum' method on array. <===== TODO: Document
21
+ * Added 'loading' option to [filter].
22
+ * Added 'master_template' zafu method to access the master template used for compilation.
23
+ * Fixed creation of modules bug.
24
+ * Using latest QueryBuilder (fixes default scope bug).
25
+ * Added 'ssl_on_auth' option to force https after (and during) login. <=== TODO: Document
26
+ * Removing evaluated strings if copy_id is blank.
27
+ * Exporting relations by class name instead of kpath (may differ from site to site).
28
+ * Using any character to build kpath if no character from the class name can be used.
29
+ * Going through reverse order in console's foreach in case we destroy nodes.
30
+ * Added support for "target" in [zazen] when rendering links.
31
+ * Fixed kpath propagation to relations on kpath change.
32
+ * Fixed [block] in [block] with [filter] bug.
33
+ * Added support for KPATH_VALUE(ClassName) in custom queries. <==== TODO: Document
34
+ * Fixed class scoping Contact? when current node is more specialized.
35
+ * Fixed bug on syntax error in Acl query.
36
+ * Fixed cache expire bug (some pages were not properly removed).
37
+
38
+ == 1.2.0, 1.2.1 2012-05-01
2
39
 
3
40
  * Major changes
4
41
  * Added 'remove_from_db' method to remove a site from the database.
@@ -61,14 +61,16 @@ class DocumentsController < ApplicationController
61
61
  else
62
62
  page.call 'UploadProgress.setAsFinished'
63
63
  page.delay(1) do # allow the progress bar fade to complete
64
- if params[:redir]
65
- page << "Zena.reload_and_close(#{params[:redir].inspect})"
66
- end
67
64
  if params[:js]
68
65
  page << params[:js]
69
66
  end
70
- if !params[:redir] && !params[:js]
71
- page.redirect_to document_url(@node[:zip])
67
+ if params[:reload]
68
+ page << "Zena.t().Zena.reload(#{params[:reload].inspect})"
69
+ end
70
+ if params[:redir]
71
+ page << "Zena.reload_and_close(#{params[:redir].inspect})"
72
+ else
73
+ page.redirect_to document_url(@node[:zip], :reload => params[:reload], :js => params[:js])
72
74
  end
73
75
  end
74
76
  end
@@ -235,9 +235,19 @@ class NodesController < ApplicationController
235
235
  format.html {
236
236
  redirect_to params[:redir] || zen_path(@node, :mode => params[:mode], :new => 'true')
237
237
  }
238
- format.js
238
+ format.js do
239
+ if params[:zjs]
240
+ attrs = {'id' => @node.zip}
241
+ params[:node].each do |k,v|
242
+ v = @node.zafu_eval(k, params[:opts])
243
+ attrs[k] = v
244
+ end
245
+ render :json => attrs.to_json, :status => :created
246
+ end
247
+ end
239
248
  format.xml { render :xml => @node.to_xml(:root => 'node'), :status => :created, :location => node_url(@node) }
240
249
  else
250
+ # ERROR
241
251
  format.html do
242
252
  flash[:error] = error_messages_for('node', :object => @node)
243
253
  if request.referer
@@ -246,7 +256,11 @@ class NodesController < ApplicationController
246
256
  raise ActiveRecord::RecordNotFound
247
257
  end
248
258
  end
249
- format.js
259
+ format.js do
260
+ if params[:zjs]
261
+ render :json => @node.errors, :status => :unprocessable_entity
262
+ end
263
+ end
250
264
  format.xml { render :xml => @node.errors, :status => :unprocessable_entity }
251
265
  end
252
266
  end
@@ -279,7 +293,7 @@ class NodesController < ApplicationController
279
293
  end
280
294
  end
281
295
 
282
- format.xml do
296
+ format.xml do
283
297
  node_xml = @node.to_xml #need to be allocated before destroying
284
298
  if node_xml && @node.destroy
285
299
  render :xml => node_xml, :status => 200
@@ -289,7 +303,21 @@ class NodesController < ApplicationController
289
303
  end
290
304
  end
291
305
 
292
- format.js
306
+ format.js do
307
+
308
+ if params[:zjs]
309
+ node_json = @node.to_json
310
+ if @node.destroy
311
+ render :json => node_json, :status => 200
312
+ else
313
+ render :json => @node.errors, :status => :unprocessable_entity
314
+ end
315
+ else
316
+ @parent = @node.parent
317
+ @node.destroy
318
+ # update_page_content(page, @parent)
319
+ end
320
+ end
293
321
 
294
322
  end
295
323
  end
@@ -410,7 +438,21 @@ class NodesController < ApplicationController
410
438
  end
411
439
  end # html
412
440
 
413
- format.js { @flash = flash }
441
+ format.js do
442
+ @flash = flash
443
+ if params[:zjs]
444
+ if @node.errors.empty?
445
+ attrs = {}
446
+ params[:node].each do |k,v|
447
+ v = @node.zafu_eval(k, params[:opts])
448
+ attrs[k] = v
449
+ end
450
+ render :json => attrs.to_json, :status => :ok
451
+ else
452
+ render :json => @node.errors, :status => :unprocessable_entity
453
+ end
454
+ end
455
+ end
414
456
 
415
457
  format.xml do
416
458
  if @node.errors.empty?
@@ -544,7 +586,6 @@ class NodesController < ApplicationController
544
586
  if path = request.env['REQUEST_PATH'].split('/')[2..-1]
545
587
  params[:path] = path
546
588
  else
547
- Node.logger.warn("REQUEST_PATH: #{request.env['REQUEST_PATH'].inspect}")
548
589
  path = params[:path]
549
590
  end
550
591
  end
@@ -28,13 +28,14 @@ class UserSessionsController < ApplicationController
28
28
  end
29
29
 
30
30
  def destroy
31
+ port = request.port == 80 ? '' : ":#{request.port}"
31
32
  if @user_session = UserSession.find
32
33
  @user_session.destroy
33
34
  reset_session
34
35
  #flash.now[:notice] = _("Successfully logged out.")
35
- redirect_to params[:redirect] || home_path(:prefix => prefix)
36
+ redirect_to "http://#{current_site.host}#{port}#{params[:redirect] || home_path(:prefix => prefix)}"
36
37
  else
37
- redirect_to home_path(:prefix => prefix)
38
+ redirect_to "http://#{current_site.host}#{port}#{home_path(:prefix => prefix)}"
38
39
  end
39
40
  end
40
41
 
@@ -52,5 +53,13 @@ class UserSessionsController < ApplicationController
52
53
  def redirect_after_login
53
54
  session.delete(:after_login_path) || home_path(:prefix => AUTHENTICATED_PREFIX)
54
55
  end
55
-
56
+
57
+ # Overwrite redirect on https rules for this controller
58
+ def redirect_to_https
59
+ if params[:action] == 'destroy'
60
+ # ignore
61
+ else
62
+ redirect_to :protocol => "https://" if current_site.ssl_on_auth && !ssl_request? && !local_request?
63
+ end
64
+ end
56
65
  end
@@ -133,9 +133,15 @@ class VirtualClassesController < ApplicationController
133
133
  end
134
134
 
135
135
  def create
136
- type = params[:virtual_class].delete(:type)
136
+ attrs = params[:virtual_class]
137
+ type = attrs.delete(:type)
137
138
  if type == 'Role'
138
- @virtual_class = ::Role.new(params[:virtual_class])
139
+ # Remove invalid attributes
140
+ accessible = ::Role.accessible_attributes
141
+ attrs.each do |k,v|
142
+ attrs.delete(k) if v.blank? or !accessible.include?(k)
143
+ end
144
+ @virtual_class = ::Role.new(attrs)
139
145
  else
140
146
  @virtual_class = VirtualClass.new(params[:virtual_class])
141
147
  end
@@ -29,7 +29,7 @@ class Acl < ActiveRecord::Base
29
29
  end
30
30
 
31
31
  def authorize?(base_node, params, request)
32
- res = Node.find_by_sql(eval(make_query(base_node, params, request).to_s))
32
+ res = Node.find_by_sql(eval(make_query(base_node, params, request).to_s)) rescue nil
33
33
  if res.empty?
34
34
  nil
35
35
  else
@@ -95,8 +95,11 @@ class Acl < ActiveRecord::Base
95
95
  errors.add(:query, err.message)
96
96
  end
97
97
  nil
98
+ rescue RubyLess::SyntaxError => err
99
+ errors.add(:query, err.message.strip)
100
+ nil
98
101
  rescue => err
99
- errors.add(:query, err.message)
102
+ errors.add(:query, err.message.strip)
100
103
  nil
101
104
  end
102
105
  end
@@ -68,12 +68,13 @@ class CachedPage < ActiveRecord::Base
68
68
  end
69
69
 
70
70
  # Remove cached pages related to the given node.
71
- def expire_with(node, opts = {})
72
- if opts
73
- expire(node.cached_pages.find(:all, opts))
71
+ def expire_with(node, filter = nil)
72
+ if filter
73
+ list = CachedPage.find(:all, :conditions => filter[:conditions], :joins => "INNER JOIN cached_pages_nodes AS cpn ON cpn.cached_page_id = cached_pages.id AND cpn.node_id = #{node.id}")
74
74
  else
75
- expire(node.cached_pages)
75
+ list = node.cached_pages
76
76
  end
77
+ expire(list)
77
78
  end
78
79
 
79
80
  private
@@ -127,7 +128,6 @@ class CachedPage < ActiveRecord::Base
127
128
  def cached_page_on_destroy
128
129
  # allow ../public for single site mode
129
130
  filepath = "#{SITES_ROOT}#{path.gsub(%r{\.\./(?!public)},'NO/')}" # just in case...
130
- CachedPage.logger.info "remove #{filepath}"
131
131
  # if symlink points to a dead file, exist? returns false...
132
132
  FileUtils.rm(filepath) if File.exist?(filepath) || File.symlink?(filepath)
133
133
  CachedPage.connection.execute "DELETE FROM cached_pages_nodes WHERE cached_page_id = '#{id}'"
@@ -1,7 +1,7 @@
1
1
  class Column < ActiveRecord::Base
2
2
  include RubyLess
3
3
  include Property::StoredColumn
4
- TYPES_FOR_FORM = %w{string datetime integer float}
4
+ TYPES_FOR_FORM = %w{string datetime integer float hash}
5
5
 
6
6
  INDICES_FOR_FORM = %w{string ml_string datetime integer float}
7
7
 
@@ -70,16 +70,39 @@ class Column < ActiveRecord::Base
70
70
  end
71
71
 
72
72
  def type_cast(value)
73
+ if value.blank?
74
+ return nil
75
+ end
73
76
  if ptype == 'datetime'
74
- if value.blank?
75
- nil
76
- elsif value.kind_of?(Time)
77
+ if value.kind_of?(Time)
77
78
  value
78
79
  elsif value.kind_of?(String)
79
80
  value.to_utc(_(Zena::Use::Dates::DATETIME), visitor.tz)
80
81
  else
81
82
  nil
82
83
  end
84
+ elsif ptype == 'hash'
85
+ if value.kind_of?(Hash)
86
+ StringHash.from_hash(value)
87
+ elsif value.kind_of?(String)
88
+ StringHash.from_string(value)
89
+ end
90
+ else
91
+ nil
92
+ end
93
+ end
94
+
95
+ def merge_hash(orig, value)
96
+ unless orig.kind_of?(StringHash)
97
+ orig = StringHash.from_hash(orig)
98
+ end
99
+ orig.merge!(value)
100
+ return orig
101
+ end
102
+
103
+ def klass
104
+ if ptype == 'hash'
105
+ StringHash
83
106
  else
84
107
  nil
85
108
  end
@@ -13,7 +13,7 @@ class Group < ActiveRecord::Base
13
13
 
14
14
  include RubyLess
15
15
  safe_method :name => String
16
- attr_accessible :name, :user_ids, :replace_by # FIXME: add user_ids ? + add users validation (are in site)
16
+ attr_accessible :name, :user_ids, :replace_by, :auto_publish # FIXME: add user_ids ? + add users validation (are in site)
17
17
  has_and_belongs_to_many :users, :order=>'login'
18
18
  validates_presence_of :name
19
19
  validate :valid_group
@@ -185,6 +185,7 @@ class Node < ActiveRecord::Base
185
185
  before_create :node_before_create
186
186
  after_save :spread_project_and_section
187
187
  after_create :node_after_create
188
+ after_destroy :node_after_destroy
188
189
  attr_protected :zip, :id, :section_id, :project_id, :publish_from, :created_at, :updated_at
189
190
  attr_protected :site_id
190
191
 
@@ -208,6 +209,7 @@ class Node < ActiveRecord::Base
208
209
  safe_property :title, :text, :summary
209
210
 
210
211
  safe_attribute :created_at, :updated_at, :event_at, :log_at, :publish_from, :basepath, :inherit, :position
212
+ safe_attribute :idx_datetime1, :idx_datetime2, :idx_float1, :idx_float2, :idx_string1, :idx_string2, :idx_integer1, :idx_integer2
211
213
 
212
214
 
213
215
  # safe_node_context defined in Enrollable
@@ -245,7 +247,9 @@ class Node < ActiveRecord::Base
245
247
  :user => 'User',
246
248
  :author => author_proc,
247
249
  :vclass => {:class => 'VirtualClass', :method => 'virtual_class'},
248
- :new_record? => Boolean
250
+ :new_record? => Boolean,
251
+ [:eval, String] => {:class => String, :method => 'zafu_eval'},
252
+ [:eval, String, Hash] => {:class => String, :method => 'zafu_eval'}
249
253
 
250
254
  # This is needed so that we can use secure_scope and secure in search.
251
255
  extend Zena::Acts::Secure
@@ -290,6 +294,50 @@ class Node < ActiveRecord::Base
290
294
  def v_number
291
295
  version.number
292
296
  end
297
+
298
+ Caster = ::ActiveRecord::ConnectionAdapters::Column
299
+
300
+ # Return class of cast value.
301
+ def self.cast_to_class(type)
302
+ case type
303
+ when :string then String
304
+ when :text then String
305
+ when :integer then Number
306
+ when :float then Number
307
+ when :decimal then Number
308
+ when :datetime then Time
309
+ when :timestamp then Time
310
+ when :time then Time
311
+ when :date then Time
312
+ when :binary then String
313
+ when :boolean then Boolean
314
+ else nil
315
+ end
316
+ end
317
+
318
+ # Read with cast to an appropriate instance. This is used along with
319
+ # custom select in QueryBuilder queries.
320
+ def rcast(key, type)
321
+ @rcast_cache ||= {}
322
+ @rcast_cache[key] ||= begin
323
+ value = @attributes[key]
324
+ return nil if value.nil?
325
+ case type
326
+ when :string then value
327
+ when :text then value
328
+ when :integer then value.to_i rescue value ? 1 : 0
329
+ when :float then value.to_f
330
+ when :decimal then Caster.value_to_decimal(value)
331
+ when :datetime then Caster.string_to_time(value)
332
+ when :timestamp then Caster.string_to_time(value)
333
+ when :time then Caster.string_to_time(value)
334
+ when :date then Caster.string_to_time(value)
335
+ when :binary then Caster.binary_to_string(value)
336
+ when :boolean then Caster.value_to_boolean(value)
337
+ else value
338
+ end
339
+ end
340
+ end
293
341
 
294
342
  # This is an adaptation of Versions::Multi code to use our special v_ shortcut
295
343
  # to access version attributes.
@@ -307,6 +355,9 @@ class Node < ActiveRecord::Base
307
355
  include Zena::Use::ScopeIndex::ModelMethods
308
356
 
309
357
  include Zena::Use::QueryNode::ModelMethods
358
+
359
+ # Used by zafu_eval when parsing dates.
360
+ include Zena::Use::Dates::ModelMethods
310
361
 
311
362
  @@native_node_classes = {'N' => self}
312
363
  @@native_node_classes_by_name = {'Node' => self}
@@ -624,7 +675,7 @@ class Node < ActiveRecord::Base
624
675
  end
625
676
 
626
677
  entries = Dir.entries(folder).reject { |f| f =~ /^[\.~]|^__/ }.map do |filename|
627
- String.from_filename(filename)
678
+ [filename, String.from_filename(filename)]
628
679
  end.sort
629
680
 
630
681
  index = 0
@@ -633,17 +684,16 @@ class Node < ActiveRecord::Base
633
684
  catch (:next_entry) do
634
685
  type = current_obj = sub_folder = document_path = nil
635
686
  versions = []
636
- filename = entries[index]
687
+ filename, title = *entries[index]
637
688
 
638
689
  path = File.join(folder, filename)
639
690
 
640
691
  if File.stat(path).directory?
641
692
  type = :folder
642
- title = filename
643
693
  sub_folder = path
644
694
  attrs = defaults.dup
645
695
  attrs['v_lang'] ||= visitor.lang
646
- elsif filename =~ /^(.+?)(\.\w\w|)(\.\d+|)\.zml$/ # bird.jpg.en.zml
696
+ elsif title =~ /^(.+?)(\.\w\w|)(\.\d+|)\.zml$/ # bird.jpg.en.zml
647
697
  # node content in yaml
648
698
  type = :node
649
699
  title = "#{$1}#{$4}"
@@ -654,7 +704,7 @@ class Node < ActiveRecord::Base
654
704
  attrs['title'] = title
655
705
  attrs['v_lang'] = lang || attrs['v_lang'] || visitor.lang
656
706
  versions << attrs
657
- elsif filename =~ /^((.+?)\.(.+?))(\.\w\w|)(\.\d+|)$/ # bird.jpg.en
707
+ elsif title =~ /^((.+?)\.(.+?))(\.\w\w|)(\.\d+|)$/ # bird.jpg.en
658
708
  type = :document
659
709
  title = $1
660
710
  attrs = defaults.dup
@@ -665,7 +715,6 @@ class Node < ActiveRecord::Base
665
715
  else
666
716
  # Document without extension
667
717
  type = :document
668
- title = filename
669
718
  attrs = defaults.dup
670
719
  lang = nil
671
720
  attrs['v_lang'] = lang || attrs['v_lang'] || visitor.lang
@@ -674,9 +723,9 @@ class Node < ActiveRecord::Base
674
723
  end
675
724
 
676
725
  index += 1
677
- while entries[index] =~ /^#{title}(\.\w\w|)(\.\d+|)\.zml$/ # bird.jpg.en.zml
726
+ while entries[index] && entries[index][1] =~ /^#{title}(\.\w\w|)(\.\d+|)\.zml$/ # bird.jpg.en.zml
678
727
  lang = $1.blank? ? visitor.lang : $1[1..-1]
679
- path = File.join(folder,entries[index])
728
+ path = File.join(folder,entries[index][0])
680
729
 
681
730
  # we have a zml file. Create a version with this file
682
731
  # no need for base_node (this is done after all with parse_assets in the controller)
@@ -848,10 +897,14 @@ class Node < ActiveRecord::Base
848
897
 
849
898
  copy_node = new_attributes.delete(:_copy)
850
899
  attributes = new_attributes.stringify_keys
851
-
900
+
852
901
  if copy_node || attributes['copy_id']
853
- copy_node ||= Node.find_by_zip(attributes.delete('copy_id'))
854
- attributes = copy_node.replace_attributes_in_values(attributes)
902
+ if !copy_node && attributes['copy_id'].blank?
903
+ attributes = Node.new.replace_attributes_in_values(attributes)
904
+ else
905
+ copy_node ||= Node.find_by_zip(attributes.delete('copy_id'))
906
+ attributes = copy_node.replace_attributes_in_values(attributes)
907
+ end
855
908
  end
856
909
 
857
910
  if !res['parent_id'] && p = attributes['parent_id']
@@ -936,6 +989,23 @@ class Node < ActiveRecord::Base
936
989
  def zafu_versions
937
990
  versions.all(:order => 'number desc')
938
991
  end
992
+
993
+ # Enable dynamic property evaluation
994
+ def zafu_eval(str, opts = {})
995
+ value = safe_eval(str)
996
+ if value.kind_of?(String)
997
+ value
998
+ elsif value.kind_of?(Time)
999
+ format_date(value, opts)
1000
+ elsif value.kind_of?(Array)
1001
+ value.join(',')
1002
+ else
1003
+ value.to_s
1004
+ end
1005
+ rescue RubyLess::Error
1006
+ nil
1007
+ end
1008
+
939
1009
  # Remove loaded version and properties on reload.
940
1010
  def reload
941
1011
  @version = nil
@@ -1326,12 +1396,12 @@ class Node < ActiveRecord::Base
1326
1396
  visitor.commentator? && discussion && discussion.open?
1327
1397
  end
1328
1398
 
1329
- # TODO: test
1330
- def sweep_cache(opts = {})
1331
- return if current_site.being_created?
1399
+ def sweep_cache(filter = nil)
1400
+ return true if current_site.being_created?
1332
1401
 
1333
1402
  # Clear element cache
1334
- Cache.sweep(:visitor_id=>self[:user_id], :visitor_groups=>[rgroup_id, wgroup_id, dgroup_id], :kpath=>self.vclass.kpath)
1403
+ # Partial cache not used
1404
+ # Cache.sweep(:visitor_id=>self[:user_id], :visitor_groups=>[rgroup_id, wgroup_id, dgroup_id], :kpath=>self.vclass.kpath)
1335
1405
 
1336
1406
  # Clear full result cache
1337
1407
 
@@ -1340,11 +1410,12 @@ class Node < ActiveRecord::Base
1340
1410
  # FIXME: use self + modified relations instead of parent/project
1341
1411
  [self, self.real_project(false), self.real_section(false), self.parent(false)].compact.uniq.each do |obj|
1342
1412
  # destroy all pages in project, parent and section !
1343
- CachedPage.expire_with(obj, opts)
1413
+ CachedPage.expire_with(obj, filter)
1344
1414
  end
1345
1415
 
1346
1416
  # clear assets
1347
1417
  FileUtils::rmtree(asset_path(''))
1418
+ true
1348
1419
  end
1349
1420
 
1350
1421
  # Include data entry verification in multiversion's empty? method.
@@ -1635,15 +1706,18 @@ class Node < ActiveRecord::Base
1635
1706
  Discussion.create(:node_id=>self[:id], :lang=>v_lang, :inside => false)
1636
1707
  end
1637
1708
  end
1709
+
1710
+ def node_after_destroy
1711
+ sweep_cache
1712
+ end
1638
1713
 
1639
1714
  # Called after a node is 'unpublished'
1640
1715
  def after_unpublish
1641
1716
  if !self[:publish_from] && !@new_record_before_save
1642
1717
  # not published any more. 'unpublish' documents
1643
1718
  sync_documents(:unpublish)
1644
- else
1645
- true
1646
1719
  end
1720
+ sweep_cache
1647
1721
  end
1648
1722
 
1649
1723
  def after_redit
@@ -1653,8 +1727,10 @@ class Node < ActiveRecord::Base
1653
1727
 
1654
1728
  # Called after a node is 'removed'
1655
1729
  def after_remove
1656
- return true if @new_record_before_save
1657
- sync_documents(:remove)
1730
+ if !@new_record_before_save
1731
+ sync_documents(:remove)
1732
+ end
1733
+ sweep_cache
1658
1734
  end
1659
1735
 
1660
1736
  # Called after a node is 'proposed'
@@ -1671,8 +1747,15 @@ class Node < ActiveRecord::Base
1671
1747
 
1672
1748
  # Called after a node is published
1673
1749
  def after_publish
1674
- return true if @new_record_before_save
1675
- sync_documents(:publish)
1750
+ if !@new_record_before_save
1751
+ sync_documents(:publish)
1752
+ end
1753
+ sweep_cache
1754
+ end
1755
+
1756
+ # Called after a node is modified and directly published.
1757
+ def after_auto_publish
1758
+ sweep_cache
1676
1759
  end
1677
1760
 
1678
1761
  # Publish, refuse, propose the Documents of a redaction
@@ -1709,7 +1792,6 @@ class Node < ActiveRecord::Base
1709
1792
  # This method is run whenever 'apply' is called.
1710
1793
  def after_all
1711
1794
  return unless super
1712
- sweep_cache
1713
1795
  if @add_comment
1714
1796
  # add comment
1715
1797
  @discussion ||= self.discussion