sinatra-authentication 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/Rakefile +6 -1
  2. data/lib/models/abstract_user.rb +39 -1
  3. data/lib/models/datamapper_user.rb +2 -1
  4. data/lib/models/dm_adapter.rb +15 -4
  5. data/lib/models/mm_adapter.rb +21 -9
  6. data/lib/models/mongoid_adapter.rb +67 -0
  7. data/lib/models/mongoid_user.rb +41 -0
  8. data/lib/models/mongomapper_user.rb +4 -8
  9. data/lib/models/rufus_tokyo_user.rb +48 -19
  10. data/lib/models/sequel_adapter.rb +68 -0
  11. data/lib/models/sequel_user.rb +53 -0
  12. data/lib/models/tc_adapter.rb +20 -2
  13. data/lib/sinatra-authentication.rb +35 -23
  14. data/lib/sinatra-authentication/models.rb +5 -0
  15. data/lib/views/edit.haml +1 -1
  16. data/lib/views/login.haml +3 -3
  17. data/lib/views/signup.haml +4 -4
  18. data/readme.markdown +53 -3
  19. data/sinatra-authentication-0.3.2.gem +0 -0
  20. data/sinatra-authentication.gemspec +86 -60
  21. data/spec/run_all_specs.rb +8 -0
  22. data/spec/unit/dm_model_spec.rb +3 -0
  23. data/spec/unit/mm_model_spec.rb +3 -0
  24. data/spec/unit/mongoid_model_spec.rb +3 -0
  25. data/spec/unit/sequel_model_spec.rb +10 -0
  26. data/spec/unit/tc_model_spec.rb +3 -0
  27. data/spec/unit/user_specs.rb +119 -0
  28. data/test/lib/dm_app.rb +1 -0
  29. data/test/lib/dm_extend_app.rb +1 -0
  30. data/test/lib/extend_views/edit.haml +4 -0
  31. data/test/lib/extend_views/signup.haml +4 -4
  32. data/test/lib/helper.rb +4 -0
  33. data/test/lib/mm_app.rb +16 -15
  34. data/test/lib/mongoid_app.rb +29 -0
  35. data/test/lib/sequel_app.rb +22 -0
  36. data/test/lib/tc_app.rb +2 -0
  37. data/test/mongoid_test.rb +5 -0
  38. data/test/mongomapper_test.rb +36 -35
  39. data/test/sequel_test.rb +5 -0
  40. metadata +40 -24
  41. data/.gitignore +0 -4
data/Rakefile CHANGED
@@ -1,12 +1,13 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
+ #require 'spec/rake/spectask'
3
4
 
4
5
  begin
5
6
  require 'jeweler'
6
7
 
7
8
  Jeweler::Tasks.new do |gemspec|
8
9
  gemspec.name = 'sinatra-authentication'
9
- gemspec.version = '0.3.2'
10
+ gemspec.version = '0.4.0'
10
11
  gemspec.description = "Simple authentication plugin for sinatra."
11
12
  gemspec.summary = "Simple authentication plugin for sinatra."
12
13
  gemspec.homepage = "http://github.com/maxjustus/sinatra-authentication"
@@ -36,3 +37,7 @@ Rake::TestTask.new do |t|
36
37
  t.verbose = true
37
38
  end
38
39
 
40
+ #desc 'Run all specs'
41
+ #Spec::Rake::SpecTask.new('specs') do |t|
42
+ # t.spec_files = FileList['spec/**/*.rb']
43
+ #end
@@ -10,6 +10,12 @@ elsif Object.const_defined?("Rufus") && Rufus.const_defined?("Tokyo")
10
10
  elsif Object.const_defined?("MongoMapper")
11
11
  require Pathname(__FILE__).dirname.expand_path + "mongomapper_user.rb"
12
12
  require Pathname(__FILE__).dirname.expand_path + "mm_adapter.rb"
13
+ elsif Object.const_defined?("Sequel")
14
+ require Pathname(__FILE__).dirname.expand_path + "sequel_user.rb"
15
+ require Pathname(__FILE__).dirname.expand_path + "sequel_adapter.rb"
16
+ elsif Object.const_defined?("Mongoid")
17
+ require Pathname(__FILE__).dirname.expand_path + "mongoid_user.rb"
18
+ require Pathname(__FILE__).dirname.expand_path + "mongoid_adapter.rb"
13
19
  end
14
20
 
15
21
  class User
@@ -19,8 +25,12 @@ class User
19
25
  include TcAdapter
20
26
  elsif Object.const_defined?("MongoMapper")
21
27
  include MmAdapter
28
+ elsif Object.const_defined?("Sequel")
29
+ include SequelAdapter
30
+ elsif Object.const_defined?("Mongoid")
31
+ include MongoidAdapter
22
32
  else
