hobo 0.7.2 → 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/hobo +24 -7
- data/hobo_files/plugin/CHANGES.txt +501 -0
- data/hobo_files/plugin/generators/hobo/hobo_generator.rb +8 -6
- data/hobo_files/plugin/generators/hobo/templates/application.dryml +3 -0
- data/hobo_files/plugin/generators/hobo/templates/dryml-support.js +132 -0
- data/hobo_files/plugin/generators/hobo_front_controller/hobo_front_controller_generator.rb +4 -5
- data/hobo_files/plugin/generators/hobo_model_resource/hobo_model_resource_generator.rb +75 -0
- data/hobo_files/plugin/generators/hobo_model_resource/templates/controller.rb +7 -0
- data/hobo_files/plugin/generators/hobo_model_resource/templates/functional_test.rb +8 -0
- data/hobo_files/plugin/generators/hobo_model_resource/templates/helper.rb +2 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo-rapid.js +30 -11
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/application.css +149 -92
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +0 -48
- data/hobo_files/plugin/init.rb +45 -13
- data/hobo_files/plugin/lib/action_view_extensions/base.rb +4 -3
- data/hobo_files/plugin/lib/active_record/association_proxy.rb +18 -0
- data/hobo_files/plugin/lib/active_record/association_reflection.rb +5 -0
- data/hobo_files/plugin/lib/active_record/has_many_association.rb +7 -11
- data/hobo_files/plugin/lib/active_record/has_many_through_association.rb +8 -0
- data/hobo_files/plugin/lib/extensions/test_case.rb +1 -1
- data/hobo_files/plugin/lib/hobo.rb +38 -60
- data/hobo_files/plugin/lib/hobo/authentication_support.rb +1 -1
- data/hobo_files/plugin/lib/hobo/bundle.rb +131 -34
- data/hobo_files/plugin/lib/hobo/composite_model.rb +1 -1
- data/hobo_files/plugin/lib/hobo/controller.rb +7 -8
- data/hobo_files/plugin/lib/hobo/dev_controller.rb +21 -0
- data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +14 -8
- data/hobo_files/plugin/lib/hobo/dryml/dryml_support_controller.rb +13 -0
- data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +6 -7
- data/hobo_files/plugin/lib/hobo/dryml/template.rb +207 -73
- data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +67 -55
- data/hobo_files/plugin/lib/hobo/dryml/template_handler.rb +53 -3
- data/hobo_files/plugin/lib/hobo/hobo_helper.rb +75 -107
- data/hobo_files/plugin/lib/hobo/model.rb +236 -429
- data/hobo_files/plugin/lib/hobo/model_controller.rb +277 -437
- data/hobo_files/plugin/lib/hobo/model_router.rb +62 -29
- data/hobo_files/plugin/lib/hobo/rapid_helper.rb +48 -9
- data/hobo_files/plugin/lib/hobo/scopes.rb +98 -0
- data/hobo_files/plugin/lib/hobo/scopes/association_proxy_extensions.rb +31 -0
- data/hobo_files/plugin/lib/hobo/scopes/automatic_scopes.rb +282 -0
- data/hobo_files/plugin/lib/hobo/scopes/defined_scope_proxy_extender.rb +88 -0
- data/hobo_files/plugin/lib/hobo/scopes/scope_reflection.rb +18 -0
- data/hobo_files/plugin/lib/hobo/scopes/scoped_proxy.rb +59 -0
- data/hobo_files/plugin/lib/hobo/undefined.rb +2 -0
- data/hobo_files/plugin/lib/hobo/user.rb +31 -14
- data/hobo_files/plugin/lib/hobo/user_controller.rb +41 -27
- data/hobo_files/plugin/taglibs/core.dryml +9 -11
- data/hobo_files/plugin/taglibs/rapid.dryml +51 -108
- data/hobo_files/plugin/taglibs/rapid_editing.dryml +25 -25
- data/hobo_files/plugin/taglibs/rapid_forms.dryml +111 -79
- data/hobo_files/plugin/taglibs/rapid_generics.dryml +74 -0
- data/hobo_files/plugin/taglibs/rapid_navigation.dryml +23 -21
- data/hobo_files/plugin/taglibs/rapid_pages.dryml +83 -169
- data/hobo_files/plugin/taglibs/rapid_plus.dryml +16 -2
- data/hobo_files/plugin/taglibs/rapid_support.dryml +3 -3
- data/hobo_files/plugin/taglibs/rapid_user_pages.dryml +104 -0
- metadata +60 -55
- data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +0 -276
- data/hobo_files/plugin/generators/hobo_migration/templates/migration.rb +0 -9
- data/hobo_files/plugin/lib/active_record/table_definition.rb +0 -34
- data/hobo_files/plugin/lib/extensions.rb +0 -375
- data/hobo_files/plugin/lib/hobo/email_address.rb +0 -12
- data/hobo_files/plugin/lib/hobo/enum_string.rb +0 -50
- data/hobo_files/plugin/lib/hobo/field_declaration_dsl.rb +0 -43
- data/hobo_files/plugin/lib/hobo/field_spec.rb +0 -68
- data/hobo_files/plugin/lib/hobo/html_string.rb +0 -7
- data/hobo_files/plugin/lib/hobo/lazy_hash.rb +0 -40
- data/hobo_files/plugin/lib/hobo/markdown_string.rb +0 -11
- data/hobo_files/plugin/lib/hobo/migrations.rb +0 -12
- data/hobo_files/plugin/lib/hobo/model_queries.rb +0 -117
- data/hobo_files/plugin/lib/hobo/password_string.rb +0 -7
- data/hobo_files/plugin/lib/hobo/percentage.rb +0 -14
- data/hobo_files/plugin/lib/hobo/predicate_dispatch.rb +0 -78
- data/hobo_files/plugin/lib/hobo/proc_binding.rb +0 -32
- data/hobo_files/plugin/lib/hobo/text.rb +0 -3
- data/hobo_files/plugin/lib/hobo/textile_string.rb +0 -25
- data/hobo_files/plugin/lib/hobo/where_fragment.rb +0 -28
@@ -0,0 +1,88 @@
|
|
1
|
+
module Hobo
|
2
|
+
|
3
|
+
module Scopes
|
4
|
+
|
5
|
+
module DefinedScopeProxyExtender
|
6
|
+
|
7
|
+
attr_accessor :reflections
|
8
|
+
|
9
|
+
include AutomaticScopes
|
10
|
+
|
11
|
+
def method_missing(name, *args, &block)
|
12
|
+
if (scope = named_scope(name))
|
13
|
+
association_proxy_for_scope(name, scope, args)
|
14
|
+
elsif member_class.create_automatic_scope(name)
|
15
|
+
# create_automatic_scope returned true -- the method now exists
|
16
|
+
send(name, *args, &block)
|
17
|
+
else
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def named_scope(name)
|
24
|
+
proxy_reflection.klass.try.defined_scopes._?[name.to_sym]
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def association_proxy_for_scope(name, scope_or_proc, args)
|
29
|
+
if scope_or_proc.is_a?(Proc)
|
30
|
+
scope = scope_or_proc.call(*args)
|
31
|
+
create_association_proxy_for_scope(name, scope)
|
32
|
+
else
|
33
|
+
# This scope is not parameterised so we can cache the
|
34
|
+
# association-proxy in an instance variable
|
35
|
+
scope = scope_or_proc
|
36
|
+
scope_ivar = "@#{name.to_s.gsub('?','')}_scope"
|
37
|
+
|
38
|
+
# Some craziness here -- calling instance_variable_get or
|
39
|
+
# set directly causes self to get loaded, hence the 'bind'
|
40
|
+
# tricks
|
41
|
+
Kernel.instance_method(:instance_variable_get).bind(self).call(scope_ivar) or
|
42
|
+
begin
|
43
|
+
assoc = create_association_proxy_for_scope(name, scope)
|
44
|
+
Kernel.instance_method(:instance_variable_set).bind(self).call(scope_ivar, assoc)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def create_association_proxy_for_scope(name, scope)
|
51
|
+
options = proxy_reflection.options
|
52
|
+
has_many_conditions = options[:conditions]
|
53
|
+
has_many_conditions = nil if has_many_conditions.blank?
|
54
|
+
source = proxy_reflection.source_reflection
|
55
|
+
scope_conditions = scope[:conditions]
|
56
|
+
scope_conditions = nil if scope_conditions.blank?
|
57
|
+
conditions = if has_many_conditions && scope_conditions
|
58
|
+
"(#{sanitize_sql scope_conditions}) AND (#{sanitize_sql has_many_conditions})"
|
59
|
+
else
|
60
|
+
scope_conditions || has_many_conditions
|
61
|
+
end
|
62
|
+
|
63
|
+
options = options.merge(scope).update(:class_name => proxy_reflection.klass.name,
|
64
|
+
:foreign_key => proxy_reflection.primary_key_name)
|
65
|
+
options[:conditions] = conditions unless conditions.blank?
|
66
|
+
options[:source] = source.name if source
|
67
|
+
|
68
|
+
options[:limit] = scope[:limit] if scope[:limit]
|
69
|
+
options[:order] = scope[:order] if scope[:order]
|
70
|
+
options[:include] = scope[:include] if scope[:include]
|
71
|
+
|
72
|
+
r = ScopeReflection.new(:has_many, name, options, proxy_owner.class, proxy_reflection.name)
|
73
|
+
|
74
|
+
@reflections ||= {}
|
75
|
+
@reflections[name] = r
|
76
|
+
|
77
|
+
if source
|
78
|
+
ActiveRecord::Associations::HasManyThroughAssociation
|
79
|
+
else
|
80
|
+
ActiveRecord::Associations::HasManyAssociation
|
81
|
+
end.new(proxy_owner, r)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Hobo
|
2
|
+
|
3
|
+
module Scopes
|
4
|
+
|
5
|
+
class ScopeReflection < ActiveRecord::Reflection::AssociationReflection
|
6
|
+
|
7
|
+
def initialize(macro, name, options, klass, association_name)
|
8
|
+
super(macro, name, options, klass)
|
9
|
+
@association_name = association_name
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :association_name
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Hobo
|
2
|
+
|
3
|
+
module Scopes
|
4
|
+
|
5
|
+
class ScopedProxy
|
6
|
+
|
7
|
+
#include AutomaticScopes
|
8
|
+
|
9
|
+
def initialize(klass, scope)
|
10
|
+
@klass = klass
|
11
|
+
@scope = scope
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def method_missing(name, *args, &block)
|
16
|
+
if name.to_sym.in?(@klass.defined_scopes.keys) || @klass.create_automatic_scope(name)
|
17
|
+
proxy = @klass.send(name, *args)
|
18
|
+
proxy.instance_variable_set("@parent_scope", self)
|
19
|
+
proxy
|
20
|
+
else
|
21
|
+
_apply_scope { @klass.send(name, *args, &block) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def all
|
26
|
+
self.find(:all)
|
27
|
+
end
|
28
|
+
|
29
|
+
def first
|
30
|
+
self.find(:first)
|
31
|
+
end
|
32
|
+
|
33
|
+
def member_class
|
34
|
+
@klass
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def _apply_scope
|
39
|
+
if @parent_scope
|
40
|
+
@parent_scope.send(:_apply_scope) do
|
41
|
+
@scope ? @klass.send(:with_scope, :find => @scope) { yield } : yield
|
42
|
+
end
|
43
|
+
else
|
44
|
+
@scope ? @klass.send(:with_scope, :find => @scope) { yield } : yield
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
(Object.instance_methods +
|
50
|
+
Object.private_instance_methods +
|
51
|
+
Object.protected_instance_methods).each do |m|
|
52
|
+
ScopedProxy.send(:undef_method, m) unless
|
53
|
+
m.in?(%w{initialize method_missing send instance_variable_set instance_variable_get puts}) || m.starts_with?('_')
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -4,6 +4,12 @@ module Hobo
|
|
4
4
|
|
5
5
|
module User
|
6
6
|
|
7
|
+
@user_models = []
|
8
|
+
|
9
|
+
def self.default_user_model
|
10
|
+
@user_models.first._?.constantize
|
11
|
+
end
|
12
|
+
|
7
13
|
AUTHENTICATION_FIELDS = [:salt, :crypted_password, :remember_token, :remember_token_expires_at]
|
8
14
|
|
9
15
|
# Extend the base class with AuthenticatedUser functionality
|
@@ -12,9 +18,12 @@ module Hobo
|
|
12
18
|
# - plaintext password validation
|
13
19
|
# - login token for rembering a login during multiple browser sessions
|
14
20
|
def self.included(base)
|
21
|
+
@user_models << base.name
|
22
|
+
|
15
23
|
base.extend(ClassMethods)
|
16
24
|
|
17
25
|
base.class_eval do
|
26
|
+
|
18
27
|
fields do
|
19
28
|
crypted_password :string, :limit => 40
|
20
29
|
salt :string, :limit => 40
|
@@ -22,21 +31,20 @@ module Hobo
|
|
22
31
|
remember_token_expires_at :datetime
|
23
32
|
end
|
24
33
|
|
25
|
-
|
26
|
-
attr_accessor :password
|
34
|
+
validates_confirmation_of :password, :if => :password_required?
|
27
35
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
36
|
+
# Virtual attributes for setting and changing the password
|
37
|
+
attr_accessor :current_password, :password, :password_confirmation, :type => :password
|
38
|
+
|
39
|
+
|
40
|
+
validate :validate_current_password_when_changing_password
|
41
|
+
|
32
42
|
before_save :encrypt_password
|
33
43
|
|
34
44
|
never_show *AUTHENTICATION_FIELDS
|
35
45
|
|
36
46
|
attr_protected *AUTHENTICATION_FIELDS
|
37
47
|
|
38
|
-
set_field_type :password => :password, :password_confirmation => :password
|
39
|
-
|
40
48
|
password_validations
|
41
49
|
end
|
42
50
|
end
|
@@ -50,23 +58,22 @@ module Hobo
|
|
50
58
|
end
|
51
59
|
|
52
60
|
def login_attribute=(attr, validate=true)
|
53
|
-
@
|
61
|
+
@login_attribute = attr = attr.to_sym
|
54
62
|
unless attr == :login
|
55
63
|
alias_attribute(:login, attr)
|
56
|
-
|
64
|
+
declare_attr_type(:login, attr_type(attr)) if table_exists? # this breaks if the table doesn't exist
|
57
65
|
end
|
58
66
|
|
59
67
|
if validate
|
60
|
-
validates_presence_of attr
|
61
68
|
validates_length_of attr, :within => 3..100
|
62
69
|
validates_uniqueness_of attr, :case_sensitive => false
|
63
70
|
end
|
64
71
|
end
|
65
|
-
attr_reader :
|
72
|
+
attr_reader :login_attribute
|
66
73
|
|
67
74
|
# Authenticates a user by their login name and unencrypted password. Returns the user or nil.
|
68
75
|
def authenticate(login, password)
|
69
|
-
u = find(:first, :conditions => ["#{@
|
76
|
+
u = find(:first, :conditions => ["#{@login_attribute} = ?", login]) # need to get the salt
|
70
77
|
|
71
78
|
if u && u.authenticated?(password)
|
72
79
|
if u.respond_to?(:last_login_at) || u.respond_to?(:login_count)
|
@@ -125,6 +132,10 @@ module Hobo
|
|
125
132
|
false
|
126
133
|
end
|
127
134
|
|
135
|
+
def changing_password?
|
136
|
+
crypted_password? && (password || password_confirmation)
|
137
|
+
end
|
138
|
+
|
128
139
|
protected
|
129
140
|
# Before filter that encrypts the password before having it stored in the database.
|
130
141
|
def encrypt_password
|
@@ -133,9 +144,15 @@ module Hobo
|
|
133
144
|
self.crypted_password = encrypt(password)
|
134
145
|
end
|
135
146
|
|
147
|
+
|
136
148
|
# Is a password required for login? (or do we have an empty password?)
|
137
149
|
def password_required?
|
138
|
-
(crypted_password.blank? && password != nil) || !password.blank?
|
150
|
+
(crypted_password.blank? && password != nil) || !password.blank? || changing_password?
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
def validate_current_password_when_changing_password
|
155
|
+
changing_password? && !authenticated?(current_password) and errors.add :current_password, "is not correct"
|
139
156
|
end
|
140
157
|
|
141
158
|
end
|
@@ -2,15 +2,18 @@ module Hobo
|
|
2
2
|
|
3
3
|
module UserController
|
4
4
|
|
5
|
-
@user_models = []
|
6
|
-
|
7
5
|
class << self
|
8
|
-
attr_reader :user_models
|
9
|
-
|
10
6
|
def included(base)
|
11
|
-
base.
|
12
|
-
|
13
|
-
|
7
|
+
base.class_eval do
|
8
|
+
filter_parameter_logging "password"
|
9
|
+
skip_before_filter :login_required, :only => [:login, :signup]
|
10
|
+
|
11
|
+
include_taglib "rapid_user_pages", :plugin => "hobo"
|
12
|
+
|
13
|
+
show_action :account
|
14
|
+
|
15
|
+
alias_method_chain :hobo_update, :account_flash
|
16
|
+
end
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
@@ -20,9 +23,10 @@ module Hobo
|
|
20
23
|
|
21
24
|
def logout; hobo_logout; end
|
22
25
|
|
26
|
+
private
|
27
|
+
|
23
28
|
def hobo_login(options={})
|
24
|
-
|
25
|
-
login_attr = model.login_attr.to_s.titleize.downcase
|
29
|
+
login_attr = model.login_attribute.to_s.titleize.downcase
|
26
30
|
options.reverse_merge!(:success_notice => "You have logged in.",
|
27
31
|
:failure_notice => "You did not provide a valid #{login_attr} and password.")
|
28
32
|
|
@@ -36,10 +40,12 @@ module Hobo
|
|
36
40
|
|
37
41
|
# If supplied, a block can be used to test if this user is
|
38
42
|
# allowed to log in (e.g. the account may be disabled)
|
39
|
-
|
43
|
+
account_available = block_given? ? yield : true
|
44
|
+
|
45
|
+
if !account_available
|
40
46
|
# block returned false - cancel this login
|
41
47
|
self.current_user = old_user
|
42
|
-
|
48
|
+
render :action => :account_disabled unless performed?
|
43
49
|
else
|
44
50
|
if params[:remember_me] == "1"
|
45
51
|
current_user.remember_me
|
@@ -50,30 +56,21 @@ module Hobo
|
|
50
56
|
end
|
51
57
|
end
|
52
58
|
end
|
53
|
-
|
54
|
-
hobo_render unless performed?
|
55
59
|
end
|
56
60
|
|
57
61
|
|
58
62
|
def hobo_signup(&b)
|
59
63
|
if request.post?
|
60
|
-
|
61
|
-
|
62
|
-
save_and_set_status!(@user)
|
63
|
-
self.current_user = @user if valid?
|
64
|
+
self.this = model.user_create(current_user, params[model.name.underscore])
|
65
|
+
self.current_user = this if valid?
|
64
66
|
response_block(&b) or
|
65
67
|
if valid?
|
66
68
|
flash[:notice] ||= "Thanks for signing up!"
|
67
69
|
redirect_back_or_default(home_page)
|
68
|
-
elsif invalid?
|
69
|
-
hobo_render
|
70
|
-
elsif not_allowed?
|
71
|
-
permission_denied
|
72
70
|
end
|
73
71
|
else
|
74
|
-
|
72
|
+
self.this = model.new
|
75
73
|
yield if block_given?
|
76
|
-
hobo_render unless performed?
|
77
74
|
end
|
78
75
|
end
|
79
76
|
|
@@ -81,15 +78,32 @@ module Hobo
|
|
81
78
|
def hobo_logout(options={})
|
82
79
|
options = options.reverse_merge(:notice => "You have logged out.",
|
83
80
|
:redirect_to => base_url)
|
84
|
-
|
85
|
-
|
86
|
-
cookies.delete :auth_token
|
87
|
-
reset_session
|
81
|
+
|
82
|
+
logout_current_user
|
88
83
|
yield if block_given?
|
89
84
|
flash[:notice] ||= options[:notice]
|
90
85
|
redirect_back_or_default(options[:redirect_to]) unless performed?
|
91
86
|
end
|
92
87
|
|
88
|
+
|
89
|
+
def hobo_update_with_account_flash(*args)
|
90
|
+
hobo_update_without_account_flash(*args) do
|
91
|
+
flash[:notice] = "Changes to your account were saved" if valid? && @this == current_user
|
92
|
+
yield if block_given?
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def logout_current_user
|
99
|
+
if logged_in?
|
100
|
+
current_user.forget_me
|
101
|
+
cookies.delete :auth_token
|
102
|
+
reset_session
|
103
|
+
self.current_user = nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
93
107
|
end
|
94
108
|
|
95
109
|
end
|
@@ -3,9 +3,9 @@
|
|
3
3
|
</def>
|
4
4
|
|
5
5
|
|
6
|
-
<def tag="wrap" attrs="tag, when">
|
7
|
-
<%
|
8
|
-
<%= when_ ?
|
6
|
+
<def tag="wrap" attrs="tag, when, parameter">
|
7
|
+
<% parameter ||= :default %>
|
8
|
+
<%= when_ ? send(tag, attributes, { parameter.to_sym => parameters[:default] }) : parameter.default %>
|
9
9
|
</def>
|
10
10
|
|
11
11
|
|
@@ -15,8 +15,8 @@
|
|
15
15
|
%></def>
|
16
16
|
|
17
17
|
|
18
|
-
<def tag="repeat" attrs="even-odd, join"
|
19
|
-
if
|
18
|
+
<def tag="repeat" attrs="even-odd, join">
|
19
|
+
<if><%=
|
20
20
|
if even_odd
|
21
21
|
map_this do
|
22
22
|
klass = [attributes[:class], cycle("even", "odd")].compact.join(' ')
|
@@ -31,15 +31,13 @@
|
|
31
31
|
res
|
32
32
|
end.join(join)
|
33
33
|
end
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
%></def>
|
34
|
+
end %>
|
35
|
+
</if>
|
36
|
+
</def>
|
39
37
|
|
40
38
|
|
41
39
|
<def tag="do"><%= parameters.default %></def>
|
42
|
-
<def tag="with"
|
40
|
+
<def tag="with" alias-of="do"/>
|
43
41
|
|
44
42
|
|
45
43
|
<def tag="if" attrs="test"><%=
|