zena 1.2.3 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/History.txt +29 -1
  2. data/Rakefile +0 -1
  3. data/app/controllers/documents_controller.rb +1 -1
  4. data/app/controllers/nodes_controller.rb +34 -8
  5. data/app/controllers/sites_controller.rb +8 -1
  6. data/app/controllers/user_sessions_controller.rb +13 -3
  7. data/app/models/acl.rb +16 -0
  8. data/app/models/document.rb +33 -14
  9. data/app/models/idx_nodes_integer.rb +5 -0
  10. data/app/models/image.rb +16 -4
  11. data/app/models/node.rb +16 -3
  12. data/app/models/relation_proxy.rb +3 -3
  13. data/app/models/site.rb +11 -1
  14. data/app/models/string_hash.rb +1 -1
  15. data/app/models/template.rb +1 -1
  16. data/app/models/user.rb +6 -1
  17. data/app/models/virtual_class.rb +36 -1
  18. data/app/views/acls/_form.rhtml +5 -1
  19. data/app/views/acls/_li.rhtml +1 -1
  20. data/app/views/templates/document_create_tabs/_file.rhtml +1 -0
  21. data/app/views/templates/document_create_tabs/_template.rhtml +1 -1
  22. data/app/views/users/_form.rhtml +1 -0
  23. data/app/views/virtual_classes/_form.erb +8 -7
  24. data/bricks/acls/lib/bricks/acls.rb +43 -15
  25. data/bricks/acls/zena/migrate/20130313110443_add_create_kpath_to_acl.rb +13 -0
  26. data/bricks/acls/zena/migrate/20130429073432_fix_create_kpath_default.rb +8 -0
  27. data/bricks/acls/zena/test/integration/acl_integration_test.rb +53 -1
  28. data/bricks/acls/zena/test/sites/erebus/acls.yml +21 -0
  29. data/bricks/acls/zena/test/unit/acl_test.rb +35 -2
  30. data/bricks/math/lib/bricks/math.rb +1 -1
  31. data/bricks/sphinx/zena/tasks.rb +1 -1
  32. data/bricks/spreadsheet/lib/bricks/spreadsheet.rb +1 -1
  33. data/bricks/worker/zena/worker +25 -0
  34. data/config/environment.rb +1 -1
  35. data/config/environments/production.rb +1 -1
  36. data/config/gems.yml +6 -5
  37. data/lib/bricks/requirements_validation.rb +1 -1
  38. data/lib/log_recorder/lib/log_recorder.rb +1 -1
  39. data/lib/tasks/zena.rake +10 -2
  40. data/lib/zena.rb +4 -3
  41. data/lib/zena/app.rb +1 -0
  42. data/lib/zena/deploy/httpd.rhtml +2 -2
  43. data/lib/zena/deploy/template.rb +15 -5
  44. data/lib/zena/info.rb +1 -1
  45. data/lib/zena/parser/zazen_rules.rb +9 -2
  46. data/lib/zena/remote/connection.rb +2 -2
  47. data/lib/zena/remote/interface.rb +8 -2
  48. data/lib/zena/remote/node.rb +1 -1
  49. data/lib/zena/routes.rb +2 -1
  50. data/lib/zena/use/action.rb +8 -2
  51. data/lib/zena/use/ajax.rb +31 -20
  52. data/lib/zena/use/calendar.rb +2 -0
  53. data/lib/zena/use/conditional.rb +15 -14
  54. data/lib/zena/use/dates.rb +5 -2
  55. data/lib/zena/use/display.rb +3 -2
  56. data/lib/zena/use/forms.rb +36 -9
  57. data/lib/zena/use/i18n.rb +8 -2
  58. data/lib/zena/use/image_builder.rb +7 -0
  59. data/lib/zena/use/query_node.rb +24 -8
  60. data/lib/zena/use/relations.rb +2 -6
  61. data/lib/zena/use/rendering.rb +10 -6
  62. data/lib/zena/use/upload.rb +6 -4
  63. data/lib/zena/use/urls.rb +13 -5
  64. data/lib/zena/use/zafu_safe_definitions.rb +1 -1
  65. data/public/javascripts/grid.js +11 -2
  66. data/public/javascripts/upload-progress.js +5 -3
  67. data/public/javascripts/zena.js +6 -2
  68. data/public/stylesheets/upload-progress.css +1 -0
  69. data/test/fixtures/files/TestNode.zafu +2 -2
  70. data/test/fixtures/files/translations_fr.yml +2 -1
  71. data/test/functional/acls_controller_test.rb +6 -0
  72. data/test/functional/nodes_controller_test.rb +1 -1
  73. data/test/functional/sites_controller_test.rb +19 -0
  74. data/test/integration/navigation_test.rb +7 -0
  75. data/test/integration/query_node/filters.yml +10 -0
  76. data/test/integration/zafu_compiler/action.yml +8 -4
  77. data/test/integration/zafu_compiler/ajax.yml +4 -4
  78. data/test/integration/zafu_compiler/calendar.yml +8 -15
  79. data/test/integration/zafu_compiler/context.yml +1 -1
  80. data/test/integration/zafu_compiler/dates.yml +5 -1
  81. data/test/integration/zafu_compiler/display.yml +1 -2
  82. data/test/integration/zafu_compiler/forms.yml +37 -10
  83. data/test/integration/zafu_compiler/query.yml +5 -5
  84. data/test/integration/zafu_compiler/relations.yml +8 -8
  85. data/test/integration/zafu_compiler/safe_definitions.yml +7 -2
  86. data/test/integration/zafu_compiler/urls.yml +24 -3
  87. data/test/integration/zafu_compiler/zazen.yml +9 -1
  88. data/test/selenium/Destroy/destroy1.rsel +2 -1
  89. data/test/selenium/Destroy/destroy2.rsel +17 -0
  90. data/test/unit/document_test.rb +17 -4
  91. data/test/unit/relation_proxy_test.rb +19 -8
  92. data/test/unit/string_hash_test.rb +1 -1
  93. data/test/unit/template_test.rb +3 -3
  94. data/test/unit/virtual_class_test.rb +77 -0
  95. data/test/unit/zena/use/urls_test.rb +9 -1
  96. data/vendor/plugins/selenium-on-rails/lib/selenium_on_rails_config.rb +1 -1
  97. data/zena.gemspec +60 -53
  98. metadata +145 -125
