hobo 0.6 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/hobo +2 -3
- data/hobo_files/plugin/CHANGES.txt +139 -0
- data/hobo_files/plugin/generators/hobo_front_controller/hobo_front_controller_generator.rb +1 -8
- data/hobo_files/plugin/generators/hobo_front_controller/templates/controller.rb +1 -39
- data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +2 -2
- data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +27 -7
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.js +1 -2
- data/hobo_files/plugin/generators/hobo_user_controller/USAGE +34 -0
- data/hobo_files/plugin/generators/hobo_user_controller/hobo_user_controller_generator.rb +43 -0
- data/hobo_files/plugin/generators/hobo_user_controller/templates/controller.rb +5 -0
- data/hobo_files/plugin/generators/hobo_user_controller/templates/functional_test.rb +18 -0
- data/hobo_files/plugin/generators/hobo_user_controller/templates/helper.rb +2 -0
- data/hobo_files/plugin/generators/hobo_user_controller/templates/view.rhtml +2 -0
- data/hobo_files/plugin/init.rb +6 -2
- data/hobo_files/plugin/lib/extensions.rb +28 -41
- data/hobo_files/plugin/lib/hobo.rb +37 -17
- data/hobo_files/plugin/lib/hobo/authentication_support.rb +25 -10
- data/hobo_files/plugin/lib/hobo/composite_model.rb +2 -2
- data/hobo_files/plugin/lib/hobo/controller.rb +8 -34
- data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +1 -1
- data/hobo_files/plugin/lib/hobo/dryml/part_context.rb +103 -0
- data/hobo_files/plugin/lib/hobo/dryml/template.rb +10 -11
- data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +29 -72
- data/hobo_files/plugin/lib/hobo/hobo_helper.rb +11 -10
- data/hobo_files/plugin/lib/hobo/migrations.rb +12 -0
- data/hobo_files/plugin/lib/hobo/model.rb +3 -3
- data/hobo_files/plugin/lib/hobo/model_controller.rb +3 -3
- data/hobo_files/plugin/lib/hobo/rapid_helper.rb +3 -3
- data/hobo_files/plugin/lib/hobo/user_controller.rb +80 -0
- data/hobo_files/plugin/tags/rapid.dryml +36 -20
- data/hobo_files/plugin/tags/rapid_editing.dryml +4 -5
- data/hobo_files/plugin/tags/rapid_forms.dryml +6 -6
- data/hobo_files/plugin/tags/rapid_navigation.dryml +7 -5
- data/hobo_files/plugin/tags/rapid_pages.dryml +116 -10
- data/hobo_files/plugin/tags/rapid_support.dryml +23 -0
- metadata +13 -5
- data/hobo_files/plugin/generators/hobo_front_controller/templates/login.dryml +0 -42
- data/hobo_files/plugin/generators/hobo_front_controller/templates/signup.dryml +0 -43
- data/hobo_files/plugin/lib/hobo/mapping_tags.rb +0 -262
@@ -70,13 +70,40 @@ class Module
|
|
70
70
|
end
|
71
71
|
|
72
72
|
module Kernel
|
73
|
-
|
73
|
+
|
74
74
|
def extract_options_from_args!(args) #:nodoc:
|
75
75
|
args.last.is_a?(Hash) ? args.pop : {}
|
76
76
|
end
|
77
77
|
|
78
|
+
def it() It.new end
|
79
|
+
alias its it
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
class It
|
85
|
+
|
86
|
+
undef_method(*(instance_methods - %w*__id__ __send__*))
|
87
|
+
|
88
|
+
def initialize
|
89
|
+
@methods = []
|
90
|
+
end
|
91
|
+
|
92
|
+
def method_missing(*args, &block)
|
93
|
+
@methods << [args, block] unless args == [:respond_to?, :to_proc]
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_proc
|
98
|
+
lambda do |obj|
|
99
|
+
@methods.inject(obj) do |current,(args,block)|
|
100
|
+
current.send(*args, &block)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
78
104
|
end
|
79
105
|
|
106
|
+
|
80
107
|
class Object
|
81
108
|
|
82
109
|
def in?(array)
|
@@ -112,30 +139,6 @@ end
|
|
112
139
|
|
113
140
|
module Enumerable
|
114
141
|
|
115
|
-
def omap(method = nil, &b)
|
116
|
-
if method
|
117
|
-
map(&method)
|
118
|
-
else
|
119
|
-
map {|x| x.instance_eval(&b)}
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def oselect(method = nil, &b)
|
124
|
-
if method
|
125
|
-
select(&method)
|
126
|
-
else
|
127
|
-
select {|x| x.instance_eval(&b)}
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
def ofind(method=nil, &b)
|
132
|
-
if method
|
133
|
-
find(&method)
|
134
|
-
else
|
135
|
-
find {|x| x.instance_eval(&b)}
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
142
|
def search(not_found=nil)
|
140
143
|
each do |x|
|
141
144
|
val = yield(x)
|
@@ -144,22 +147,6 @@ module Enumerable
|
|
144
147
|
not_found
|
145
148
|
end
|
146
149
|
|
147
|
-
def oany?(method=nil, &b)
|
148
|
-
if method
|
149
|
-
any?(&method)
|
150
|
-
else
|
151
|
-
any? {|x| x.instance_eval(&b)}
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def oall?(method=nil, &b)
|
156
|
-
if method
|
157
|
-
all?(&method)
|
158
|
-
else
|
159
|
-
all? {|x| x.instance_eval(&b)}
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
150
|
def every(proc)
|
164
151
|
map(&proc)
|
165
152
|
end
|
@@ -16,7 +16,7 @@ module Hobo
|
|
16
16
|
field_types.index(type)
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
19
|
+
def type_id(type)
|
20
20
|
symbolic_type_name(type) || type.name.underscore.gsub("/", "__")
|
21
21
|
end
|
22
22
|
|
@@ -52,7 +52,7 @@ module Hobo
|
|
52
52
|
end
|
53
53
|
@models_loaded = true
|
54
54
|
end
|
55
|
-
@models.
|
55
|
+
@models.every(:constantize)
|
56
56
|
end
|
57
57
|
|
58
58
|
|
@@ -64,21 +64,25 @@ module Hobo
|
|
64
64
|
def object_from_dom_id(dom_id)
|
65
65
|
return nil if dom_id == 'nil'
|
66
66
|
|
67
|
-
_, name, id, attr = *dom_id.match(/^([a-z_]+)_([0-9]+(?:_[0-9]+)*)(_[a-z_]+)?$/)
|
67
|
+
_, name, id, attr = *dom_id.match(/^([a-z_]+)(?:_([0-9]+(?:_[0-9]+)*))?(?:_([a-z_]+))?$/)
|
68
68
|
raise ArgumentError.new("invalid model-reference in dom id") unless name
|
69
69
|
if name
|
70
70
|
model_class = name.camelize.constantize rescue (raise ArgumentError.new("no such class in dom-id"))
|
71
71
|
return nil unless model_class
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
72
|
+
|
73
|
+
if id
|
74
|
+
obj = if false and attr and model_class.reflections[attr.to_sym].klass.superclass == ActiveRecord::Base
|
75
|
+
# DISABLED - Eager loading is broken - doesn't support ordering
|
76
|
+
# http://dev.rubyonrails.org/ticket/3438
|
77
|
+
# Don't do this for STI subclasses - it breaks!
|
78
|
+
model_class.find(id, :include => attr)
|
79
|
+
else
|
80
|
+
model_class.find(id)
|
81
|
+
end
|
82
|
+
attr ? obj.send(attr) : obj
|
83
|
+
else
|
84
|
+
model_class
|
85
|
+
end
|
82
86
|
end
|
83
87
|
end
|
84
88
|
|
@@ -91,6 +95,8 @@ module Hobo
|
|
91
95
|
if obj.is_a?(Array) and obj.respond_to?(:proxy_owner)
|
92
96
|
attr = obj.proxy_reflection.name
|
93
97
|
obj = obj.proxy_owner
|
98
|
+
elsif obj.is_a?(Class)
|
99
|
+
return type_id(obj)
|
94
100
|
elsif !obj.respond_to?(:typed_id)
|
95
101
|
if attr
|
96
102
|
return dom_id(get_field(obj, attr))
|
@@ -133,7 +139,13 @@ module Hobo
|
|
133
139
|
end
|
134
140
|
|
135
141
|
def add_routes(map)
|
136
|
-
|
142
|
+
begin
|
143
|
+
ActiveRecord::Base.connection.reconnect! unless ActiveRecord::Base.connection.active?
|
144
|
+
rescue
|
145
|
+
# No database, no routes
|
146
|
+
return
|
147
|
+
end
|
148
|
+
|
137
149
|
require "#{RAILS_ROOT}/app/controllers/application" unless Object.const_defined? :ApplicationController
|
138
150
|
require "#{RAILS_ROOT}/app/assemble.rb" if File.exists? "#{RAILS_ROOT}/app/assemble.rb"
|
139
151
|
|
@@ -150,9 +162,8 @@ module Hobo
|
|
150
162
|
map.connect "#{web_name}/:id", :controller => web_name, :action => 'show'
|
151
163
|
|
152
164
|
elsif controller < Hobo::ModelController
|
153
|
-
|
154
165
|
map.resources web_name, :collection => { :completions => :get }
|
155
|
-
|
166
|
+
|
156
167
|
for collection in controller.collections
|
157
168
|
new_method = Hobo.simple_has_many_association?(model.reflections[collection])
|
158
169
|
Hobo.add_collection_routes(map, web_name, collection, new_method)
|
@@ -173,6 +184,15 @@ module Hobo
|
|
173
184
|
:action => view.to_s,
|
174
185
|
:conditions => { :method => :get })
|
175
186
|
end
|
187
|
+
|
188
|
+
if controller < Hobo::UserController
|
189
|
+
map.named_route("#{web_name.singularize}_login", "#{web_name.singularize}_login",
|
190
|
+
:controller => web_name, :action => 'login')
|
191
|
+
map.named_route("#{web_name.singularize}_logout", "#{web_name.singularize}_logout",
|
192
|
+
:controller => web_name, :action => 'logout')
|
193
|
+
map.named_route("#{web_name.singularize}_signup", "#{web_name.singularize}_signup",
|
194
|
+
:controller => web_name, :action => 'signup')
|
195
|
+
end
|
176
196
|
end
|
177
197
|
end
|
178
198
|
end
|
@@ -337,7 +357,7 @@ module Hobo
|
|
337
357
|
else
|
338
358
|
File.join(File.dirname(__FILE__), "hobo/static_tags")
|
339
359
|
end
|
340
|
-
File.readlines(path).
|
360
|
+
File.readlines(path).every(:chop)
|
341
361
|
end
|
342
362
|
end
|
343
363
|
|
@@ -36,12 +36,17 @@ module Hobo
|
|
36
36
|
#
|
37
37
|
# skip_before_filter :login_required
|
38
38
|
#
|
39
|
-
def login_required
|
40
|
-
if current_user.guest?
|
39
|
+
def login_required(user_model=nil)
|
40
|
+
if current_user.guest?
|
41
|
+
auth_model = user_model || UserController.user_models.first
|
41
42
|
username, passwd = get_auth_data
|
42
|
-
self.current_user =
|
43
|
+
self.current_user = auth_model.authenticate(username, passwd) || :false if username && passwd && auth_model
|
44
|
+
end
|
45
|
+
if logged_in? && authorized? && (user_model.nil? || current_user.is_a?(user_model))
|
46
|
+
true
|
47
|
+
else
|
48
|
+
access_denied
|
43
49
|
end
|
44
|
-
logged_in? && authorized? ? true : access_denied
|
45
50
|
end
|
46
51
|
|
47
52
|
# Redirect as appropriate when an access request fails.
|
@@ -84,16 +89,22 @@ module Hobo
|
|
84
89
|
# When called with before_filter :login_from_cookie will check for an :auth_token
|
85
90
|
# cookie and log the user back in if apropriate
|
86
91
|
def login_from_cookie
|
87
|
-
return unless cookies[:auth_token] && !logged_in?
|
92
|
+
return unless (token = cookies[:auth_token]) && !logged_in?
|
88
93
|
|
89
|
-
|
94
|
+
user_model = token[:user_model].constantize
|
95
|
+
user = user_model.find_by_remember_token(token)
|
90
96
|
if user && user.remember_token?
|
91
97
|
user.remember_me
|
92
|
-
|
93
|
-
|
94
|
-
:expires => self.current_user.remember_token_expires_at }
|
98
|
+
current_user = user
|
99
|
+
create_auth_cookie
|
95
100
|
end
|
96
101
|
end
|
102
|
+
|
103
|
+
def create_auth_cookie
|
104
|
+
cookies[:auth_token] = { :value => current_user.remember_token ,
|
105
|
+
:expires => current_user.remember_token_expires_at,
|
106
|
+
:user_model => current_user.model }
|
107
|
+
end
|
97
108
|
|
98
109
|
private
|
99
110
|
@@http_auth_headers = %w(X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION Authorization)
|
@@ -101,7 +112,11 @@ module Hobo
|
|
101
112
|
def get_auth_data
|
102
113
|
auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
|
103
114
|
auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
|
104
|
-
|
115
|
+
username, pw = if auth_data && auth_data[0] == 'Basic'
|
116
|
+
Base64.decode64(auth_data[1]).split(':')[0..1]
|
117
|
+
else
|
118
|
+
[nil, nil]
|
119
|
+
end
|
105
120
|
end
|
106
121
|
|
107
122
|
end
|
@@ -12,7 +12,7 @@ module Hobo
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def compose(*models)
|
15
|
-
@models = models.
|
15
|
+
@models = models.map &it.to_s.camelize
|
16
16
|
attr_reader *models
|
17
17
|
CompositeModel.composites ||= {}
|
18
18
|
CompositeModel.composites[@models.sort] = self.name
|
@@ -57,7 +57,7 @@ module Hobo
|
|
57
57
|
|
58
58
|
def id
|
59
59
|
objects = self.class.models.map {|m| instance_variable_get("@#{m.underscore}")}
|
60
|
-
objects.
|
60
|
+
objects.every(:id).join("_")
|
61
61
|
end
|
62
62
|
|
63
63
|
end
|
@@ -56,7 +56,6 @@ module Hobo
|
|
56
56
|
|
57
57
|
|
58
58
|
def ajax_update_response(this, part_page, render_specs, results={})
|
59
|
-
before_ajax if respond_to? :before_ajax
|
60
59
|
add_variables_to_assigns
|
61
60
|
renderer = Hobo::Dryml.page_renderer(@template, [], part_page) if part_page
|
62
61
|
|
@@ -64,45 +63,20 @@ module Hobo
|
|
64
63
|
page << "var _update = typeof Hobo == 'undefined' ? Element.update : Hobo.updateElement;"
|
65
64
|
for spec in render_specs
|
66
65
|
function = spec[:function] || "_update"
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
else
|
74
|
-
Hobo.object_from_dom_id(spec[:object])
|
75
|
-
end
|
76
|
-
|
77
|
-
if spec[:as]
|
78
|
-
part_content = render(:partial => (Hobo::ModelController.find_partial(obj.class, spec[:as])),
|
79
|
-
:locals => { :this => obj })
|
80
|
-
page.call(function, spec[:id], part_content)
|
81
|
-
|
82
|
-
elsif spec[:part]
|
83
|
-
dom_id = spec[:id] || spec[:part]
|
84
|
-
part_content = renderer.call_part(dom_id, spec[:part], obj)
|
85
|
-
page.call(function, dom_id, part_content)
|
86
|
-
end
|
87
|
-
|
66
|
+
dom_id = spec[:id]
|
67
|
+
|
68
|
+
if spec[:part_context]
|
69
|
+
part_name, part_this, locals = Dryml::PartContext.unmarshal(spec[:part_context], this, session)
|
70
|
+
part_content = renderer.call_part(dom_id, part_name, part_this, *locals)
|
71
|
+
page.call(function, dom_id, part_content)
|
88
72
|
elsif spec[:result]
|
89
73
|
result = results[spec[:result].to_sym]
|
90
74
|
page.call(function, spec[:id], result)
|
91
|
-
|
92
75
|
else
|
93
76
|
# spec didn't specify any action :-/
|
94
77
|
end
|
95
78
|
end
|
96
|
-
if renderer
|
97
|
-
renderer.part_contexts.each_pair do |dom_id, p|
|
98
|
-
part_id, model_id = p
|
99
|
-
page.assign "hoboParts.#{dom_id}", [part_id, model_id]
|
100
|
-
|
101
|
-
# not sure why this isn't happending automatically
|
102
|
-
# but it's messing up ARTS, so chuck a newline in
|
103
|
-
page << "\n"
|
104
|
-
end
|
105
|
-
end
|
79
|
+
page << renderer.part_contexts_storage if renderer
|
106
80
|
end
|
107
81
|
end
|
108
82
|
|
@@ -140,7 +114,7 @@ module Hobo
|
|
140
114
|
|
141
115
|
# Store the given user in the session.
|
142
116
|
def current_user=(new_user)
|
143
|
-
session[:user] = (new_user.nil? || new_user.is_a?(Symbol)) ? nil : new_user.
|
117
|
+
session[:user] = (new_user.nil? || new_user.is_a?(Symbol)) ? nil : new_user.typed_id
|
144
118
|
@current_user = new_user
|
145
119
|
end
|
146
120
|
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Hobo
|
2
|
+
|
3
|
+
module Dryml
|
4
|
+
|
5
|
+
# Raised when the part context fails its integrity check.
|
6
|
+
class PartContext
|
7
|
+
|
8
|
+
class TamperedWithPartContext < StandardError; end
|
9
|
+
|
10
|
+
class Id < String; end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :secret, :digest
|
14
|
+
end
|
15
|
+
self.digest = 'SHA1'
|
16
|
+
|
17
|
+
|
18
|
+
def self.client_side_storage(contexts, session)
|
19
|
+
return "" if contexts.empty?
|
20
|
+
|
21
|
+
contexts.map do |dom_id, context|
|
22
|
+
code = context.marshal(session).split("\n").map{|line| "'#{line}\\n'"}.join(" +\n ")
|
23
|
+
"hoboParts.#{dom_id} = (#{code})\n"
|
24
|
+
end.join
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def initialize(part_name, this_id, locals)
|
29
|
+
@part_name = part_name
|
30
|
+
@this_id = this_id
|
31
|
+
@locals = locals.map {|l| pre_marshal(l) }
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def pre_marshal(x)
|
36
|
+
if x.is_a?(ActiveRecord::Base) && x.respond_to?(:typed_id)
|
37
|
+
Id.new(x.typed_id)
|
38
|
+
else
|
39
|
+
x
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def marshal(session)
|
45
|
+
context = [@part_name, @this_id, @locals]
|
46
|
+
puts "STORE: " + context.inspect
|
47
|
+
data = Base64.encode64(Marshal.dump(context)).strip
|
48
|
+
"#{data}--#{self.class.generate_digest(data, session)}"
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
class << self
|
53
|
+
|
54
|
+
# Generate the HMAC keyed message digest. Uses SHA1 by default.
|
55
|
+
def generate_digest(data, session)
|
56
|
+
secret = self.secret || ActionController::Base.cached_session_options.first[:secret]
|
57
|
+
key = secret.respond_to?(:call) ? secret.call(session) : secret
|
58
|
+
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(digest), key, data)
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# Unmarshal part context to a hash and verify its integrity.
|
63
|
+
def unmarshal(client_store, this, session)
|
64
|
+
data, digest = CGI.unescape(client_store).strip.split('--')
|
65
|
+
|
66
|
+
raise TamperedWithPartContext unless digest == generate_digest(data, session)
|
67
|
+
|
68
|
+
part_name, this_id, locals = Marshal.load(Base64.decode64(data))
|
69
|
+
puts "RESTORE: " + [part_name, this_id, locals].inspect
|
70
|
+
|
71
|
+
x = [part_name, restore_part_this(this_id, this), restore_locals(locals)]
|
72
|
+
puts this_id, x.inspect
|
73
|
+
x
|
74
|
+
end
|
75
|
+
|
76
|
+
def restore_part_this(this_id, this)
|
77
|
+
if this_id == "this" or this_id.blank?
|
78
|
+
this
|
79
|
+
elsif this_id == "nil"
|
80
|
+
nil
|
81
|
+
else
|
82
|
+
Hobo.object_from_dom_id(this_id)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def restore_locals(locals)
|
88
|
+
locals.map do |l|
|
89
|
+
if l.is_a?(Id)
|
90
|
+
Hobo.object_from_dom_id(l)
|
91
|
+
else
|
92
|
+
l
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|