zena 0.15.2 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (284) hide show
  1. data/.gitignore +20 -0
  2. data/CREDITS +27 -0
  3. data/Capfile +3 -0
  4. data/DEVELOPERS +46 -0
  5. data/History.txt +15 -0
  6. data/MIT-LICENSE +19 -0
  7. data/Rakefile +44 -0
  8. data/TODO +24 -0
  9. data/TODO_ZENA_1_0 +23 -0
  10. data/app/controllers/application_controller.rb +3 -0
  11. data/app/controllers/documents_controller.rb +22 -56
  12. data/app/controllers/nodes_controller.rb +42 -27
  13. data/app/controllers/pings_controller.rb +19 -0
  14. data/app/controllers/relations_controller.rb +5 -1
  15. data/app/controllers/sites_controller.rb +1 -46
  16. data/app/controllers/user_sessions_controller.rb +47 -0
  17. data/app/controllers/users_controller.rb +1 -0
  18. data/app/controllers/versions_controller.rb +25 -7
  19. data/app/controllers/virtual_classes_controller.rb +1 -1
  20. data/app/helpers/application_helper.rb +1 -1
  21. data/app/models/comment.rb +2 -1
  22. data/app/models/contact_content.rb +2 -2
  23. data/app/models/data_entry.rb +5 -6
  24. data/app/models/document.rb +14 -10
  25. data/app/models/document_content.rb +4 -6
  26. data/app/models/iformat.rb +2 -2
  27. data/app/models/image_content.rb +6 -9
  28. data/app/models/node.rb +106 -164
  29. data/app/models/page.rb +0 -20
  30. data/app/models/site.rb +42 -12
  31. data/app/models/template.rb +3 -8
  32. data/app/models/template_content.rb +2 -0
  33. data/app/models/text_document.rb +13 -8
  34. data/app/models/user.rb +47 -100
  35. data/app/models/user_session.rb +4 -0
  36. data/app/models/version.rb +1 -1
  37. data/app/views/comments/create.rjs +3 -3
  38. data/app/views/comments/edit.rjs +1 -1
  39. data/app/views/comments/update.rjs +1 -1
  40. data/app/views/nodes/_import_results.rhtml +1 -1
  41. data/app/views/nodes/create.rjs +3 -3
  42. data/app/views/templates/document_create_tabs/_file.rhtml +1 -2
  43. data/app/views/templates/document_create_tabs/_import.rhtml +7 -2
  44. data/app/views/templates/edit_tabs/_document.rhtml +1 -3
  45. data/app/views/templates/edit_tabs/_image.rhtml +1 -3
  46. data/app/views/versions/_tr.rhtml +1 -1
  47. data/app/views/versions/edit.rhtml +2 -26
  48. data/bin/zena +6 -1
  49. data/bricks/delayed_job/README +18 -0
  50. data/bricks/delayed_job/migrate/20091104191643_create_delayed_jobs_table.rb +19 -0
  51. data/bricks/delayed_job/misc/init.rb +8 -0
  52. data/bricks/delayed_job/misc/tasks.rb +2 -0
  53. data/bricks/math/patch/application_helper.rb +1 -1
  54. data/bricks/sphinx/MIT-LICENSE +19 -0
  55. data/bricks/sphinx/README +19 -0
  56. data/bricks/sphinx/lib/use_sphinx.rb +78 -0
  57. data/bricks/sphinx/migrate/20091102171258_add_delta_for_sphinx.rb +9 -0
  58. data/bricks/sphinx/misc/deploy.rb +20 -0
  59. data/bricks/sphinx/misc/sphinx.yml +12 -0
  60. data/bricks/sphinx/misc/tasks.rb +21 -0
  61. data/bricks/sphinx/patch/node.rb +8 -0
  62. data/bricks/tags/lib/has_tags.rb +5 -3
  63. data/bricks/tags/test/zafu/tags.yml +13 -1
  64. data/config/bricks.yml +35 -0
  65. data/config/deploy.rb +8 -1
  66. data/config/environment.rb +1 -1
  67. data/config/environments/production.rb +1 -1
  68. data/config/gems.yml +28 -5
  69. data/config/sphinx.yml +12 -0
  70. data/db/init/base/skins/default/Node-+popupLayout.zafu +1 -16
  71. data/db/migrate/20091026161708_add_persistence_token.rb +13 -0
  72. data/db/migrate/20091101184952_add_session_table.rb +16 -0
  73. data/db/migrate/20091123175137_add_single_access_token.rb +9 -0
  74. data/db/migrate/20091124161608_rebuild_fullpath.rb +11 -0
  75. data/db/schema.rb +21 -8
  76. data/doc/README_FOR_APP +24 -0
  77. data/doc/fixtures.graffle +19568 -0
  78. data/doc/fixtures.pdf +0 -0
  79. data/doc/template/LICENSE +184 -0
  80. data/doc/template/README +37 -0
  81. data/doc/template/allison.css +283 -0
  82. data/doc/template/allison.js +307 -0
  83. data/doc/template/allison.rb +260 -0
  84. data/doc/template/cache/BODY +588 -0
  85. data/doc/template/cache/CLASS_INDEX +4 -0
  86. data/doc/template/cache/CLASS_PAGE +1 -0
  87. data/doc/template/cache/FILE_INDEX +4 -0
  88. data/doc/template/cache/FILE_PAGE +1 -0
  89. data/doc/template/cache/FONTS +1 -0
  90. data/doc/template/cache/FR_INDEX_BODY +1 -0
  91. data/doc/template/cache/IMGPATH +1 -0
  92. data/doc/template/cache/INDEX +1 -0
  93. data/doc/template/cache/JAVASCRIPT +307 -0
  94. data/doc/template/cache/METHOD_INDEX +4 -0
  95. data/doc/template/cache/METHOD_LIST +1 -0
  96. data/doc/template/cache/SRC_PAGE +1 -0
  97. data/doc/template/cache/STYLE +283 -0
  98. data/doc/template/cache/URL +1 -0
  99. data/doc/zafu_changes.yml +29 -0
  100. data/lib/base_additions.rb +1 -1
  101. data/lib/bricks.rb +9 -0
  102. data/lib/bricks/loader.rb +86 -0
  103. data/lib/bricks/requirements_validation.rb +71 -0
  104. data/lib/tasks/zena.rake +42 -4
  105. data/lib/zafu/action.rb +285 -0
  106. data/lib/zafu/ajax.rb +93 -0
  107. data/lib/zafu/attributes.rb +117 -0
  108. data/lib/zafu/calendar.rb +159 -0
  109. data/lib/zafu/context.rb +330 -0
  110. data/lib/zafu/core/html.rb +102 -0
  111. data/lib/zafu/core/move_to_parser.rb +167 -0
  112. data/lib/zafu/dates.rb +58 -0
  113. data/lib/zafu/display.rb +502 -0
  114. data/lib/zafu/eval.rb +66 -0
  115. data/lib/zafu/experimental.rb +66 -0
  116. data/lib/zafu/i18n.rb +64 -0
  117. data/lib/zafu/meta.rb +25 -0
  118. data/lib/zafu/refactor.rb +73 -0
  119. data/lib/zafu/support/context.rb +265 -0
  120. data/lib/zafu/support/dom.rb +145 -0
  121. data/lib/zafu/support/erb.rb +62 -0
  122. data/lib/zafu/support/flow.rb +401 -0
  123. data/lib/zafu/support/forms.rb +461 -0
  124. data/lib/zafu/support/links.rb +306 -0
  125. data/lib/zafu_parser.rb +26 -2
  126. data/lib/zena.rb +34 -15
  127. data/lib/zena/acts/multiversion.rb +2 -2
  128. data/lib/zena/acts/secure.rb +41 -30
  129. data/lib/zena/app.rb +7 -10
  130. data/lib/zena/controller/test_case.rb +12 -7
  131. data/lib/zena/crypto_provider/initial.rb +15 -0
  132. data/lib/zena/db.rb +6 -1
  133. data/lib/zena/deploy.rb +34 -6
  134. data/lib/zena/deploy/logrotate_app.rhtml +9 -0
  135. data/lib/zena/deploy/logrotate_host.rhtml +34 -0
  136. data/lib/zena/deploy/template.rb +1 -9
  137. data/lib/zena/foxy_parser.rb +1 -1
  138. data/lib/zena/info.rb +3 -1
  139. data/lib/zena/migrator.rb +1 -1
  140. data/lib/zena/parser.rb +12 -4
  141. data/lib/zena/parser/zazen_rules.rb +6 -6
  142. data/lib/zena/parser/zena_rules.rb +1 -7
  143. data/lib/zena/routes.rb +5 -5
  144. data/lib/zena/test_controller.rb +7 -2
  145. data/lib/zena/unit/test_case.rb +6 -8
  146. data/lib/zena/use/ajax.rb +10 -10
  147. data/lib/zena/use/authlogic.rb +93 -0
  148. data/lib/zena/use/dyn_attributes.rb +5 -0
  149. data/lib/zena/use/html_tags.rb +16 -34
  150. data/lib/zena/use/i18n.rb +4 -1
  151. data/lib/zena/use/node_query_finders.rb +8 -4
  152. data/lib/zena/use/refactor.rb +8 -20
  153. data/lib/zena/use/relations.rb +1 -0
  154. data/lib/zena/use/rendering.rb +4 -2
  155. data/lib/zena/use/search.rb +52 -0
  156. data/lib/zena/use/test_helper.rb +27 -28
  157. data/lib/zena/use/upload.rb +188 -0
  158. data/lib/zena/use/urls.rb +16 -14
  159. data/lib/zena/use/zafu.rb +16 -63
  160. data/lib/zena/use/zazen.rb +8 -8
  161. data/lib/zena/view/test_case.rb +8 -4
  162. data/locale/en/LC_MESSAGES/zena.mo +0 -0
  163. data/locale/en/zena.po +3 -3
  164. data/public/.htaccess +40 -0
  165. data/public/javascripts/upload-progress.js +17 -8
  166. data/public/javascripts/zena.js +8 -2
  167. data/public/stylesheets/popup.css +1 -0
  168. data/script/about +3 -0
  169. data/script/apache_logging +25 -0
  170. data/script/breakpointer +3 -0
  171. data/script/console +3 -0
  172. data/script/dbconsole +3 -0
  173. data/script/destroy +3 -0
  174. data/script/generate +3 -0
  175. data/script/performance/benchmarker +3 -0
  176. data/script/performance/profiler +3 -0
  177. data/script/plugin +3 -0
  178. data/script/process/inspector +3 -0
  179. data/script/process/reaper +3 -0
  180. data/script/process/spawner +3 -0
  181. data/script/runner +3 -0
  182. data/script/server +3 -0
  183. data/script/set_revision +29 -0
  184. data/spec/controllers/versions_controller_spec.rb +11 -0
  185. data/test/fixtures/files/Node-test.zafu +1 -1
  186. data/test/functional/nodes_controller_test.rb +25 -0
  187. data/test/functional/pings_controller_test.rb +8 -0
  188. data/test/functional/user_sessions_controller_test.rb +59 -0
  189. data/test/functional/users_controller_test.rb +81 -19
  190. data/test/helpers/node_query/filters.yml +5 -0
  191. data/test/helpers/node_query_test.rb +3 -3
  192. data/test/integration/multiple_hosts_test.rb +1 -1
  193. data/test/integration/navigation_test.rb +1 -1
  194. data/test/sites/complex/users.yml +1 -1
  195. data/test/sites/ocean/users.yml +3 -3
  196. data/test/sites/zena/users.yml +5 -4
  197. data/test/test_zena.rb +38 -38
  198. data/test/unit/cached_page_test.rb +2 -2
  199. data/test/unit/comment_test.rb +0 -1
  200. data/test/unit/document_test.rb +23 -11
  201. data/test/unit/helpers/ping_helper_test.rb +4 -0
  202. data/test/unit/multiversion_test.rb +24 -16
  203. data/test/unit/node_test.rb +32 -93
  204. data/test/unit/note_test.rb +9 -0
  205. data/test/unit/page_test.rb +2 -2
  206. data/test/unit/secure_test.rb +2 -12
  207. data/test/unit/site_test.rb +43 -24
  208. data/test/unit/template_test.rb +45 -3
  209. data/test/unit/text_document_test.rb +4 -3
  210. data/test/unit/user_test.rb +13 -33
  211. data/test/unit/zena/db_test.rb +8 -0
  212. data/test/unit/zena/parser/zazen.yml +4 -4
  213. data/test/unit/zena/use/dates_view_methods_test.rb +2 -1
  214. data/test/unit/zena/use/html_tags_test.rb +12 -4
  215. data/test/unit/zena/use/refactor_test.rb +4 -3
  216. data/test/unit/zena/use/rendering_test.rb +1 -0
  217. data/test/unit/zena/use/upload_test.rb +76 -0
  218. data/test/unit/zena/use/urls_test.rb +4 -0
  219. data/test/unit/zena/use/zafu_test.rb +8 -0
  220. data/test/unit/zena/workflow/status_version_test.rb +6 -0
  221. data/test/unit/zena/zena_tags/ajax.yml +4 -4
  222. data/test/unit/zena/zena_tags/basic.yml +21 -10
  223. data/test/unit/zena/zena_tags/relations.yml +0 -6
  224. data/test/unit/zena/zena_tags/rubyless.yml +35 -0
  225. data/test/unit/zena/zena_tags/zazen.yml +4 -4
  226. data/test/unit/zena/zena_tags_test.rb +36 -4
  227. data/vendor/TextMate/Zena.tmbundle/Commands/Run all yaml tests.tmCommand +1 -1
  228. data/vendor/TextMate/Zena.tmbundle/Commands/Run focused yaml test.tmCommand +2 -3
  229. data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/catch_exception.rb +39 -0
  230. data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/run_script.rb +102 -58
  231. data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/stdin_dialog.rb +14 -0
  232. data/vendor/TextMate/Zena.tmbundle/info.plist +2 -0
  233. data/zena.gemspec +2085 -0
  234. metadata +265 -90
  235. data/app/controllers/sessions_controller.rb +0 -41
  236. data/app/views/sites/zena_up.html.erb +0 -11
  237. data/config/database.yml +0 -40
  238. data/db/production.sqlite3 +0 -0
  239. data/lib/bricks/patcher.rb +0 -68
  240. data/lib/zena/parser/zena_tags.rb +0 -3562
  241. data/lib/zena/use/authentification.rb +0 -120
  242. data/public/images/ext/contact_pv.png +0 -0
  243. data/public/images/ext/other_pv.png +0 -0
  244. data/public/images/ext/page_pv.png +0 -0
  245. data/public/images/ext/page_tiny.png +0 -0
  246. data/public/images/ext/pdf_pv.png +0 -0
  247. data/public/images/ext/post_pv.png +0 -0
  248. data/public/images/ext/post_tiny.png +0 -0
  249. data/public/images/ext/project_pv.png +0 -0
  250. data/public/images/ext/project_tiny.png +0 -0
  251. data/public/images/ext/tag_pv.png +0 -0
  252. data/public/images/ext/zip_pv.png +0 -0
  253. data/tasks/ann.rake +0 -80
  254. data/tasks/bones.rake +0 -20
  255. data/tasks/gem.rake +0 -201
  256. data/tasks/git.rake +0 -40
  257. data/tasks/notes.rake +0 -27
  258. data/tasks/post_load.rake +0 -34
  259. data/tasks/rdoc.rake +0 -51
  260. data/tasks/rubyforge.rake +0 -55
  261. data/tasks/setup.rb +0 -292
  262. data/tasks/spec.rake +0 -54
  263. data/tasks/svn.rake +0 -47
  264. data/tasks/test.rake +0 -40
  265. data/tasks/zentest.rake +0 -36
  266. data/test/fixtures/comments.yml +0 -126
  267. data/test/fixtures/contact_contents.yml +0 -132
  268. data/test/fixtures/data_entries.yml +0 -65
  269. data/test/fixtures/discussions.yml +0 -48
  270. data/test/fixtures/document_contents.yml +0 -108
  271. data/test/fixtures/dyn_attributes.yml +0 -66
  272. data/test/fixtures/groups.yml +0 -86
  273. data/test/fixtures/groups_users.yml +0 -81
  274. data/test/fixtures/iformats.yml +0 -29
  275. data/test/fixtures/links.yml +0 -313
  276. data/test/fixtures/nodes.yml +0 -2592
  277. data/test/fixtures/relations.yml +0 -126
  278. data/test/fixtures/sites.yml +0 -58
  279. data/test/fixtures/template_contents.yml +0 -172
  280. data/test/fixtures/users.yml +0 -167
  281. data/test/fixtures/versions.yml +0 -1911
  282. data/test/fixtures/virtual_classes.yml +0 -87
  283. data/test/fixtures/zips.yml +0 -15
  284. data/test/functional/sessions_controller_test.rb +0 -73
