sinatra-authentication-oran 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/Gemfile +33 -0
  2. data/History.txt +4 -0
  3. data/Manifest +26 -0
  4. data/Rakefile +43 -0
  5. data/TODO +53 -0
  6. data/UNLICENSE +24 -0
  7. data/example/database.yml +3 -0
  8. data/example/dm_extend_app.rb +26 -0
  9. data/example/dm_sinbook.rb +56 -0
  10. data/example/extend_views/edit.haml +42 -0
  11. data/example/extend_views/index.haml +31 -0
  12. data/example/extend_views/login.haml +21 -0
  13. data/example/extend_views/show.haml +9 -0
  14. data/example/extend_views/signup.haml +30 -0
  15. data/example/mm_app.rb +22 -0
  16. data/example/tc_app.rb +16 -0
  17. data/example/tc_sinbook.rb +62 -0
  18. data/lib/models/abstract_user.rb +95 -0
  19. data/lib/models/activerecord_user.rb +56 -0
  20. data/lib/models/ar_adapter.rb +66 -0
  21. data/lib/models/datamapper_user.rb +43 -0
  22. data/lib/models/dm_adapter.rb +61 -0
  23. data/lib/models/mm_adapter.rb +65 -0
  24. data/lib/models/mongoid_adapter.rb +67 -0
  25. data/lib/models/mongoid_user.rb +42 -0
  26. data/lib/models/mongomapper_user.rb +38 -0
  27. data/lib/models/rufus_tokyo_user.rb +206 -0
  28. data/lib/models/sequel_adapter.rb +68 -0
  29. data/lib/models/sequel_user.rb +53 -0
  30. data/lib/models/tc_adapter.rb +101 -0
  31. data/lib/sinatra-authentication-o.rb +305 -0
  32. data/lib/sinatra-authentication.rb +305 -0
  33. data/lib/sinatra-authentication/models.rb +5 -0
  34. data/lib/views/edit.haml +45 -0
  35. data/lib/views/edit.slim +46 -0
  36. data/lib/views/index.haml +29 -0
  37. data/lib/views/index.slim +30 -0
  38. data/lib/views/login.haml +24 -0
  39. data/lib/views/login.slim +25 -0
  40. data/lib/views/show.haml +9 -0
  41. data/lib/views/show.slim +10 -0
  42. data/lib/views/signup.haml +28 -0
  43. data/lib/views/signup.slim +33 -0
  44. data/readme.markdown +295 -0
  45. data/sinatra-authentication-oran.gemspec +137 -0
  46. data/spec/run_all_specs.rb +8 -0
  47. data/spec/unit/ar_model_spec.rb +3 -0
  48. data/spec/unit/dm_model_spec.rb +3 -0
  49. data/spec/unit/mm_model_spec.rb +3 -0
  50. data/spec/unit/mongoid_model_spec.rb +3 -0
  51. data/spec/unit/sequel_model_spec.rb +10 -0
  52. data/spec/unit/tc_model_spec.rb +3 -0
  53. data/spec/unit/user_specs.rb +119 -0
  54. data/test/activerecord_test.rb +5 -0
  55. data/test/datamapper_test.rb +5 -0
  56. data/test/lib/ar_app.rb +27 -0
  57. data/test/lib/dm_app.rb +20 -0
  58. data/test/lib/dm_extend_app.rb +27 -0
  59. data/test/lib/dm_sinbook.rb +54 -0
  60. data/test/lib/extend_views/edit.haml +46 -0
  61. data/test/lib/extend_views/index.haml +31 -0
  62. data/test/lib/extend_views/login.haml +21 -0
  63. data/test/lib/extend_views/show.haml +9 -0
  64. data/test/lib/extend_views/signup.haml +29 -0
  65. data/test/lib/helper.rb +16 -0
  66. data/test/lib/mm_app.rb +24 -0
  67. data/test/lib/mongoid_app.rb +28 -0
  68. data/test/lib/sequel_app.rb +21 -0
  69. data/test/lib/tc_app.rb +17 -0
  70. data/test/lib/tc_sinbook.rb +61 -0
  71. data/test/mongoid_test.rb +5 -0
  72. data/test/mongomapper_test.rb +40 -0
  73. data/test/route_tests.rb +29 -0
  74. data/test/rufus_tokyo_test.rb +5 -0
  75. data/test/sequel_test.rb +5 -0
  76. metadata +220 -0
