hobo 0.8.4 → 0.8.5
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.
- data/CHANGES.txt +27 -0
- data/Rakefile +3 -3
- data/bin/hobo +1 -1
- data/hobo.gemspec +5 -5
- data/lib/hobo.rb +1 -1
- data/lib/hobo/accessible_associations.rb +31 -20
- data/lib/hobo/controller.rb +2 -2
- data/lib/hobo/lifecycles/lifecycle.rb +2 -1
- data/lib/hobo/model_controller.rb +1 -1
- data/lib/hobo/permissions.rb +27 -35
- data/rails_generators/hobo/hobo_generator.rb +18 -10
- data/rails_generators/hobo/templates/initializer.rb +0 -8
- data/taglibs/rapid_forms.dryml +2 -2
- data/test/permissions/models/test.sqlite3 +0 -0
- data/test/permissions/test_permissions.rb +16 -1
- metadata +4 -4
data/CHANGES.txt
CHANGED
@@ -1,3 +1,30 @@
|
|
1
|
+
=== Hobo 0.8.5 ===
|
2
|
+
|
3
|
+
New permission system
|
4
|
+
|
5
|
+
Various fixes
|
6
|
+
|
7
|
+
Now runs permission checks *before* callbacks, not after
|
8
|
+
|
9
|
+
In the switch to the new permissions system, we changed to running them after all callbacks. This turned
|
10
|
+
out to be wrong. Permissions should only be about what the user tried to change, not other changes
|
11
|
+
triggered by application logic
|
12
|
+
|
13
|
+
API change: Web method permissions should now be defined as foo_permitted? instead of foo_call_permitted?
|
14
|
+
|
15
|
+
Updated hobo command and hobo generator to use the new config.gem style for apps that use the Hobo gem
|
16
|
+
|
17
|
+
The --add-gem option to script/generate hobo will add "config.gem 'hobo'" to environment.rb. The hobo command
|
18
|
+
does this automatically
|
19
|
+
|
20
|
+
Lifecycles fix -- state_name would throw a nil error if there was no state (not returns nil)
|
21
|
+
|
22
|
+
This was causing the :new_key option to fail on a create step
|
23
|
+
|
24
|
+
Fixes to problems with live-search introduced with the Rails 2.2 upgrade
|
25
|
+
|
26
|
+
|
27
|
+
|
1
28
|
=== Hobo 0.8.4 ===
|
2
29
|
|
3
30
|
Rails 2.2 compatible. Rails 2.1 support dropped.
|
data/Rakefile
CHANGED
@@ -40,11 +40,11 @@ Echoe.new('hobo') do |p|
|
|
40
40
|
p.project = "hobo"
|
41
41
|
|
42
42
|
p.changelog = "CHANGES.txt"
|
43
|
-
p.version = "0.8.
|
43
|
+
p.version = "0.8.5"
|
44
44
|
|
45
45
|
p.dependencies = [
|
46
|
-
'hobosupport =0.8.
|
47
|
-
'hobofields =0.8.
|
46
|
+
'hobosupport =0.8.5',
|
47
|
+
'hobofields =0.8.5',
|
48
48
|
'rails >=2.2.2',
|
49
49
|
'mislav-will_paginate >=2.2.1']
|
50
50
|
|
data/bin/hobo
CHANGED
@@ -74,7 +74,7 @@ Dir.chdir(app_path) do
|
|
74
74
|
FileUtils.touch("public/stylesheets/application.css")
|
75
75
|
|
76
76
|
puts "\nInitialising Hobo...\n"
|
77
|
-
command(gen, "hobo --add-routes")
|
77
|
+
command(gen, "hobo --add-gem --add-routes")
|
78
78
|
|
79
79
|
puts "\nInstalling Hobo Rapid and default theme...\n"
|
80
80
|
command("#{gen} hobo_rapid --import-tags")
|
data/hobo.gemspec
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
|
2
|
-
# Gem::Specification for Hobo-0.8.
|
2
|
+
# Gem::Specification for Hobo-0.8.5
|
3
3
|
# Originally generated by Echoe
|
4
4
|
|
5
5
|
--- !ruby/object:Gem::Specification
|
6
6
|
name: hobo
|
7
7
|
version: !ruby/object:Gem::Version
|
8
|
-
version: 0.8.
|
8
|
+
version: 0.8.5
|
9
9
|
platform: ruby
|
10
10
|
authors:
|
11
11
|
- Tom Locke
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
|
15
|
-
date: 2008-12-
|
15
|
+
date: 2008-12-09 00:00:00 +00:00
|
16
16
|
default_executable:
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
@@ -23,7 +23,7 @@ dependencies:
|
|
23
23
|
requirements:
|
24
24
|
- - "="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.8.
|
26
|
+
version: 0.8.5
|
27
27
|
version:
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: hobofields
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
requirements:
|
34
34
|
- - "="
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version: 0.8.
|
36
|
+
version: 0.8.5
|
37
37
|
version:
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: rails
|
data/lib/hobo.rb
CHANGED
@@ -9,31 +9,36 @@ module Hobo
|
|
9
9
|
|
10
10
|
array = params_hash_to_array(array_or_hash)
|
11
11
|
array.map! do |record_hash_or_string|
|
12
|
-
|
12
|
+
finder = association.member_class.scoped :conditions => association.conditions
|
13
|
+
find_or_create_and_update(owner, association_name, finder, record_hash_or_string) do |id|
|
14
|
+
# The block is required to either locate find an existing record in the collection, or build a new one
|
15
|
+
if id
|
16
|
+
# TODO: We don't really want to find these one by one
|
17
|
+
association.find(id)
|
18
|
+
else
|
19
|
+
association.build
|
20
|
+
end
|
21
|
+
end
|
13
22
|
end
|
14
23
|
array.compact
|
15
24
|
end
|
16
25
|
|
17
26
|
|
18
|
-
def find_or_create_and_update(owner,
|
27
|
+
def find_or_create_and_update(owner, association_name, finder, record_hash_or_string)
|
19
28
|
if record_hash_or_string.is_a?(String)
|
20
|
-
# An ID
|
21
|
-
record =
|
29
|
+
# An ID or a name - the passed block will find the record
|
30
|
+
record = find_by_name_or_id(finder, record_hash_or_string)
|
22
31
|
|
23
32
|
elsif record_hash_or_string.is_a?(Hash)
|
24
33
|
# A hash of attributes
|
25
34
|
hash = record_hash_or_string
|
26
35
|
|
27
36
|
# Remove completely blank hashes
|
28
|
-
return nil if hash.values.
|
37
|
+
return nil if hash.values.all?(&:blank?)
|
29
38
|
|
30
39
|
id = hash.delete(:id)
|
31
40
|
|
32
|
-
record =
|
33
|
-
association.find(id) # TODO: We don't really want to find these one by one
|
34
|
-
else
|
35
|
-
record = yield
|
36
|
-
end
|
41
|
+
record = yield id
|
37
42
|
record.attributes = hash
|
38
43
|
owner.include_in_save(association_name, record) unless owner.new_record? && record.new_record?
|
39
44
|
|
@@ -43,7 +48,7 @@ module Hobo
|
|
43
48
|
end
|
44
49
|
record
|
45
50
|
end
|
46
|
-
|
51
|
+
|
47
52
|
|
48
53
|
def params_hash_to_array(array_or_hash)
|
49
54
|
if array_or_hash.is_a?(Hash)
|
@@ -54,17 +59,12 @@ module Hobo
|
|
54
59
|
end
|
55
60
|
|
56
61
|
|
57
|
-
def
|
58
|
-
klass = association.member_class
|
62
|
+
def find_by_name_or_id(finder, id_or_name)
|
59
63
|
if id_or_name =~ /^@(.*)/
|
60
64
|
id = $1
|
61
|
-
|
62
|
-
Hobo::Model.find_by_typed_id(id)
|
63
|
-
else
|
64
|
-
klass.find(id)
|
65
|
-
end
|
65
|
+
finder.find(id)
|
66
66
|
else
|
67
|
-
|
67
|
+
finder.named(id_or_name)
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -103,7 +103,18 @@ module Hobo
|
|
103
103
|
if options[:accessible]
|
104
104
|
class_eval %{
|
105
105
|
def #{name}_with_accessible=(record_hash_or_string)
|
106
|
-
|
106
|
+
refl = self.class.reflections[:#{name}]
|
107
|
+
conditions = ActiveRecord::Associations::BelongsToAssociation.new(self, refl).conditions
|
108
|
+
finder = refl.klass.scoped(:conditions => conditions)
|
109
|
+
record = Hobo::AccessibleAssociations.find_or_create_and_update(self, :#{name}, finder, record_hash_or_string) do |id|
|
110
|
+
if id
|
111
|
+
raise ArgumentError, "attempted to update the wrong record in belongs_to association #{self}##{name}" unless
|
112
|
+
#{name} && id == self.#{name}.id
|
113
|
+
#{name}
|
114
|
+
else
|
115
|
+
refl.klass.new
|
116
|
+
end
|
117
|
+
end
|
107
118
|
self.#{name}_without_accessible = record
|
108
119
|
end
|
109
120
|
}, __FILE__, __LINE__ - 5
|
data/lib/hobo/controller.rb
CHANGED
@@ -122,7 +122,7 @@ module Hobo
|
|
122
122
|
|
123
123
|
def tag_renderer
|
124
124
|
@tag_renderer ||= begin
|
125
|
-
|
125
|
+
@template.send(:_evaluate_assigns_and_ivars)
|
126
126
|
Hobo::Dryml.empty_page_renderer(@template)
|
127
127
|
end
|
128
128
|
end
|
@@ -135,7 +135,7 @@ module Hobo
|
|
135
135
|
NO_SEARCH_RESULTS_HTML = "<p>Your search returned no matches.</p>"
|
136
136
|
def site_search(query)
|
137
137
|
results_hash = Hobo.find_by_search(query)
|
138
|
-
all_results = results_hash.values.flatten.select { |r|
|
138
|
+
all_results = results_hash.values.flatten.select { |r| r.viewable_by?(current_user) }
|
139
139
|
if all_results.empty?
|
140
140
|
render :text => NO_SEARCH_RESULTS_HTML
|
141
141
|
else
|
@@ -111,7 +111,7 @@ module Hobo
|
|
111
111
|
# Make sure we have a copy of the options - it is being mutated somewhere
|
112
112
|
opts = {}.merge(options)
|
113
113
|
self.this = find_instance(opts) unless opts[:no_find]
|
114
|
-
raise Hobo::PermissionDeniedError unless
|
114
|
+
raise Hobo::PermissionDeniedError unless @this.method_callable_by?(current_user, method)
|
115
115
|
if got_block
|
116
116
|
instance_eval(&block)
|
117
117
|
else
|
data/lib/hobo/permissions.rb
CHANGED
@@ -7,16 +7,12 @@ module Hobo
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.included(klass)
|
10
|
-
klass.extend ClassMethods
|
11
|
-
|
12
|
-
create_with_callbacks = find_aliased_name klass, :create_with_callbacks
|
13
|
-
update_with_callbacks = find_aliased_name klass, :update_with_callbacks
|
14
|
-
destroy_with_callbacks = find_aliased_name klass, :destroy_with_callbacks
|
15
|
-
|
16
10
|
klass.class_eval do
|
17
|
-
|
18
|
-
|
19
|
-
|
11
|
+
extend ClassMethods
|
12
|
+
|
13
|
+
alias_method_chain :create, :hobo_permission_check
|
14
|
+
alias_method_chain :update, :hobo_permission_check
|
15
|
+
alias_method_chain :destroy, :hobo_permission_check
|
20
16
|
|
21
17
|
attr_accessor :acting_user, :origin, :origin_attribute
|
22
18
|
|
@@ -91,40 +87,26 @@ module Hobo
|
|
91
87
|
acting_user && !(self.class.has_lifecycle? && lifecycle.active_step)
|
92
88
|
end
|
93
89
|
|
94
|
-
def
|
95
|
-
return false if callback(:before_create) == false
|
96
|
-
|
90
|
+
def create_with_hobo_permission_check(*args, &b)
|
97
91
|
if permission_check_required?
|
98
92
|
create_permitted? or raise PermissionDeniedError, "#{self.class.name}#create"
|
99
93
|
end
|
100
|
-
|
101
|
-
result = create_without_callbacks
|
102
|
-
callback(:after_create)
|
103
|
-
result
|
94
|
+
create_without_hobo_permission_check(*args, &b)
|
104
95
|
end
|
105
96
|
|
106
|
-
def
|
107
|
-
return false if callback(:before_update) == false
|
108
|
-
|
97
|
+
def update_with_hobo_permission_check(*args)
|
109
98
|
if permission_check_required?
|
110
99
|
update_permitted? or raise PermissionDeniedError, "#{self.class.name}#update"
|
111
100
|
end
|
112
|
-
|
113
|
-
result = update_without_callbacks(*args)
|
114
|
-
callback(:after_update)
|
115
|
-
result
|
101
|
+
update_without_hobo_permission_check(*args)
|
116
102
|
end
|
117
103
|
|
118
|
-
def
|
119
|
-
return false if callback(:before_destroy) == false
|
120
|
-
|
104
|
+
def destroy_with_hobo_permission_check
|
121
105
|
if permission_check_required?
|
122
106
|
destroy_permitted? or raise PermissionDeniedError, "#{self.class.name}#.destroy"
|
123
107
|
end
|
124
108
|
|
125
|
-
|
126
|
-
callback(:after_destroy)
|
127
|
-
result
|
109
|
+
destroy_without_hobo_permission_check
|
128
110
|
end
|
129
111
|
|
130
112
|
# -------------------------------------- #
|
@@ -184,8 +166,8 @@ module Hobo
|
|
184
166
|
end
|
185
167
|
|
186
168
|
def method_callable_by?(user, method)
|
187
|
-
permission_method = "#{method}
|
188
|
-
respond_to?(permission_method) && with_acting_user(
|
169
|
+
permission_method = "#{method}_permitted?"
|
170
|
+
respond_to?(permission_method) && with_acting_user(user) { send(permission_method) }
|
189
171
|
end
|
190
172
|
|
191
173
|
def viewable_by?(user, attribute=nil)
|
@@ -337,20 +319,30 @@ module Hobo
|
|
337
319
|
|
338
320
|
# By default, attempt to derive edit permission from create/update permission
|
339
321
|
def edit_permitted?(attribute)
|
340
|
-
|
322
|
+
if attribute
|
323
|
+
with_attribute_or_belongs_to_keys(attribute) do |attr, ftype|
|
324
|
+
unknownify_attribute(self, attr)
|
325
|
+
unknownify_attribute(self, ftype) if ftype
|
326
|
+
end
|
327
|
+
end
|
341
328
|
new_record? ? create_permitted? : update_permitted?
|
342
329
|
rescue Hobo::UndefinedAccessError
|
343
330
|
# The permission is dependent on the unknown value
|
344
331
|
# so this attribute is not editable
|
345
332
|
false
|
346
333
|
ensure
|
347
|
-
|
334
|
+
if attribute
|
335
|
+
with_attribute_or_belongs_to_keys(attribute) do |attr, ftype|
|
336
|
+
deunknownify_attribute(self, attr)
|
337
|
+
deunknownify_attribute(self, ftype) if ftype
|
338
|
+
end
|
339
|
+
end
|
348
340
|
end
|
349
341
|
|
350
342
|
|
351
343
|
# Add some singleton methods to +record+ so give the effect that +attribute+ is unknown. That is,
|
352
344
|
# attempts to access the attribute will result in a Hobo::UndefinedAccessError
|
353
|
-
def
|
345
|
+
def unknownify_attribute(record, attr)
|
354
346
|
record.metaclass.class_eval do
|
355
347
|
|
356
348
|
define_method attr do
|
@@ -386,7 +378,7 @@ module Hobo
|
|
386
378
|
end
|
387
379
|
|
388
380
|
# Best. Name. Ever
|
389
|
-
def
|
381
|
+
def deunknownify_attribute(record, attr)
|
390
382
|
[attr, "#{attr}_change", "#{attr}_was", "#{attr}_changed?", :changed?, :changed, :changes].each do |m|
|
391
383
|
record.metaclass.send :remove_method, m.to_sym
|
392
384
|
end
|
@@ -1,16 +1,12 @@
|
|
1
1
|
class HoboGenerator < Rails::Generator::Base
|
2
2
|
|
3
3
|
def manifest
|
4
|
+
if options[:add_gem]
|
5
|
+
add_to_file "config/environment.rb", "Rails::Initializer.run do |config|", " config.gem 'hobo'\n"
|
6
|
+
end
|
7
|
+
|
4
8
|
if options[:add_routes]
|
5
|
-
|
6
|
-
|
7
|
-
route = " Hobo.add_routes(map)\n"
|
8
|
-
route_src = File.read(routes_path)
|
9
|
-
unless route_src.include?(route)
|
10
|
-
head = "ActionController::Routing::Routes.draw do |map|"
|
11
|
-
route_src.sub!(head, head + "\n\n" + route)
|
12
|
-
File.open(routes_path, 'w') {|f| f.write(route_src) }
|
13
|
-
end
|
9
|
+
add_to_file "config/routes.rb", "ActionController::Routing::Routes.draw do |map|", "\n Hobo.add_routes(map)\n"
|
14
10
|
end
|
15
11
|
|
16
12
|
record do |m|
|
@@ -32,7 +28,7 @@ class HoboGenerator < Rails::Generator::Base
|
|
32
28
|
|
33
29
|
protected
|
34
30
|
def banner
|
35
|
-
"Usage: #{$0} #{spec.name} [--add-routes]"
|
31
|
+
"Usage: #{$0} #{spec.name} [--add-routes] [--add-gem]"
|
36
32
|
end
|
37
33
|
|
38
34
|
def add_options!(opt)
|
@@ -40,5 +36,17 @@ class HoboGenerator < Rails::Generator::Base
|
|
40
36
|
opt.separator 'Options:'
|
41
37
|
opt.on("--add-routes",
|
42
38
|
"Add Hobo routes to config/routes.rb") { |v| options[:add_routes] = v }
|
39
|
+
opt.on("--add-gem",
|
40
|
+
"Edit environment.rb to require the hobo gem") { |v| options[:add_gem] = v }
|
43
41
|
end
|
42
|
+
|
43
|
+
def add_to_file(filename, after_line, new_line)
|
44
|
+
filename = File.join(RAILS_ROOT, filename)
|
45
|
+
src = File.read filename
|
46
|
+
unless src.include? new_line
|
47
|
+
src.sub!(after_line, after_line + "\n" + new_line)
|
48
|
+
File.open(filename, 'w') {|f| f.write(src) }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
44
52
|
end
|
data/taglibs/rapid_forms.dryml
CHANGED
@@ -773,8 +773,8 @@ Use the `uri` option to specify a redirect location:
|
|
773
773
|
|
774
774
|
|
775
775
|
<def tag="or-cancel">
|
776
|
-
<if test="&linkable?">or <a>Cancel</a></if>
|
776
|
+
<if test="&linkable?">or <a merge-attrs>Cancel</a></if>
|
777
777
|
<else>
|
778
|
-
<if test="&linkable?(this.class)">or <a to="&this.class">Cancel</a></if>
|
778
|
+
<if test="&linkable?(this.class)">or <a to="&this.class" merge-attrs>Cancel</a></if>
|
779
779
|
</else>
|
780
780
|
</def>
|
Binary file
|
@@ -254,6 +254,18 @@ class PermissionsTest < Test::Unit::TestCase
|
|
254
254
|
assert_equal("code.zip", @r.code_example.filename)
|
255
255
|
end
|
256
256
|
|
257
|
+
should "allow the code example related to a recipe to be changed" do
|
258
|
+
r = existing_recipe @user
|
259
|
+
c1 = CodeExample.create! :filename => "exmaple1.zip"
|
260
|
+
c2 = CodeExample.create! :filename => "exmaple2.zip"
|
261
|
+
r.code_example = c1
|
262
|
+
r.save
|
263
|
+
|
264
|
+
r.user_update_attributes! @user, :code_example => "@#{c2.id}"
|
265
|
+
|
266
|
+
assert_equal(c2, r.code_example)
|
267
|
+
end
|
268
|
+
|
257
269
|
context "on an existing recipe with a code example" do
|
258
270
|
setup do
|
259
271
|
@ce = CodeExample.create! :filename => "exmaple.zip"
|
@@ -261,8 +273,11 @@ class PermissionsTest < Test::Unit::TestCase
|
|
261
273
|
end
|
262
274
|
|
263
275
|
should "allow update of the code-example" do
|
264
|
-
|
276
|
+
# To update the exsting target of a belongs_to association, the id must be included in the hash
|
277
|
+
# It is an error to provide any id other than that of the existing target
|
278
|
+
@r.user_update_attributes! @user, :code_example => { :id => @ce.id, :filename => "changed.zip" }
|
265
279
|
assert_equal("changed.zip", @r.code_example.filename)
|
280
|
+
assert_equal(@ce, @r.code_example)
|
266
281
|
end
|
267
282
|
|
268
283
|
should "allow removal of the code-example" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hobo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Locke
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-12-
|
12
|
+
date: 2008-12-09 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - "="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0.8.
|
23
|
+
version: 0.8.5
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: hobofields
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.8.
|
33
|
+
version: 0.8.5
|
34
34
|
version:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: rails
|