@@ -120,6 +120,8 @@ and the 'photos' url is now in the worldTour project's basepath:
120
120
  Setting 'custom_base' on a node should be done with caution as the node's zip is on longer in the url and when you move the node around, there is no way to find the new location from the old url. Custom_base should therefore only be used for nodes that are not going to move.
121
121
  =end
122
122
  class Node < ActiveRecord::Base
123
+ extend Zena::Use::Upload::UploadedFile
124
+ extend Zena::Use::Search::NodeClassMethods
123
125
 
124
126
  include RubyLess::SafeClass
125
127
  safe_attribute :created_at, :updated_at, :event_at, :log_at, :publish_from, :basepath, :inherit
@@ -142,13 +144,14 @@ class Node < ActiveRecord::Base
142
144
  has_and_belongs_to_many :cached_pages
143
145
  belongs_to :virtual_class, :foreign_key => 'vclass_id'
144
146
  belongs_to :site
145
- before_validation :node_before_validation # run our 'before_validation' after 'secure'
147
+ before_validation :set_defaults
148
+ before_validation :node_before_validation
146
149
  validates_presence_of :name
147
150
  validate :validate_node
148
151
  before_create :node_before_create
149
152
  before_save :change_klass
150
153
  after_save :spread_project_and_section
151
- after_save :clear_children_fullpath
154
+ after_save :rebuild_children_fullpath
152
155
  after_create :node_after_create