@@ -70,7 +70,7 @@ class RelationProxy < Relation
70
70
  # get
71
71
 
72
72
  def other_link
73
- other_links ? other_links[0] : nil
73
+ other_links ? other_links.first : nil
74
74
  end
75
75
 
76
76
  def other_id
@@ -100,9 +100,9 @@ class RelationProxy < Relation
100
100
  }.merge(opts)
101
101
  @records = secure(Node) { Node.find(:all, options) }
102
102
  end
103
-
103
+
104
104
  LINK_ATTRIBUTES.each do |sym|
105
- define_method(sym) do
105
+ define_method(:"other_#{sym}") do
106
106
  other_link ? other_link[sym] : nil
107
107
  end
108
108
  end
@@ -470,9 +470,19 @@ class Site < ActiveRecord::Base
470
470
  # unpublished templates).
471
471
  def rebuild_index(nodes = nil, page = nil, page_count = nil)
472
472
  if !page
473
- Site.logger.error("\n----------------- REBUILD INDEX FOR SITE #{host} -----------------\n")
474
473
  Zena::SiteWorker.perform(self, :rebuild_index)
475
474
  else
475
+ if page == 1
476
+ Site.logger.error("\n----------------- REBUILD INDEX FOR SITE #{host} -----------------\n")
477
+ # Reset reference to cache origin to make sure it is always overwritten
478
+ Zena::Use::ScopeIndex::AVAILABLE_MODELS.each do |klass|
479
+ changes = klass.column_names.select{|n| n =~ %r{(.*)_id}}.reject {|n| %w{node_id site_id}.include?(n)}.map do |c|
480
+ "#{c} = NULL"
481
+ end.join(', ')
482
+ Site.logger.error("#{klass.name}: reset #{changes}\n")
483
+ Zena::Db.execute "UPDATE #{klass.table_name} SET #{changes} WHERE site_id = #{id}"
484
+ end
485
+ end
476
486
  # do things
477
487
  nodes.each do |node|
478
488
  node.rebuild_index!
@@ -61,5 +61,5 @@ class StringHash < Hash
61
61
  end
