zena 1.2.3 → 1.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +29 -1
- data/Rakefile +0 -1
- data/app/controllers/documents_controller.rb +1 -1
- data/app/controllers/nodes_controller.rb +34 -8
- data/app/controllers/sites_controller.rb +8 -1
- data/app/controllers/user_sessions_controller.rb +13 -3
- data/app/models/acl.rb +16 -0
- data/app/models/document.rb +33 -14
- data/app/models/idx_nodes_integer.rb +5 -0
- data/app/models/image.rb +16 -4
- data/app/models/node.rb +16 -3
- data/app/models/relation_proxy.rb +3 -3
- data/app/models/site.rb +11 -1
- data/app/models/string_hash.rb +1 -1
- data/app/models/template.rb +1 -1
- data/app/models/user.rb +6 -1
- data/app/models/virtual_class.rb +36 -1
- data/app/views/acls/_form.rhtml +5 -1
- data/app/views/acls/_li.rhtml +1 -1
- data/app/views/templates/document_create_tabs/_file.rhtml +1 -0
- data/app/views/templates/document_create_tabs/_template.rhtml +1 -1
- data/app/views/users/_form.rhtml +1 -0
- data/app/views/virtual_classes/_form.erb +8 -7
- data/bricks/acls/lib/bricks/acls.rb +43 -15
- data/bricks/acls/zena/migrate/20130313110443_add_create_kpath_to_acl.rb +13 -0
- data/bricks/acls/zena/migrate/20130429073432_fix_create_kpath_default.rb +8 -0
- data/bricks/acls/zena/test/integration/acl_integration_test.rb +53 -1
- data/bricks/acls/zena/test/sites/erebus/acls.yml +21 -0
- data/bricks/acls/zena/test/unit/acl_test.rb +35 -2
- data/bricks/math/lib/bricks/math.rb +1 -1
- data/bricks/sphinx/zena/tasks.rb +1 -1
- data/bricks/spreadsheet/lib/bricks/spreadsheet.rb +1 -1
- data/bricks/worker/zena/worker +25 -0
- data/config/environment.rb +1 -1
- data/config/environments/production.rb +1 -1
- data/config/gems.yml +6 -5
- data/lib/bricks/requirements_validation.rb +1 -1
- data/lib/log_recorder/lib/log_recorder.rb +1 -1
- data/lib/tasks/zena.rake +10 -2
- data/lib/zena.rb +4 -3
- data/lib/zena/app.rb +1 -0
- data/lib/zena/deploy/httpd.rhtml +2 -2
- data/lib/zena/deploy/template.rb +15 -5
- data/lib/zena/info.rb +1 -1
- data/lib/zena/parser/zazen_rules.rb +9 -2
- data/lib/zena/remote/connection.rb +2 -2
- data/lib/zena/remote/interface.rb +8 -2
- data/lib/zena/remote/node.rb +1 -1
- data/lib/zena/routes.rb +2 -1
- data/lib/zena/use/action.rb +8 -2
- data/lib/zena/use/ajax.rb +31 -20
- data/lib/zena/use/calendar.rb +2 -0
- data/lib/zena/use/conditional.rb +15 -14
- data/lib/zena/use/dates.rb +5 -2
- data/lib/zena/use/display.rb +3 -2
- data/lib/zena/use/forms.rb +36 -9
- data/lib/zena/use/i18n.rb +8 -2
- data/lib/zena/use/image_builder.rb +7 -0
- data/lib/zena/use/query_node.rb +24 -8
- data/lib/zena/use/relations.rb +2 -6
- data/lib/zena/use/rendering.rb +10 -6
- data/lib/zena/use/upload.rb +6 -4
- data/lib/zena/use/urls.rb +13 -5
- data/lib/zena/use/zafu_safe_definitions.rb +1 -1
- data/public/javascripts/grid.js +11 -2
- data/public/javascripts/upload-progress.js +5 -3
- data/public/javascripts/zena.js +6 -2
- data/public/stylesheets/upload-progress.css +1 -0
- data/test/fixtures/files/TestNode.zafu +2 -2
- data/test/fixtures/files/translations_fr.yml +2 -1
- data/test/functional/acls_controller_test.rb +6 -0
- data/test/functional/nodes_controller_test.rb +1 -1
- data/test/functional/sites_controller_test.rb +19 -0
- data/test/integration/navigation_test.rb +7 -0
- data/test/integration/query_node/filters.yml +10 -0
- data/test/integration/zafu_compiler/action.yml +8 -4
- data/test/integration/zafu_compiler/ajax.yml +4 -4
- data/test/integration/zafu_compiler/calendar.yml +8 -15
- data/test/integration/zafu_compiler/context.yml +1 -1
- data/test/integration/zafu_compiler/dates.yml +5 -1
- data/test/integration/zafu_compiler/display.yml +1 -2
- data/test/integration/zafu_compiler/forms.yml +37 -10
- data/test/integration/zafu_compiler/query.yml +5 -5
- data/test/integration/zafu_compiler/relations.yml +8 -8
- data/test/integration/zafu_compiler/safe_definitions.yml +7 -2
- data/test/integration/zafu_compiler/urls.yml +24 -3
- data/test/integration/zafu_compiler/zazen.yml +9 -1
- data/test/selenium/Destroy/destroy1.rsel +2 -1
- data/test/selenium/Destroy/destroy2.rsel +17 -0
- data/test/unit/document_test.rb +17 -4
- data/test/unit/relation_proxy_test.rb +19 -8
- data/test/unit/string_hash_test.rb +1 -1
- data/test/unit/template_test.rb +3 -3
- data/test/unit/virtual_class_test.rb +77 -0
- data/test/unit/zena/use/urls_test.rb +9 -1
- data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails_config.rb +1 -1
- data/zena.gemspec +60 -53
- metadata +145 -125
data/History.txt
CHANGED
@@ -1,8 +1,36 @@
|
|
1
|
+
== 1.2.4 2013-06-13
|
2
|
+
|
3
|
+
* Major changes
|
4
|
+
* Added class filtering to Acl in 'create' action. <== TODO: Document
|
5
|
+
* Uploading html files does not transform them into zafu (use .zafu ext for this)
|
6
|
+
* Added file upload support from zena remote API.
|
7
|
+
* Added 'content_type' regexp to force virtual class on Document creation. <== TODO: Document
|
8
|
+
* Extended "create group" in vclass to be "allow group" (edit).
|
9
|
+
* Added support for [versions_list] to display list of versions and status.
|
10
|
+
|
11
|
+
* Minor changes
|
12
|
+
* Support for raw html in zazen with '<notextile>' or '<html>' tag. Must be allowed with notextile='true' on [zazen] tag.
|
13
|
+
* Fixed preview of content with ACL (considering the POST on /zafu as a 'read').
|
14
|
+
* Added support for "class not like Image" or "class <> Image" to sqliss.
|
15
|
+
* Added url to clear cache with /sites/clear_cache (admin only). <== TODO: Document
|
16
|
+
* encode_params now supports arrays.
|
17
|
+
* Add 'id' to date input.
|
18
|
+
* Fixed 404 error.
|
19
|
+
* Toggle takes dynamic parameters for "js" and "arity".
|
20
|
+
* Fixed multiple toggles side-by-side.
|
21
|
+
* Fixed nested blocks and class scoping.
|
22
|
+
* Added support for "onUpdate" in [input] with date type.
|
23
|
+
* Hash 'keys' returns sorted elements in zafu.
|
24
|
+
* Improved computation of width and height in [img] when using 'forced' iformat.
|
25
|
+
* Image width and height properties auto-fix themselves (need to read file on each display if not fixed).
|
26
|
+
* Added support for 'mode' in encode_params.
|
27
|
+
* Fixed [link_name]_status, _comment and other relation proxy methods.
|
28
|
+
|
1
29
|
== 1.2.3 2013-03-11
|
2
30
|
|
3
31
|
* Major changes
|
4
32
|
* Better support for Passenger (deploy receipt, asset host)
|
5
|
-
* Support for 'sortable'
|
33
|
+
* Support for 'sortable'
|
6
34
|
* html_escape all properties by default
|
7
35
|
* Better support for Passenger (default deployment method now)
|
8
36
|
* Simplified caching (using cachestamp in filename)
|
data/Rakefile
CHANGED
@@ -13,7 +13,7 @@ class DocumentsController < ApplicationController
|
|
13
13
|
def new
|
14
14
|
# Use the Template class so that we can use the same object in forms which need the Template properties.
|
15
15
|
@node = @parent.new_child(:class => Template)
|
16
|
-
|
16
|
+
|
17
17
|
respond_to do |format|
|
18
18
|
format.html
|
19
19
|
end
|
@@ -23,7 +23,7 @@ class NodesController < ApplicationController
|
|
23
23
|
if Bricks.raw_config['passenger']
|
24
24
|
before_filter :escape_path, :only => [:index, :show]
|
25
25
|
end
|
26
|
-
before_filter :find_node, :except => [:index, :create, :not_found, :catch_all, :search]
|
26
|
+
before_filter :find_node, :except => [:index, :create, :update, :zafu, :not_found, :catch_all, :search]
|
27
27
|
before_filter :check_can_drive, :only => [:edit]
|
28
28
|
before_filter :check_path, :only => [:index, :show]
|
29
29
|
|
@@ -113,10 +113,23 @@ class NodesController < ApplicationController
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
-
# RJS method.
|
117
|
-
# FIXME: remove.
|
116
|
+
# RJS method. Enables using POST in JS for large text preview. Seen as 'read' in ACL.
|
118
117
|
def zafu
|
119
|
-
|
118
|
+
# We allow preview by using POST requests (long text in js) but they should appear as 'GET' in
|
119
|
+
# find_node.
|
120
|
+
request.method = 'GET' if request.method == 'POST'
|
121
|
+
|
122
|
+
@node = visitor.find_node(nil, params[:id], nil, request)
|
123
|
+
|
124
|
+
if params[:link_id]
|
125
|
+
@link = Link.find_through(@node, params[:link_id])
|
126
|
+
end
|
127
|
+
|
128
|
+
# security risk with ACL (change an object before display with extended rights). Must check no ACL before
|
129
|
+
# preview. Only enable with proper security if this is really needed.
|
130
|
+
# if params['node']
|
131
|
+
# @node.attributes = secure(Node) {Node.transform_attributes(params['node'], @node, true)}
|
132
|
+
# end
|
120
133
|
respond_to do |format|
|
121
134
|
format.js { render :action => 'show' }
|
122
135
|
end
|
@@ -225,12 +238,20 @@ class NodesController < ApplicationController
|
|
225
238
|
|
226
239
|
begin
|
227
240
|
# Make sure we can load parent (also enables ACL to work for us here).
|
228
|
-
|
241
|
+
zip = attrs.delete('parent_zip')
|
242
|
+
parent = visitor.find_node(nil, zip, nil, request, true)
|
243
|
+
|
229
244
|
@node = parent.new_child(attrs, false)
|
230
|
-
@node.
|
245
|
+
if visitor.exec_acl && !(@node.kpath =~ %r{^#{visitor.exec_acl.create_kpath}})
|
246
|
+
# Document creation can change initial klass depending on mime type. Make sure it is still allowed.
|
247
|
+
@node.errors.add('klass', 'Not allowed')
|
248
|
+
else
|
249
|
+
@node.save
|
250
|
+
end
|
231
251
|
rescue ActiveRecord::RecordNotFound
|
232
252
|
# Let normal processing insert errors
|
233
|
-
@node =
|
253
|
+
@node = Node.new
|
254
|
+
@node.errors.add('base', 'Not allowed')
|
234
255
|
end
|
235
256
|
@node.errors.add('file', file_error) if file_error
|
236
257
|
|
@@ -388,6 +409,12 @@ class NodesController < ApplicationController
|
|
388
409
|
end
|
389
410
|
|
390
411
|
def update
|
412
|
+
@node = visitor.find_node(nil, params[:id], nil, request, true)
|
413
|
+
|
414
|
+
if params[:link_id]
|
415
|
+
@link = Link.find_through(@node, params[:link_id])
|
416
|
+
end
|
417
|
+
|
391
418
|
params['node'] ||= {}
|
392
419
|
file, file_error = get_attachment
|
393
420
|
params['node']['file'] = file if file
|
@@ -612,7 +639,6 @@ class NodesController < ApplicationController
|
|
612
639
|
else
|
613
640
|
set_format(stamp_and_format)
|
614
641
|
end
|
615
|
-
|
616
642
|
# We use the visitor to find the node in order to ease implementation
|
617
643
|
# of custom access rules (Acl).
|
618
644
|
@node = visitor.find_node(path, zip, name, request)
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# TODO: Cleanup sites_controller now that we only support visitors for a single site !!
|
1
2
|
class SitesController < ApplicationController
|
2
3
|
before_filter :remove_methods, :only => [:new, :create, :destroy]
|
3
|
-
before_filter :find_site, :except => [:index, :create, :new]
|
4
|
+
before_filter :find_site, :except => [:index, :create, :new, :clear_cache]
|
4
5
|
before_filter :visitor_node
|
5
6
|
before_filter :check_is_admin
|
6
7
|
layout :admin_layout
|
@@ -51,6 +52,12 @@ class SitesController < ApplicationController
|
|
51
52
|
end
|
52
53
|
end
|
53
54
|
end
|
55
|
+
|
56
|
+
def clear_cache
|
57
|
+
@site = secure!(Site) { Site.first }
|
58
|
+
@site.clear_cache
|
59
|
+
redirect_to '/'
|
60
|
+
end
|
54
61
|
|
55
62
|
def action
|
56
63
|
if Site::ACTIONS.include?(params[:do])
|
@@ -3,7 +3,7 @@
|
|
3
3
|
Create, destroy sessions by letting users login and logout. When the user does not login, he/she is considered to be the anonymous user.
|
4
4
|
=end
|
5
5
|
class UserSessionsController < ApplicationController
|
6
|
-
skip_before_filter :
|
6
|
+
skip_before_filter :force_authentication?, :redirect_to_https
|
7
7
|
before_filter :session_redirect_to_https
|
8
8
|
|
9
9
|
# /login
|
@@ -28,15 +28,25 @@ class UserSessionsController < ApplicationController
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
# Logout
|
31
32
|
def destroy
|
32
33
|
port = request.port == 80 ? '' : ":#{request.port}"
|
33
34
|
if @user_session = UserSession.find
|
34
35
|
@user_session.destroy
|
35
36
|
reset_session
|
37
|
+
if current_site.ssl_on_auth
|
38
|
+
# SSH only when authenticated
|
39
|
+
host = current_site.host
|
40
|
+
http = 'http'
|
41
|
+
else
|
42
|
+
# Keep current host and port settings
|
43
|
+
host = host_with_port
|
44
|
+
http = host =~ /:/ ? 'https' : 'http'
|
45
|
+
end
|
36
46
|
#flash.now[:notice] = _("Successfully logged out.")
|
37
|
-
redirect_to "http://#{
|
47
|
+
redirect_to "#{http}://#{host}#{params[:redirect] || home_path(:prefix => prefix)}"
|
38
48
|
else
|
39
|
-
redirect_to "http://#{
|
49
|
+
redirect_to "http://#{host}#{home_path(:prefix => prefix)}"
|
40
50
|
end
|
41
51
|
end
|
42
52
|
|
data/app/models/acl.rb
CHANGED
@@ -49,6 +49,18 @@ class Acl < ActiveRecord::Base
|
|
49
49
|
def visitor
|
50
50
|
super
|
51
51
|
end
|
52
|
+
|
53
|
+
def create_vclass_name
|
54
|
+
if create_kpath
|
55
|
+
if klass = VirtualClass.find_by_kpath(create_kpath)
|
56
|
+
klass.name
|
57
|
+
else
|
58
|
+
create_kpath
|
59
|
+
end
|
60
|
+
else
|
61
|
+
'Node'
|
62
|
+
end
|
63
|
+
end
|
52
64
|
|
53
65
|
protected
|
54
66
|
def set_defaults
|
@@ -66,6 +78,10 @@ class Acl < ActiveRecord::Base
|
|
66
78
|
|
67
79
|
def validate_acl
|
68
80
|
make_query(visitor.prototype)
|
81
|
+
self[:create_kpath] = 'N' if self[:create_kpath].blank?
|
82
|
+
unless VirtualClass.find_by_kpath(create_kpath)
|
83
|
+
errors.add(:create_kpath, 'invalid (could not find class)')
|
84
|
+
end
|
69
85
|
end
|
70
86
|
|
71
87
|
def make_query(node, params = {}, request = nil)
|
data/app/models/document.rb
CHANGED
@@ -63,29 +63,34 @@ class Document < Node
|
|
63
63
|
def new(attrs = {}, vclass = nil)
|
64
64
|
attrs = attrs.stringify_keys
|
65
65
|
file = attrs['file'] || ((attrs['version_attributes'] || {})['content_attributes'] || {})['file']
|
66
|
-
|
67
|
-
|
68
|
-
elsif file && file.respond_to?(:content_type)
|
69
|
-
content_type = file.content_type
|
70
|
-
elsif ct = attrs['content_type']
|
66
|
+
|
67
|
+
if ct = attrs['content_type']
|
71
68
|
content_type = ct
|
69
|
+
elsif file && file.respond_to?(:content_type) && file.content_type != 'application/octet-stream'
|
70
|
+
content_type = file.content_type
|
72
71
|
elsif attrs['title'] =~ /^.*\.(\w+)$/ && types = Zena::EXT_TO_TYPE[$1.downcase]
|
73
72
|
content_type = types[0]
|
73
|
+
elsif file
|
74
|
+
content_type = 'application/octet-stream'
|
75
|
+
elsif attrs['target_klass'] || self <= Template
|
76
|
+
content_type = 'text/zafu'
|
77
|
+
else
|
78
|
+
content_type = 'text/plain'
|
74
79
|
end
|
75
80
|
|
76
|
-
|
81
|
+
klass = document_class_from_content_type(content_type)
|
82
|
+
real_class = klass.real_class
|
77
83
|
|
78
|
-
|
79
|
-
|
80
|
-
vclass = VirtualClass[real_class.to_s]
|
84
|
+
if vclass && vclass.kpath =~ /\A#{real_class.kpath}/ && vclass.content_type_re =~ content_type
|
85
|
+
klass = vclass
|
81
86
|
end
|
82
87
|
|
83
88
|
attrs['content_type'] = content_type
|
84
89
|
|
85
90
|
if real_class != self
|
86
|
-
secure(real_class) { real_class.o_new(attrs,
|
91
|
+
secure(real_class) { real_class.o_new(attrs, klass) }
|
87
92
|
else
|
88
|
-
super(attrs,
|
93
|
+
super(attrs, klass)
|
89
94
|
end
|
90
95
|
end
|
91
96
|
|
@@ -99,7 +104,7 @@ class Document < Node
|
|
99
104
|
|
100
105
|
# Return document class and content_type from content_type
|
101
106
|
def document_class_from_content_type(content_type)
|
102
|
-
if content_type
|
107
|
+
base = if content_type
|
103
108
|
if Image.accept_content_type?(content_type)
|
104
109
|
Image
|
105
110
|
elsif Template.accept_content_type?(content_type)
|
@@ -115,6 +120,18 @@ class Document < Node
|
|
115
120
|
else
|
116
121
|
self
|
117
122
|
end
|
123
|
+
|
124
|
+
# Try to find a virtual sub-class accepting the content type
|
125
|
+
vclass = nil
|
126
|
+
VirtualClass[base.to_s].sub_classes.each do |v|
|
127
|
+
next if v.real_class?
|
128
|
+
|
129
|
+
if content_type =~ v.content_type_re
|
130
|
+
vclass = v
|
131
|
+
break
|
132
|
+
end
|
133
|
+
end
|
134
|
+
vclass || VirtualClass[base.to_s]
|
118
135
|
end
|
119
136
|
|
120
137
|
# Return true if the content_type can change independantly from the file
|
@@ -156,7 +173,7 @@ class Document < Node
|
|
156
173
|
def filepath(format=nil)
|
157
174
|
version.attachment.filepath(format)
|
158
175
|
end
|
159
|
-
|
176
|
+
|
160
177
|
protected
|
161
178
|
def set_defaults
|
162
179
|
set_defaults_from_file
|
@@ -200,8 +217,10 @@ class Document < Node
|
|
200
217
|
end
|
201
218
|
|
202
219
|
klass = Document.document_class_from_content_type(content_type)
|
220
|
+
|
221
|
+
real_class = klass.real_class
|
203
222
|
|
204
|
-
if
|
223
|
+
if real_class != self.class
|
205
224
|
if @new_file
|
206
225
|
errors.add('file', 'incompatible with this class')
|
207
226
|
else
|
data/app/models/image.rb
CHANGED
@@ -82,8 +82,10 @@ class Image < Document
|
|
82
82
|
|
83
83
|
# Return the width in pixels for an image at the given format.
|
84
84
|
def width(format=nil)
|
85
|
-
if format.nil? || format
|
85
|
+
if format.nil? || format[:size] == :keep
|
86
86
|
prop['width']
|
87
|
+
elsif format[:size] == :force
|
88
|
+
format[:width]
|
87
89
|
else
|
88
90
|
if img = image_with_format(format)
|
89
91
|
img.width
|
@@ -95,8 +97,10 @@ class Image < Document
|
|
95
97
|
|
96
98
|
# Return the height in pixels for an image at the given format.
|
97
99
|
def height(format=nil)
|
98
|
-
if format.nil? || format
|
100
|
+
if format.nil? || format[:size] == :keep
|
99
101
|
prop['height']
|
102
|
+
elsif format[:size] == :force
|
103
|
+
format[:height]
|
100
104
|
else
|
101
105
|
if img = image_with_format(format)
|
102
106
|
img.height
|
@@ -147,7 +151,7 @@ class Image < Document
|
|
147
151
|
|
148
152
|
# Return a file with the data for the given format. It is the receiver's responsability to close the file.
|
149
153
|
def file(format=nil)
|
150
|
-
if format.nil? || format
|
154
|
+
if format.nil? || format[:size] == :keep
|
151
155
|
super()
|
152
156
|
else
|
153
157
|
if File.exist?(self.filepath(format)) || make_image(format)
|
@@ -199,6 +203,14 @@ class Image < Document
|
|
199
203
|
fname = "#{filename}.#{Zena::TYPE_TO_EXT[ctype][0]}"
|
200
204
|
uploaded_file(file, filename, ctype)
|
201
205
|
end
|
206
|
+
|
207
|
+
# This is called if the image's width and/or height is nil and image builder could
|
208
|
+
# compute the size.
|
209
|
+
def fix_sizes(w, h)
|
210
|
+
prop['width'] = w
|
211
|
+
prop['height'] = h
|
212
|
+
Zena::Db.set_attribute(version, 'properties', encode_properties(@properties))
|
213
|
+
end
|
202
214
|
|
203
215
|
private
|
204
216
|
|
@@ -234,7 +246,7 @@ class Image < Document
|
|
234
246
|
format ||= Iformat['full']
|
235
247
|
@formats ||= {}
|
236
248
|
@formats[format[:name]] ||= Zena::Use::ImageBuilder.new(:path => filepath,
|
237
|
-
:width => prop['width'], :height => prop['height']).transform!(format)
|
249
|
+
:width => prop['width'], :height => prop['height'], :node => self).transform!(format)
|
238
250
|
else
|
239
251
|
raise StandardError, "No image to work on"
|
240
252
|
end
|
data/app/models/node.rb
CHANGED
@@ -619,7 +619,9 @@ class Node < ActiveRecord::Base
|
|
619
619
|
def new_node(new_attributes, transform = true)
|
620
620
|
attributes = transform ? transform_attributes(new_attributes) : new_attributes
|
621
621
|
|
622
|
-
klass_name = attributes.delete('class') || attributes.delete('klass')
|
622
|
+
klass_name = attributes.delete('class') || attributes.delete('klass')
|
623
|
+
klass_name ||= attributes['file'] ? 'Document' : 'Page'
|
624
|
+
|
623
625
|
if klass_name.kind_of?(VirtualClass) || klass_name.kind_of?(Class)
|
624
626
|
klass = klass_name
|
625
627
|
else
|
@@ -633,6 +635,10 @@ class Node < ActiveRecord::Base
|
|
633
635
|
return node
|
634
636
|
end
|
635
637
|
end
|
638
|
+
|
639
|
+
if attributes['file'] && !(klass.kpath =~ %r{^ND})
|
640
|
+
klass = VirtualClass['Document']
|
641
|
+
end
|
636
642
|
|
637
643
|
if klass.kind_of?(VirtualClass)
|
638
644
|
node = secure(klass.real_class) { klass.new_instance(attributes) }
|
@@ -766,6 +772,7 @@ class Node < ActiveRecord::Base
|
|
766
772
|
if ['html','xhtml'].include?(attrs['ext']) && attrs['title'] == 'index'
|
767
773
|
attrs['ext'] = 'zafu'
|
768
774
|
attrs['title'] = 'Node'
|
775
|
+
attrs['content_type'] = 'text/zafu'
|
769
776
|
insert_zafu_headings = true
|
770
777
|
elsif attrs['ext'] == 'yml' && attrs['title'] == '_roles'
|
771
778
|
# import roles
|
@@ -908,7 +915,7 @@ class Node < ActiveRecord::Base
|
|
908
915
|
end
|
909
916
|
|
910
917
|
if !res['parent_id'] && p = attributes['parent_id']
|
911
|
-
res['parent_zip'] = p
|
918
|
+
res['parent_zip'] = p unless p.blank?
|
912
919
|
end
|
913
920
|
|
914
921
|
attributes.each do |key, value|
|
@@ -942,7 +949,7 @@ class Node < ActiveRecord::Base
|
|
942
949
|
elsif key =~ /^(\w+)_id$/
|
943
950
|
res["#{$1}_zip"] = value
|
944
951
|
elsif key =~ /^(\w+)_ids$/
|
945
|
-
res["#{$1}_zips"] = value.kind_of?(Array) ? value : value.split(',')
|
952
|
+
res["#{$1}_zips"] = value.kind_of?(Array) ? value : value.split(',').map(&:strip)
|
946
953
|
elsif key == 'v_status' || key == 'file'
|
947
954
|
res[key] = value unless value.blank?
|
948
955
|
elsif value.kind_of?(Hash)
|
@@ -1684,6 +1691,10 @@ class Node < ActiveRecord::Base
|
|
1684
1691
|
errors.add('klass', 'invalid') if !self.class.allowed_change_to_classes.include?(@new_klass)
|
1685
1692
|
end
|
1686
1693
|
end
|
1694
|
+
|
1695
|
+
if vclass.create_group_id
|
1696
|
+
errors.add('klass', 'unauthorized') if !visitor.group_ids.include?(vclass.create_group_id)
|
1697
|
+
end
|
1687
1698
|
end
|
1688
1699
|
|
1689
1700
|
# Called before destroy. An node must be empty to be destroyed
|
@@ -1811,8 +1822,10 @@ class Node < ActiveRecord::Base
|
|
1811
1822
|
def change_klass
|
1812
1823
|
if @new_klass
|
1813
1824
|
if !can_drive? || !self[:parent_id]
|
1825
|
+
# not allowed
|
1814
1826
|
return
|
1815
1827
|
elsif !self.class.allowed_change_to_classes.include?(@new_klass)
|
1828
|
+
# invalid class (unknown or visitor does have access)
|
1816
1829
|
return
|
1817
1830
|
end
|
1818
1831
|
end
|