153
156
  attr_protected :site_id, :zip, :id, :section_id, :project_id, :publish_from
154
157
  attr_protected :site_id
@@ -161,16 +164,15 @@ class Node < ActiveRecord::Base
161
164
  nested_attributes_alias %r{^c_(\w+)} => ['version', 'content']
162
165
  nested_attributes_alias %r{^d_(\w+)} => ['version', 'dyn']
163
166
 
164
- zafu_context :author => "Contact", :parent => "Node",
165
- :project => "Project", :section => "Section",
166
- :real_project => "Project", :real_section => "Section",
167
- :user => "User",
168
- :version => "Version", :comments => ["Comment"],
169
- :data => {:node_class => ["DataEntry"], :data_root => 'node_a'},
170
- :data_a => {:node_class => ["DataEntry"], :data_root => 'node_a'},
171
- :data_b => {:node_class => ["DataEntry"], :data_root => 'node_b'},
172
- :data_c => {:node_class => ["DataEntry"], :data_root => 'node_c'},
173
- :data_d => {:node_class => ["DataEntry"], :data_root => 'node_d'}
167
+ safe_context :author => 'Contact', :parent => 'Node',
168
+ :project => 'Project', :section => 'Section',
169
+ :real_project => 'Project', :real_section => 'Section',
170
+ :user => 'User', :version => 'Version', :comments => ['Comment'],
171
+ :data => {:class => ['DataEntry'], :data_root => 'node_a'},
172
+ :data_a => {:class => ['DataEntry'], :data_root => 'node_a'},
173
+ :data_b => {:class => ['DataEntry'], :data_root => 'node_b'},
174
+ :data_c => {:class => ['DataEntry'], :data_root => 'node_c'},
175
+ :data_d => {:class => ['DataEntry'], :data_root => 'node_d'}
174
176
 
