hobo 0.8.10 → 0.9.0
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 +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>
|