hobo 0.7.0 → 0.7.1
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/hobo_files/plugin/CHANGES.txt +220 -23
- data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +18 -25
- data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +20 -15
- data/hobo_files/plugin/generators/hobo_model/templates/model.rb +3 -3
- data/hobo_files/plugin/generators/hobo_rapid/hobo_rapid_generator.rb +3 -3
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo-rapid.css +1 -2
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo-rapid.js +21 -4
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/images/fieldbg.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/images/spinner.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/application.css +154 -26
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid-ui.css +144 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +1 -1
- data/hobo_files/plugin/generators/hobo_user_controller/templates/controller.rb +1 -1
- data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +8 -11
- data/hobo_files/plugin/init.rb +0 -2
- data/hobo_files/plugin/lib/active_record/has_many_association.rb +0 -9
- data/hobo_files/plugin/lib/active_record/has_many_through_association.rb +0 -10
- data/hobo_files/plugin/lib/hobo.rb +57 -44
- data/hobo_files/plugin/lib/hobo/bundle.rb +222 -0
- data/hobo_files/plugin/lib/hobo/controller.rb +2 -5
- data/hobo_files/plugin/lib/hobo/dryml.rb +8 -7
- data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +10 -21
- data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +107 -80
- data/hobo_files/plugin/lib/hobo/dryml/template.rb +27 -20
- data/hobo_files/plugin/lib/hobo/enum_string.rb +1 -1
- data/hobo_files/plugin/lib/hobo/field_declaration_dsl.rb +7 -0
- data/hobo_files/plugin/lib/hobo/guest.rb +4 -0
- data/hobo_files/plugin/lib/hobo/hobo_helper.rb +37 -9
- data/hobo_files/plugin/lib/hobo/model.rb +79 -17
- data/hobo_files/plugin/lib/hobo/model_controller.rb +59 -60
- data/hobo_files/plugin/lib/hobo/model_router.rb +16 -4
- data/hobo_files/plugin/lib/hobo/rapid_helper.rb +2 -1
- data/hobo_files/plugin/lib/hobo/user.rb +10 -7
- data/hobo_files/plugin/lib/hobo/user_controller.rb +6 -6
- data/hobo_files/plugin/{tags → taglibs}/core.dryml +5 -4
- data/hobo_files/plugin/{tags → taglibs}/rapid.dryml +54 -7
- data/hobo_files/plugin/{tags → taglibs}/rapid_document_tags.dryml +0 -0
- data/hobo_files/plugin/{tags → taglibs}/rapid_editing.dryml +4 -2
- data/hobo_files/plugin/{tags → taglibs}/rapid_forms.dryml +1 -4
- data/hobo_files/plugin/{tags → taglibs}/rapid_navigation.dryml +1 -2
- data/hobo_files/plugin/taglibs/rapid_pages.dryml +411 -0
- data/hobo_files/plugin/{tags → taglibs}/rapid_plus.dryml +0 -0
- data/hobo_files/plugin/{tags → taglibs}/rapid_support.dryml +9 -6
- data/hobo_files/plugin/tasks/fix_dryml.rake +0 -1
- metadata +16 -14
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/clean/public/stylesheets/rapid_ui.css +0 -167
- data/hobo_files/plugin/lib/hobo/plugins.rb +0 -75
- data/hobo_files/plugin/tags/rapid_pages.dryml +0 -341
@@ -2,6 +2,10 @@ module Hobo
|
|
2
2
|
|
3
3
|
module Model
|
4
4
|
|
5
|
+
NAME_FIELD_GUESS = %w(name title)
|
6
|
+
PRIMARY_CONTENT_GUESS = %w(description body content profile)
|
7
|
+
SEARCH_COLUMNS_GUESS = %w(name title body content profile)
|
8
|
+
|
5
9
|
PLAIN_TYPES = { :boolean => TrueClass,
|
6
10
|
:date => Date,
|
7
11
|
:datetime => Time,
|
@@ -18,10 +22,12 @@ module Hobo
|
|
18
22
|
base.extend(ClassMethods)
|
19
23
|
base.class_eval do
|
20
24
|
alias_method_chain :attributes=, :hobo_type_conversion
|
25
|
+
default_scopes
|
21
26
|
end
|
22
27
|
class << base
|
23
28
|
alias_method_chain :has_many, :defined_scopes
|
24
29
|
alias_method_chain :belongs_to, :foreign_key_declaration
|
30
|
+
alias_method_chain :belongs_to, :hobo_metadata
|
25
31
|
alias_method_chain :acts_as_list, :fields if defined?(ActiveRecord::Acts::List)
|
26
32
|
def inherited(klass)
|
27
33
|
fields do
|
@@ -37,6 +43,44 @@ module Hobo
|
|
37
43
|
# include methods also shared by CompositeModel
|
38
44
|
include ModelSupport::ClassMethods
|
39
45
|
|
46
|
+
attr_accessor :creator_attribute
|
47
|
+
attr_writer :name_attribute, :primary_content_attribute
|
48
|
+
|
49
|
+
def default_scopes
|
50
|
+
def_scope :recent do |*args|
|
51
|
+
count = args.first || 3
|
52
|
+
{ :limit => count, :order => "#{table_name}.created_at DESC" }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def name_attribute
|
57
|
+
@name_attribute ||= begin
|
58
|
+
cols = columns.every :name
|
59
|
+
NAME_FIELD_GUESS.detect {|f| f.in? columns.every(:name) }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def primary_content_attribute
|
65
|
+
@description_attribute ||= begin
|
66
|
+
cols = columns.every :name
|
67
|
+
PRIMARY_CONTENT_GUESS.detect {|f| f.in? columns.every(:name) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def dependent_collections
|
72
|
+
reflections.values.select do |refl|
|
73
|
+
refl.macro == :has_many && refl.options[:dependent]
|
74
|
+
end.every(:name)
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def dependent_on
|
79
|
+
reflections.values.select do |refl|
|
80
|
+
refl.macro == :belongs_to && (rev = reverse_reflection(refl.name) and rev.options[:dependent])
|
81
|
+
end.every(:name)
|
82
|
+
end
|
83
|
+
|
40
84
|
private
|
41
85
|
|
42
86
|
def return_type(type)
|
@@ -75,6 +119,13 @@ module Hobo
|
|
75
119
|
end
|
76
120
|
res
|
77
121
|
end
|
122
|
+
|
123
|
+
|
124
|
+
def belongs_to_with_hobo_metadata(name, *args, &block)
|
125
|
+
options = args.extract_options!
|
126
|
+
self.creator_attribute = name.to_sym if options.delete(:creator)
|
127
|
+
belongs_to_without_hobo_metadata(name, *args + [options], &block)
|
128
|
+
end
|
78
129
|
|
79
130
|
|
80
131
|
def acts_as_list_with_fields(options = {})
|
@@ -125,12 +176,6 @@ module Hobo
|
|
125
176
|
end
|
126
177
|
public :never_show?
|
127
178
|
|
128
|
-
def set_creator_attr(attr)
|
129
|
-
@creator_attr = attr.to_sym
|
130
|
-
end
|
131
|
-
attr_reader :creator_attr
|
132
|
-
public :creator_attr
|
133
|
-
|
134
179
|
def set_search_columns(*columns)
|
135
180
|
class_eval %{
|
136
181
|
def self.search_columns
|
@@ -281,12 +326,12 @@ module Hobo
|
|
281
326
|
end
|
282
327
|
|
283
328
|
def creator_type
|
284
|
-
reflections[
|
329
|
+
reflections[creator_attribute]._?.klass
|
285
330
|
end
|
286
331
|
|
287
332
|
def search_columns
|
288
333
|
cols = columns.every(:name)
|
289
|
-
|
334
|
+
SEARCH_COLUMNS_GUESS.select{|c| c.in?(cols) }
|
290
335
|
end
|
291
336
|
|
292
337
|
# This should really be a method on AssociationReflection
|
@@ -300,9 +345,9 @@ module Hobo
|
|
300
345
|
:has_many
|
301
346
|
end
|
302
347
|
refl.klass.reflections.values.find do |r|
|
303
|
-
r.macro == reverse_macro
|
304
|
-
r.klass == self
|
305
|
-
!r.options[:conditions]
|
348
|
+
r.macro == reverse_macro &&
|
349
|
+
r.klass == self &&
|
350
|
+
!r.options[:conditions] &&
|
306
351
|
r.primary_key_name == refl.primary_key_name
|
307
352
|
end
|
308
353
|
end
|
@@ -457,6 +502,11 @@ module Hobo
|
|
457
502
|
end
|
458
503
|
|
459
504
|
|
505
|
+
def dependent_on
|
506
|
+
self.class.dependent_on.map { |assoc| send(assoc) }
|
507
|
+
end
|
508
|
+
|
509
|
+
|
460
510
|
def attributes_with_hobo_type_conversion=(attributes, guard_protected_attributes=true)
|
461
511
|
converted = attributes.map_hash { |k, v| convert_type_for_mass_assignment(self.class.field_type(k), v) }
|
462
512
|
send(:attributes_without_hobo_type_conversion=, converted, guard_protected_attributes)
|
@@ -465,7 +515,17 @@ module Hobo
|
|
465
515
|
|
466
516
|
|
467
517
|
def set_creator(user)
|
468
|
-
|
518
|
+
attr = self.class.creator_attribute
|
519
|
+
return unless attr
|
520
|
+
|
521
|
+
# Is creator a string field or an association?
|
522
|
+
if self.class.reflections[attr]
|
523
|
+
# It's an association
|
524
|
+
self.send("#{attr}=", user) if (t = self.class.creator_type) && user.is_a?(t)
|
525
|
+
else
|
526
|
+
# Assume it's a string field -- set it to the name of the current user
|
527
|
+
self.send("#{attr}=", user.to_s) unless user.guest?
|
528
|
+
end
|
469
529
|
end
|
470
530
|
|
471
531
|
|
@@ -487,11 +547,15 @@ module Hobo
|
|
487
547
|
|
488
548
|
|
489
549
|
def same_fields?(other, *fields)
|
550
|
+
return true if other.nil?
|
551
|
+
|
490
552
|
fields = fields.flatten
|
491
553
|
fields.all?{|f| self.send(f) == other.send(f)}
|
492
554
|
end
|
493
555
|
|
494
556
|
def only_changed_fields?(other, *changed_fields)
|
557
|
+
return true if other.nil?
|
558
|
+
|
495
559
|
changed_fields = changed_fields.flatten.every(:to_s)
|
496
560
|
all_cols = self.class.columns.every(:name) - []
|
497
561
|
all_cols.all?{|c| c.in?(changed_fields) || self.send(c) == other.send(c) }
|
@@ -514,12 +578,10 @@ module Hobo
|
|
514
578
|
end
|
515
579
|
|
516
580
|
def to_s
|
517
|
-
if
|
518
|
-
|
519
|
-
elsif respond_to? :name
|
520
|
-
name
|
581
|
+
if self.class.name_attribute
|
582
|
+
send self.class.name_attribute
|
521
583
|
else
|
522
|
-
"#{self.class.name.
|
584
|
+
"#{self.class.name.titleize} #{id}"
|
523
585
|
end
|
524
586
|
end
|
525
587
|
|
@@ -4,18 +4,10 @@ module Hobo
|
|
4
4
|
|
5
5
|
include Hobo::Controller
|
6
6
|
|
7
|
-
class PermissionDeniedError < RuntimeError; end
|
8
|
-
class UserPermissionError < StandardError
|
9
|
-
attr :models
|
10
|
-
def initialize(models)
|
11
|
-
@models = models || []
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
7
|
VIEWLIB_DIR = "taglibs"
|
16
8
|
|
17
9
|
PAGINATE_FORMATS = [ Mime::HTML, Mime::ALL ]
|
18
|
-
|
10
|
+
|
19
11
|
class << self
|
20
12
|
|
21
13
|
def included(base)
|
@@ -23,38 +15,14 @@ module Hobo
|
|
23
15
|
@auto_actions ||= {}
|
24
16
|
|
25
17
|
extend ClassMethods
|
26
|
-
|
18
|
+
|
19
|
+
helper_method :model, :current_user
|
27
20
|
before_filter :set_no_cache_headers
|
28
21
|
end
|
22
|
+
base.template_path_cache = {}
|
29
23
|
|
30
24
|
Hobo::Controller.included_in_class(base)
|
31
25
|
end
|
32
|
-
|
33
|
-
def find_partial(klass, as)
|
34
|
-
find_model_template(klass, as, :is_parital => true)
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
def template_path(dir, name, is_partial)
|
39
|
-
fileRx = is_partial ? /^_#{name}\.[^.]+/ : /^#{name}\.[^.]+/
|
40
|
-
full_dir = "#{RAILS_ROOT}/app/views/#{dir}"
|
41
|
-
if File.exists?(full_dir) && Dir.entries(full_dir).grep(fileRx).any?
|
42
|
-
return "#{dir}/#{name}"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
def find_model_template(klass, name, options={})
|
48
|
-
while klass and klass != ActiveRecord::Base
|
49
|
-
dir = klass.name.underscore.pluralize
|
50
|
-
dir = File.join(options[:subsite], dir) if options[:subsite]
|
51
|
-
path = template_path(dir, name, options[:is_partial])
|
52
|
-
return path if path
|
53
|
-
|
54
|
-
klass = klass.superclass
|
55
|
-
end
|
56
|
-
nil
|
57
|
-
end
|
58
26
|
|
59
27
|
end
|
60
28
|
|
@@ -62,6 +30,8 @@ module Hobo
|
|
62
30
|
|
63
31
|
attr_writer :model
|
64
32
|
|
33
|
+
attr_accessor :template_path_cache
|
34
|
+
|
65
35
|
def add_collection_actions(name)
|
66
36
|
defined_methods = instance_methods
|
67
37
|
|
@@ -400,6 +370,24 @@ module Hobo
|
|
400
370
|
end
|
401
371
|
|
402
372
|
|
373
|
+
def destination_after_create(record)
|
374
|
+
# The after_submit post parameter takes priority
|
375
|
+
params[:after_submit] ||
|
376
|
+
|
377
|
+
# Then try the records show page
|
378
|
+
object_url(@this, :if_available => true) ||
|
379
|
+
|
380
|
+
# Then the show page of the 'owning' object if there is one
|
381
|
+
(@this.dependent_on.first && object_url(@this.dependent_on.first, :if_available => true)) ||
|
382
|
+
|
383
|
+
# Last try - the index page for this model
|
384
|
+
object_url(@this.class, :if_available => true) ||
|
385
|
+
|
386
|
+
# Give up
|
387
|
+
home_page
|
388
|
+
end
|
389
|
+
|
390
|
+
|
403
391
|
# --- Action implementations --- #
|
404
392
|
|
405
393
|
def hobo_index(*args, &b)
|
@@ -478,7 +466,7 @@ module Hobo
|
|
478
466
|
response_block(&b) or
|
479
467
|
if valid?
|
480
468
|
respond_to do |wants|
|
481
|
-
wants.html { redirect_to(
|
469
|
+
wants.html { redirect_to(destination_after_create(@this)) }
|
482
470
|
wants.js { hobo_ajax_response || render(:text => "") }
|
483
471
|
end
|
484
472
|
elsif invalid?
|
@@ -510,14 +498,14 @@ module Hobo
|
|
510
498
|
@this.send(:clear_aggregation_cache)
|
511
499
|
@this.send(:clear_association_cache)
|
512
500
|
|
513
|
-
changes = params[
|
501
|
+
changes = params[@this.class.name.underscore]
|
514
502
|
@this.attributes = changes
|
515
503
|
save_and_set_status!(@this, original)
|
516
504
|
|
517
505
|
# Ensure current_user isn't out of date
|
518
506
|
@current_user = @this if @this == current_user
|
519
507
|
|
520
|
-
flash[:notice] = "Changes to the #{
|
508
|
+
flash[:notice] = "Changes to the #{@this.class.name.titleize.downcase} were saved" if !request.xhr? && valid?
|
521
509
|
|
522
510
|
set_named_this!
|
523
511
|
response_block(&b) or
|
@@ -671,32 +659,43 @@ module Hobo
|
|
671
659
|
end
|
672
660
|
end
|
673
661
|
|
662
|
+
|
663
|
+
def hobo_template_exists?(dir, name)
|
664
|
+
self.class.template_path_cache.clear if RAILS_ENV == "development"
|
665
|
+
self.class.template_path_cache.fetch([dir, name],
|
666
|
+
begin
|
667
|
+
full_dir = "#{RAILS_ROOT}/app/views/#{dir}"
|
668
|
+
!Dir["#{full_dir}/#{name}.*"].empty?
|
669
|
+
end)
|
670
|
+
end
|
671
|
+
|
672
|
+
|
673
|
+
def find_model_template(klass, name)
|
674
|
+
while klass and klass != ActiveRecord::Base
|
675
|
+
dir = klass.name.underscore.pluralize
|
676
|
+
dir = File.join(subsite, dir) if subsite
|
677
|
+
if hobo_template_exists?(dir, name)
|
678
|
+
return "#{dir}/#{name}"
|
679
|
+
end
|
680
|
+
klass = klass.superclass
|
681
|
+
end
|
682
|
+
nil
|
683
|
+
end
|
674
684
|
|
685
|
+
|
675
686
|
def hobo_render(page_kind = nil, page_model=nil)
|
676
687
|
page_kind ||= params[:action].to_sym
|
677
688
|
page_model ||= model
|
678
|
-
|
679
|
-
template = ModelController.find_model_template(page_model, page_kind, :subsite => subsite)
|
680
689
|
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
e = wrapper.original_exception if wrapper.respond_to? :original_exception
|
691
|
-
if e.is_a? Hobo::ModelController::UserPermissionError
|
692
|
-
if current_user.guest?
|
693
|
-
redirect_to login_url(e.models.first || UserController.user_models.first)
|
694
|
-
else
|
695
|
-
permission_denied(:message => e.message)
|
696
|
-
end
|
697
|
-
else
|
698
|
-
raise
|
699
|
-
end
|
690
|
+
if hobo_template_exists?(controller_path, page_kind)
|
691
|
+
render :action => page_kind
|
692
|
+
true
|
693
|
+
elsif (template = find_model_template(page_model, page_kind))
|
694
|
+
render :template => template
|
695
|
+
true
|
696
|
+
else
|
697
|
+
# This returns false if no such tag exists
|
698
|
+
render_tag("#{page_kind.to_s.dasherize}-page", :with => @this)
|
700
699
|
end
|
701
700
|
end
|
702
701
|
|
@@ -1,13 +1,24 @@
|
|
1
|
+
class ActionController::Routing::RouteSet
|
2
|
+
# Monkey patch this method so routes are reloaded on *every*
|
3
|
+
# request. Without this Rails checks the mtime of config/routes.rb
|
4
|
+
# which doesn't take into account Hobo's auto routing
|
5
|
+
def reload
|
6
|
+
load!
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
1
10
|
module Hobo
|
2
11
|
|
3
12
|
class ModelRouter
|
4
13
|
|
5
|
-
@linkable = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = {} } }
|
6
|
-
|
7
14
|
APP_ROOT = "#{RAILS_ROOT}/app"
|
8
15
|
|
9
16
|
class << self
|
10
17
|
|
18
|
+
def reset_linkables
|
19
|
+
@linkable = Hash.new {|h, k| h[k] = Hash.new {|h, k| h[k] = {} } }
|
20
|
+
end
|
21
|
+
|
11
22
|
def linkable(subsite, klass, action)
|
12
23
|
@linkable[subsite][klass.name][action] = true
|
13
24
|
end
|
@@ -17,6 +28,7 @@ module Hobo
|
|
17
28
|
end
|
18
29
|
|
19
30
|
def add_routes(map)
|
31
|
+
reset_linkables
|
20
32
|
begin
|
21
33
|
ActiveRecord::Base.connection.reconnect! unless ActiveRecord::Base.connection.active?
|
22
34
|
rescue
|
@@ -25,8 +37,8 @@ module Hobo
|
|
25
37
|
end
|
26
38
|
|
27
39
|
require "#{APP_ROOT}/controllers/application" unless Object.const_defined? :ApplicationController
|
28
|
-
|
29
|
-
|
40
|
+
load "#{APP_ROOT}/assemble.rb" if File.exists? "#{APP_ROOT}/assemble.rb"
|
41
|
+
|
30
42
|
# Add non-subsite routes
|
31
43
|
add_routes_for(map, nil)
|
32
44
|
|
@@ -11,6 +11,7 @@ module Hobo::RapidHelper
|
|
11
11
|
js_options['resultUpdate'] = js_result_updates(options[:result_update]) if options[:result_update]
|
12
12
|
js_options['resetForm'] = options[:reset_form] if options.has_key?(:reset_form)
|
13
13
|
js_options['refocusForm'] = options[:refocus_form] if options.has_key?(:refocus_form)
|
14
|
+
js_options['spinnerNextTo'] = options[:spinner_next_to] if options.has_key?(:spinner_next_to)
|
14
15
|
|
15
16
|
js_options.empty? ? nil : options_for_javascript(js_options)
|
16
17
|
end
|
@@ -97,7 +98,7 @@ module Hobo::RapidHelper
|
|
97
98
|
|
98
99
|
AJAX_ATTRS = [:before, :success, :failure, :complete, :type, :method,
|
99
100
|
:script, :form, :params, :confirm,
|
100
|
-
:reset_form, :refocus_form, :result_update]
|
101
|
+
:reset_form, :refocus_form, :result_update, :spinner_next_to]
|
101
102
|
|
102
103
|
|
103
104
|
def editor_class
|
@@ -41,7 +41,7 @@ module Hobo
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
# Additional classmethods for
|
44
|
+
# Additional classmethods for authentication
|
45
45
|
module ClassMethods
|
46
46
|
|
47
47
|
# Validation of the plaintext password
|
@@ -49,22 +49,20 @@ module Hobo
|
|
49
49
|
validates_length_of :password, :within => 4..40, :if => :password_required?
|
50
50
|
end
|
51
51
|
|
52
|
-
def
|
52
|
+
def login_attribute=(attr, validate=true)
|
53
53
|
@login_attr = attr = attr.to_sym
|
54
54
|
unless attr == :login
|
55
55
|
alias_attribute(:login, attr)
|
56
56
|
set_field_type :login => field_type(attr)
|
57
57
|
end
|
58
58
|
|
59
|
-
if
|
60
|
-
yield
|
61
|
-
else
|
59
|
+
if validate
|
62
60
|
validates_presence_of attr
|
63
61
|
validates_length_of attr, :within => 3..100
|
64
62
|
validates_uniqueness_of attr, :case_sensitive => false
|
65
63
|
end
|
66
64
|
end
|
67
|
-
|
65
|
+
attr_reader :login_attr
|
68
66
|
|
69
67
|
# Authenticates a user by their login name and unencrypted password. Returns the user or nil.
|
70
68
|
def authenticate(login, password)
|
@@ -86,6 +84,11 @@ module Hobo
|
|
86
84
|
def encrypt(password, salt)
|
87
85
|
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
|
88
86
|
end
|
87
|
+
|
88
|
+
|
89
|
+
def set_admin_on_first_user
|
90
|
+
before_create { |user| user.administrator = true if count == 0 }
|
91
|
+
end
|
89
92
|
|
90
93
|
end
|
91
94
|
|
@@ -121,7 +124,7 @@ module Hobo
|
|
121
124
|
def guest?
|
122
125
|
false
|
123
126
|
end
|
124
|
-
|
127
|
+
|
125
128
|
protected
|
126
129
|
# Before filter that encrypts the password before having it stored in the database.
|
127
130
|
def encrypt_password
|