175
177
  extend Zena::Acts::SecureNode
176
178
  extend Zena::Acts::Multiversion
@@ -299,7 +301,7 @@ class Node < ActiveRecord::Base
299
301
  find_by_zip(str)
300
302
  elsif str =~ /\A:?([0-9a-zA-Z ]+)(\+*)\Z/
301
303
  offset = $2.to_s.size
302
- find(:first, Node.match_query($1.gsub('-',' '), :offset => offset))
304
+ Node.search_records($1.gsub('-',' '), :offset => offset, :limit => 1).first
303
305
  elsif path = str[/\A\(([^\)]*)\)\Z/,1]
304
306
  if path[0..0] == '/'
305
307
  find_by_path(path[1..-1])
@@ -367,9 +369,6 @@ class Node < ActiveRecord::Base
367
369
  def create_node(new_attributes)
368
370
  attributes = transform_attributes(new_attributes)
369
371
 
370
- # the way this works here and in do_update_attributes is not good
371
- publish_after_save = (attributes.delete('v_status').to_i == Zena::Status[:pub])
372
-
373
372
  # TODO: replace this hack with a proper class method 'secure' behaving like the
374
373
  # instance method. It would get the visitor and scope from the same hack below.
375
374
  scope = self.scoped_methods[0] || {}
@@ -392,7 +391,6 @@ class Node < ActiveRecord::Base
392
391
  self.create_instance(attributes)
393
392
  end
394
393
 
395
- node.publish if publish_after_save
396
394
  node
