hobo 0.5.3
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/LICENSE.txt +22 -0
- data/README.txt +18 -0
- data/bin/hobo +81 -0
- data/hobo_files/plugin/CHANGES.txt +963 -0
- data/hobo_files/plugin/LICENSE.txt +22 -0
- data/hobo_files/plugin/README +4 -0
- data/hobo_files/plugin/Rakefile +11 -0
- data/hobo_files/plugin/generators/hobo/hobo_generator.rb +37 -0
- data/hobo_files/plugin/generators/hobo/templates/application.dryml +2 -0
- data/hobo_files/plugin/generators/hobo/templates/guest.rb +31 -0
- data/hobo_files/plugin/generators/hobo_front_controller/USAGE +11 -0
- data/hobo_files/plugin/generators/hobo_front_controller/hobo_front_controller_generator.rb +90 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/controller.rb +51 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/functional_test.rb +18 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/helper.rb +2 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +43 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/login.dryml +44 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/search.dryml +18 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/signup.dryml +45 -0
- data/hobo_files/plugin/generators/hobo_model/USAGE +26 -0
- data/hobo_files/plugin/generators/hobo_model/hobo_model_generator.rb +38 -0
- data/hobo_files/plugin/generators/hobo_model/templates/fixtures.yml +11 -0
- data/hobo_files/plugin/generators/hobo_model/templates/migration.rb +13 -0
- data/hobo_files/plugin/generators/hobo_model/templates/model.rb +24 -0
- data/hobo_files/plugin/generators/hobo_model/templates/unit_test.rb +10 -0
- data/hobo_files/plugin/generators/hobo_model_controller/USAGE +30 -0
- data/hobo_files/plugin/generators/hobo_model_controller/hobo_model_controller_generator.rb +43 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/controller.rb +5 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/functional_test.rb +18 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/helper.rb +2 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/view.rhtml +2 -0
- data/hobo_files/plugin/generators/hobo_rapid/hobo_rapid_generator.rb +51 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.js +436 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/default_mapping.rb +11 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/banner.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_bodytop.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_01.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_02.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_03.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_04.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_bottom.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_left.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_right.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_top.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_blue.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_dblue.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_green.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_purple.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_red.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/logo.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/spinner.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_dblue.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_green.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_purple.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_red.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_01.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_02.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_03.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_04.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_bottom.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_left.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_right.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_top.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/stylesheets/application.css +390 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +104 -0
- data/hobo_files/plugin/generators/hobo_user_model/USAGE +26 -0
- data/hobo_files/plugin/generators/hobo_user_model/hobo_user_model_generator.rb +38 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/fixtures.yml +11 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/migration.rb +15 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +58 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/unit_test.rb +10 -0
- data/hobo_files/plugin/init.rb +44 -0
- data/hobo_files/plugin/lib/action_view_extensions/base.rb +14 -0
- data/hobo_files/plugin/lib/active_record/has_many_association.rb +54 -0
- data/hobo_files/plugin/lib/active_record/has_many_through_association.rb +22 -0
- data/hobo_files/plugin/lib/active_record/table_definition.rb +34 -0
- data/hobo_files/plugin/lib/extensions.rb +245 -0
- data/hobo_files/plugin/lib/extensions/test_case.rb +130 -0
- data/hobo_files/plugin/lib/hobo.rb +353 -0
- data/hobo_files/plugin/lib/hobo/HtmlString +3 -0
- data/hobo_files/plugin/lib/hobo/authenticated_user.rb +106 -0
- data/hobo_files/plugin/lib/hobo/authentication_support.rb +108 -0
- data/hobo_files/plugin/lib/hobo/composite_model.rb +66 -0
- data/hobo_files/plugin/lib/hobo/controller.rb +134 -0
- data/hobo_files/plugin/lib/hobo/controller_helpers.rb +135 -0
- data/hobo_files/plugin/lib/hobo/core.rb +475 -0
- data/hobo_files/plugin/lib/hobo/define_tags.rb +56 -0
- data/hobo_files/plugin/lib/hobo/dryml.rb +161 -0
- data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +126 -0
- data/hobo_files/plugin/lib/hobo/dryml/tag_module.rb +9 -0
- data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +57 -0
- data/hobo_files/plugin/lib/hobo/dryml/template.rb +586 -0
- data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +302 -0
- data/hobo_files/plugin/lib/hobo/dryml/template_handler.rb +19 -0
- data/hobo_files/plugin/lib/hobo/generator.rb +25 -0
- data/hobo_files/plugin/lib/hobo/html_string.rb +3 -0
- data/hobo_files/plugin/lib/hobo/lazy_hash.rb +28 -0
- data/hobo_files/plugin/lib/hobo/mapping_tags.rb +262 -0
- data/hobo_files/plugin/lib/hobo/markdown_string.rb +7 -0
- data/hobo_files/plugin/lib/hobo/model.rb +391 -0
- data/hobo_files/plugin/lib/hobo/model_controller.rb +676 -0
- data/hobo_files/plugin/lib/hobo/model_queries.rb +92 -0
- data/hobo_files/plugin/lib/hobo/model_support.rb +44 -0
- data/hobo_files/plugin/lib/hobo/password_string.rb +3 -0
- data/hobo_files/plugin/lib/hobo/predicate_dispatch.rb +78 -0
- data/hobo_files/plugin/lib/hobo/proc_binding.rb +32 -0
- data/hobo_files/plugin/lib/hobo/rapid.rb +447 -0
- data/hobo_files/plugin/lib/hobo/static_tags +92 -0
- data/hobo_files/plugin/lib/hobo/text.rb +3 -0
- data/hobo_files/plugin/lib/hobo/textile_string.rb +13 -0
- data/hobo_files/plugin/lib/hobo/undefined.rb +41 -0
- data/hobo_files/plugin/lib/hobo/undefined_access_error.rb +5 -0
- data/hobo_files/plugin/lib/hobo/where_fragment.rb +23 -0
- data/hobo_files/plugin/lib/rexml.rb +345 -0
- data/hobo_files/plugin/tags/core.dryml +6 -0
- data/hobo_files/plugin/tags/rapid.dryml +177 -0
- data/hobo_files/plugin/tags/rapid_editing.dryml +168 -0
- data/hobo_files/plugin/tags/rapid_navigation.dryml +95 -0
- data/hobo_files/plugin/tags/rapid_pages.dryml +175 -0
- data/hobo_files/plugin/tasks/environments.rake +19 -0
- data/hobo_files/plugin/tasks/hobo_tasks.rake +4 -0
- data/hobo_files/plugin/test/hobo_dryml_template_test.rb +7 -0
- data/hobo_files/plugin/test/hobo_test.rb +7 -0
- data/hobo_files/plugin/uninstall.rb +1 -0
- metadata +206 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
require 'digest/sha1'
|
|
2
|
+
|
|
3
|
+
module Hobo
|
|
4
|
+
|
|
5
|
+
module AuthenticatedUser
|
|
6
|
+
|
|
7
|
+
def self.included(base)
|
|
8
|
+
base.extend(ClassMethods)
|
|
9
|
+
|
|
10
|
+
base.class_eval do
|
|
11
|
+
# Virtual attribute for the unencrypted password
|
|
12
|
+
attr_accessor :password
|
|
13
|
+
|
|
14
|
+
validates_presence_of :password, :if => :password_required?
|
|
15
|
+
validates_presence_of :password_confirmation, :if => :password_required?
|
|
16
|
+
validates_confirmation_of :password, :if => :password_required?
|
|
17
|
+
|
|
18
|
+
before_save :encrypt_password
|
|
19
|
+
|
|
20
|
+
never_show :salt, :crypted_password, :remember_token, :remember_token_expires_at
|
|
21
|
+
|
|
22
|
+
set_field_type :password => :password, :password_confirmation => :password
|
|
23
|
+
|
|
24
|
+
password_validations
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
module ClassMethods
|
|
29
|
+
|
|
30
|
+
def password_validations
|
|
31
|
+
validates_length_of :password, :within => 4..40, :if => :password_required?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def set_login_attr(attr)
|
|
35
|
+
@login_attr = attr = attr.to_sym
|
|
36
|
+
alias_attribute(:login, attr) unless attr == :login
|
|
37
|
+
|
|
38
|
+
if block_given?
|
|
39
|
+
yield
|
|
40
|
+
else
|
|
41
|
+
validates_presence_of attr
|
|
42
|
+
validates_length_of attr, :within => 3..100
|
|
43
|
+
validates_uniqueness_of attr, :case_sensitive => false
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Authenticates a user by their login name and unencrypted password. Returns the user or nil.
|
|
48
|
+
def authenticate(login, password)
|
|
49
|
+
u = find(:first, :conditions => ["#{@login_attr} = ?", login]) # need to get the salt
|
|
50
|
+
|
|
51
|
+
if u && u.authenticated?(password)
|
|
52
|
+
u.last_login_at = Time.now and u.save if u.respond_to?(:last_login_at)
|
|
53
|
+
u
|
|
54
|
+
else
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Encrypts some data with the salt.
|
|
60
|
+
def encrypt(password, salt)
|
|
61
|
+
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Encrypts the password with the user salt
|
|
67
|
+
def encrypt(password)
|
|
68
|
+
self.class.encrypt(password, salt)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def authenticated?(password)
|
|
72
|
+
crypted_password == encrypt(password)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def remember_token?
|
|
76
|
+
remember_token_expires_at && Time.now.utc < remember_token_expires_at
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# These create and unset the fields required for remembering users between browser closes
|
|
80
|
+
def remember_me
|
|
81
|
+
self.remember_token_expires_at = 2.weeks.from_now.utc
|
|
82
|
+
self.remember_token = encrypt("#{login}--#{remember_token_expires_at}")
|
|
83
|
+
save(false)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def forget_me
|
|
87
|
+
self.remember_token_expires_at = nil
|
|
88
|
+
self.remember_token = nil
|
|
89
|
+
save(false)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
protected
|
|
93
|
+
# before filter
|
|
94
|
+
def encrypt_password
|
|
95
|
+
return if password.blank?
|
|
96
|
+
self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
|
|
97
|
+
self.crypted_password = encrypt(password)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def password_required?
|
|
101
|
+
(crypted_password.blank? && password != nil) || !password.blank?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
module Hobo
|
|
2
|
+
|
|
3
|
+
module AuthenticationSupport
|
|
4
|
+
|
|
5
|
+
# Filter method to enforce a login requirement.
|
|
6
|
+
def logged_in?
|
|
7
|
+
not current_user.guest?
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Check if the user is authorized.
|
|
11
|
+
#
|
|
12
|
+
# Override this method in your controllers if you want to restrict access
|
|
13
|
+
# to only a few actions or if you want to check if the user
|
|
14
|
+
# has the correct rights.
|
|
15
|
+
#
|
|
16
|
+
# Example:
|
|
17
|
+
#
|
|
18
|
+
# # only allow nonbobs
|
|
19
|
+
# def authorize?
|
|
20
|
+
# current_user.login != "bob"
|
|
21
|
+
# end
|
|
22
|
+
def authorized?
|
|
23
|
+
true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
# To require logins for all actions, use this in your controllers:
|
|
28
|
+
#
|
|
29
|
+
# before_filter :login_required
|
|
30
|
+
#
|
|
31
|
+
# To require logins for specific actions, use this in your controllers:
|
|
32
|
+
#
|
|
33
|
+
# before_filter :login_required, :only => [ :edit, :update ]
|
|
34
|
+
#
|
|
35
|
+
# To skip this in a subclassed controller:
|
|
36
|
+
#
|
|
37
|
+
# skip_before_filter :login_required
|
|
38
|
+
#
|
|
39
|
+
def login_required
|
|
40
|
+
if current_user.guest?
|
|
41
|
+
username, passwd = get_auth_data
|
|
42
|
+
self.current_user = Hobo.user_model.authenticate(username, passwd) || :false if username && passwd
|
|
43
|
+
end
|
|
44
|
+
logged_in? && authorized? ? true : access_denied
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Redirect as appropriate when an access request fails.
|
|
48
|
+
#
|
|
49
|
+
# The default action is to redirect to the login screen.
|
|
50
|
+
#
|
|
51
|
+
# Override this method in your controllers if you want to have special
|
|
52
|
+
# behavior in case the user is not authorized
|
|
53
|
+
# to access the requested action. For example, a popup window might
|
|
54
|
+
# simply close itself.
|
|
55
|
+
def access_denied
|
|
56
|
+
respond_to do |accepts|
|
|
57
|
+
accepts.html do
|
|
58
|
+
store_location
|
|
59
|
+
redirect_to login_url
|
|
60
|
+
end
|
|
61
|
+
accepts.xml do
|
|
62
|
+
headers["Status"] = "Unauthorized"
|
|
63
|
+
headers["WWW-Authenticate"] = %(Basic realm="Web Password")
|
|
64
|
+
render :text => "Could't authenticate you", :status => '401 Unauthorized'
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
false
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Store the URI of the current request in the session.
|
|
71
|
+
#
|
|
72
|
+
# We can return to this location by calling #redirect_back_or_default.
|
|
73
|
+
def store_location
|
|
74
|
+
session[:return_to] = request.request_uri
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Redirect to the URI stored by the most recent store_location call or
|
|
78
|
+
# to the passed default.
|
|
79
|
+
def redirect_back_or_default(default)
|
|
80
|
+
session[:return_to] ? redirect_to_url(session[:return_to]) : redirect_to(default)
|
|
81
|
+
session[:return_to] = nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# When called with before_filter :login_from_cookie will check for an :auth_token
|
|
85
|
+
# cookie and log the user back in if apropriate
|
|
86
|
+
def login_from_cookie
|
|
87
|
+
return unless cookies[:auth_token] && !logged_in?
|
|
88
|
+
user = Hobo.user_model.find_by_remember_token(cookies[:auth_token])
|
|
89
|
+
if user && user.remember_token?
|
|
90
|
+
user.remember_me
|
|
91
|
+
self.current_user = user
|
|
92
|
+
cookies[:auth_token] = { :value => self.current_user.remember_token ,
|
|
93
|
+
:expires => self.current_user.remember_token_expires_at }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
@@http_auth_headers = %w(X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION Authorization)
|
|
99
|
+
# gets BASIC auth info
|
|
100
|
+
def get_auth_data
|
|
101
|
+
auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
|
|
102
|
+
auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
|
|
103
|
+
return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Hobo
|
|
2
|
+
|
|
3
|
+
class CompositeModel
|
|
4
|
+
|
|
5
|
+
include ModelSupport
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
|
|
9
|
+
def find(id)
|
|
10
|
+
ids = id.split('_')
|
|
11
|
+
new(*ids.map_with_index{|id, i| @models[i].constantize.find(id)})
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def compose(*models)
|
|
15
|
+
@models = models.omap{to_s.camelize}
|
|
16
|
+
attr_reader *models
|
|
17
|
+
CompositeModel.composites ||= {}
|
|
18
|
+
CompositeModel.composites[@models.sort] = self.name
|
|
19
|
+
|
|
20
|
+
Hobo.register_model(self)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attr_accessor :composites
|
|
24
|
+
|
|
25
|
+
attr_reader :models
|
|
26
|
+
|
|
27
|
+
def new_for(objects)
|
|
28
|
+
classes = objects.map{|o| o.class.name}.sort
|
|
29
|
+
composite_class = CompositeModel.composites[classes].constantize rescue
|
|
30
|
+
(raise ArgumentError, "No composite model for #{classes.inspect}")
|
|
31
|
+
composite_class.new(*objects)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def initialize(*objects)
|
|
38
|
+
objects.each do |obj|
|
|
39
|
+
raise ArgumentError, "invalid objects for composition: #{objects.inspect}" unless
|
|
40
|
+
obj.class.name.in? self.class.models
|
|
41
|
+
instance_variable_set("@#{obj.class.name.underscore}", obj)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def compose_with(object, use=nil)
|
|
47
|
+
self_classes = use ? use.models : self.class.models
|
|
48
|
+
from_self = (self_classes - [object.class.name]).map {|classname| send(classname.underscore)}
|
|
49
|
+
CompositeModel.new_for(from_self + [object])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def typed_id
|
|
54
|
+
"#{self.class.name.underscore}_#{id}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def id
|
|
59
|
+
objects = self.class.models.map {|m| instance_variable_get("@#{m.underscore}")}
|
|
60
|
+
objects.omap{id}.join("_")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
module Hobo
|
|
2
|
+
|
|
3
|
+
module Controller
|
|
4
|
+
|
|
5
|
+
include ControllerHelpers
|
|
6
|
+
|
|
7
|
+
include AuthenticationSupport
|
|
8
|
+
|
|
9
|
+
def self.included(base)
|
|
10
|
+
if base.is_a?(Class)
|
|
11
|
+
Hobo::ControllerHelpers.public_instance_methods.each {|m| base.hide_action(m)}
|
|
12
|
+
base.class_eval do
|
|
13
|
+
alias_method_chain :redirect_to, :object_url
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
protected
|
|
20
|
+
|
|
21
|
+
def redirect_to_with_object_url(destination, view=nil)
|
|
22
|
+
if destination.is_a?(String, Hash, Symbol)
|
|
23
|
+
redirect_to_without_object_url(destination)
|
|
24
|
+
else
|
|
25
|
+
redirect_to_without_object_url(object_url(destination, view))
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def hobo_ajax_response(this=nil, results={})
|
|
30
|
+
this ||= @this
|
|
31
|
+
part_page = params[:part_page]
|
|
32
|
+
r = params[:render]
|
|
33
|
+
if r
|
|
34
|
+
ajax_update_response(this, part_page, r.values, results)
|
|
35
|
+
true
|
|
36
|
+
else
|
|
37
|
+
false
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def ajax_update_response(this, part_page, render_specs, results={})
|
|
43
|
+
before_ajax if respond_to? :before_ajax
|
|
44
|
+
add_variables_to_assigns
|
|
45
|
+
renderer = Hobo::Dryml.page_renderer(@template, [], part_page) if part_page
|
|
46
|
+
|
|
47
|
+
render :update do |page|
|
|
48
|
+
page << "var _update = typeof Hobo == 'undefined' ? Element.update : Hobo.updateElement;"
|
|
49
|
+
for spec in render_specs
|
|
50
|
+
function = spec[:function] || "_update"
|
|
51
|
+
|
|
52
|
+
if spec[:as] or spec[:part]
|
|
53
|
+
obj = if spec[:object] == "this" or spec[:object].blank?
|
|
54
|
+
this
|
|
55
|
+
elsif spec[:object] == "nil"
|
|
56
|
+
nil
|
|
57
|
+
else
|
|
58
|
+
Hobo.object_from_dom_id(spec[:object])
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
if spec[:as]
|
|
62
|
+
part_content = render(:partial => (Hobo::ModelController.find_partial(obj.class, spec[:as])),
|
|
63
|
+
:locals => { :this => obj })
|
|
64
|
+
page.call(function, spec[:id], part_content)
|
|
65
|
+
|
|
66
|
+
elsif spec[:part]
|
|
67
|
+
dom_id = spec[:id] || spec[:part]
|
|
68
|
+
part_content = renderer.call_part(dom_id, spec[:part], obj)
|
|
69
|
+
page.call(function, dom_id, part_content)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
elsif spec[:result]
|
|
73
|
+
result = results[spec[:result].to_sym]
|
|
74
|
+
page.call(function, spec[:id], result)
|
|
75
|
+
|
|
76
|
+
else
|
|
77
|
+
# spec didn't specify any action :-/
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
if renderer
|
|
81
|
+
renderer.part_contexts.each_pair do |dom_id, p|
|
|
82
|
+
part_id, model_id = p
|
|
83
|
+
page.assign "hoboParts.#{dom_id}", [part_id, model_id]
|
|
84
|
+
|
|
85
|
+
# not sure why this isn't happending automatically
|
|
86
|
+
# but it's messing up ARTS, so chuck a newline in
|
|
87
|
+
page << "\n"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def render_tag(tag, options={})
|
|
95
|
+
add_variables_to_assigns
|
|
96
|
+
render :text => Hobo::Dryml.render_tag(@template, tag, options), :layout => false
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def render_tags(objects, tag, options={})
|
|
101
|
+
add_variables_to_assigns
|
|
102
|
+
dryml_renderer = Hobo::Dryml.empty_page_renderer(@template)
|
|
103
|
+
render :text => objects.map {|o| dryml_renderer.send(tag, options.merge(:obj => o))}.join +
|
|
104
|
+
dryml_renderer.part_contexts_js
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def site_search(query)
|
|
109
|
+
results = Hobo.find_by_search(query).select {|r| Hobo.can_view?(current_user, r, nil)}
|
|
110
|
+
if results.empty?
|
|
111
|
+
render :text => "<p>Your search returned no matches.</p>"
|
|
112
|
+
else
|
|
113
|
+
render_tags(results, "tag_for_object", :name => "search_result")
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# Store the given user in the session.
|
|
119
|
+
def current_user=(new_user)
|
|
120
|
+
session[:user] = (new_user.nil? || new_user.is_a?(Symbol)) ? nil : new_user.id
|
|
121
|
+
@current_user = new_user
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def request_no_cache?
|
|
126
|
+
request.env['HTTP_CACHE_CONTROL'] =~ /max-age=\s*0/
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def not_found
|
|
130
|
+
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
module Hobo::ControllerHelpers
|
|
2
|
+
|
|
3
|
+
protected
|
|
4
|
+
|
|
5
|
+
def current_user
|
|
6
|
+
# simple one-hit-per-request cache
|
|
7
|
+
@current_user or
|
|
8
|
+
@current_user = if Hobo.user_model and session and id = session[:user]
|
|
9
|
+
Hobo.user_model.find(id)
|
|
10
|
+
else
|
|
11
|
+
Guest.new
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def logged_in?
|
|
17
|
+
not current_user.guest?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def urlb
|
|
22
|
+
request.relative_url_root
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def controller_for(obj)
|
|
27
|
+
if obj.is_a? Class
|
|
28
|
+
obj.name.underscore.pluralize
|
|
29
|
+
else
|
|
30
|
+
obj.class.name.underscore.pluralize
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def object_url(obj, action=nil, *param_hashes)
|
|
36
|
+
action &&= action.to_s
|
|
37
|
+
|
|
38
|
+
controller_name = controller_for(obj)
|
|
39
|
+
|
|
40
|
+
parts = if obj.is_a? Class
|
|
41
|
+
[urlb, controller_name]
|
|
42
|
+
|
|
43
|
+
elsif obj.is_a? Hobo::CompositeModel
|
|
44
|
+
[urlb, controller_name, obj.id]
|
|
45
|
+
|
|
46
|
+
elsif obj.is_a? ActiveRecord::Base
|
|
47
|
+
if obj.new_record?
|
|
48
|
+
[urlb, controller_name]
|
|
49
|
+
else
|
|
50
|
+
raise HoboError.new("invalid object url: new for existing object") if action == "new"
|
|
51
|
+
|
|
52
|
+
klass = obj.class
|
|
53
|
+
id = if klass.id_name?
|
|
54
|
+
obj.id_name(true)
|
|
55
|
+
else
|
|
56
|
+
obj.id
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
[urlb, controller_name, id]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
elsif obj.is_a? Array # warning - this breaks if we use `case/when Array`
|
|
63
|
+
owner = obj.proxy_owner
|
|
64
|
+
new_model = obj.proxy_reflection.klass
|
|
65
|
+
[object_url(owner), obj.proxy_reflection.name]
|
|
66
|
+
|
|
67
|
+
else
|
|
68
|
+
raise HoboError.new("cannot create url for #{obj.inspect} (#{obj.class})")
|
|
69
|
+
end
|
|
70
|
+
basic = parts.join("/")
|
|
71
|
+
|
|
72
|
+
controller = (controller_name.camelize + "Controller").constantize rescue nil
|
|
73
|
+
url = if action && controller && action.to_sym.in?(controller.web_methods)
|
|
74
|
+
basic + "/#{action}"
|
|
75
|
+
else
|
|
76
|
+
case action
|
|
77
|
+
when "new"
|
|
78
|
+
basic + "/new"
|
|
79
|
+
when "destroy"
|
|
80
|
+
basic + "?_method=DELETE"
|
|
81
|
+
when "update"
|
|
82
|
+
basic + "?_method=PUT"
|
|
83
|
+
when nil
|
|
84
|
+
basic
|
|
85
|
+
else
|
|
86
|
+
basic + ";" + action
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
params = make_params(*param_hashes)
|
|
90
|
+
params.blank? ? url : url + "?" + params
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _as_params(name, obj)
|
|
95
|
+
if obj.is_a? Array
|
|
96
|
+
obj.map {|x| _as_params("#{name}[]", x)}.join("&")
|
|
97
|
+
elsif obj.is_a? Hash
|
|
98
|
+
obj.map {|k,v| _as_params("#{name}[#{k}]", v)}.join("&")
|
|
99
|
+
elsif obj.is_a? Hobo::RawJs
|
|
100
|
+
"#{name}=' + #{obj} + '"
|
|
101
|
+
else
|
|
102
|
+
v = if obj.is_a?(ActiveRecord::Base) or obj.is_a?(Array)
|
|
103
|
+
"@" + dom_id(obj)
|
|
104
|
+
else
|
|
105
|
+
obj.to_s.gsub("'"){"\\'"}
|
|
106
|
+
end
|
|
107
|
+
"#{name}=#{v}"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def make_params(*hashes)
|
|
113
|
+
hash = {}
|
|
114
|
+
hashes.each {|h| hash.update(h) if h}
|
|
115
|
+
hash.map {|k,v| _as_params(k, v)}.join("&")
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def dom_id(x, attr=nil)
|
|
120
|
+
Hobo.dom_id(x, attr)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# debugging support
|
|
125
|
+
|
|
126
|
+
def debug(*args)
|
|
127
|
+
logger.debug(args.map{|arg| PP.pp(arg, "")}.join("\n"))
|
|
128
|
+
return args.first
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def abort_with(*args)
|
|
132
|
+
raise args.map{|arg| PP.pp(arg, "")}.join("\n")
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
end
|