23
- throw "you need to require either 'dm-core', 'mongo_mapper', or 'rufus-tokyo' for sinatra-authentication to work"
33
+ throw "you need to require either 'dm-core', 'mongo_mapper', 'sequel', 'mongoid', or 'rufus-tokyo' for sinatra-authentication to work"
24
34
  end
25
35
 
26
36
  def initialize(interfacing_class_instance)
@@ -38,6 +48,10 @@ class User
38
48
  nil
39
49
  end
40
50
 
51
+ def db_instance
52
+ @instance
53
+ end
54
+
41
55
  protected
42
56
 
43
57
  def self.encrypt(pass, salt)
@@ -51,4 +65,28 @@ class User
51
65
  1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
52
66
  return newpass
53
67
  end
68
+
69
+ #def self.page_limit
70
+ # 20
71
+ #end
72
+
73
+ #def self.page_offset(page = 0)
74
+ # page.to_i * self.page_limit
75
+ #end
76
+ end
77
+
78
+ class Hash
79
+ def stringify
80
+ inject({}) do |options, (key, value)|
81
+ options[key.to_s] = value.to_s
82
+ options
83
+ end
84
+ end
85
+
86
+ def stringify!
87
+ each do |key, value|
88
+ delete(key)
89
+ store(key.to_s, value.to_s)
90
+ end
91
+ end
54
92
  end
@@ -5,7 +5,8 @@ class DmUser
5
5
  property :email, String, :length => (5..40), :unique => true, :format => :email_address
6
6
  property :hashed_password, String
7
7
  property :salt, String
8
- property :created_at, DateTime
8
+ #Was DateTime should be DateTime?
9
+ property :created_at, Time
9
10
  property :permission_level, Integer, :default => 1
10
11
  if Sinatra.const_defined?('FacebookObject')
11
12
  property :fb_uid, String
@@ -6,8 +6,8 @@ module DmAdapter
6
6
 
7
7
  module ClassMethods
8
8
  #pass all args to this
9
- def all(*args)
10
- result = DmUser.all(*args)
9
+ def all
10
+ result = DmUser.all(:order => [:created_at.desc])
11
11
  result.collect {|instance| self.new instance}
12
12
  end
13
13
 
@@ -22,13 +22,13 @@ module DmAdapter
22
22
  def set(attributes)
23
23
  user = DmUser.new attributes
24
24
  user.save
25
- user
25
+ self.new user
26
26
  end
27
27
 
28
28
  def set!(attributes)
29
29
  user = DmUser.new attributes
30
30
  user.save!
31
- user
31
+ self.new user
32
32
  end
33
33
 
34
34
  def delete(pk)
@@ -38,8 +38,19 @@ module DmAdapter
38
38
  end
39
39
 
40
40
  module InstanceMethods
41
+ def valid
42
+ @instance.valid?
43
+ end
44
+
45
+ def errors
46
+ @instance.errors.collect do |k,v|
47
+ "#{k} #{v}"
48
+ end.join(', ')
49
+ end
50
+
41
51
  def update(attributes)
42
52
  @instance.update attributes
53
+ #self
43
54
  end
44
55
 
45
56
  def method_missing(meth, *args, &block)
@@ -6,7 +6,7 @@ module MmAdapter
6
6
 
7
7
  module ClassMethods
8
8
  def all
9
- result = MmUser.all
9
+ result = MmUser.all(:order => 'created_at desc')
10
10
  result.collect {|instance| self.new instance}
11
11
  end
12
12
 
@@ -19,32 +19,44 @@ module MmAdapter
19
19
  end
20
20
 
21
21
  def set(attributes)
22
- puts attributes.inspect
22
+ #puts attributes.inspect
23
23
  user = MmUser.new attributes
24
- puts user.inspect
25
- puts user.to_json
26
- user.save
27
- user
24
+ user.id = nil unless user.save
25
+ self.new user
28
26
  end
29
27
 
30
28
  def set!(attributes)
31
29
  user = MmUser.new attributes
32
- user.save!
33
- user
30
+ user.save(:validate => false)
31
+ self.new user
34
32
  end
35
33
 
36
34
  def delete(pk)
37
- user = User.first(:id => pk)
35
+ user = MmUser.first(:id => pk)
36
+ #returns nil on success. Is this correct? Will it return something else on failure?
38
37
  user.destroy
38
+ user.destroyed?
39
39
  end
40
40
  end
41
41
 
42
42
  module InstanceMethods
43
+ def valid
44
+ @instance.valid?
45
+ end
46
+
43
47
  def update(attributes)
44
48
  @instance.update_attributes attributes
45
49
  @instance.save
46
50
  end
47
51
 