62
62
 
63
63
  safe_context [:[], String] => String
64
- safe_method :keys => [String]
64
+ safe_method :keys => {:class => [String], :method => 'keys.sort'}
65
65
  end
@@ -40,7 +40,7 @@ class Template < TextDocument
40
40
  # Class Methods
41
41
  class << self
42
42
  def accept_content_type?(content_type)
43
- content_type =~ /text\/(html|zafu)/
43
+ content_type =~ /text\/(zafu)/
44
44
  end
45
45
  end # Class Methods
46
46
 
@@ -340,7 +340,7 @@ class User < ActiveRecord::Base
340
340
  end
341
341
  end
342
342
 
343
- def find_node(path, zip, name, request)
343
+ def find_node(path, zip, name, request, need_write = false)
344
344
  secure!(Node) do
345
345
  if name =~ /^\d+$/
346
346
  Node.find_by_zip(name)
@@ -397,6 +397,11 @@ class User < ActiveRecord::Base
397
397
  if login.blank? && !is_anon?
398
398
  self.login = name
399
399
  end
400
+
401
+ if !is_admin?
402
+ # Make sure we remove dev_skin settings if user is not an admin.
403
+ self[:dev_skin_id] = nil
404
+ end
400
405
  end
401
406
 
402
407
  # Validates that anon user does not have a login, that other users have a password
@@ -34,7 +34,7 @@ class VirtualClass < Role
34
34
  attr_accessor :export_attributes
35
35
  end
36
36
 
37
- self.export_attributes = %w{auto_create_discussion icon monolingual}
37
+ self.export_attributes = %w{auto_create_discussion icon monolingual content_type}
38
38
 
39
39
  attr_accessor :import_result
40
40
  belongs_to :create_group, :class_name => 'Group', :foreign_key => 'create_group_id'
@@ -52,7 +52,10 @@ class VirtualClass < Role
52
52
  include Zena::Use::ScopeIndex::VirtualClassMethods
53
53
 
54
54
  property.boolean 'monolingual'
55
+ property.text 'content_type'
56
+
55
57
  safe_method :monolingual? => Boolean
58
+ safe_method :content_type => String
56
59
  safe_method :roles => {:class => ['Role'], :method => 'sorted_roles'}
57
60
  safe_method :relations => {:class => ['RelationProxy'], :method => 'all_relations'}
58
61
  safe_method [:relations, String] => {:class => ['RelationProxy'], :method => 'filtered_relations'}
@@ -68,6 +71,17 @@ class VirtualClass < Role
68
71
  end
69
72
  end
70
73
 
