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.
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