52
+ def saved
53
+ @instance.valid?
54
+ end
55
+
56
+ def errors
57
+ @instance.errors.full_messages.join(', ')
58
+ end
59
+
48
60
  def method_missing(meth, *args, &block)
49
61
  #cool I just found out * on an array turns the array into a list of args for a function
50
62
  @instance.send(meth, *args, &block)
@@ -0,0 +1,67 @@
1
+ module MongoidAdapter
2
+ def self.included(base)
3
+ base.extend ClassMethods
4
+ base.class_eval { include MongoidAdapter::InstanceMethods }
5
+ end
6
+
7
+ module ClassMethods
8
+ def all
9
+ result = MongoidUser.criteria.order_by([[:created_at, :desc]])
10
+ result.collect {|instance| self.new instance }
11
+ end
12
+
13
+ def get(hash)
14
+ if user = MongoidUser.first(:conditions => hash)
15
+ self.new user
16
+ else
17
+ nil
18
+ end
19
+ end
20
+
21
+ def set(attributes)
22
+ #puts attributes.inspect
23
+ user = MongoidUser.new attributes
24
+ #puts user.inspect
25
+ #puts user.to_json
26
+ user.save
27
+ self.new user
28
+ end
29
+
30
+ def set!(attributes)
31
+ user = MongoidUser.new attributes
32
+ user.save(:validate => false)
33
+ self.new user
34
+ end
35
+
36
+ def delete(pk)
37
+ user = MongoidUser.find(pk)
38
+ #returns nil on success. Is this correct? Will it return something else on failure?
39
+ user.destroy
40
+ user.destroyed?
41
+ end
42
+ end
43
+
44
+ module InstanceMethods
45
+ def valid
46
+ @instance.valid?
47
+ end
48
+
49
+ def update(attributes)
50
+ @instance.update_attributes(attributes)
51
+ @instance.save
52
+ end
53
+
54
+ def saved
55
+ @instance.valid?
56
+ end
57
+
58
+ def errors
59
+ @instance.errors.full_messages.join(', ')
60
+ end
61
+
62
+ def method_missing(meth, *args, &block)
63
+ #cool I just found out * on an array turns the array into a list of args for a function
64
+ @instance.send(meth, *args, &block)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,41 @@
1
+ class MongoidUser
2
+ include Mongoid::Document
3
+ include Mongoid::Timestamps
4
+ field :email
5
+ field :hashed_password
6
+ field :salt
7
+ field :permission_level, :type => Integer, :default => 1
8
+ if Sinatra.const_defined?('FacebookObject')
9
+ field :fb_uid
10
+ end
11
+
12
+ # Validations
13
+ validates_uniqueness_of :email
14
+ validates_format_of :email, :with => /(\A(\s*)\Z)|(\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z)/i
15
+ validates_presence_of :password
16
+ validates_confirmation_of :password
17
+
18
+ #attr_protected :_id, :salt
19
+
20
+ attr_accessor :password, :password_confirmation
21
+
22
+ def password=(pass)
23
+ @password = pass
24
+ self.salt = User.random_string(10) if !self.salt
25
+ self.hashed_password = User.encrypt(@password, self.salt)
26
+ end
27
+
28
+ def admin?
29
+ self.permission_level == -1 || self.id == 1
30
+ end
31
+
32
+ def site_admin?
33
+ self.id == 1
34
+ end
35
+
36
+ protected
37
+
38
+ def method_missing(m, *args)
39
+ return false
40
+ end
41
+ end
@@ -1,7 +1,8 @@
1
1
  class MmUser
2
2
  include MongoMapper::Document
3
3
 
4
- key :email, String, :length => (5..40), :unique => true
4
+ email_regexp = /(\A(\s*)\Z)|(\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z)/i
5
+ key :email, String, :unique => true, :format => email_regexp
5
6
  key :hashed_password, String
6
7
  key :salt, String
7
8
  key :permission_level, Integer, :default => 1
@@ -12,13 +13,8 @@ class MmUser
12
13
  timestamps!
13
14
 
14
15
  attr_accessor :password, :password_confirmation
15
- #protected equievelant? :protected => true doesn't exist in dm 0.10.0
16
- #protected :id, :salt
17
- #doesn't behave correctly, I'm not even sure why I did this.
18
-
19
- #validates_presence_of :password_confirmation, :unless => Proc.new { |t| t.hashed_password }
20
- #validates_presence_of :password, :unless => Proc.new { |t| t.hashed_password }
21
- #validates_is_confirmed :password
16
+ validates_presence_of :password, :allow_blank => true
17
+ validates_confirmation_of :password
22
18
 
23
19
  def password=(pass)
24
20
  @password = pass
@@ -1,4 +1,5 @@
1
1
  class TcUser
2
+ attr_accessor :errors
2
3
  #include RufusOrm