74
+ # Class path hierarchy. Example for (Post) : N, NN, NNP
75
+ def self.split_kpath(kpath)
76
+ parts = []
77
+ kpath.split(//).each_index { |i| parts << kpath[0..i] }
78
+ parts
79
+ end
80
+
81
+ def split_kpath
82
+ @split_kpath ||= VirtualClass.split_kpath(kpath)
83
+ end
84
+
71
85
  class Cache
72
86
  def initialize
73
87
  clear_cache!
@@ -240,6 +254,7 @@ class VirtualClass < Role
240
254
  attribute = opts[:class_attr] || 'name'
241
255
 
242
256
  VirtualClass.all_classes(base_kpath, opts[:without]).map do |vclass|
257
+ # Only insert allowed classes.
243
258
  if vclass.create_group_id.nil? || group_ids.include?(vclass.create_group_id)
244
259
  # white spaces are insecable spaces (not ' ')
245
260
  a, b = vclass.kpath, vclass.name
@@ -249,6 +264,15 @@ class VirtualClass < Role
249
264
  end
250
265
  end.compact
251
266
  end
267
+
268
+ def sub_classes
269
+ @sub_classes ||= VirtualClass.all_classes(self.kpath).sort {|a,b| a.name <=> b.name}
270
+ end
271
+
272
+ def content_type_re
273
+ # if content_type is empty => match all
274
+ @content_type_re ||= %r{^#{content_type || ".*"}$}
275
+ end
252
276
 
253
277
  # Include all roles into the this schema. By including the superclass
254
278
  # and all roles related to this class.
@@ -579,6 +603,17 @@ class VirtualClass < Role
579
603
  unless self[:real_class]
580
604
  errors.add('superclass', 'invalid')
581
605
  end
606
+
607
+ if content_type =~ /[^a-zA-Z\.\-\/\*\|\\]/
608
+ errors.add('content_type', 'invalid characters')
609
+ else
610
+ begin
611
+ re = %r{^#{content_type}$}
612
+ rescue RegexpError => err
613
+ errors.add('content_type', err.message)
614
+ end
615
+ end
616
+
582
617
  end
583
618
 
584
619
  def get_real_class(klass)
@@ -21,7 +21,11 @@
21
21
  </tr>
22
22
  <tr>
23
23
  <td class='label'><%= _('action')%> <%= help(_('acl_action_help')) %></td>
24
- <td><%= select('acl', 'action', Acl::ACTIONS ) %></td>
24
+ <td>
25
+ <%= select('acl', 'action', Acl::ACTIONS ) %>
26
+
27
+ <%= _('create only: allow') %> <%= select('acl', 'create_kpath', Node.kpaths_for_form ) %>
28
+ </td>
25
29
  </tr>
26
30
  <tr class='priority'>
27
31
  <td class='label'><%= _('priority')%> <%= help(_('acl_priority_help')) %></td>
@@ -1,7 +1,7 @@
1
1
  <tr id='acl<%= li[:id] %>'>
2
2
  <td class="adm_icon"><%= link_to_remote( _("img_acl"), :update=>"acl#{li[:id]}", :url=>edit_acl_path(li), :method=>:get) %></td>
3
3
  <td class='group'><%= li.group.name %></td>
4
- <td class='act'><%= li.action %></td>
4
+ <td class='act'><%= li.action %><% if li.action == 'create' %> <span class='constant'><%= li.create_vclass_name %></span><% end %></td>
5
5
  <td class='name'><%= li.name %></td>
6
6
  <td class='mode'><%= li.mode %></td>
7
7
  <td class='format'><%= li.format %></td>
@@ -12,4 +12,5 @@
12
12
 
13
13
  <label for='node_summary'><%= _('summary') %></label>
14
14
  <textarea id='node_summary' rows='3' name='node[summary]'></textarea><br/>
15
+ <input type='hidden' name='redir' value='more'/>
15
16
  </form>
@@ -11,7 +11,7 @@
11
11
  <input id='title' type='text' name='node[title]'/><br/>
12
12
 
13
13
  <label for='node_target_klass'><%= _('class scope') %></label>
14
- <%= select('node', 'target_klass', Node.classes_for_form, {:include_blank => true} ) %><br/>
14
+ <%= select('node', 'target_klass', Node.classes_for_form, {:include_blank => true}, {} ) %><br/>
15
15
 
16
16
  <label for='node_mode'><%= _('mode') %></label>
17
17
  <input id='node_mode' type='text' name='node[mode]'/><br/>
@@ -23,6 +23,7 @@
23
23
  <% end -%>
24
24
  <% end -%>
25
25
  <tr><td class='label'><%= _("status")%> </td><td><%= select('user', 'status', User::Status.reject {|k,v| v > User::Status[:admin]}.map{|k,v| [_(k.to_s),v]}.sort{|a,b| b[1] <=> a[1]}) %></td></tr>
26
+ <tr><td class='label'><%= _("single_access_token")%> </td><td><%= @user.single_access_token %></td></tr>
26
27
  <tr><td class='label'><%= _('language')%> </td><td><%= select('user', 'lang', visitor.site.lang_list.map {|l| [_(l),l]}) %></td></tr>
27
28
  <tr><td class='label'><%= _("time zone")%> </td><td><select name='user[time_zone]'><%= options_for_select([''] + TZInfo::Timezone.all_identifiers, @user[:time_zone] || '') %></select></td></tr>
28
29
  <% unless @user.is_anon? -%>
@@ -32,16 +32,17 @@
32
32
 
33
33
  <% if @virtual_class.kind_of?(VirtualClass) -%>
34
34
  <% Zena::Use::Fulltext::FULLTEXT_FIELDS.reverse_each do |fld| -%>
35
- <tr><td class='label'><%= _(fld)%></td><td><%= text_area('virtual_class', fld, :rows => 2, :cols => 30) %></td></tr>
35
+ <tr><td class='label'><%= _(fld) %></td><td><%= text_area('virtual_class', fld, :rows => 2, :cols => 30) %></td></tr>
36
36
  <% end -%>
37
- <tr><td class='label'><%= _('idx_class')%></td><td><%= select('virtual_class', 'idx_class', Zena::Use::ScopeIndex.models_for_form) %></td></tr>
38
- <tr><td class='label'><%= _('idx_scope')%></td><td><%= text_area('virtual_class', 'idx_scope', :rows => 2, :cols => 30) %></td></tr>
39
- <tr><td class='label'><%= _('idx_reverse_scope')%></td><td><%= text_area('virtual_class', 'idx_reverse_scope', :rows => 2, :cols => 30) %></td></tr>
40
- <tr><td class='label'><%= _('prop eval')%></td><td><%= text_area('virtual_class', 'prop_eval', :rows => 2, :cols => 30) %></td></tr>
37
+ <tr><td class='label'><%= _('idx_class') %></td><td><%= select('virtual_class', 'idx_class', Zena::Use::ScopeIndex.models_for_form) %></td></tr>
38
+ <tr><td class='label'><%= _('idx_scope') %></td><td><%= text_area('virtual_class', 'idx_scope', :rows => 2, :cols => 30) %></td></tr>
39
+ <tr><td class='label'><%= _('idx_reverse_scope') %></td><td><%= text_area('virtual_class', 'idx_reverse_scope', :rows => 2, :cols => 30) %></td></tr>
40
+ <tr><td class='label'><%= _('prop eval') %></td><td><%= text_area('virtual_class', 'prop_eval', :rows => 2, :cols => 30) %></td></tr>
41
41
 
42
- <tr><td class='label'><%= _('create group')%></td><td><%= select('virtual_class', 'create_group_id', visitor.all_groups.map{|g| [g.name, g.id]} ) %></td></tr>
42
+ <tr><td class='label'><%= _('edit group') %></td><td><%= select('virtual_class', 'create_group_id', visitor.all_groups.map{|g| [g.name, g.id]} ) %></td></tr>
43
43
  <tr><td class='label'><%= _('auto create discussion')%></td><td><%= check_box('virtual_class', 'auto_create_discussion') %></td></tr>
44
- <tr><td class='label'><%= _('monolingual')%></td><td><%= check_box('virtual_class', 'monolingual') %></td></tr>
44
+ <tr><td class='label'><%= _('monolingual') %></td><td><%= check_box('virtual_class', 'monolingual') %></td></tr>
45
+ <tr><td class='label'><%= _('content_type')%></td><td><%= text_field('virtual_class', 'content_type') %></td></tr>
45
46
  <% end -%>
46
47
  <tr><td class='label'><%= _('icon')%> </td><td><%= text_field('virtual_class', 'icon', :size=>15 ) %></td></tr>
47
48
  <tr><td colspan='2'><p class='btn_validate'><input type='submit' value='<%= _('validate') %>'/></p></td></tr>
@@ -34,7 +34,11 @@ module Bricks
34
34
  def acl_authorized?(action, params, request)
35
35
  node = nil
36
36
  group_ids_bak = group_ids.dup
37
- acls(action, params[:mode], params[:format]).each do |acl|
37
+ if action == 'create'
38
+ klass = (params['node'] || {})['klass']
39
+ end
40
+
41
+ acls(action, params[:mode], params[:format], klass).each do |acl|
38
42
  # Load exec_group to execute query
39
43
  if acl.exec_group_id
40
44
  @group_ids = group_ids_bak + [acl.exec_group_id]
@@ -56,27 +60,46 @@ module Bricks
56
60
 
57
61
  # Find all acls for the visitor for a given action. The action should
58
62
  # be one of the following: 'create', 'read', 'update', 'delete'. See
59
- # Acl::ACTIONS.
60
- def acls(action, mode, format)
63
+ # Acl::ACTIONS. If the action is 'create', we should also pass the class
64
+ # of the object to create.
65
+ def acls(action, mode, format, klass = nil)
61
66
  mode = '' if mode.blank?
62
67
  # Can the format be blank ?
63
68
  format = 'html' if format.blank?
64
- secure(Acl) { Acl.find(:all,
65
- :conditions => [
66
- 'group_id IN (?) AND action = ? AND (mode = ? OR mode = ?) AND (format = ? OR format = ?)',
67
- group_ids, action, '*', mode, '*', format],
68
- :order => 'priority DESC'
69
- )} || []
69
+ if action == 'create'
70
+ return [] unless klass = VirtualClass[klass || 'Node']
71
+ # Can the format be blank ?
72
+ format = 'html' if format.blank?
73
+ secure(Acl) { Acl.find(:all,
74
+ :conditions => [
75
+ 'group_id IN (?) AND action = ? AND (mode = ? OR mode = ?) AND (format = ? OR format = ?) AND create_kpath IN (?)',
76
+ group_ids, action, '*', mode, '*', format, klass.split_kpath],
77
+ :order => 'priority DESC'
78
+ )}
79
+ else
80
+ secure(Acl) { Acl.find(:all,
81
+ :conditions => [
82
+ 'group_id IN (?) AND action = ? AND (mode = ? OR mode = ?) AND (format = ? OR format = ?)',
83
+ group_ids, action, '*', mode, '*', format],
84
+ :order => 'priority DESC'
85
+ )}
86
+ end || []
70
87
  end
71
88
 
72
89
  def get_skin_with_acls(node)
73
90
  exec_acl ? exec_acl.exec_skin : get_skin_without_acls(node)
74
91
  end
75
92
 
76
- def find_node_with_acls(path, zip, name, request)
77
- find_node_without_acls(path, zip, name, request)
78
- rescue ActiveRecord::RecordNotFound
79
- raise unless visitor.use_acls?
93
+ def find_node_with_acls(path, zip, name, request, need_write = false)
94
+ n = find_node_without_acls(path, zip, name, request, need_write) rescue nil
95
+ if !n || (!n.can_write? && need_write)
96
+ n = find_node_force_acls(path, zip, name, request) || n
97
+ end
98
+ n
99
+ end
100
+
101
+ def find_node_force_acls(path, zip, name, request)
102
+ raise ActiveRecord::RecordNotFound unless visitor.use_acls?
80
103
  acl_params = request.params.dup
81
104
  if name =~ /^\d+$/
82
105
  acl_params[:id] = name
@@ -86,8 +109,13 @@ module Bricks
86
109
  else
87
110
  acl_params[:id] = zip
88
111
  end
89
-
90
- visitor.acl_authorized?(::Acl::ACTION_FROM_METHOD[request.method], acl_params, request)
112
+ if request.path =~ %r{^/nodes/\d+/zafu$}
113
+ # This is to allow preview by using POST requests (long text in js).
114
+ action = 'read'
115
+ else
116
+ action = ::Acl::ACTION_FROM_METHOD[request.method]
117
+ end
118
+ visitor.acl_authorized?(action, acl_params, request)
91
119
  end
92
120
  end # UserMethods
93
121
  end # Acls
@@ -0,0 +1,13 @@
1
+ class AddCreateKpathToAcl < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :acls, :create_kpath, :string, :limit => 200
4
+ add_index :acls, ["create_kpath", "group_id", "action", "site_id"]
5
+ rescue
6
+ # Could be run twice (was in zena brick by mistake in zena 1.2.4pre)
7
+ end
8
+
9
+ def self.down
10
+ remove_column :groups, :auto_publish
11
+ remove_index :acls, :column => ["create_kpath", "group_id", "action", "site_id"]
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ class FixCreateKpathDefault < ActiveRecord::Migration
2
+ def self.up
3
+ execute %Q{UPDATE acls SET create_kpath = 'N' WHERE create_kpath IS NULL}
4
+ end
5
+
6
+ def self.down
7
+ end
8
+ end
@@ -145,7 +145,8 @@ class AclIntegrationTest < Zena::Integration::TestCase
145
145
  setup do
146
146
  # The visitor can create objects in assigned_project as direct parent
147
147
  Zena::Db.execute "UPDATE acls SET query = '%q{assigned_project}', action = 'create' WHERE id = #{acls_id(:rap)}"
148
- @create_url = "http://erebus.host/nodes?node[parent_id]=#{nodes_zip(:queen)}&node[klass]=Page&node[title]=foobar"
148
+ @create_url = "http://erebus.host/nodes?node[parent_id]=#{nodes_zip(:queen)}&node[klass]=Contact&node[title]=foobar"
149
+ @create_bad = "http://erebus.host/nodes?node[parent_id]=#{nodes_zip(:queen)}&node[klass]=Page&node[title]=foobar"
149
150
  end
150
151
 
151
152
  context 'with wrong user status' do
@@ -170,6 +171,14 @@ class AclIntegrationTest < Zena::Integration::TestCase
170
171
  assert_equal nodes_id(:queen), node.parent_id
171
172
  assert_equal 'foobar', node.title
172
173
  end
174
+
175
+ context 'with wrong klass type' do
176
+ should 'create item' do
177
+ assert_difference('Node.count', 0) do
178
+ post @create_bad
179
+ end
180
+ end
181
+ end
173
182
 
174
183
  should 'not create item out of acl scope' do
175
184
  assert_difference('Node.count', 0) do
@@ -177,6 +186,30 @@ class AclIntegrationTest < Zena::Integration::TestCase
177
186
  end
178
187
  assert_response :missing
179
188
  end
189
+
190
+ context 'with read access' do
191
+ setup do
192
+ # We must grant read access on visitor node to avoid errors in page rendering
193
+ Zena::Db.execute "UPDATE nodes SET rgroup_id = #{groups_id(:site)} WHERE id IN (#{nodes_id(:queen)},#{nodes_id(:demeter)})"
194
+ end
195
+
196
+ should 'read without acl' do
197
+ get "http://erebus.host/oo/project#{nodes_zip(:queen)}.html"
198
+ assert_response :success
199
+ assert_nil visitor.exec_acl
200
+ end
201
+
202
+ should 'load acl' do
203
+ assert_difference('Node.count', 1) do
204
+ post @create_url
205
+ end
206
+ node = assigns(:node)
207
+ assert visitor.exec_acl
208
+ assert_equal visitor.id, node.user_id
209
+ assert_equal nodes_id(:queen), node.parent_id
210
+ assert_equal 'foobar', node.title
211
+ end
212
+ end
180
213
 
181
214
  context 'without use acl' do
182
215
  setup do
@@ -223,6 +256,25 @@ class AclIntegrationTest < Zena::Integration::TestCase
223
256
  put "http://erebus.host/nodes/#{nodes_zip(:queen)}?node[title]=foobar"
224
257
  assert_response :missing
225
258
  end
259
+
260
+ context 'with read access' do
261
+ setup do
262
+ # We must grant read access on visitor node to avoid errors in page rendering
263
+ Zena::Db.execute "UPDATE nodes SET rgroup_id = #{groups_id(:site)} WHERE id IN (#{nodes_id(:persephone)},#{nodes_id(:demeter)})"
264
+ end
265
+
266
+ should 'read without acl' do
267
+ get "http://erebus.host/oo/contact#{nodes_zip(:persephone)}.html"
268
+ assert_response :success
269
+ assert_nil visitor.exec_acl
270
+ end
271
+
272
+ should 'load acl' do
273
+ put @update_url
274
+ assert_equal 'foobar', nodes(:persephone).title
275
+ assert visitor.exec_acl
276
+ end
277
+ end
226
278
 
227
279
  context 'without use acl' do
228
280
  setup do
@@ -17,6 +17,27 @@ rap:
17
17
  # allow any format
18
18
  format: '*'
19
19
 
20
+ # Create Posts in assigned projects
21
+ create_rap:
22
+ name: create posts in assigned projects
23
+ # Anyone in the 'sky' group
24
+ group: sky
25
+ # can create
26
+ action: create
27
+ # in 'assigned_projects'
28
+ query: "%q{assigned_projects}"
29
+ # objects with kpath
30
+ create_kpath: NRC
31
+ # by receiving the 'erebus' access group
32
+ exec_group: erebus
33
+ # and viewing it through the 'sky' Skin.
34
+ exec_skin: sky
35
+ priority: 10
36
+ # allow any mode
37
+ mode: '*'
38
+ # allow any format
39
+ format: '*'
40
+
20
41
  # Read self (this never matches)
21
42
  self:
22
43
  name: read assigned projects