zena 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
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