sinatra-authentication-oran 0.0.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/Gemfile +33 -0
- data/History.txt +4 -0
- data/Manifest +26 -0
- data/Rakefile +43 -0
- data/TODO +53 -0
- data/UNLICENSE +24 -0
- data/example/database.yml +3 -0
- data/example/dm_extend_app.rb +26 -0
- data/example/dm_sinbook.rb +56 -0
- data/example/extend_views/edit.haml +42 -0
- data/example/extend_views/index.haml +31 -0
- data/example/extend_views/login.haml +21 -0
- data/example/extend_views/show.haml +9 -0
- data/example/extend_views/signup.haml +30 -0
- data/example/mm_app.rb +22 -0
- data/example/tc_app.rb +16 -0
- data/example/tc_sinbook.rb +62 -0
- data/lib/models/abstract_user.rb +95 -0
- data/lib/models/activerecord_user.rb +56 -0
- data/lib/models/ar_adapter.rb +66 -0
- data/lib/models/datamapper_user.rb +43 -0
- data/lib/models/dm_adapter.rb +61 -0
- data/lib/models/mm_adapter.rb +65 -0
- data/lib/models/mongoid_adapter.rb +67 -0
- data/lib/models/mongoid_user.rb +42 -0
- data/lib/models/mongomapper_user.rb +38 -0
- data/lib/models/rufus_tokyo_user.rb +206 -0
- data/lib/models/sequel_adapter.rb +68 -0
- data/lib/models/sequel_user.rb +53 -0
- data/lib/models/tc_adapter.rb +101 -0
- data/lib/sinatra-authentication-o.rb +305 -0
- data/lib/sinatra-authentication.rb +305 -0
- data/lib/sinatra-authentication/models.rb +5 -0
- data/lib/views/edit.haml +45 -0
- data/lib/views/edit.slim +46 -0
- data/lib/views/index.haml +29 -0
- data/lib/views/index.slim +30 -0
- data/lib/views/login.haml +24 -0
- data/lib/views/login.slim +25 -0
- data/lib/views/show.haml +9 -0
- data/lib/views/show.slim +10 -0
- data/lib/views/signup.haml +28 -0
- data/lib/views/signup.slim +33 -0
- data/readme.markdown +295 -0
- data/sinatra-authentication-oran.gemspec +137 -0
- data/spec/run_all_specs.rb +8 -0
- data/spec/unit/ar_model_spec.rb +3 -0
- data/spec/unit/dm_model_spec.rb +3 -0
- data/spec/unit/mm_model_spec.rb +3 -0
- data/spec/unit/mongoid_model_spec.rb +3 -0
- data/spec/unit/sequel_model_spec.rb +10 -0
- data/spec/unit/tc_model_spec.rb +3 -0
- data/spec/unit/user_specs.rb +119 -0
- data/test/activerecord_test.rb +5 -0
- data/test/datamapper_test.rb +5 -0
- data/test/lib/ar_app.rb +27 -0
- data/test/lib/dm_app.rb +20 -0
- data/test/lib/dm_extend_app.rb +27 -0
- data/test/lib/dm_sinbook.rb +54 -0
- data/test/lib/extend_views/edit.haml +46 -0
- data/test/lib/extend_views/index.haml +31 -0
- data/test/lib/extend_views/login.haml +21 -0
- data/test/lib/extend_views/show.haml +9 -0
- data/test/lib/extend_views/signup.haml +29 -0
- data/test/lib/helper.rb +16 -0
- data/test/lib/mm_app.rb +24 -0
- data/test/lib/mongoid_app.rb +28 -0
- data/test/lib/sequel_app.rb +21 -0
- data/test/lib/tc_app.rb +17 -0
- data/test/lib/tc_sinbook.rb +61 -0
- data/test/mongoid_test.rb +5 -0
- data/test/mongomapper_test.rb +40 -0
- data/test/route_tests.rb +29 -0
- data/test/rufus_tokyo_test.rb +5 -0
- data/test/sequel_test.rb +5 -0
- 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
|