397
395
  end
398
396
 
@@ -526,22 +524,20 @@ class Node < ActiveRecord::Base
526
524
  # file
527
525
  insert_zafu_headings = false
528
526
  if opts[:parent_class] == 'Skin' && ['html','xhtml'].include?(attrs['c_ext']) && attrs['name'] == 'index'
529
- attrs['c_ext'] = 'zafu'
530
- attrs['name'] = 'Node'
527
+ attrs['c_ext'] = 'zafu'
528
+ attrs['name'] = 'Node'
531
529
  insert_zafu_headings = true
532
530
  end
533
531
 
534
- ctype = EXT_TO_TYPE[attrs['c_ext']]
532
+ ctype = Zena::EXT_TO_TYPE[attrs['c_ext']]
535
533
  ctype = ctype ? ctype[0] : "application/octet-stream"
536
534
  attrs['c_content_type'] = ctype
537
535
 
538
536
 
539
- File.open(document_path) do |file|
537
+ File.open(document_path) do |f|
538
+ file = uploaded_file(f, filename, ctype)
540
539
  (class << file; self; end;).class_eval do
541
- alias local_path path if defined?(:path)
542
540
  alias o_read read
543
- define_method(:original_filename) { filename }
544
- define_method(:content_type) { ctype }
545
541
  define_method(:read) do
546
542
  if insert_zafu_headings
547
543
  o_read.sub(%r{</head>}," <r:stylesheets/>\n <r:javascripts/>\n <r:uses_datebox/>\n</head>")
@@ -578,88 +574,12 @@ class Node < ActiveRecord::Base
578
574
  node
579
575
  end
580
576
 
581
- # Find a node by it's full path. Cache 'fullpath' if found.
577
+ # Find a node by it's full path. Cache 'fullpath' if found. This is useless now
578
+ # that fullpath is properly cached. REMOVE !
582
579
  def find_by_path(path)
583
580
  return nil unless scope = scoped_methods[0]
584
581
  return nil unless scope[:find] # not secured find. refuse.
585
- node = self.find_by_fullpath(path)
586
- if node.nil?
587
- path = path.split('/')
588
- last = path.pop
589
- # FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
590
- Node.send(:with_exclusive_scope) do
591
- node = Node.find(current_site[:root_id])
592
- path.each do |p|
593
- raise ActiveRecord::RecordNotFound unless node = Node.find_by_name_and_parent_id(p, node[:id])
594
- end
595
- end
596
- raise ActiveRecord::RecordNotFound unless node = self.find_by_name_and_parent_id(last, node[:id])
597
- path << last
598
- node.fullpath = path.join('/')
599
- # bypass callbacks here
600
- Node.connection.execute "UPDATE #{Node.table_name} SET fullpath='#{path.join('/').gsub("'",'"')}' WHERE id='#{node[:id]}'"
601
- end
602
- node
603
- end
604
-
605
- # Paginate found results. Returns [previous_page, collection, next_page]. You can specify page and items per page in the query hash :
606
- # :page => 1, :per_page => 20. This should be wrapped into a secure scope.
607
- def find_with_pagination(count, opts)
608
- previous_page, collection, next_page, count_all = nil, [], nil, nil
609
- per_page = (opts.delete(:per_page) || 20).to_i
610
- page = opts.delete(:page) || 1
611
- page = page > 0 ? page.to_i : 1
612
- offset = (page - 1) * per_page
613
-
614
- if opts[:group]
615
- count_select = "DISTINCT #{opts[:group]}"
616
- else
617
- count_select = opts.delete(:count) || 'nodes.id'
618
- end
619
-
620
- # FIXME: why do we need 'exclusive scope' here ?
621
- with_exclusive_scope(self.scoped_methods[0] || {}) do
622
- count_all = count(opts.merge( :select => count_select, :order => nil, :group => nil ))
623
- if count_all > offset
624
- collection = find(count, opts.merge(:offset => offset, :limit => per_page))
625
- if count_all > (offset + per_page)
626
- next_page = page + 1
627
- end
628
- previous_page = page > 1 ? (page - 1) : nil
629
- else
630
- # offset too big, previous page = last page
631
- previous_page = page > 1 ? ((count_all + per_page - 1) / per_page) : nil
632
- end
633
- end
634
- [previous_page, collection, next_page, count_all]
635
- end
636
-
637
- # Return a hash to do a fulltext query.
638
- def match_query(query, opts={})
639
- node = opts.delete(:node)
640
- if query == '.' && node
641
- return opts.merge(
642
- :conditions => ["parent_id = ?",node[:id]],
643
- :order => 'name ASC' )
644
- elsif !query.blank?
645
- if Zena::Db.adapter == 'mysql' && RAILS_ENV != 'test'
646
- match = sanitize_sql(["MATCH (vs.title,vs.text,vs.summary) AGAINST (?) OR nodes.name LIKE ?", query, "#{opts[:name_query] || query.url_name}%"])
647
- select = sanitize_sql(["nodes.*, MATCH (vs.title,vs.text,vs.summary) AGAINST (?) + (5 * (nodes.name LIKE ?)) AS score", query, "#{query}%"])
648
- else
649
- match = sanitize_sql(["nodes.name LIKE ?", "#{query}%"])
650
- select = "nodes.*, #{match} AS score"
651
- end
652
-
653
- return opts.merge(
654
- :select => select,
655
- :joins => "INNER JOIN versions AS vs ON vs.node_id = nodes.id AND vs.status >= #{Zena::Status[:pub]}",
656
- :conditions => match,
657
- :group => "nodes.id",
658
- :order => "score DESC, zip ASC")
659
- else
660
- # error
661
- return opts.merge(:conditions => '0')
662
- end
582
+ self.find_by_fullpath(path)
663
583
  end
