zena 1.2.3 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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