hobo 0.8.10 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +126 -2
- data/Rakefile +4 -1
- data/bin/hobo +1 -1
- data/doctest/scopes.rdoctest +11 -4
- data/dryml_generators/rapid/cards.dryml.erb +8 -2
- data/dryml_generators/rapid/forms.dryml.erb +5 -4
- data/dryml_generators/rapid/pages.dryml.erb +150 -65
- data/lib/hobo.rb +1 -1
- data/lib/hobo/accessible_associations.rb +2 -0
- data/lib/hobo/authentication_support.rb +1 -1
- data/lib/hobo/controller.rb +11 -3
- data/lib/hobo/dryml/dryml_doc.rb +1 -1
- data/lib/hobo/fake_initializer.rb +14 -0
- data/lib/hobo/hobo_helper.rb +94 -6
- data/lib/hobo/lifecycles.rb +17 -2
- data/lib/hobo/lifecycles/lifecycle.rb +1 -1
- data/lib/hobo/lifecycles/transition.rb +12 -4
- data/lib/hobo/model.rb +25 -22
- data/lib/hobo/model_controller.rb +42 -37
- data/lib/hobo/model_router.rb +11 -7
- data/lib/hobo/permissions.rb +12 -10
- data/lib/hobo/permissions/associations.rb +1 -1
- data/lib/hobo/static_tags +21 -0
- data/lib/hobo/user.rb +7 -3
- data/lib/hobo/user_controller.rb +7 -7
- data/lib/hobo/view_hints.rb +10 -3
- data/rails_generators/hobo/USAGE +4 -0
- data/rails_generators/hobo_admin_site/USAGE +16 -0
- data/rails_generators/hobo_front_controller/hobo_front_controller_generator.rb +11 -2
- data/rails_generators/hobo_front_controller/templates/controller.rb +6 -0
- data/rails_generators/hobo_front_controller/templates/summary.dryml +103 -0
- data/rails_generators/hobo_model_resource/USAGE +38 -0
- data/rails_generators/hobo_rapid/USAGE +3 -0
- data/rails_generators/hobo_rapid/templates/hobo-rapid.js +7 -3
- data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/clean.css +4 -0
- data/rails_generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +5 -0
- data/rails_generators/hobo_subsite/USAGE +16 -0
- data/rails_generators/hobo_subsite/hobo_subsite_generator.rb +1 -1
- data/rails_generators/hobo_user_controller/templates/controller.rb +2 -2
- data/rails_generators/hobo_user_model/templates/model.rb +6 -1
- data/taglibs/rapid.dryml +1 -0
- data/taglibs/rapid_core.dryml +4 -4
- data/taglibs/rapid_forms.dryml +29 -21
- data/taglibs/rapid_generics.dryml +3 -1
- data/taglibs/rapid_lifecycles.dryml +14 -9
- data/taglibs/rapid_navigation.dryml +1 -1
- data/taglibs/rapid_plus.dryml +1 -0
- data/taglibs/rapid_summary.dryml +300 -0
- data/taglibs/rapid_support.dryml +1 -1
- data/taglibs/rapid_user_pages.dryml +21 -19
- data/test/permissions/test_permissions.rb +1 -1
- metadata +12 -4
data/lib/hobo/model_router.rb
CHANGED
@@ -227,14 +227,14 @@ module Hobo
|
|
227
227
|
def lifecycle_routes
|
228
228
|
model::Lifecycle.creators.values.where.publishable?.*.name.each do |creator|
|
229
229
|
linkable_route("do_#{singular}_#{creator}", "#{plural}/#{creator}", "do_#{creator}",
|
230
|
-
:conditions => { :method => :post }, :
|
231
|
-
linkable_route("#{singular}_#{creator}", "#{plural}/#{creator}", creator, :conditions => { :method => :get }
|
230
|
+
:conditions => { :method => :post }, :linkable_action => creator)
|
231
|
+
linkable_route("#{singular}_#{creator}", "#{plural}/#{creator}", creator, :conditions => { :method => :get })
|
232
232
|
end
|
233
233
|
model::Lifecycle.transitions.where.publishable?.*.name.each do |transition|
|
234
234
|
linkable_route("do_#{singular}_#{transition}", "#{plural}/:id/#{transition}", "do_#{transition}",
|
235
|
-
:conditions => { :method => :put }, :
|
235
|
+
:conditions => { :method => :put }, :linkable_action => transition)
|
236
236
|
linkable_route("#{singular}_#{transition}", "#{plural}/:id/#{transition}", transition,
|
237
|
-
:conditions => { :method => :get }
|
237
|
+
:conditions => { :method => :get })
|
238
238
|
end
|
239
239
|
end
|
240
240
|
|
@@ -252,9 +252,13 @@ module Hobo
|
|
252
252
|
options.reverse_merge!(:controller => route_with_subsite(plural))
|
253
253
|
name = name_with_subsite(name)
|
254
254
|
route = route_with_subsite(route)
|
255
|
-
|
256
|
-
|
257
|
-
|
255
|
+
if HoboSupport::RAILS_AT_LEAST_23
|
256
|
+
map.named_route(name, "#{route}.:format", options)
|
257
|
+
else
|
258
|
+
# kick it old-skool
|
259
|
+
map.named_route(name, route, options)
|
260
|
+
map.named_route("formatted_#{name}", "#{route}.:format", options)
|
261
|
+
end
|
258
262
|
true
|
259
263
|
else
|
260
264
|
false
|
data/lib/hobo/permissions.rb
CHANGED
@@ -46,7 +46,7 @@ module Hobo
|
|
46
46
|
r.set_creator user
|
47
47
|
yield r if block_given?
|
48
48
|
r.user_view(user)
|
49
|
-
r.send :callback, :after_user_new
|
49
|
+
r.with_acting_user(user) { r.send :callback, :after_user_new }
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -75,7 +75,7 @@ module Hobo
|
|
75
75
|
def viewable_by?(user, attribute=nil)
|
76
76
|
new.viewable_by?(user, attribute)
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
end
|
80
80
|
|
81
81
|
|
@@ -190,9 +190,9 @@ module Hobo
|
|
190
190
|
if attribute
|
191
191
|
attribute = attribute.to_s.sub(/\?$/, '').to_sym
|
192
192
|
|
193
|
-
# Try the attribute-
|
193
|
+
# Try the attribute-specific edit-permission method if there is one
|
194
194
|
if has_hobo_method?(meth = "#{attribute}_edit_permitted?")
|
195
|
-
with_acting_user(user) { send(meth) }
|
195
|
+
return with_acting_user(user) { send(meth) }
|
196
196
|
end
|
197
197
|
|
198
198
|
# No setter = no edit permission
|
@@ -375,20 +375,22 @@ module Hobo
|
|
375
375
|
end
|
376
376
|
end
|
377
377
|
end
|
378
|
-
|
378
|
+
|
379
379
|
# Best. Name. Ever
|
380
|
-
def deunknownify_attribute(attr)
|
380
|
+
def deunknownify_attribute(attr, remove_globals = true)
|
381
381
|
attr = attr.to_sym
|
382
|
-
|
382
|
+
|
383
383
|
metaclass.send :remove_method, attr
|
384
|
-
|
384
|
+
|
385
385
|
if (refl = self.class.reflections[attr]) && refl.macro == :belongs_to
|
386
386
|
# A belongs_to -- restore the underlying fields
|
387
387
|
deunknownify_attribute refl.primary_key_name
|
388
|
-
deunknownify_attribute
|
388
|
+
deunknownify_attribute(refl.options[:foreign_type], false) if refl.options[:polymorphic]
|
389
389
|
else
|
390
390
|
# A regular field -- restore the dirty tracking methods
|
391
|
-
|
391
|
+
# if remove_globals is false, skip the top-level methods, as we have already removed them
|
392
|
+
to_remove = remove_globals ? [:changed?, :changed, :changes] : []
|
393
|
+
(["#{attr}_change", "#{attr}_was", "#{attr}_changed?"] + to_remove).each do |m|
|
392
394
|
metaclass.send :remove_method, m.to_sym
|
393
395
|
end
|
394
396
|
end
|
data/lib/hobo/static_tags
CHANGED
@@ -2,6 +2,8 @@ abbr
|
|
2
2
|
acronym
|
3
3
|
address
|
4
4
|
applet
|
5
|
+
article
|
6
|
+
audio
|
5
7
|
b
|
6
8
|
basefont
|
7
9
|
bdo
|
@@ -9,14 +11,20 @@ big
|
|
9
11
|
blockquote
|
10
12
|
body
|
11
13
|
button
|
14
|
+
canvas
|
12
15
|
caption
|
13
16
|
center
|
14
17
|
cite
|
15
18
|
code
|
16
19
|
colgroup
|
20
|
+
command
|
21
|
+
datagrid
|
22
|
+
datalist
|
17
23
|
dd
|
18
24
|
del
|
25
|
+
details
|
19
26
|
dfn
|
27
|
+
dialog
|
20
28
|
dir
|
21
29
|
div
|
22
30
|
dl
|
@@ -24,6 +32,7 @@ dt
|
|
24
32
|
em
|
25
33
|
embed
|
26
34
|
fieldset
|
35
|
+
figure
|
27
36
|
font
|
28
37
|
frameset
|
29
38
|
h1
|
@@ -33,6 +42,7 @@ h4
|
|
33
42
|
h5
|
34
43
|
h6
|
35
44
|
head
|
45
|
+
hgroup
|
36
46
|
i
|
37
47
|
iframe
|
38
48
|
ins
|
@@ -42,21 +52,30 @@ label
|
|
42
52
|
legend
|
43
53
|
li
|
44
54
|
map
|
55
|
+
mark
|
45
56
|
menu
|
57
|
+
meter
|
58
|
+
nav
|
46
59
|
noframes
|
47
60
|
noscript
|
48
61
|
object
|
49
62
|
ol
|
50
63
|
optgroup
|
51
64
|
option
|
65
|
+
output
|
52
66
|
p
|
53
67
|
pre
|
68
|
+
progress
|
54
69
|
q
|
70
|
+
rp
|
71
|
+
rt
|
72
|
+
ruby
|
55
73
|
s
|
56
74
|
samp
|
57
75
|
script
|
58
76
|
select
|
59
77
|
small
|
78
|
+
source
|
60
79
|
span
|
61
80
|
strike
|
62
81
|
strong
|
@@ -69,9 +88,11 @@ textarea
|
|
69
88
|
tfoot
|
70
89
|
th
|
71
90
|
thead
|
91
|
+
time
|
72
92
|
title
|
73
93
|
tr
|
74
94
|
tt
|
75
95
|
u
|
76
96
|
ul
|
77
97
|
var
|
98
|
+
video
|
data/lib/hobo/user.rb
CHANGED
@@ -37,6 +37,10 @@ module Hobo
|
|
37
37
|
validate :validate_current_password_when_changing_password
|
38
38
|
|
39
39
|
# Virtual attributes for setting and changing the password
|
40
|
+
# note that :password_confirmation= is also defined by
|
41
|
+
# validates_confirmation_of, so this line must follow any
|
42
|
+
# validates_confirmation_of statements.
|
43
|
+
# https://hobo.lighthouseapp.com/projects/8324-hobo/tickets/530
|
40
44
|
attr_accessor :current_password, :password, :password_confirmation, :type => :password
|
41
45
|
|
42
46
|
before_save :encrypt_password
|
@@ -70,7 +74,7 @@ module Hobo
|
|
70
74
|
end
|
71
75
|
end
|
72
76
|
|
73
|
-
|
77
|
+
inheriting_cattr_reader :login_attribute
|
74
78
|
|
75
79
|
|
76
80
|
# Authenticates a user by their login name and unencrypted password. Returns the user or nil.
|
@@ -153,7 +157,7 @@ module Hobo
|
|
153
157
|
|
154
158
|
|
155
159
|
def lifecycle_changing_password?
|
156
|
-
lifecycle.active_step && :password.in?(lifecycle.active_step.parameters)
|
160
|
+
self.class.has_lifecycle? && lifecycle.active_step && :password.in?(lifecycle.active_step.parameters)
|
157
161
|
end
|
158
162
|
|
159
163
|
# Is a new password (and confirmation) required? (i.e. signing up or changing password)
|
@@ -163,7 +167,7 @@ module Hobo
|
|
163
167
|
|
164
168
|
|
165
169
|
def validate_current_password_when_changing_password
|
166
|
-
changing_password? && !authenticated?(current_password) and errors.add :current_password, "is not correct"
|
170
|
+
changing_password? && !authenticated?(current_password) and errors.add :current_password, ht(:hobo.messages.current_password_is_not_correct, :default["is not correct"])
|
167
171
|
end
|
168
172
|
|
169
173
|
end
|
data/lib/hobo/user_controller.rb
CHANGED
@@ -57,8 +57,8 @@ module Hobo
|
|
57
57
|
(redirect_to home_page; return) if logged_in?
|
58
58
|
|
59
59
|
login_attr = model.login_attribute.to_s.titleize.downcase
|
60
|
-
options.reverse_merge!(:success_notice => "You have logged in.",
|
61
|
-
:failure_notice => "You did not provide a valid #{login_attr} and password.")
|
60
|
+
options.reverse_merge!(:success_notice => ht(:"users.messages.login.success", :default=>["You have logged in."]),
|
61
|
+
:failure_notice => ht(:"users.messages.login.error", :login=>login_attr, :default=>["You did not provide a valid #{login_attr} and password."]))
|
62
62
|
|
63
63
|
if request.post?
|
64
64
|
user = model.authenticate(params[:login], params[:password])
|
@@ -97,8 +97,8 @@ module Hobo
|
|
97
97
|
def hobo_do_signup(&b)
|
98
98
|
do_creator_action(:signup) do
|
99
99
|
if valid?
|
100
|
-
flash[:notice] = "Thanks for signing up!"
|
101
|
-
flash[:notice] << " You must activate your account before you can log in. Please check your email." unless this.account_active?
|
100
|
+
flash[:notice] = ht(:"users.messages.signup.success", :default=>["Thanks for signing up!"])
|
101
|
+
flash[:notice] << ht(:"users.messages.signup.must_activate", :default=>[" You must activate your account before you can log in. Please check your email."]) unless this.account_active?
|
102
102
|
end
|
103
103
|
response_block(&b) or if valid?
|
104
104
|
if this.account_active?
|
@@ -111,7 +111,7 @@ module Hobo
|
|
111
111
|
|
112
112
|
|
113
113
|
def hobo_logout(options={})
|
114
|
-
options = options.reverse_merge(:notice => "You have logged out.",
|
114
|
+
options = options.reverse_merge(:notice => ht(:"users.messages.logout", :default=>["You have logged out."]),
|
115
115
|
:redirect_to => base_url)
|
116
116
|
|
117
117
|
logout_current_user
|
@@ -136,7 +136,7 @@ module Hobo
|
|
136
136
|
do_transition_action :reset_password do
|
137
137
|
response_block(&b) or if valid?
|
138
138
|
self.current_user = this
|
139
|
-
flash[:notice] = "Your password has been reset"
|
139
|
+
flash[:notice] = ht(:"users.messages.reset_password", :default=>["Your password has been reset"])
|
140
140
|
redirect_to home_page
|
141
141
|
end
|
142
142
|
end
|
@@ -145,7 +145,7 @@ module Hobo
|
|
145
145
|
|
146
146
|
def hobo_update_with_account_flash(*args)
|
147
147
|
hobo_update_without_account_flash(*args) do
|
148
|
-
flash[:notice] = "Changes to your account were saved" if valid? && @this == current_user
|
148
|
+
flash[:notice] = ht(:"users.messages.update.success", :default=>["Changes to your account were saved"]) if valid? && @this == current_user
|
149
149
|
yield if block_given?
|
150
150
|
end
|
151
151
|
end
|
data/lib/hobo/view_hints.rb
CHANGED
@@ -18,7 +18,7 @@ module Hobo
|
|
18
18
|
val
|
19
19
|
else
|
20
20
|
arg = if block
|
21
|
-
|
21
|
+
instance_exec(*args, &block)
|
22
22
|
else
|
23
23
|
args.first
|
24
24
|
end
|
@@ -43,9 +43,16 @@ module Hobo
|
|
43
43
|
model < ActiveRecord::Acts::List::InstanceMethods &&
|
44
44
|
model.new.try.scope_condition == "1 = 1" }
|
45
45
|
|
46
|
-
|
46
|
+
setter :inline_booleans, [] do |*args|
|
47
|
+
if args[0] == true
|
48
|
+
model.columns.select { |c| c.type == :boolean }.*.name
|
49
|
+
else
|
50
|
+
args.*.to_s
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
47
54
|
# Accessors
|
48
|
-
|
55
|
+
|
49
56
|
class << self
|
50
57
|
|
51
58
|
def model
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Description:
|
2
|
+
|
3
|
+
Creates a subsite, a namespaced section of your application.
|
4
|
+
|
5
|
+
The subsite will use app/views/taglibs/<subsite_name>_site.dryml
|
6
|
+
instead of app/views/taglibs/appplication.dryml. This allows you
|
7
|
+
to easily set different themes and choose different CSS files for
|
8
|
+
the subsite.
|
9
|
+
|
10
|
+
Controllers for the subsite are created in
|
11
|
+
app/controllers/<subsite_name>/ and views are also in their own
|
12
|
+
subdirectory. This allows you to have two different controllers
|
13
|
+
and two different sets of views for the same model.
|
14
|
+
|
15
|
+
The difference between hobo_admin_site and hobo_subsite is that
|
16
|
+
hobo_admin_site limits the subsite to use by administrators only.
|
@@ -35,6 +35,7 @@ class HoboFrontControllerGenerator < Rails::Generator::NamedBase
|
|
35
35
|
|
36
36
|
|
37
37
|
m.template("index.dryml", File.join('app/views', class_path, file_name, "index.dryml"))
|
38
|
+
m.template("summary.dryml", File.join('app/views', class_path, file_name, "summary.dryml"))
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
@@ -46,8 +47,16 @@ class HoboFrontControllerGenerator < Rails::Generator::NamedBase
|
|
46
47
|
routes_path = File.join(RAILS_ROOT, "config/routes.rb")
|
47
48
|
name = full_class_path
|
48
49
|
|
49
|
-
|
50
|
-
|
50
|
+
root = class_nesting_depth>0 ? class_nesting.underscore : "root"
|
51
|
+
|
52
|
+
route = " map.site_search 'search', :controller => '#{name}', :action => 'search'\n"
|
53
|
+
if class_nesting_depth == 0
|
54
|
+
route+= " map.root :controller => '#{name}', :action => 'index'"
|
55
|
+
elsif class_nesting_depth == 1
|
56
|
+
route+= " map.#{class_nesting.underscore} '/#{class_nesting.underscore}', :controller => '#{name}', :action => 'index'"
|
57
|
+
else
|
58
|
+
assert false, "no support for class_nesting_depth>1"
|
59
|
+
end
|
51
60
|
|
52
61
|
route_src = File.read(routes_path)
|
53
62
|
return if route_src.include?(route)
|
@@ -0,0 +1,103 @@
|
|
1
|
+
<page>
|
2
|
+
<content:>
|
3
|
+
<div class="content-body">
|
4
|
+
<h2>Application Summary</h2>
|
5
|
+
|
6
|
+
<table class="app-summary">
|
7
|
+
<tr> <th></th><th></th></tr>
|
8
|
+
<tr> <td>Application Name</td> <td><app-name/></td> </tr>
|
9
|
+
<tr> <td>Application Location</td> <td><rails-root/></td> </tr>
|
10
|
+
<tr> <td>Rails Version</td> <td><rails-version/></td> </tr>
|
11
|
+
<tr> <td>Rails Location</td> <td><rails-location/></td> </tr>
|
12
|
+
<tr> <td>Mode</td> <td><rails-env/></td> </tr>
|
13
|
+
</table>
|
14
|
+
|
15
|
+
<h3>Change Control</h3>
|
16
|
+
<table class="app-summary">
|
17
|
+
<tr> <th></th><th></th></tr>
|
18
|
+
<tr> <td>Method</td> <td><cms-method/></td> </tr>
|
19
|
+
<if test="&cms_method.strip=='git'">
|
20
|
+
<tr> <td>Version</td> <td><cms-version/></td> </tr>
|
21
|
+
<tr> <td>Date</td> <td><cms-last-commit-time/></td> </tr>
|
22
|
+
<tr> <td>Branch</td> <td><cms-branch/></td> </tr>
|
23
|
+
<tr> <td>Clean?</td> <td><cms-clean/></td></tr>
|
24
|
+
</if>
|
25
|
+
</table>
|
26
|
+
|
27
|
+
|
28
|
+
<h3>Gems</h3>
|
29
|
+
<table class="app-summary">
|
30
|
+
<with-gems>
|
31
|
+
<tr if="&first_item?"><th></th><th>Required</th><th>Installed</th><th>Status</th><th>Dependencies</th></tr>
|
32
|
+
<tr>
|
33
|
+
<td><gem-name/></td>
|
34
|
+
<td><gem-version-required/></td>
|
35
|
+
<td><gem-version/></td>
|
36
|
+
<td><gem-frozen/></td>
|
37
|
+
<td><gem-dependencies/></td>
|
38
|
+
</tr>
|
39
|
+
</with-gems>
|
40
|
+
</table>
|
41
|
+
|
42
|
+
<h3>Plugins</h3>
|
43
|
+
<table class="app-summary">
|
44
|
+
<with-plugins>
|
45
|
+
<tr if="&first_item?"><th></th><th>Location</th><th>Method</th><th>Clean?</th><th>Version</th></tr>
|
46
|
+
<tr>
|
47
|
+
<td><plugin-name/></td>
|
48
|
+
<td><plugin-location/></td>
|
49
|
+
<td><plugin-method/></td>
|
50
|
+
<td><plugin-clean/></td>
|
51
|
+
<td><plugin-version/></td>
|
52
|
+
</tr>
|
53
|
+
</with-plugins>
|
54
|
+
</table>
|
55
|
+
|
56
|
+
<h3>Environments</h3>
|
57
|
+
<table class="app-summary">
|
58
|
+
<tr><th></th><th colspan='2'>database</th></tr>
|
59
|
+
<with-environments>
|
60
|
+
<tr>
|
61
|
+
<td><environment-name /></td>
|
62
|
+
<td><database-type /></td>
|
63
|
+
<td><database-name /></td>
|
64
|
+
</tr>
|
65
|
+
</with-environments>
|
66
|
+
</table>
|
67
|
+
|
68
|
+
<h2>Models</h2>
|
69
|
+
<table class="app-summary">
|
70
|
+
<tr><th>Class</th><th>Table</th></tr>
|
71
|
+
<with-models>
|
72
|
+
<tr>
|
73
|
+
<td><model-name/></td>
|
74
|
+
<td><model-table-name/></td>
|
75
|
+
</tr>
|
76
|
+
</with-models>
|
77
|
+
</table>
|
78
|
+
|
79
|
+
<with-models>
|
80
|
+
<h3 if="&this.try.table_name"><model-name /></h3>
|
81
|
+
<table class="app-summary">
|
82
|
+
<with-model-columns>
|
83
|
+
<tr if="&first_item?"><th>Column</th><th>Type</th></tr>
|
84
|
+
<tr>
|
85
|
+
<td><model-column-name/></td>
|
86
|
+
<td><model-column-type/></td>
|
87
|
+
</tr>
|
88
|
+
</with-model-columns>
|
89
|
+
</table>
|
90
|
+
<table class="app-summary">
|
91
|
+
<with-model-associations>
|
92
|
+
<tr if="&first_item?"><th>Association</th><th>Macro</th><th>Class</th></tr>
|
93
|
+
<tr>
|
94
|
+
<td><model-association-name/></td>
|
95
|
+
<td><model-association-macro/></td>
|
96
|
+
<td><model-association-class-name/></td>
|
97
|
+
</tr>
|
98
|
+
</with-model-associations>
|
99
|
+
</table>
|
100
|
+
</with-models>
|
101
|
+
</div>
|
102
|
+
</content:>
|
103
|
+
</page>
|