664
584
 
665
585
  # FIXME: Where is this used ?
@@ -834,13 +754,14 @@ class Node < ActiveRecord::Base
834
754
  alias_method_chain :versions, :secure
835
755
 
836
756
  # Additional security so that unsecure finders explode when trying to update/save or follow relations.
837
- def visitor
838
- return @visitor if @visitor
839
- # We need to be more tolerant during object creation since 'v_foo' can be
840
- # set before 'visitor' and we need visitor.lang when creating versions.
841
- return Thread.current.visitor if new_record?
842
- raise Zena::RecordNotSecured.new("Visitor not set, record not secured.")
843
- end
757
+ # def visitor
758
+ # return @visitor if @visitor
759
+ # @visitor = Thread.current[:visitor] || Zena::RecordNotSecured.new("Visitor not set, record not secured.")
760
+ # # We need to be more tolerant during object creation since 'v_foo' can be
761
+ # # set before 'visitor' and we need visitor.lang when creating versions.
762
+ # #return Thread.current[:visitor] #if new_record?
763
+ # #raise Zena::RecordNotSecured.new("Visitor not set, record not secured.")
764
+ # end
844
765
 
845
766
  # Return an attribute if it is safe (RubyLess allowed). Return nil otherwise.
846
767
  # This is mostly used when the zafu compiler cannot decide whether a method is safe or not at compile time.
@@ -946,38 +867,13 @@ class Node < ActiveRecord::Base
946
867
  end
947
868
 
948
869
 
949
- # Return the same basepath as the parent. Is overwriten by 'Page' class.
950
- def basepath(rebuild=false, update= true)
951
- if !self[:basepath] || rebuild
952
- if self[:parent_id]
953
- parent = parent(false)
954
- path = parent ? parent.basepath(rebuild) : ''
955
- else
956
- path = ''
957
- end
958
- self.connection.execute "UPDATE #{self.class.table_name} SET basepath='#{path}' WHERE id='#{self[:id]}'" if path != self[:basepath] && update
959
- self[:basepath] = path
960
- end
870
+ # url base path. If a node is in 'projects' and projects has custom_base set, the
871
+ # node's basepath becomes 'projects', so the url will be 'projects/node34.html'.
872
+ # The basepath is cached. If rebuild is set to true, the cache is updated.
873
+ def basepath
961
874
  self[:basepath]
962
875
  end
963
876
 
964
- # Return the full path as an array if it is cached or build it when asked for.
965
- def fullpath(rebuild=false, update = true, loop_ids = [])
966
- return "" if loop_ids.include?(self.id)
967
- loop_ids << self.id
968
- if !self[:fullpath] || rebuild
969
- if parent = parent(false)
970
- path = parent.fullpath(rebuild,true,loop_ids).split('/') + [name.gsub("'",'')]
971
- else
972
- path = []
973
- end
974
- path = path.join('/')
975
- self.connection.execute "UPDATE #{self.class.table_name} SET fullpath='#{path}' WHERE id='#{self[:id]}'" if path != self[:fullpath] && update
976
- self[:fullpath] = path
977
- end
978
- self[:fullpath]
979
- end
980
-
981
877
  # Same as fullpath, but the path includes the root node.
982
878
  def rootpath
983
879
  current_site.name + (fullpath != "" ? "/#{fullpath}" : "")
@@ -1477,32 +1373,56 @@ class Node < ActiveRecord::Base
1477
1373
  end
1478
1374
 
1479
1375
  private
1480
- def node_before_validation
1481
- self[:kpath] = self.vclass.kpath
1482
1376
 
1483
- self.name ||= (version.title || '').url_name
1377
+ def rebuild_fullpath
1378
+ return unless new_record? || name_changed? || parent_id_changed? || fullpath.nil?
1379
+ if parent = parent(false)
1380
+ path = parent.fullpath.split('/') + [name]
1381
+ else
1382
+ path = []
1383
+ end
1384
+ self[:fullpath] = path.join('/')
1385
+ end
1386
+
1387
+ def rebuild_basepath
1388
+ return unless new_record? || name_changed? || parent_id_changed? || custom_base_changed? || basepath.nil?
1389
+ if custom_base
1390
+ self[:basepath] = self.fullpath
1391
+ elsif parent = parent(false)
1392
+ self[:basepath] = parent.basepath
1393
+ else
1394
+ self[:basepath] = ""
1395
+ end
1396
+ end
1484
1397
 
1398
+ def set_defaults
1399
+ # sync version title and name
1485
1400
  if ref_lang == version.lang &&
1486
1401
  ((full_drive? && version.status == Zena::Status[:pub]) ||
1487
1402
  (can_drive? && vhash['r'][ref_lang].nil?))
1488
1403
  if name_changed? && !name.blank?
1489
- version.title = self.name.gsub(/([A-Z])/) { " #{$1.downcase}" }
1404
+ version.title = self.name
1490
1405
  elsif !version.title.blank?
1491
1406
  self.name = version.title.url_name
1492
1407
  end
1493
1408
  end
1494
1409
 
