zena 1.0.0.rc2 → 1.0.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +23 -0
- data/README.rdoc +1 -1
- data/app/controllers/columns_controller.rb +3 -31
- data/app/controllers/comments_controller.rb +8 -3
- data/app/controllers/data_entries_controller.rb +1 -1
- data/app/controllers/documents_controller.rb +2 -2
- data/app/controllers/nodes_controller.rb +29 -12
- data/app/controllers/relations_controller.rb +2 -2
- data/app/controllers/sites_controller.rb +1 -1
- data/app/controllers/user_sessions_controller.rb +6 -3
- data/app/controllers/users_controller.rb +18 -16
- data/app/controllers/versions_controller.rb +20 -18
- data/app/controllers/virtual_classes_controller.rb +103 -17
- data/app/helpers/users_helper.rb +1 -1
- data/app/models/column.rb +19 -50
- data/app/models/comment.rb +2 -1
- data/app/models/node.rb +45 -22
- data/app/models/relation.rb +13 -0
- data/app/models/relation_proxy.rb +3 -2
- data/app/models/role.rb +213 -4
- data/app/models/site.rb +18 -11
- data/app/models/template.rb +37 -35
- data/app/models/version.rb +1 -1
- data/app/models/virtual_class.rb +154 -86
- data/app/views/columns/_li.html.erb +1 -1
- data/app/views/columns/index.html.erb +1 -9
- data/app/views/comments/index.rhtml +10 -8
- data/app/views/documents/_crop.rhtml +5 -6
- data/app/views/documents/crop_form.rjs +3 -2
- data/app/views/groups/index.rhtml +1 -1
- data/app/views/iformats/index.rhtml +1 -1
- data/app/views/nodes/_import_results.rhtml +1 -1
- data/app/views/nodes/_parent.rhtml +1 -2
- data/app/views/nodes/update.rjs +3 -4
- data/app/views/relations/index.erb +1 -1
- data/app/views/sites/index.erb +1 -1
- data/app/views/templates/drive_tabs/_drive.rhtml +0 -2
- data/app/views/templates/edit_tabs/_image.rhtml +1 -1
- data/app/views/templates/edit_tabs/_title.rhtml +0 -6
- data/app/views/users/index.rhtml +1 -1
- data/app/views/users/preferences.html.erb +2 -2
- data/app/views/versions/backup.rjs +1 -1
- data/app/views/versions/custom_tab.rhtml +9 -4
- data/app/views/versions/destroy.rjs +2 -2
- data/app/views/versions/update.rjs +2 -9
- data/app/views/virtual_classes/_form.erb +3 -2
- data/app/views/virtual_classes/import_prepare.html.erb +13 -0
- data/app/views/virtual_classes/index.erb +28 -8
- data/app/views/zafu/default/Node-+adminLayout.zafu +1 -13
- data/app/views/zafu/default/Node-+login.zafu +1 -0
- data/app/views/zafu/default/Node-+notFound.zafu +1 -1
- data/app/views/zafu/default/Node-+popupLayout.zafu +1 -2
- data/app/views/zafu/default/Node-+search.zafu +1 -1
- data/app/views/zafu/default/Node-admin.zafu +205 -0
- data/app/views/zafu/default/Node.zafu +11 -11
- data/bricks/captcha/lib/bricks/captcha.rb +3 -2
- data/bricks/mongrel/zena/init.rb +2 -1
- data/bricks/pdf/README +5 -5
- data/bricks/pdf/lib/bricks/pdf/engine/prince.rb +2 -2
- data/bricks/pdf/lib/bricks/pdf/engine/xhtml2pdf.rb +2 -2
- data/bricks/pdf/lib/bricks/pdf/install.rb +5 -5
- data/bricks/pdf/lib/bricks/pdf.rb +11 -11
- data/bricks/pdf/test/engines/test_prince.rb +4 -4
- data/bricks/pdf/test/engines/test_xhtml2pdf.rb +4 -4
- data/bricks/pdf/test/shoulda_macros/shoulda_pdf.rb +2 -2
- data/bricks/pdf/zena/init.rb +2 -2
- data/bricks/pdf/zena/tasks.rb +2 -2
- data/bricks/sphinx/lib/bricks/sphinx.rb +6 -2
- data/bricks/sphinx/zena/{sphinx.yml → sphinx.yml.erb} +2 -2
- data/bricks/sphinx/zena/tasks.rb +28 -2
- data/bricks/tags/lib/bricks/tags.rb +16 -1
- data/bricks/tags/zena/test/unit/tags_test.rb +15 -0
- data/bricks/tags/zena/test/zafu/tags.yml +5 -1
- data/bricks/worker/lib/bricks/worker.rb +39 -0
- data/bricks/worker/zena/deploy.rb +0 -2
- data/bricks/worker/zena/init.rb +1 -0
- data/bricks/worker/zena/test/sites/zena/delayed_jobs.yml +16 -0
- data/bricks/worker/zena/test/zafu/worker.yml +8 -0
- data/bricks/zena/zena/migrate/01_base.rb +36 -60
- data/bricks/zena/zena/migrate/02_zerox1_schema.rb +388 -0
- data/bricks/zena/zena/migrate/03_zerox1_data.rb +380 -0
- data/bricks/zena/zena/migrate/20110315161158_add_reverse_scope_to_roles.rb +9 -0
- data/config/database_example.yml +1 -1
- data/config/environment.rb +1 -1
- data/config/gems.yml +17 -14
- data/db/init/base/skins/default/Node-+index.zafu +8 -1
- data/db/init/base/skins/default/Node-+login.zafu +1 -0
- data/db/init/base/skins/default/Node-+popupLayout.zafu +1 -2
- data/db/init/base/skins/default/Node-+search.zafu +2 -2
- data/db/init/base/skins/default/Node.zafu +9 -9
- data/db/init/base/skins/default/{favicon.png → img/favicon.png} +0 -0
- data/db/init/base/skins/default/{style.css → img/style.css} +0 -0
- data/db/init/base/skins/default/img/translations.yml +11 -0
- data/db/init/base/skins/default/notes.zafu +7 -9
- data/doc/zafu_changes.yml +12 -0
- data/lib/bricks/loader.rb +38 -15
- data/lib/tasks/zena.rake +74 -24
- data/lib/zena/acts/enrollable.rb +4 -1
- data/lib/zena/acts/secure.rb +2 -48
- data/lib/zena/acts/serializable.rb +13 -1
- data/lib/zena/app.rb +9 -0
- data/lib/zena/code_syntax.rb +154 -151
- data/lib/zena/console.rb +141 -0
- data/lib/zena/controller/test_case.rb +1 -1
- data/lib/zena/db_helper/abstract_db.rb +17 -5
- data/lib/zena/db_helper/mysql.rb +14 -12
- data/lib/zena/db_helper/postgresql.rb +1 -2
- data/lib/zena/db_helper/sqlite3.rb +6 -6
- data/lib/zena/deploy/awstats.conf.rhtml +1 -1
- data/lib/zena/deploy/httpd.rhtml +6 -1
- data/lib/zena/deploy/vhost.rhtml +9 -1
- data/lib/zena/deploy.rb +12 -7
- data/lib/zena/foxy_parser.rb +3 -1
- data/lib/zena/info.rb +1 -1
- data/lib/zena/parser/zafu_tags.rb +1 -0
- data/lib/zena/parser/zazen_rules.rb +1 -1
- data/lib/zena/remote/node.rb +15 -3
- data/lib/zena/remote/serializable_array.rb +19 -0
- data/lib/zena/remote.rb +1 -0
- data/lib/zena/routes.rb +7 -2
- data/lib/zena/site_worker.rb +11 -1
- data/lib/zena/unit/test_case.rb +68 -0
- data/lib/zena/use/action.rb +6 -2
- data/lib/zena/use/ajax.rb +127 -53
- data/lib/zena/use/ancestry.rb +11 -8
- data/lib/zena/use/calendar.rb +265 -129
- data/lib/zena/use/conditional.rb +1 -1
- data/lib/zena/use/context.rb +5 -5
- data/lib/zena/use/dates.rb +172 -60
- data/lib/zena/use/display.rb +70 -39
- data/lib/zena/use/error_rendering.rb +1 -3
- data/lib/zena/use/field_index.rb +4 -1
- data/lib/zena/use/forms.rb +94 -72
- data/lib/zena/use/fulltext.rb +16 -24
- data/lib/zena/use/html_tags.rb +20 -12
- data/lib/zena/use/i18n.rb +37 -37
- data/lib/zena/use/image_builder.rb +8 -1
- data/lib/zena/use/ml_index.rb +16 -16
- data/lib/zena/use/prop_eval.rb +10 -5
- data/lib/zena/use/query_builder.rb +55 -23
- data/lib/zena/use/query_node.rb +51 -25
- data/lib/zena/use/refactor.rb +2 -28
- data/lib/zena/use/relations.rb +1 -1
- data/lib/zena/use/rendering.rb +29 -0
- data/lib/zena/use/scope_index.rb +75 -14
- data/lib/zena/use/search.rb +5 -10
- data/lib/zena/use/test_helper.rb +2 -2
- data/lib/zena/use/urls.rb +125 -104
- data/lib/zena/use/workflow.rb +2 -1
- data/lib/zena/use/zafu_attributes.rb +2 -2
- data/lib/zena/use/zafu_safe_definitions.rb +20 -0
- data/lib/zena/use/zafu_templates.rb +20 -6
- data/lib/zena/use/zazen.rb +31 -20
- data/lib/zena/view/test_case.rb +5 -0
- data/lib/zena/zafu_compiler.rb +24 -2
- data/lib/zena.rb +12 -6
- data/locale/de/LC_MESSAGES/zena.mo +0 -0
- data/locale/de/zena.po +1345 -1164
- data/locale/en/LC_MESSAGES/zena.mo +0 -0
- data/locale/en/zena.po +1275 -1129
- data/locale/fr/LC_MESSAGES/zena.mo +0 -0
- data/locale/fr/zena.mo +0 -0
- data/locale/fr/zena.po +1617 -1441
- data/locale/log.txt +9 -0
- data/locale/zena.pot +957 -748
- data/public/javascripts/prototype.js +1 -1
- data/public/javascripts/zena.js +99 -44
- data/public/stylesheets/admin.css +6 -4
- data/public/stylesheets/backend.css +71 -0
- data/public/stylesheets/calendar.css +24 -25
- data/public/stylesheets/code.css +11 -6
- data/public/stylesheets/comment.css +2 -1
- data/public/stylesheets/popup.css +7 -8
- data/test/custom_queries/complex.host.yml +15 -1
- data/test/fixtures/files/Node-test.zafu +29 -28
- data/test/fixtures/files/translations_de.yml +12 -1
- data/test/fixtures/files/translations_fr.yml +12 -1
- data/test/functional/comments_controller_test.rb +9 -0
- data/test/functional/iformats_controller_test.rb +1 -1
- data/test/functional/nodes_controller_test.rb +124 -35
- data/test/functional/users_controller_test.rb +132 -3
- data/test/functional/virtual_classes_controller_test.rb +75 -4
- data/test/integration/navigation_test.rb +51 -9
- data/test/integration/query_node/basic.yml +19 -7
- data/test/integration/query_node/complex.yml +1 -1
- data/test/integration/query_node/dates.yml +27 -1
- data/test/integration/query_node/filters.yml +1 -1
- data/test/integration/query_node/relations.yml +13 -4
- data/test/integration/query_node_test.rb +4 -0
- data/test/integration/xml_api_test.rb +6 -1
- data/test/integration/zafu_compiler/action.yml +3 -3
- data/test/integration/zafu_compiler/ajax.yml +103 -22
- data/test/integration/zafu_compiler/basic.yml +0 -52
- data/test/integration/zafu_compiler/calendar.yml +44 -20
- data/test/integration/zafu_compiler/comments.yml +53 -0
- data/test/integration/zafu_compiler/complex.yml +11 -11
- data/test/integration/zafu_compiler/complex_ok.yml +16 -3
- data/test/integration/zafu_compiler/conditional.yml +15 -5
- data/test/integration/zafu_compiler/context.yml +9 -0
- data/test/integration/zafu_compiler/dates.yml +43 -15
- data/test/integration/zafu_compiler/display.yml +60 -6
- data/test/integration/zafu_compiler/errors.yml +6 -2
- data/test/integration/zafu_compiler/forms.yml +45 -6
- data/test/integration/zafu_compiler/i18n.yml +8 -1
- data/test/integration/zafu_compiler/meta.yml +38 -0
- data/test/integration/zafu_compiler/query.yml +43 -4
- data/test/integration/zafu_compiler/relations.yml +26 -33
- data/test/integration/zafu_compiler/rubyless.yml +10 -0
- data/test/integration/zafu_compiler/safe_definitions.yml +21 -1
- data/test/integration/zafu_compiler/urls.yml +75 -5
- data/test/integration/zafu_compiler/version.yml +2 -2
- data/test/integration/zafu_compiler/zafu_attributes.yml +5 -1
- data/test/integration/zafu_compiler/zazen.yml +14 -6
- data/test/integration/zafu_compiler_test.rb +5 -1
- data/test/sites/complex/columns.yml +5 -0
- data/test/sites/complex/roles.yml +4 -0
- data/test/sites/zena/nodes.yml +13 -2
- data/test/sites/zena/roles.yml +13 -5
- data/test/sites/zena/versions.yml +27 -9
- data/test/unit/column_test.rb +51 -5
- data/test/unit/iformat_test.rb +2 -2
- data/test/unit/node_test.rb +29 -17
- data/test/unit/note_test.rb +1 -1
- data/test/unit/relation_proxy_test.rb +4 -5
- data/test/unit/relation_test.rb +16 -0
- data/test/unit/remote_test.rb +2 -2
- data/test/unit/role_test.rb +292 -4
- data/test/unit/site_test.rb +12 -0
- data/test/unit/template_test.rb +1 -1
- data/test/unit/text_document_test.rb +1 -1
- data/test/unit/virtual_class_test.rb +200 -83
- data/test/unit/zena/acts/enrollable_test.rb +26 -31
- data/test/unit/zena/use/calendar_test.rb +90 -37
- data/test/unit/zena/use/field_index_test.rb +28 -0
- data/test/unit/zena/use/html_tags_test.rb +7 -3
- data/test/unit/zena/use/ml_index_test.rb +2 -16
- data/test/unit/zena/use/nested_attributes_alias_view_test.rb +2 -2
- data/test/unit/zena/use/prop_eval_test.rb +50 -8
- data/test/unit/zena/use/query_node_test.rb +11 -0
- data/test/unit/zena/use/rendering_test.rb +72 -0
- data/test/unit/zena/use/scope_index_test.rb +37 -2
- data/test/unit/zena/use/urls_test.rb +10 -0
- data/test/unit/zena/use/zazen_test.rb +3 -3
- data/vendor/plugins/gettext_i18n_rails/Gemfile +11 -0
- data/vendor/plugins/gettext_i18n_rails/Gemfile.lock +92 -0
- data/vendor/plugins/gettext_i18n_rails/Rakefile +12 -17
- data/vendor/plugins/gettext_i18n_rails/Readme.md +215 -0
- data/vendor/plugins/gettext_i18n_rails/VERSION +1 -1
- data/vendor/plugins/gettext_i18n_rails/gettext_i18n_rails.gemspec +38 -34
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/active_record.rb +1 -1
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/backend.rb +30 -14
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/haml_parser.rb +1 -1
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/html_safe_translations.rb +29 -0
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/i18n_hacks.rb +29 -1
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/model_attributes_finder.rb +7 -1
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/railtie.rb +10 -0
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/ruby_gettext_extractor.rb +6 -2
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/string_interpolate_fix.rb +20 -0
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/tasks.rb +120 -0
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails.rb +10 -3
- data/vendor/plugins/gettext_i18n_rails/lib/tasks/gettext_rails_i18n.rake +1 -74
- data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/active_record_spec.rb +51 -20
- data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/backend_spec.rb +12 -7
- data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/string_interpolate_fix_spec.rb +32 -0
- data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails_spec.rb +38 -1
- data/vendor/plugins/gettext_i18n_rails/spec/rails2/Gemfile +11 -0
- data/vendor/plugins/gettext_i18n_rails/spec/spec_helper.rb +1 -8
- data/zena.gemspec +2241 -2217
- metadata +123 -83
- data/.gitignore +0 -36
- data/app/views/nodes/_dates.rhtml +0 -13
- data/db/init/base/skins/default/Node-+adminLayout.zafu +0 -46
- data/db/init/base/skins/default/Node-tree.zafu +0 -19
- data/vendor/plugins/gettext_i18n_rails/README.markdown +0 -143
data/app/helpers/users_helper.rb
CHANGED
@@ -5,7 +5,7 @@ module UsersHelper
|
|
5
5
|
begin
|
6
6
|
@node = @user.node || visitor.prototype
|
7
7
|
begin
|
8
|
-
res =render :file => template_url(:mode => '+user', :format => 'html')
|
8
|
+
res = render :file => template_url(:mode => '+user', :format => 'html')
|
9
9
|
rescue ActiveRecord::RecordNotFound
|
10
10
|
res = render :file => 'versions/custom_tab'
|
11
11
|
end
|
data/app/models/column.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
class Column < ActiveRecord::Base
|
2
|
-
attr_accessor :import_result
|
3
2
|
include RubyLess
|
4
3
|
include Property::StoredColumn
|
5
4
|
TYPES_FOR_FORM = %w{string datetime integer float}
|
@@ -14,6 +13,7 @@ class Column < ActiveRecord::Base
|
|
14
13
|
validates_presence_of :role
|
15
14
|
validates_uniqueness_of :name, :scope => :site_id
|
16
15
|
validate :name_not_in_models
|
16
|
+
validate :valid_ptype_and_index
|
17
17
|
|
18
18
|
after_save :expire_vclass_cache
|
19
19
|
after_destroy :expire_vclass_cache
|
@@ -48,55 +48,6 @@ class Column < ActiveRecord::Base
|
|
48
48
|
FIELD_INDICES << idx
|
49
49
|
end
|
50
50
|
end
|
51
|
-
|
52
|
-
# Import a hash of virtual class definitions and try to build the virtual classes.
|
53
|
-
def import(data)
|
54
|
-
data.keys.map do |klass|
|
55
|
-
build_column(klass, data)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
# Build a virtual class from a name and a hash of virtual class definitions. If
|
60
|
-
# the superclass is in the data hash, it is built first.
|
61
|
-
def build_column(klass, data)
|
62
|
-
# TODO
|
63
|
-
# return data[klass]['result'] if data[klass].has_key?('result')
|
64
|
-
# if virtual_class = Node.get_class(klass)
|
65
|
-
# if virtual_class.superclass.to_s == data[klass]['superclass']
|
66
|
-
# virtual_class.import_result = 'same'
|
67
|
-
# return data[klass]['result'] = virtual_class
|
68
|
-
# else
|
69
|
-
# virtual_class.errors.add(:base, 'conflict')
|
70
|
-
# return data[klass]['result'] = virtual_class
|
71
|
-
# end
|
72
|
-
# else
|
73
|
-
# superclass_name = data[klass]['superclass']
|
74
|
-
# if data[superclass_name]
|
75
|
-
# superclass = build_virtual_class(superclass_name, data)
|
76
|
-
# unless superclass.errors.empty?
|
77
|
-
# virtual_class = VirtualClass.new(:name => klass, :superclass => superclass_name, :create_group_id => current_site.public_group_id)
|
78
|
-
# virtual_class.errors.add(:base, 'conflict in superclass')
|
79
|
-
# return data[klass]['result'] = virtual_class
|
80
|
-
# end
|
81
|
-
# elsif superclass = Node.get_class(superclass_name)
|
82
|
-
# # ok
|
83
|
-
# else
|
84
|
-
# virtual_class = VirtualClass.new(:name => klass, :superclass => superclass_name, :create_group_id => current_site.public_group_id)
|
85
|
-
# virtual_class.errors.add(:base, 'missing superclass')
|
86
|
-
# return data[klass]['result'] = virtual_class
|
87
|
-
# end
|
88
|
-
#
|
89
|
-
# # build
|
90
|
-
# create_group_id = superclass.kind_of?(VirtualClass) ? superclass.create_group_id : current_site.public_group_id
|
91
|
-
# virtual_class = create(data[klass].merge(:name => klass, :create_group_id => create_group_id))
|
92
|
-
# virtual_class.import_result = 'new'
|
93
|
-
# return data[klass]['result'] = virtual_class
|
94
|
-
# end
|
95
|
-
end
|
96
|
-
|
97
|
-
def export
|
98
|
-
# TODO
|
99
|
-
end
|
100
51
|
end
|
101
52
|
|
102
53
|
def kpath
|
@@ -108,8 +59,16 @@ class Column < ActiveRecord::Base
|
|
108
59
|
self.index.to_s.gsub(/\A\./,'')
|
109
60
|
end
|
110
61
|
|
62
|
+
def export
|
63
|
+
{
|
64
|
+
'ptype' => ptype,
|
65
|
+
'index' => index,
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
111
69
|
protected
|
112
70
|
def set_defaults
|
71
|
+
self.index = nil if index.blank?
|
113
72
|
self[:site_id] = current_site.id
|
114
73
|
end
|
115
74
|
|
@@ -134,4 +93,14 @@ class Column < ActiveRecord::Base
|
|
134
93
|
def expire_vclass_cache
|
135
94
|
VirtualClass.expire_cache!
|
136
95
|
end
|
96
|
+
|
97
|
+
def valid_ptype_and_index
|
98
|
+
if !TYPES_FOR_FORM.include?(self.ptype)
|
99
|
+
errors.add(:ptype, 'invalid')
|
100
|
+
end
|
101
|
+
|
102
|
+
if !index.blank? && !(INDICES_FOR_FORM + FIELD_INDICES.map {|i| ".#{i}"}).include?(index)
|
103
|
+
errors.add(:index, 'invalid')
|
104
|
+
end
|
105
|
+
end
|
137
106
|
end
|
data/app/models/comment.rb
CHANGED
@@ -13,7 +13,8 @@ class Comment < ActiveRecord::Base
|
|
13
13
|
:discussion_id => Number,
|
14
14
|
:user_name => {:class => String, :nil => true},
|
15
15
|
:user => {:class => 'User', :nil => true},
|
16
|
-
:author => Node.author_proc
|
16
|
+
:author => Node.author_proc,
|
17
|
+
:author_name => String
|
17
18
|
|
18
19
|
safe_context :replies => ['Comment'], :node => 'Node'
|
19
20
|
|
data/app/models/node.rb
CHANGED
@@ -113,6 +113,10 @@ class Node < ActiveRecord::Base
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
+
def klass_changed?
|
117
|
+
kpath_changed?
|
118
|
+
end
|
119
|
+
|
116
120
|
def virtual_class=(vclass)
|
117
121
|
@virtual_class = vclass
|
118
122
|
self[:vclass_id] = vclass.id
|
@@ -174,9 +178,11 @@ class Node < ActiveRecord::Base
|
|
174
178
|
belongs_to :skin
|
175
179
|
before_validation :set_defaults
|
176
180
|
before_validation :node_before_validation
|
181
|
+
# We need to change class before validation so that prop_eval is triggered with
|
182
|
+
# the new class.
|
183
|
+
before_validation :change_klass
|
177
184
|
validate :validate_node
|
178
185
|
before_create :node_before_create
|
179
|
-
before_save :change_klass
|
180
186
|
after_save :spread_project_and_section
|
181
187
|
after_create :node_after_create
|
182
188
|
attr_protected :zip, :id, :section_id, :project_id, :publish_from, :created_at, :updated_at
|
@@ -220,7 +226,7 @@ class Node < ActiveRecord::Base
|
|
220
226
|
:traductions => ['Version'], :discussion => 'Discussion'
|
221
227
|
|
222
228
|
# we use safe_method because the columns can be null, but the values are never null
|
223
|
-
safe_method :kpath => String, :user_zip => Number,
|
229
|
+
safe_method :kpath => String, :user_zip => Number, :user_id => Number,
|
224
230
|
:parent_zip => Number, :project_zip => Number, :section_zip => Number,
|
225
231
|
:ref_lang => String,
|
226
232
|
:position => Number, :rgroup_id => Number,
|
@@ -229,7 +235,7 @@ class Node < ActiveRecord::Base
|
|
229
235
|
:m_text => String, :m_title => String, :m_author => String,
|
230
236
|
:id => {:class => Number, :method => 'zip'},
|
231
237
|
:skin => 'Skin', :ref_lang => String,
|
232
|
-
:visitor => 'User', [:
|
238
|
+
:visitor => 'User', [:is_ancestor?, Node] => Boolean,
|
233
239
|
:comments_count => Number,
|
234
240
|
:v => {:class => 'Version', :method => 'version'},
|
235
241
|
:version => 'Version', :v_status => Number, :v_lang => String,
|
@@ -257,7 +263,7 @@ class Node < ActiveRecord::Base
|
|
257
263
|
# compute vhash (must come before Fulltext)
|
258
264
|
include Zena::Use::VersionHash::ModelMethods
|
259
265
|
|
260
|
-
# computed properties (vclass prop_eval)
|
266
|
+
# computed properties (vclass prop_eval, must come after MLIndex)
|
261
267
|
include Zena::Use::PropEval::ModelMethods
|
262
268
|
|
263
269
|
# fulltext indices (must come after PropEval)
|
@@ -424,8 +430,8 @@ class Node < ActiveRecord::Base
|
|
424
430
|
def get_class(rel, opts={})
|
425
431
|
# mushroom_types ==> MushroomType
|
426
432
|
class_name = rel =~ /\A[a-z]/ ? rel.singularize.camelize : rel
|
427
|
-
vclass = VirtualClass
|
428
|
-
if opts[:create] && vclass.id
|
433
|
+
vclass = VirtualClass[class_name]
|
434
|
+
if vclass && opts[:create] && vclass.id
|
429
435
|
# TODO: how do we deal with real class ? (Currently = pass).
|
430
436
|
visitor.group_ids.include?(vclass.create_group_id) ? vclass : nil
|
431
437
|
else
|
@@ -461,9 +467,6 @@ class Node < ActiveRecord::Base
|
|
461
467
|
if str =~ /\A\d+\Z/
|
462
468
|
# zip
|
463
469
|
find_by_zip(str)
|
464
|
-
elsif str =~ /\A:?([0-9a-zA-Z ]+)(\+*)\Z/
|
465
|
-
offset = $2.to_s.size
|
466
|
-
Node.search_records($1.gsub('-',' '), :offset => offset, :limit => 1).first
|
467
470
|
elsif path = str[/\A\(([^\)]+)\)\Z/,1]
|
468
471
|
if path[0..0] == '/'
|
469
472
|
path = path[1..-1].split('/').map {|p| String.from_filename(p) }
|
@@ -495,6 +498,9 @@ class Node < ActiveRecord::Base
|
|
495
498
|
# FIXME: path pseudo is needed for links... and it should be done here (egg and hen problem)
|
496
499
|
nil
|
497
500
|
end
|
501
|
+
elsif str =~ /\A:?([^\+]+)(\+*)\Z/
|
502
|
+
offset = $2.to_s.size
|
503
|
+
Node.search_records($1.gsub('-',' '), :offset => offset, :limit => 1).first
|
498
504
|
end
|
499
505
|
end
|
500
506
|
|
@@ -601,6 +607,7 @@ class Node < ActiveRecord::Base
|
|
601
607
|
parent_id = opts[:parent_id] || opts[:parent][:id]
|
602
608
|
folder = opts[:folder]
|
603
609
|
defaults = (opts[:defaults] || {}).stringify_keys
|
610
|
+
# Initial object class
|
604
611
|
klass = opts[:class] || opts[:klass] || "Page"
|
605
612
|
res = {}
|
606
613
|
|
@@ -652,6 +659,15 @@ class Node < ActiveRecord::Base
|
|
652
659
|
attrs['v_lang'] = lang || attrs['v_lang'] || visitor.lang
|
653
660
|
attrs['ext'] = $3
|
654
661
|
document_path = path
|
662
|
+
else
|
663
|
+
# Document without extension
|
664
|
+
type = :document
|
665
|
+
title = filename
|
666
|
+
attrs = defaults.dup
|
667
|
+
lang = nil
|
668
|
+
attrs['v_lang'] = lang || attrs['v_lang'] || visitor.lang
|
669
|
+
attrs['ext'] = 'bin'
|
670
|
+
document_path = path
|
655
671
|
end
|
656
672
|
|
657
673
|
index += 1
|
@@ -839,6 +855,9 @@ class Node < ActiveRecord::Base
|
|
839
855
|
res["#{key}_id"] = Group.translate_pseudo_id(value, :id) || value
|
840
856
|
elsif %w{user_id}.include?(key)
|
841
857
|
res[key] = User.translate_pseudo_id(value, :id) || value
|
858
|
+
elsif %w{link_id}.include?(key)
|
859
|
+
# Link id, not translated
|
860
|
+
res[key] = value
|
842
861
|
elsif %w{id create_at updated_at}.include?(key)
|
843
862
|
# ignore (can be present in xml)
|
844
863
|
elsif %w{log_at event_at v_publish_from}.include?(key) || (is_link && %w{date}.include?(key))
|
@@ -890,6 +909,7 @@ class Node < ActiveRecord::Base
|
|
890
909
|
RubyLess::SafeClass.safe_method_type_for(self, signature)
|
891
910
|
else
|
892
911
|
method = signature.first
|
912
|
+
|
893
913
|
if type = super
|
894
914
|
type
|
895
915
|
elsif method == 'cached_role_ids'
|
@@ -898,13 +918,6 @@ class Node < ActiveRecord::Base
|
|
898
918
|
elsif method =~ /^(.+)_((id|zip|status|comment)(s?))\Z/ && !instance_methods.include?(method)
|
899
919
|
key = $3 == 'id' ? "zip#{$4}" : $2
|
900
920
|
{:method => "rel[#{$1.inspect}].try(:other_#{key})", :nil => true, :class => ($4.blank? ? Number : [Number])}
|
901
|
-
elsif receiver && query = receiver.opts[:query]
|
902
|
-
# Resolve by using information in the SELECT part of the query that found this node
|
903
|
-
if query.select_keys.include?(method)
|
904
|
-
{:class => String, :method => "attributes[#{method.inspect}]", :nil => true}
|
905
|
-
else
|
906
|
-
nil
|
907
|
-
end
|
908
921
|
else
|
909
922
|
nil
|
910
923
|
end
|
@@ -978,9 +991,7 @@ class Node < ActiveRecord::Base
|
|
978
991
|
|
979
992
|
# include virtual classes to check inheritance chain
|
980
993
|
def vkind_of?(klass)
|
981
|
-
if
|
982
|
-
true
|
983
|
-
elsif virt = VirtualClass.find(:first, :conditions=>["site_id = ? AND name = ?",current_site[:id], klass])
|
994
|
+
if virt = VirtualClass[klass.to_s]
|
984
995
|
kpath_match?(virt.kpath)
|
985
996
|
end
|
986
997
|
end
|
@@ -1606,6 +1617,7 @@ class Node < ActiveRecord::Base
|
|
1606
1617
|
errors.add(:base, 'You do not have the rights to post comments.') if @add_comment && !can_comment?
|
1607
1618
|
|
1608
1619
|
if @new_klass
|
1620
|
+
# If you change this, update 'change_klass' (triggered before_validation)
|
1609
1621
|
if !can_drive? || !self[:parent_id]
|
1610
1622
|
errors.add('klass', 'You do not have the rights to change class.')
|
1611
1623
|
else
|
@@ -1726,17 +1738,28 @@ class Node < ActiveRecord::Base
|
|
1726
1738
|
end
|
1727
1739
|
|
1728
1740
|
def change_klass
|
1741
|
+
if @new_klass
|
1742
|
+
if !can_drive? || !self[:parent_id]
|
1743
|
+
return
|
1744
|
+
elsif !self.class.allowed_change_to_classes.include?(@new_klass)
|
1745
|
+
return
|
1746
|
+
end
|
1747
|
+
end
|
1748
|
+
|
1729
1749
|
if @new_klass && !new_record?
|
1730
1750
|
old_kpath = self.kpath
|
1731
|
-
#
|
1751
|
+
# Reset 'schema' and 'virtual_class'
|
1752
|
+
@virtual_class = nil
|
1753
|
+
|
1732
1754
|
klass = Node.get_class(@new_klass)
|
1733
1755
|
if klass.kind_of?(VirtualClass)
|
1734
|
-
self[:vclass_id] = klass
|
1756
|
+
self[:vclass_id] = klass[:id]
|
1735
1757
|
self[:type] = klass.real_class.to_s
|
1736
1758
|
else
|
1737
|
-
self[:vclass_id] =
|
1759
|
+
self[:vclass_id] = nil
|
1738
1760
|
self[:type] = klass.to_s
|
1739
1761
|
end
|
1762
|
+
|
1740
1763
|
self[:kpath] = klass.kpath
|
1741
1764
|
|
1742
1765
|
if old_kpath[/^NPS/] && !self[:kpath][/^NPS/]
|
data/app/models/relation.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
class Relation < ActiveRecord::Base
|
2
|
+
EXPORT_FIELDS = %w{target_kpath target_icon target_unique source_role source_icon source_unique rel_group}
|
3
|
+
|
2
4
|
before_validation :singularize_roles
|
3
5
|
validate :valid_relation
|
4
6
|
attr_accessor :side, :link_errors, :start, :link
|
@@ -16,6 +18,17 @@ class Relation < ActiveRecord::Base
|
|
16
18
|
target_unique ? self[:target_role] : self[:target_role].pluralize
|
17
19
|
end
|
18
20
|
|
21
|
+
def export
|
22
|
+
res = Zafu::OrderedHash.new
|
23
|
+
EXPORT_FIELDS.each do |key|
|
24
|
+
value = self[key]
|
25
|
+
if !value.blank?
|
26
|
+
res[key] = value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
res
|
30
|
+
end
|
31
|
+
|
19
32
|
private
|
20
33
|
def singularize_roles
|
21
34
|
self.source_role = self[:source_role].singularize unless self[:source_role].blank?
|
@@ -268,6 +268,7 @@ class RelationProxy < Relation
|
|
268
268
|
elsif link_id = @start.link_id
|
269
269
|
@other_link = Link.find(link_id)
|
270
270
|
@attributes_to_update[:id] = @other_link[other_side]
|
271
|
+
@attributes_to_update[:link_id] = link_id
|
271
272
|
elsif unique?
|
272
273
|
if other_id
|
273
274
|
@attributes_to_update[:id] = other_id
|
@@ -309,7 +310,7 @@ class RelationProxy < Relation
|
|
309
310
|
# TODO: this could be optimzed (avoid loading all links...)
|
310
311
|
other_links.each do |link|
|
311
312
|
obj_id = link[other_side]
|
312
|
-
if add_link_ids.include?(obj_id) && (@attributes_to_update[:date].nil? || @attributes_to_update[:date] == link[:date])
|
313
|
+
if add_link_ids.include?(obj_id) && (@attributes_to_update[:date].nil? || @attributes_to_update[:link_id] || @attributes_to_update[:date] == link[:date])
|
313
314
|
# ignore existing link
|
314
315
|
add_link_ids.delete(obj_id)
|
315
316
|
else
|
@@ -337,7 +338,7 @@ class RelationProxy < Relation
|
|
337
338
|
# delete
|
338
339
|
@del_links = other_links.select {|l| @attributes_to_update[:date] == l[:date]}
|
339
340
|
else
|
340
|
-
links = other_links.select {|l| l[other_side] == @attributes_to_update[:id] && (@attributes_to_update[:date].nil? || @attributes_to_update[:date] == l[:date])}
|
341
|
+
links = other_links.select {|l| l[other_side] == @attributes_to_update[:id] && (@attributes_to_update[:date].nil? || @attributes_to_update[:link_id] || @attributes_to_update[:date] == l[:date])}
|
341
342
|
if links != []
|
342
343
|
# update
|
343
344
|
if (@attributes_to_update.keys & LINK_ATTRIBUTES) != []
|
data/app/models/role.rb
CHANGED
@@ -13,7 +13,7 @@ class Role < ActiveRecord::Base
|
|
13
13
|
has_and_belongs_to_many :nodes
|
14
14
|
|
15
15
|
before_validation :set_defaults
|
16
|
-
validate :
|
16
|
+
validate :validate_role
|
17
17
|
attr_accessible :name, :superclass, :icon
|
18
18
|
|
19
19
|
after_save :expire_vclass_cache
|
@@ -28,6 +28,144 @@ class Role < ActiveRecord::Base
|
|
28
28
|
# We use property to store index information, default values and such
|
29
29
|
include Property
|
30
30
|
|
31
|
+
property do |p|
|
32
|
+
p.string 'icon'
|
33
|
+
end
|
34
|
+
safe_property :icon
|
35
|
+
|
36
|
+
class << self
|
37
|
+
def export
|
38
|
+
{'Node' => VirtualClass['Node'].export}
|
39
|
+
end
|
40
|
+
|
41
|
+
def import(definitions, delete = false)
|
42
|
+
res = []
|
43
|
+
post_import = []
|
44
|
+
# Create everything in a transaction
|
45
|
+
transaction do
|
46
|
+
definitions.each do |name, definition|
|
47
|
+
klass = VirtualClass[name]
|
48
|
+
if !klass || !klass.real_class?
|
49
|
+
# Error, missing superclass
|
50
|
+
raise Exception.new("Importation needs to start with a real class: '#{name}' is not a real class.")
|
51
|
+
else
|
52
|
+
# start importing
|
53
|
+
res += import_all(klass, definition, post_import)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
post_import.each do |l|
|
58
|
+
l.call
|
59
|
+
end
|
60
|
+
end
|
61
|
+
res
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
def import_all(superclass, definitions, post_import)
|
66
|
+
res = []
|
67
|
+
definitions.each do |name, sub|
|
68
|
+
next unless name =~ /\A[A-Z]/
|
69
|
+
|
70
|
+
case sub['type']
|
71
|
+
when 'Class'
|
72
|
+
klass = VirtualClass[name]
|
73
|
+
if klass && klass.real_class?
|
74
|
+
res += import_all(klass, sub, post_import)
|
75
|
+
else
|
76
|
+
raise Exception.new("Unknown real class '#{name}'.")
|
77
|
+
end
|
78
|
+
when 'Role'
|
79
|
+
res << import_role(superclass, name, sub)
|
80
|
+
when 'VirtualClass'
|
81
|
+
# VirtualClass
|
82
|
+
res += import_vclass(superclass, name, sub, post_import)
|
83
|
+
when nil
|
84
|
+
klass = VirtualClass[name]
|
85
|
+
if klass && klass.real_class?
|
86
|
+
res += import_all(klass, sub, post_import)
|
87
|
+
else
|
88
|
+
res += import_vclass(superclass, name, sub, post_import)
|
89
|
+
end
|
90
|
+
else
|
91
|
+
# Invalid type
|
92
|
+
raise Exception.new("Cannot create '#{name}': invalid type '#{sub['type']}'.")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
res
|
96
|
+
end
|
97
|
+
|
98
|
+
def import_role(superclass, name, definition)
|
99
|
+
role = ::Role.find_by_name_and_site_id(name, current_site.id)
|
100
|
+
if role && role.class != ::Role
|
101
|
+
# Change from vclass to role ?
|
102
|
+
# Reject
|
103
|
+
raise Exception.new("Cannot convert VirtualClass '#{name}' to Role.")
|
104
|
+
elsif !role
|
105
|
+
role = ::Role.new(:name => name, :superclass => superclass)
|
106
|
+
role.save!
|
107
|
+
end
|
108
|
+
|
109
|
+
# 1. create or update attributes
|
110
|
+
# noop
|
111
|
+
|
112
|
+
# 2. create or update columns (never delete)
|
113
|
+
if !role.new_record? && columns = definition['columns']
|
114
|
+
role.import_columns(columns)
|
115
|
+
end
|
116
|
+
role
|
117
|
+
end
|
118
|
+
|
119
|
+
def import_vclass(superclass, name, definition, post_import)
|
120
|
+
res = []
|
121
|
+
vclass = ::Role.find_by_name_and_site_id(name, current_site.id)
|
122
|
+
if vclass && vclass.class != VirtualClass
|
123
|
+
# Change from role to vclass ?
|
124
|
+
# Reject
|
125
|
+
raise Exception.new("Cannot convert Role '#{name}' to VirtualClass.")
|
126
|
+
elsif !vclass
|
127
|
+
vclass = VirtualClass.new(:name => name, :superclass => superclass)
|
128
|
+
end
|
129
|
+
|
130
|
+
# 1. create or update attributes
|
131
|
+
VirtualClass.export_attributes.each do |key|
|
132
|
+
if value = definition[key]
|
133
|
+
vclass.send(:"#{key}=", value)
|
134
|
+
else
|
135
|
+
# We do not clear attributes (import is ADD/UPDATE only).
|
136
|
+
end
|
137
|
+
end
|
138
|
+
vclass.save!
|
139
|
+
res << vclass
|
140
|
+
|
141
|
+
# 2. create or update columns (never delete)
|
142
|
+
if columns = definition['columns']
|
143
|
+
vclass.import_columns(columns)
|
144
|
+
end
|
145
|
+
|
146
|
+
# 3. create relations when all is done
|
147
|
+
if relations = definition['relations']
|
148
|
+
post_import << lambda do
|
149
|
+
vclass.import_relations(relations)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# 4. create or update sub-classes
|
154
|
+
res += import_all(vclass, definition, post_import)
|
155
|
+
res
|
156
|
+
end
|
157
|
+
end # class << self
|
158
|
+
|
159
|
+
def real_class?
|
160
|
+
false
|
161
|
+
end
|
162
|
+
|
163
|
+
def icon=(txt)
|
164
|
+
# FIXME: remove gsub when we stop using ImageBuilder on
|
165
|
+
# icon images. SECURITY
|
166
|
+
super(txt.gsub('..', '.'))
|
167
|
+
end
|
168
|
+
|
31
169
|
def superclass
|
32
170
|
if new_record?
|
33
171
|
Node
|
@@ -37,8 +175,8 @@ class Role < ActiveRecord::Base
|
|
37
175
|
end
|
38
176
|
|
39
177
|
def superclass=(klass)
|
40
|
-
if
|
41
|
-
|
178
|
+
if klass.kind_of?(VirtualClass) || klass = VirtualClass[klass]
|
179
|
+
@superclass = klass
|
42
180
|
else
|
43
181
|
errors.add('superclass', 'invalid')
|
44
182
|
end
|
@@ -49,17 +187,88 @@ class Role < ActiveRecord::Base
|
|
49
187
|
@safe_column ||= defined_columns.values.sort {|a,b| a.name <=> b.name}
|
50
188
|
end
|
51
189
|
|
190
|
+
def export
|
191
|
+
res = Zafu::OrderedHash.new
|
192
|
+
res['type'] = real_class? ? 'Class' : type
|
193
|
+
if !defined_columns.empty?
|
194
|
+
res['columns'] = export_columns
|
195
|
+
end
|
196
|
+
res
|
197
|
+
end
|
198
|
+
|
199
|
+
def import_columns(columns)
|
200
|
+
transaction do
|
201
|
+
columns.each do |name, definition|
|
202
|
+
column = secure(::Column) { ::Column.find_by_name(name) }
|
203
|
+
if !column
|
204
|
+
# create
|
205
|
+
column = ::Column.new(:name => name)
|
206
|
+
elsif column.role_id != self.id
|
207
|
+
# error (do not move a column)
|
208
|
+
raise Exception.new("Cannot set property '#{name}' in '#{self.name}': already defined in '#{column.role.name}'.")
|
209
|
+
end
|
210
|
+
column.role_id = self.id
|
211
|
+
column.ptype = definition['ptype']
|
212
|
+
column.index = definition['index']
|
213
|
+
column.save!
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def import_relations(relations)
|
219
|
+
relations.each do |name, definition|
|
220
|
+
relation = secure(::Relation) { ::Relation.first(
|
221
|
+
:conditions => ['target_role = ? AND source_kpath = ? AND site_id = ?',
|
222
|
+
name, self.kpath, self.site_id
|
223
|
+
]
|
224
|
+
)}
|
225
|
+
if !relation
|
226
|
+
# create
|
227
|
+
relation = ::Relation.new(:target_role => name, :source_kpath => self.kpath)
|
228
|
+
end
|
229
|
+
Relation::EXPORT_FIELDS.each do |key|
|
230
|
+
value = definition[key]
|
231
|
+
if !value.blank?
|
232
|
+
relation[key] = value
|
233
|
+
end
|
234
|
+
end
|
235
|
+
relation.save!
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
52
239
|
private
|
53
240
|
def set_defaults
|
54
241
|
self[:type] = self.class.to_s
|
55
242
|
self.site_id = visitor.site.id
|
56
243
|
end
|
57
244
|
|
58
|
-
def
|
245
|
+
def validate_role
|
59
246
|
errors.add('base', 'You do not have the rights to change roles.') unless visitor.is_admin?
|
247
|
+
if new_record?
|
248
|
+
errors.add('superclass', 'invalid') unless @superclass.kind_of?(VirtualClass) && @superclass.kpath
|
249
|
+
end
|
250
|
+
|
251
|
+
if @superclass && self.class == ::Role
|
252
|
+
self.kpath = @superclass.kpath
|
253
|
+
end
|
60
254
|
end
|
61
255
|
|
62
256
|
def expire_vclass_cache
|
63
257
|
VirtualClass.expire_cache!
|
64
258
|
end
|
259
|
+
|
260
|
+
def export_columns
|
261
|
+
res = Zafu::OrderedHash.new
|
262
|
+
|
263
|
+
defined_columns.keys.sort.each do |name|
|
264
|
+
column = defined_columns[name]
|
265
|
+
col = Zafu::OrderedHash.new
|
266
|
+
col['ptype'] = column.ptype.to_s
|
267
|
+
if column.index then
|
268
|
+
col['index'] = column.index
|
269
|
+
end
|
270
|
+
res[name] = col
|
271
|
+
end
|
272
|
+
res
|
273
|
+
end
|
65
274
|
end
|