3
4
 
4
5
  #custom_attribute :salt
@@ -29,8 +30,13 @@ class TcUser
29
30
  #and then after I've called all the setters, I store that class variable into the database.
30
31
  #or, I do all of this on the instance level, and have a save method.
31
32
 
32
- def initialize(attributes)
33
+ def initialize(attributes, errors = [])
33
34
  @attributes = attributes
35
+ if @attributes['created_at']
36
+ @attributes['created_at'] = Time.parse(@attributes['created_at'])
37
+ end
38
+
39
+ @errors = errors
34
40
  end
35
41
 
36
42
  def self.query(&block)
@@ -58,26 +64,46 @@ class TcUser
58
64
  #or maybe just write a little method that makes hash merger look a little cleaner
59
65
  pk = attributes.delete(:pk) if attributes[:pk]
60
66
 
67
+ errors = []
68
+
61
69
  email_regexp = /(\A(\s*)\Z)|(\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z)/i
62
- if attributes['email'] =~ email_regexp
63
- if attributes['password'] == attributes.delete('password_confirmation') && attributes['password'] != nil
64
- password = attributes.delete('password')
65
- attributes.merge!({'salt' => User.random_string(10)}) if !attributes['salt']
66
- attributes.merge!('hashed_password' => User.encrypt(password, attributes['salt']))
67
- permission_level = attributes['permission_level'] ? attributes['permission_level'] : '1'
68
- attributes.merge!('permission_level' => permission_level)
69
- unless attributes['created_at']
70
- attributes.merge!('created_at' => Time.now.to_s)
71
- attributes.merge!('created_at_i' => Time.now.to_i.to_s)
72
- end
70
+ attributes = attributes.stringify
71
+
72
+ unless attributes['email'] =~ email_regexp
73
+ errors << 'Email is invalid'
74
+ end
75
+
76
+ if attributes['password'] != attributes.delete('password_confirmation') && attributes['password'] != nil
77
+ errors << "Passwords don't match"
78
+ end
79
+
80
+ if attributes['password'] != nil && attributes['password'].length == 0
81
+ errors << "You need to provide a password"
82
+ end
83
+
84
+ if errors.length == 0
85
+ password = attributes.delete('password')
86
+ if !attributes['salt']
87
+ salt = User.random_string(10)
88
+ attributes.merge!({'salt' => salt})
89
+ attributes.merge!('hashed_password' => User.encrypt(password, salt))
90
+ end
91
+ permission_level = attributes['permission_level'] ? attributes['permission_level'] : '1'
92
+ attributes.merge!('permission_level' => permission_level)
93
+ if attributes['created_at']
94
+ attributes.merge!('created_at_i' => Time.parse(attributes['created_at']).to_i)
95
+ else
96
+ attributes.merge!('created_at' => Time.now.to_s)
97
+ attributes.merge!('created_at_i' => Time.now.to_i.to_s)
73
98
  end
74
99
 
75
100
  existing_user = TcUser.query do |q|
76
101
  q.add 'email', :streq, attributes['email']
77
102
  end[0]
78
103
 
79
- if existing_user && existing_user['pk'] != attributes['pk']
80
- return false
104
+ if existing_user && existing_user[:pk] != pk
105
+ errors << "Email is already taken"
106
+ return self.new(attributes, errors)
81
107
  else
82
108
  connection = TcUserTable.new
83
109
  pk ||= connection.genuid.to_s
@@ -87,10 +113,10 @@ class TcUser
87
113
  #might not need this in newer version of rufus
88
114
  result.merge!({:pk => pk})
89
115
  connection.close
90
- self.new(result)
116
+ self.new(result, errors)
91
117
  end
92
118
  else
93
- false
119
+ self.new(attributes, errors)
94
120
  end
95
121
  end
96
122
 
@@ -110,8 +136,11 @@ class TcUser
110
136
  end
111
137
 
112
138
  def update(attributes)
139
+ self.errors = []
113
140
  new_attributes = @attributes.merge(attributes)
114
- TcUser.set(new_attributes)
141
+ updated_user = TcUser.set(new_attributes)
142
+ self.errors = updated_user.errors
143
+ updated_user.errors.length < 1
115
144
  end
116
145
 
117
146
  def [](key)
@@ -133,11 +162,11 @@ class TcUser
133
162
  end
134
163
 
135
164
  def admin?
136
- #-2 is the site admin
137
- @attributes['permission_level'] == '-1' || @attributes['permission_level'] == '-2'
165
+ @attributes['permission_level'] == '-1' || site_admin?
138
166
  end
139
167
 
140
168
  def site_admin?
169
+ #-2 is the site admin
141
170
  @attributes['permission_level'] == '-2'
142
171
  end
143
172