1410
+ self[:custom_base] = false unless kind_of?(Page)
1411
+ true
1412
+ end
1413
+
1414
+ def node_before_validation
1415
+ self[:kpath] = self.vclass.kpath
1416
+
1417
+ self.name ||= (version.title || '').url_name
1418
+
1495
1419
  unless name.blank?
1496
- # update cached fullpath
1497
- if new_record? || name_changed? || parent_id_changed?
1498
- self[:fullpath] = self.fullpath(true,false)
1499
- elsif !new_record? && custom_base_changed?
1500
- self[:basepath] = self.basepath(true,false)
1501
- end
1502
- if !new_record? && fullpath_changed?
1503
- # FIXME: update children's cached fullpaths
1504
- @clear_children_fullpath = true
1505
- end
1420
+ # rebuild cached fullpath / basepath
1421
+ rebuild_fullpath
1422
+ rebuild_basepath
1423
+ # we should use a full rebuild when there are corrupt values,
1424
+ # if fullpath was blank, we have no way to find all children
1425
+ @need_rebuild_children_fullpath = !new_record? && (fullpath_changed? || basepath_changed?) && !fullpath_was.blank?
1506
1426
  end
1507
1427
 
1508
1428
  # make sure section is the same as the parent
@@ -1510,7 +1430,7 @@ class Node < ActiveRecord::Base
1510
1430
  # root node
1511
1431
  self[:section_id] = self[:id]
1512
1432
  self[:project_id] = self[:id]
1513
- elsif parent
1433
+ elsif ref = parent
1514
1434
  self[:section_id] = ref.get_section_id
1515
1435
  self[:project_id] = ref.get_project_id
1516
1436
  else
@@ -1715,16 +1635,38 @@ class Node < ActiveRecord::Base
1715
1635
  end
1716
1636
  end
1717
1637
 