@@ -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.where(hash).first
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,42 @@
1
+ class MongoidUser
2
+ include Mongoid::Document
3
+ include Mongoid::Timestamps
4
+ field :email
5
+ field :name
6
+ field :hashed_password
7
+ field :salt
8
+ field :permission_level, :type => Integer, :default => 1
9
+ if Sinatra.const_defined?('FacebookObject')
10
+ field :fb_uid
11
+ end
12
+
13
+ # Validations
14
+ validates_uniqueness_of :email ,:name
15
+ validates_format_of :email, :with => /(\A(\s*)\Z)|(\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z)/i
16
+ validates_presence_of :name ,:email
17
+ validates_confirmation_of :password
18
+
19
+ #attr_protected :_id, :salt
20
+
21
+ attr_accessor :password, :password_confirmation
22
+
23
+ def password=(pass)
24
+ @password = pass
25
+ self.salt = User.random_string(10) if !self.salt
26
+ self.hashed_password = User.encrypt(@password, self.salt)
27
+ end
28
+
29
+ def admin?
30
+ self.permission_level == -1 || self.id == 1
31
+ end
32
+
33
+ def site_admin?
34
+ self.id == 1
35
+ end
36
+
37
+ protected
38
+
39
+ def method_missing(m, *args)
40
+ return false
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ class MmUser
2
+ include MongoMapper::Document
3
+
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
6
+ key :hashed_password, String
7
+ key :salt, String
8
+ key :permission_level, Integer, :default => 1
9
+ if Sinatra.const_defined?('FacebookObject')
10
+ key :fb_uid, String
11
+ end
12
+
13
+ timestamps!
14
+
15
+ attr_accessor :password, :password_confirmation
16
+ validates_presence_of :password, :allow_blank => true
17
+ validates_confirmation_of :password
18
+
19
+ def password=(pass)
20
+ @password = pass
21
+ self.salt = User.random_string(10) if !self.salt
22
+ self.hashed_password = User.encrypt(@password, self.salt)
23
+ end
24
+
25
+ def admin?
26
+ self.permission_level == -1 || self.id == 1
27
+ end
28
+
29
+ def site_admin?
30
+ self.id == 1
31
+ end
32
+
33
+ protected
34
+
35
+ def method_missing(m, *args)
36
+ return false
37
+ end
38
+ end
@@ -0,0 +1,206 @@
1
+ class TcUser
2
+ attr_accessor :errors
3
+ #include RufusOrm
4
+
5
+ #custom_attribute :salt
6
+ #custom_attribute :hashed_password
7
+ #custom_attribute :hashed_permission_level
8
+ #custom_attribute :created_at
9
+ #custom_attribute :created_at_i
10
+
11
+ #attribute method?
12
+ #if I'm gonna write all this, I might as well create a tinyyyy
13
+ #orm, that's more just like a way to define custom attributes for cabinets
14
+ #something worth noting though is that even datamapper defines custom
15
+ #attributes by allowing the developer to override setter methods.
16
+ #and it just calls all the setter methods defined in the model.
17
+ #the only trouble with this route is it assumes a predefined schema.
18
+ #and thus it knows what setter methods to call.
19
+ #I would write a class method that allows you to declare attributes like
20
+ #attribute :salt, with an optional block (which gets passed a hash of attributes)
21
+ #if a block isn't defined, it looks in the class for a salt=(attributes) function, calls it and marges the
22
+ #result into the hash going into the database, like 'attributes.merge{"salt" => result}'
23
+ #so my 'set' method or whatever I choose to call it, has to somehow look through each
24
+ #declared attribute, call the method associated with it, and merge the result into the hash going
25
+ #into the database.
26
+ #
27
+ #but what if I don't want an attribute passed in to be stored into the database? What if I just want to
28
+ #create a virtual attribute, for declaring other attributes?
29
+ #I might create a class variable that I store all the attributes in, and the I can get to it from any setter,
30
+ #and then after I've called all the setters, I store that class variable into the database.
31
+ #or, I do all of this on the instance level, and have a save method.
32
+
33
+ def initialize(attributes, errors = [])
34
+ @attributes = attributes
35
+ if @attributes['created_at']
36
+ @attributes['created_at'] = Time.parse(@attributes['created_at'])
37
+ end
38
+
39
+ @errors = errors
40
+ end
41
+
42
+ def self.query(&block)
43
+ connection = TcUserTable.new
44
+ result_set = connection.query(&block)
45
+ output = result_set.collect { |result_hash| TcUser.new(result_hash) }
46
+ connection.close
47
+ output
48
+ end
49
+
50
+ def self.get(key)
51
+ connection = TcUserTable.new
52
+ result = connection[key]
53
+ connection.close
54
+ if result
55
+ self.new(result.merge({:pk => key}))
56
+ else
57
+ false
58
+ end
59
+ end
60
+
61
+ def self.set(attributes)
62
+ #this way of validating is real crap, replace it with Validator maybe
63
+ #and maybe replace all this hash merging with setters for the various attributes that update @attributes, and then I can call save to store to the database
64
+ #or maybe just write a little method that makes hash merger look a little cleaner
65
+ pk = attributes.delete(:pk) if attributes[:pk]
66
+
67
+ errors = []
68
+
69
+ email_regexp = /(\A(\s*)\Z)|(\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z)/i
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)
98
+ end
99
+
100
+ existing_user = TcUser.query do |q|
101
+ q.add 'email', :streq, attributes['email']
102
+ end[0]
103
+
104
+ if existing_user && existing_user[:pk] != pk
105
+ errors << "Email is already taken"
106
+ return self.new(attributes, errors)
107
+ else
108
+ connection = TcUserTable.new
109
+ pk ||= connection.genuid.to_s
110
+ #site admin if their first
111
+ attributes.merge!({'permission_level' => '-2'}) if pk == '1'
112
+ result = connection[pk] = attributes
113
+ #might not need this in newer version of rufus
114
+ result.merge!({:pk => pk})
115
+ connection.close
116
+ self.new(result, errors)
117
+ end
118
+ else
119
+ self.new(attributes, errors)
120
+ end
121
+ end
122
+
123
+ def self.set!(attributes)
124
+ connection = TcUserTable.new
125
+ pk = connection.genuid.to_s
126
+ result = connection[pk] = attributes
127
+ result.merge!({:pk => pk})
128
+ connection.close
129
+ self.new(result)
130
+ end
131
+
132
+ def self.delete(pk)
133
+ connection = TcUserTable.new
134
+ connection.delete(pk)
135
+ connection.close
136
+ end
137
+
138
+ def update(attributes)
139
+ self.errors = []
140
+ new_attributes = @attributes.merge(attributes)
141
+ updated_user = TcUser.set(new_attributes)
142
+ self.errors = updated_user.errors
143
+ updated_user.errors.length < 1
144
+ end
145
+
146
+ def [](key)
147
+ @attributes[key]
148
+ end
149
+
150
+ #saves to database and returns self
151
+ def []=(key, value)
152
+ @attributes[key] = value
153
+ #change so that it sets the attributes and then you call save to save to the database?
154
+ connection = TcUserTable.new
155
+ connection[@attributes[:pk]] = @attributes.merge!({key => value})
156
+ connection.close
157
+ self
158
+ end
159
+
160
+ def id
161
+ @attributes[:pk]
162
+ end
163
+
164
+ def admin?
165
+ @attributes['permission_level'] == '-1' || site_admin?
166
+ end
167
+
168
+ def site_admin?
169
+ #-2 is the site admin
170
+ @attributes['permission_level'] == '-2'
171
+ end
172
+
173
+ #from hash extension for making hashes like javascript objects
174
+ def method_missing(meth,*args)
175
+ if /=$/=~(meth=meth.id2name) then
176
+ self[meth[0...-1]] = (args.length<2 ? args[0] : args)
177
+ elsif @attributes[meth]
178
+ @attributes[meth]
179
+ else
180
+ false
181
+ end
182
+ end
183
+ end
184
+
185
+ if Rufus::Tokyo.const_defined?('Table')
186
+ class TokyoTableDad < Rufus::Tokyo::Table
187
+ end
188
+ elsif Rufus::Edo.const_defined?('Table')
189
+ class TokyoTableDad < Rufus::Edo::Table
190
+ end
191
+ else
192
+ throw 'wtf?'
193
+ end
194
+
195
+ class TcUserTable < TokyoTableDad
196
+ @@path = false
197
+ def initialize
198
+ #make this path configurable somehow
199
+ raise "you need to define a path for the user cabinet to be stored at, like so: TcUserTable.cabinet_path = 'folder/where/you/wanna/store/your/database'" unless @@path
200
+ super(@@path + '/users.tct')
201
+ end
202
+
203
+ def self.cabinet_path=(path)
204
+ @@path = path
205
+ end
206
+ end
@@ -0,0 +1,68 @@
1
+ module SequelAdapter
2
+ def self.included(base)
3
+ base.extend ClassMethods
4
+ base.class_eval { include SequelAdapter::InstanceMethods }
5
+ end
6
+
7
+ module ClassMethods
8
+ def all
9
+ result = SequelUser.order(:created_at.desc).all
10
+ result.collect {|instance| self.new instance}
11
+ end
12
+
13
+ def get(hash)
14
+ if user = SequelUser.first(hash)
15
+ self.new user
16
+ else
17
+ nil
18
+ end
19
+ end
20
+
21
+ def set(attributes)
22
+ user = SequelUser.new attributes
23
+ if user.valid?
24
+ user.save
25
+ #false
26
+ end
27
+
28
+ self.new user
29
+ end
30
+
31
+ def set!(attributes)
32
+ user = SequelUser.new attributes
33
+ user.save!
34
+ self.new user
35
+ end
36
+
37
+ def delete(pk)
38
+ user = SequelUser.first(:id => pk)
39
+ user.destroy
40
+ !user.exists?
41
+ end
42
+ end
43
+
44
+ module InstanceMethods
45
+ def errors
46
+ @instance.errors.full_messages.join(', ')
47
+ end
48
+
49
+ def valid
50
+ @instance.valid?
51
+ end
52
+
53
+ def update(attributes)
54
+ @instance.set attributes
55
+ if @instance.valid?
56
+ @instance.save
57
+ true
58
+ else
59
+ false
60
+ end
61
+ end
62
+
63
+ def method_missing(meth, *args, &block)
64
+ #cool I just found out * on an array turns the array into a list of args for a function
65
+ @instance.send(meth, *args, &block)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,53 @@
1
+ unless DB.table_exists? :sequel_users
2
+ DB.create_table :sequel_users do
3
+ primary_key :id
4
+ String :email, :unique => true
5
+ String :hashed_password
6
+ String :salt
7
+ DateTime :created_at
8
+ Integer :permission_level, :default => 1
9
+ if Sinatra.const_defined?('FacebookObject')
10
+ String :fb_uid
11
+ end
12
+
13
+ #check{{char_length(email)=>5..40}}
14
+ end
15
+ end
16
+
17
+ class SequelUser < Sequel::Model
18
+ attr_writer :password_confirmation
19
+ plugin :validation_helpers
20
+ plugin :timestamps, :create => :created_at
21
+
22
+ def validate
23
+ super
24
+ email_regexp = /(\A(\s*)\Z)|(\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z)/i
25
+ validates_format email_regexp, :email
26
+ validates_presence :email
27
+ validates_unique :email
28
+ validates_presence :password if new?
29
+ errors.add :passwords, ' don\'t match' unless @password == @password_confirmation
30
+ #validate equality?
31
+ end
32
+ #TODO validate format of email
33
+
34
+ def password=(pass)
35
+ @password = pass
36
+ self.salt = User.random_string(10) if !self.salt
37
+ self.hashed_password = User.encrypt(@password, self.salt)
38
+ end
39
+
40
+ def admin?
41
+ self.permission_level == -1 || self.id == 1
42
+ end
43
+
44
+ def site_admin?
45
+ self.id == 1
46
+ end
47
+
48
+ protected
49
+
50
+ def method_missing(m, *args)
51
+ return false
52
+ end
53
+ end