zena 0.15.2 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/CREDITS +27 -0
- data/Capfile +3 -0
- data/DEVELOPERS +46 -0
- data/History.txt +15 -0
- data/MIT-LICENSE +19 -0
- data/Rakefile +44 -0
- data/TODO +24 -0
- data/TODO_ZENA_1_0 +23 -0
- data/app/controllers/application_controller.rb +3 -0
- data/app/controllers/documents_controller.rb +22 -56
- data/app/controllers/nodes_controller.rb +42 -27
- data/app/controllers/pings_controller.rb +19 -0
- data/app/controllers/relations_controller.rb +5 -1
- data/app/controllers/sites_controller.rb +1 -46
- data/app/controllers/user_sessions_controller.rb +47 -0
- data/app/controllers/users_controller.rb +1 -0
- data/app/controllers/versions_controller.rb +25 -7
- data/app/controllers/virtual_classes_controller.rb +1 -1
- data/app/helpers/application_helper.rb +1 -1
- data/app/models/comment.rb +2 -1
- data/app/models/contact_content.rb +2 -2
- data/app/models/data_entry.rb +5 -6
- data/app/models/document.rb +14 -10
- data/app/models/document_content.rb +4 -6
- data/app/models/iformat.rb +2 -2
- data/app/models/image_content.rb +6 -9
- data/app/models/node.rb +106 -164
- data/app/models/page.rb +0 -20
- data/app/models/site.rb +42 -12
- data/app/models/template.rb +3 -8
- data/app/models/template_content.rb +2 -0
- data/app/models/text_document.rb +13 -8
- data/app/models/user.rb +47 -100
- data/app/models/user_session.rb +4 -0
- data/app/models/version.rb +1 -1
- data/app/views/comments/create.rjs +3 -3
- data/app/views/comments/edit.rjs +1 -1
- data/app/views/comments/update.rjs +1 -1
- data/app/views/nodes/_import_results.rhtml +1 -1
- data/app/views/nodes/create.rjs +3 -3
- data/app/views/templates/document_create_tabs/_file.rhtml +1 -2
- data/app/views/templates/document_create_tabs/_import.rhtml +7 -2
- data/app/views/templates/edit_tabs/_document.rhtml +1 -3
- data/app/views/templates/edit_tabs/_image.rhtml +1 -3
- data/app/views/versions/_tr.rhtml +1 -1
- data/app/views/versions/edit.rhtml +2 -26
- data/bin/zena +6 -1
- data/bricks/delayed_job/README +18 -0
- data/bricks/delayed_job/migrate/20091104191643_create_delayed_jobs_table.rb +19 -0
- data/bricks/delayed_job/misc/init.rb +8 -0
- data/bricks/delayed_job/misc/tasks.rb +2 -0
- data/bricks/math/patch/application_helper.rb +1 -1
- data/bricks/sphinx/MIT-LICENSE +19 -0
- data/bricks/sphinx/README +19 -0
- data/bricks/sphinx/lib/use_sphinx.rb +78 -0
- data/bricks/sphinx/migrate/20091102171258_add_delta_for_sphinx.rb +9 -0
- data/bricks/sphinx/misc/deploy.rb +20 -0
- data/bricks/sphinx/misc/sphinx.yml +12 -0
- data/bricks/sphinx/misc/tasks.rb +21 -0
- data/bricks/sphinx/patch/node.rb +8 -0
- data/bricks/tags/lib/has_tags.rb +5 -3
- data/bricks/tags/test/zafu/tags.yml +13 -1
- data/config/bricks.yml +35 -0
- data/config/deploy.rb +8 -1
- data/config/environment.rb +1 -1
- data/config/environments/production.rb +1 -1
- data/config/gems.yml +28 -5
- data/config/sphinx.yml +12 -0
- data/db/init/base/skins/default/Node-+popupLayout.zafu +1 -16
- data/db/migrate/20091026161708_add_persistence_token.rb +13 -0
- data/db/migrate/20091101184952_add_session_table.rb +16 -0
- data/db/migrate/20091123175137_add_single_access_token.rb +9 -0
- data/db/migrate/20091124161608_rebuild_fullpath.rb +11 -0
- data/db/schema.rb +21 -8
- data/doc/README_FOR_APP +24 -0
- data/doc/fixtures.graffle +19568 -0
- data/doc/fixtures.pdf +0 -0
- data/doc/template/LICENSE +184 -0
- data/doc/template/README +37 -0
- data/doc/template/allison.css +283 -0
- data/doc/template/allison.js +307 -0
- data/doc/template/allison.rb +260 -0
- data/doc/template/cache/BODY +588 -0
- data/doc/template/cache/CLASS_INDEX +4 -0
- data/doc/template/cache/CLASS_PAGE +1 -0
- data/doc/template/cache/FILE_INDEX +4 -0
- data/doc/template/cache/FILE_PAGE +1 -0
- data/doc/template/cache/FONTS +1 -0
- data/doc/template/cache/FR_INDEX_BODY +1 -0
- data/doc/template/cache/IMGPATH +1 -0
- data/doc/template/cache/INDEX +1 -0
- data/doc/template/cache/JAVASCRIPT +307 -0
- data/doc/template/cache/METHOD_INDEX +4 -0
- data/doc/template/cache/METHOD_LIST +1 -0
- data/doc/template/cache/SRC_PAGE +1 -0
- data/doc/template/cache/STYLE +283 -0
- data/doc/template/cache/URL +1 -0
- data/doc/zafu_changes.yml +29 -0
- data/lib/base_additions.rb +1 -1
- data/lib/bricks.rb +9 -0
- data/lib/bricks/loader.rb +86 -0
- data/lib/bricks/requirements_validation.rb +71 -0
- data/lib/tasks/zena.rake +42 -4
- data/lib/zafu/action.rb +285 -0
- data/lib/zafu/ajax.rb +93 -0
- data/lib/zafu/attributes.rb +117 -0
- data/lib/zafu/calendar.rb +159 -0
- data/lib/zafu/context.rb +330 -0
- data/lib/zafu/core/html.rb +102 -0
- data/lib/zafu/core/move_to_parser.rb +167 -0
- data/lib/zafu/dates.rb +58 -0
- data/lib/zafu/display.rb +502 -0
- data/lib/zafu/eval.rb +66 -0
- data/lib/zafu/experimental.rb +66 -0
- data/lib/zafu/i18n.rb +64 -0
- data/lib/zafu/meta.rb +25 -0
- data/lib/zafu/refactor.rb +73 -0
- data/lib/zafu/support/context.rb +265 -0
- data/lib/zafu/support/dom.rb +145 -0
- data/lib/zafu/support/erb.rb +62 -0
- data/lib/zafu/support/flow.rb +401 -0
- data/lib/zafu/support/forms.rb +461 -0
- data/lib/zafu/support/links.rb +306 -0
- data/lib/zafu_parser.rb +26 -2
- data/lib/zena.rb +34 -15
- data/lib/zena/acts/multiversion.rb +2 -2
- data/lib/zena/acts/secure.rb +41 -30
- data/lib/zena/app.rb +7 -10
- data/lib/zena/controller/test_case.rb +12 -7
- data/lib/zena/crypto_provider/initial.rb +15 -0
- data/lib/zena/db.rb +6 -1
- data/lib/zena/deploy.rb +34 -6
- data/lib/zena/deploy/logrotate_app.rhtml +9 -0
- data/lib/zena/deploy/logrotate_host.rhtml +34 -0
- data/lib/zena/deploy/template.rb +1 -9
- data/lib/zena/foxy_parser.rb +1 -1
- data/lib/zena/info.rb +3 -1
- data/lib/zena/migrator.rb +1 -1
- data/lib/zena/parser.rb +12 -4
- data/lib/zena/parser/zazen_rules.rb +6 -6
- data/lib/zena/parser/zena_rules.rb +1 -7
- data/lib/zena/routes.rb +5 -5
- data/lib/zena/test_controller.rb +7 -2
- data/lib/zena/unit/test_case.rb +6 -8
- data/lib/zena/use/ajax.rb +10 -10
- data/lib/zena/use/authlogic.rb +93 -0
- data/lib/zena/use/dyn_attributes.rb +5 -0
- data/lib/zena/use/html_tags.rb +16 -34
- data/lib/zena/use/i18n.rb +4 -1
- data/lib/zena/use/node_query_finders.rb +8 -4
- data/lib/zena/use/refactor.rb +8 -20
- data/lib/zena/use/relations.rb +1 -0
- data/lib/zena/use/rendering.rb +4 -2
- data/lib/zena/use/search.rb +52 -0
- data/lib/zena/use/test_helper.rb +27 -28
- data/lib/zena/use/upload.rb +188 -0
- data/lib/zena/use/urls.rb +16 -14
- data/lib/zena/use/zafu.rb +16 -63
- data/lib/zena/use/zazen.rb +8 -8
- data/lib/zena/view/test_case.rb +8 -4
- data/locale/en/LC_MESSAGES/zena.mo +0 -0
- data/locale/en/zena.po +3 -3
- data/public/.htaccess +40 -0
- data/public/javascripts/upload-progress.js +17 -8
- data/public/javascripts/zena.js +8 -2
- data/public/stylesheets/popup.css +1 -0
- data/script/about +3 -0
- data/script/apache_logging +25 -0
- data/script/breakpointer +3 -0
- data/script/console +3 -0
- data/script/dbconsole +3 -0
- data/script/destroy +3 -0
- data/script/generate +3 -0
- data/script/performance/benchmarker +3 -0
- data/script/performance/profiler +3 -0
- data/script/plugin +3 -0
- data/script/process/inspector +3 -0
- data/script/process/reaper +3 -0
- data/script/process/spawner +3 -0
- data/script/runner +3 -0
- data/script/server +3 -0
- data/script/set_revision +29 -0
- data/spec/controllers/versions_controller_spec.rb +11 -0
- data/test/fixtures/files/Node-test.zafu +1 -1
- data/test/functional/nodes_controller_test.rb +25 -0
- data/test/functional/pings_controller_test.rb +8 -0
- data/test/functional/user_sessions_controller_test.rb +59 -0
- data/test/functional/users_controller_test.rb +81 -19
- data/test/helpers/node_query/filters.yml +5 -0
- data/test/helpers/node_query_test.rb +3 -3
- data/test/integration/multiple_hosts_test.rb +1 -1
- data/test/integration/navigation_test.rb +1 -1
- data/test/sites/complex/users.yml +1 -1
- data/test/sites/ocean/users.yml +3 -3
- data/test/sites/zena/users.yml +5 -4
- data/test/test_zena.rb +38 -38
- data/test/unit/cached_page_test.rb +2 -2
- data/test/unit/comment_test.rb +0 -1
- data/test/unit/document_test.rb +23 -11
- data/test/unit/helpers/ping_helper_test.rb +4 -0
- data/test/unit/multiversion_test.rb +24 -16
- data/test/unit/node_test.rb +32 -93
- data/test/unit/note_test.rb +9 -0
- data/test/unit/page_test.rb +2 -2
- data/test/unit/secure_test.rb +2 -12
- data/test/unit/site_test.rb +43 -24
- data/test/unit/template_test.rb +45 -3
- data/test/unit/text_document_test.rb +4 -3
- data/test/unit/user_test.rb +13 -33
- data/test/unit/zena/db_test.rb +8 -0
- data/test/unit/zena/parser/zazen.yml +4 -4
- data/test/unit/zena/use/dates_view_methods_test.rb +2 -1
- data/test/unit/zena/use/html_tags_test.rb +12 -4
- data/test/unit/zena/use/refactor_test.rb +4 -3
- data/test/unit/zena/use/rendering_test.rb +1 -0
- data/test/unit/zena/use/upload_test.rb +76 -0
- data/test/unit/zena/use/urls_test.rb +4 -0
- data/test/unit/zena/use/zafu_test.rb +8 -0
- data/test/unit/zena/workflow/status_version_test.rb +6 -0
- data/test/unit/zena/zena_tags/ajax.yml +4 -4
- data/test/unit/zena/zena_tags/basic.yml +21 -10
- data/test/unit/zena/zena_tags/relations.yml +0 -6
- data/test/unit/zena/zena_tags/rubyless.yml +35 -0
- data/test/unit/zena/zena_tags/zazen.yml +4 -4
- data/test/unit/zena/zena_tags_test.rb +36 -4
- data/vendor/TextMate/Zena.tmbundle/Commands/Run all yaml tests.tmCommand +1 -1
- data/vendor/TextMate/Zena.tmbundle/Commands/Run focused yaml test.tmCommand +2 -3
- data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/catch_exception.rb +39 -0
- data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/run_script.rb +102 -58
- data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/stdin_dialog.rb +14 -0
- data/vendor/TextMate/Zena.tmbundle/info.plist +2 -0
- data/zena.gemspec +2085 -0
- metadata +265 -90
- data/app/controllers/sessions_controller.rb +0 -41
- data/app/views/sites/zena_up.html.erb +0 -11
- data/config/database.yml +0 -40
- data/db/production.sqlite3 +0 -0
- data/lib/bricks/patcher.rb +0 -68
- data/lib/zena/parser/zena_tags.rb +0 -3562
- data/lib/zena/use/authentification.rb +0 -120
- data/public/images/ext/contact_pv.png +0 -0
- data/public/images/ext/other_pv.png +0 -0
- data/public/images/ext/page_pv.png +0 -0
- data/public/images/ext/page_tiny.png +0 -0
- data/public/images/ext/pdf_pv.png +0 -0
- data/public/images/ext/post_pv.png +0 -0
- data/public/images/ext/post_tiny.png +0 -0
- data/public/images/ext/project_pv.png +0 -0
- data/public/images/ext/project_tiny.png +0 -0
- data/public/images/ext/tag_pv.png +0 -0
- data/public/images/ext/zip_pv.png +0 -0
- data/tasks/ann.rake +0 -80
- data/tasks/bones.rake +0 -20
- data/tasks/gem.rake +0 -201
- data/tasks/git.rake +0 -40
- data/tasks/notes.rake +0 -27
- data/tasks/post_load.rake +0 -34
- data/tasks/rdoc.rake +0 -51
- data/tasks/rubyforge.rake +0 -55
- data/tasks/setup.rb +0 -292
- data/tasks/spec.rake +0 -54
- data/tasks/svn.rake +0 -47
- data/tasks/test.rake +0 -40
- data/tasks/zentest.rake +0 -36
- data/test/fixtures/comments.yml +0 -126
- data/test/fixtures/contact_contents.yml +0 -132
- data/test/fixtures/data_entries.yml +0 -65
- data/test/fixtures/discussions.yml +0 -48
- data/test/fixtures/document_contents.yml +0 -108
- data/test/fixtures/dyn_attributes.yml +0 -66
- data/test/fixtures/groups.yml +0 -86
- data/test/fixtures/groups_users.yml +0 -81
- data/test/fixtures/iformats.yml +0 -29
- data/test/fixtures/links.yml +0 -313
- data/test/fixtures/nodes.yml +0 -2592
- data/test/fixtures/relations.yml +0 -126
- data/test/fixtures/sites.yml +0 -58
- data/test/fixtures/template_contents.yml +0 -172
- data/test/fixtures/users.yml +0 -167
- data/test/fixtures/versions.yml +0 -1911
- data/test/fixtures/virtual_classes.yml +0 -87
- data/test/fixtures/zips.yml +0 -15
- data/test/functional/sessions_controller_test.rb +0 -73
data/app/models/node.rb
CHANGED
@@ -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 :
|
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 :
|
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
|
-
|
165
|
-
:project =>
|
166
|
-
:real_project =>
|
167
|
-
:user =>
|
168
|
-
:
|
169
|
-
:
|
170
|
-
:
|
171
|
-
:
|
172
|
-
:
|
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
|
-
|
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']
|
530
|
-
attrs['name']
|
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 |
|
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
|
-
|
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
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
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
|
-
#
|
950
|
-
|
951
|
-
|
952
|
-
|
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
|
-
|
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
|
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
|
-
#
|
1497
|
-
|
1498
|
-
|
1499
|
-
|
1500
|
-
|
1501
|
-
|
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
|
1719
|
-
return true unless @
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1724
|
-
|
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
|
-
|
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
|
1694
|
+
Bricks.apply_patches
|
data/app/models/page.rb
CHANGED
@@ -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
|
data/app/models/site.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
113
|
-
|
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
|
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 ||=
|
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 ||=
|
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
|
385
|
+
Bricks.apply_patches
|