1718
- def clear_children_fullpath(i = self[:id])
1719
- return true unless @clear_children_fullpath
1720
- base_class.connection.execute "UPDATE nodes SET fullpath = NULL WHERE #{ref_field(false)}='#{i}'"
1721
- ids = nil
1722
- # FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
1723
- base_class.send(:with_exclusive_scope) do
1724
- ids = Zena::Db.fetch_ids("SELECT id FROM #{base_class.table_name} WHERE #{ref_field(true)} = '#{i.to_i}' AND inherit='1'")
1725
- end
1638
+ def rebuild_children_fullpath
1639
+ return true unless @need_rebuild_children_fullpath
1640
+
1641
+ # Update descendants
1642
+ fullpath_new = self.fullpath
1643
+ fullpath_new = "#{fullpath_new}/" if fullpath_was == ''
1644
+ fullpath_re = fullpath_changed? ? %r{\A#{self.fullpath_was}} : nil
1726
1645
 
1727
- ids.each { |i| clear_children_fullpath(i) }
1646
+ bases = [self.basepath]
1647
+
1648
+ i = 0
1649
+ batch_size = 100
1650
+ while true
1651
+ list = Zena::Db.fetch_attributes(['id', 'fullpath', 'basepath', 'custom_base'], 'nodes', "fullpath LIKE #{Zena::Db.quote("#{fullpath_was}%")} AND site_id = #{current_site.id} ORDER BY fullpath ASC LIMIT #{batch_size} OFFSET #{i * batch_size}")
1652
+ break if list.empty?
1653
+ list.each do |rec|
1654
+ rec['fullpath'].sub!(fullpath_re, fullpath_new) if fullpath_re
1655
+ if rec['custom_base'].to_i == 1
1656
+ rec['basepath'] = rec['fullpath']
1657
+ bases << rec['basepath']
1658
+ else
1659
+ while rec['fullpath'].size <= bases.last.size
1660
+ bases.pop
1661
+ end
1662
+ rec['basepath'] = bases.last
1663
+ end
1664
+ id = rec.delete('id')
1665
+ Zena::Db.execute "UPDATE nodes SET #{rec.map {|k,v| "#{Zena::Db.connection.quote_column_name(k)}=#{Zena::Db.quote(v)}"}.join(', ')} WHERE id = #{id}"
1666
+ end
1667
+ # 50 more
1668
+ i += 1
1669
+ end
1728
1670
  true
1729
1671
  end
1730
1672
 
@@ -1749,4 +1691,4 @@ class Node < ActiveRecord::Base
1749
1691
 
1750
1692
  end
1751
1693
 
1752
- Bricks::Patcher.apply_patches
1694
+ Bricks.apply_patches
@@ -10,28 +10,8 @@ Template:: subclass of TextDocument. Contains the zafu code to make the look an
10
10
  Skin:: subclass of Template. Contains other templates. The skin name must be unique throughout the site as it is used to identify the 'theme' of the site or parts of the site.
11
11
  =end
12
12
  class Page < Node
13
- before_validation :update_base_path #, :if => 'custom_base.changed?'
14
-
15
- # url base path. If a node is in 'projects' and projects has custom_base set, the
16
- # node's basepath becomes 'projects', so the url will be 'projects/node34.html'.
17
- # The basepath is cached. If rebuild is set to true, the cache is updated.
18
- def basepath(rebuild=false, update = true)
19
- if !self[:basepath] || rebuild
20
- if self[:custom_base]
21
- self.basepath = fullpath(rebuild, update)
22
- # FIXME: REMOVE this UPDATE !
23
- self.connection.execute "UPDATE #{self.class.table_name} SET basepath=#{Node.connection.quote(self.basepath)} WHERE id='#{self[:id]}'" if !new_record? && update && self.basepath_changed?
24
- else
25
- super
26
- end
27
- end
28
- self[:basepath]
29
- end
30
13
 
31
14
  private
32
- def update_base_path
33
- self[:basepath] = self.basepath(true)
34
- end
35
15
 
36
16
  def validate_node
37
17
  super
@@ -72,12 +72,7 @@ class Site < ActiveRecord::Base
72
72
  :first_name => "Super", :name => "User", :lang => site.default_lang, :status => User::Status[:su])
73
73
  su.site = site
74
74
 
75
- unless Thread.current.respond_to?(:visitor)
76
- class << Thread.current
77
- attr_accessor :visitor
78
- end
79
- end
80
- Thread.current.visitor = su
75
+ Thread.current[:visitor] = su
81
76
 
82
77
  unless su.save
83
78
  # rollback
@@ -109,8 +104,10 @@ class Site < ActiveRecord::Base
109
104
  # =========== CREATE Anonymous, admin =====================
110
105
  # create anon user
111
106
  # FIXME: make sure user_id = admin user
112
- anon = site.send(:secure,User) { User.new_no_defaults( :login => nil, :password => nil,
113
- :first_name => "Anonymous", :name => "User", :lang => site.default_lang, :status => User::Status[:moderated]) }
107
+
108
+ anon = site.send(:secure, User) {User.new_no_defaults( :login => nil, :password => nil,
109
+ :first_name => "Anonymous", :name => "User", :lang => site.default_lang, :status => User::Status[:moderated])}
110
+
114
111
  anon.site = site
115
112
  raise Exception.new("Could not create anonymous user for site [#{host}] (site#{site[:id]})\n#{anon.errors.map{|k,v| "[#{k}] #{v}"}.join("\n")}") unless anon.save
116
113
  site[:anon_id] = anon[:id]
@@ -134,7 +131,7 @@ class Site < ActiveRecord::Base
134
131
  #admin_user = site.send(:secure, User) { User.find(admin_user[:id]) }
135
132
 
136
133
  # make admin the current visitor
137
- Thread.current.visitor = admin_user
134
+ Thread.current[:visitor] = admin_user
138
135
 
139
136
  root = site.send(:secure,Project) { Project.create( :name => site.name, :rgroup_id => pub[:id], :wgroup_id => sgroup[:id], :dgroup_id => admin[:id], :v_title => site.name, :v_status => Zena::Status[:pub]) }
140
137
  raise Exception.new("Could not create root node for site [#{host}] (site#{site[:id]})\n#{root.errors.map{|k,v| "[#{k}] #{v}"}.join("\n")}") if root.new_record?
@@ -204,13 +201,13 @@ class Site < ActiveRecord::Base
204
201
  # Return the anonymous user, the one used by anonymous visitors to visit the public part
205
202
  # of the site.
206
203
  def anon
207
- @anon ||= secure!(User) { User.find(self[:anon_id]) }
204
+ @anon ||= User.find_by_id_and_site_id(self[:anon_id], self.id)
208
205
  end
209
206
 
210
207
  # Return the super user. This user has extended priviledges on the data (has access to private other's data).
211
208
  # This is an emergency user.
212
209
  def su
213
- @su ||= secure!(User) { User.find(self[:su_id]) }
210
+ @su ||= User.find_by_id_and_site_id(self[:su_id], self.id)
214
211
  end
215
212
 
216
213
  # TODO: test
@@ -344,6 +341,39 @@ class Site < ActiveRecord::Base
344
341
  end
345
342
  end
346
343
 
344
+ def rebuild_fullpath(parent_id = nil, parent_fullpath = "", parent_basepath = "")
345
+ i = 0
346
+ batch_size = 100
347
+ children = []
348
+ while true
349
+ rec = Zena::Db.fetch_attributes(['id', 'fullpath', 'basepath', 'custom_base', 'name'], 'nodes', "parent_id #{parent_id ? "= #{parent_id}" : "IS NULL"} AND site_id = #{self.id} ORDER BY id ASC LIMIT #{batch_size} OFFSET #{i * batch_size}")
350
+ break if rec.empty?
351
+ rec.each do |rec|
352
+ if parent_id
353
+ rec['fullpath'] = parent_fullpath == '' ? rec['name'] : "#{parent_fullpath}/#{rec['name']}"
354
+ else
355
+ # root node
356
+ rec['fullpath'] = ''
357
+ end
358
+
359
+ if rec['custom_base'].to_i == 1
360
+ rec['basepath'] = rec['fullpath']
361
+ else
362
+ rec['basepath'] = parent_basepath
363
+ end
364
+
365
+ id = rec.delete('id')
366
+ children << [id, rec['fullpath'], rec['basepath']]
367
+ Zena::Db.execute "UPDATE nodes SET #{rec.map {|k,v| "#{Zena::Db.connection.quote_column_name(k)}=#{Zena::Db.quote(v)}"}.join(', ')} WHERE id = #{id}"
368
+ end
369
+ # 50 more
370
+ i += 1
371
+ end
372
+ children.each do |child|
373
+ rebuild_fullpath(*child)
374
+ end
375
+ end
376
+
347
377
  private
348
378
  def valid_site
349
379
  errors.add(:host, 'invalid') if self[:host].nil? || (self[:host] =~ /^\./) || (self[:host] =~ /[^\w\.\-]/)
@@ -352,4 +382,4 @@ class Site < ActiveRecord::Base
352
382
  end
353
383
  end
354
384
 
355
- Bricks::Patcher.apply_patches
385
+ Bricks.apply_patches