sinatra-authentication-oran 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,101 @@
|
|
1
|
+
module TcAdapter
|
2
|
+
def self.included(base)
|
3
|
+
base.extend ClassMethods
|
4
|
+
base.class_eval {
|
5
|
+
include TcAdapter::InstanceMethods
|
6
|
+
alias :class_id :id
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
#TODO add pagination
|
12
|
+
def all
|
13
|
+
result = TcUser.query do |q|
|
14
|
+
q.order_by 'created_at_i', :numdesc
|
15
|
+
end
|
16
|
+
|
17
|
+
#these will be the same for all adapters, they should be defined in the user class, and these methods should have a different name?
|
18
|
+
result.collect {|instance| self.new instance }
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(hash)
|
22
|
+
if hash[:id]
|
23
|
+
pk = hash[:id]
|
24
|
+
if pk.length > 0
|
25
|
+
result = TcUser.get(pk)
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
else
|
30
|
+
result = TcUser.query do |q|
|
31
|
+
hash.each do |key, value|
|
32
|
+
q.add key.to_s, :streq, value.to_s
|
33
|
+
end
|
34
|
+
end[0]
|
35
|
+
end
|
36
|
+
#elsif hash[:email]
|
37
|
+
# result = TcUser.query do |q|
|
38
|
+
# q.add 'email', :streq, hash[:email]
|
39
|
+
# end[0]
|
40
|
+
#the zero is because this returns an array but get should return the first result
|
41
|
+
#end
|
42
|
+
|
43
|
+
if result
|
44
|
+
self.new result
|
45
|
+
else
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def set(attributes)
|
51
|
+
user = TcUser.query do |q|
|
52
|
+
q.add 'email', :streq, attributes['email']
|
53
|
+
end
|
54
|
+
|
55
|
+
if user == [] #no user
|
56
|
+
self.new TcUser.set(attributes)
|
57
|
+
else
|
58
|
+
if attributes['email'].length == 0
|
59
|
+
error = 'You need to provide an email address'
|
60
|
+
else
|
61
|
+
error = 'That email is already taken'
|
62
|
+
end
|
63
|
+
|
64
|
+
TcUser.new(attributes, error)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def set!(attributes)
|
69
|
+
self.new TcUser.set!(attributes)
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete(pk)
|
73
|
+
#true or false
|
74
|
+
!!TcUser.delete(pk)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
module InstanceMethods
|
79
|
+
def update(attributes)
|
80
|
+
@instance.update attributes
|
81
|
+
end
|
82
|
+
|
83
|
+
def errors
|
84
|
+
@instance.errors.join(', ')
|
85
|
+
end
|
86
|
+
|
87
|
+
def valid
|
88
|
+
@instance.errors.length == 0
|
89
|
+
end
|
90
|
+
|
91
|
+
def method_missing(meth, *args, &block)
|
92
|
+
#cool I just found out * on an array turn the array into a list of args for a function
|
93
|
+
@instance.send(meth, *args, &block)
|
94
|
+
end
|
95
|
+
|
96
|
+
#this was the only thing that didn't get passed on to method_missing because this is a method of object doh
|
97
|
+
def id
|
98
|
+
@instance.id
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,305 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require File.expand_path("../models/abstract_user", __FILE__)
|
3
|
+
|
4
|
+
module Sinatra
|
5
|
+
module SinatraAuthentication
|
6
|
+
def self.registered(app)
|
7
|
+
#INVESTIGATE
|
8
|
+
#the possibility of sinatra having an array of view_paths to load from
|
9
|
+
#PROBLEM
|
10
|
+
#sinatra 9.1.1 doesn't have multiple view capability anywhere
|
11
|
+
#so to get around I have to do it totally manually by
|
12
|
+
#loading the view from this path into a string and rendering it
|
13
|
+
app.set :sinatra_authentication_view_path, File.expand_path('../views/', __FILE__)
|
14
|
+
unless defined?(options.template_engine)
|
15
|
+
app.set :template_engine, :slim
|
16
|
+
end
|
17
|
+
|
18
|
+
app.get '/users/?' do
|
19
|
+
login_required
|
20
|
+
redirect "/" unless current_user.admin?
|
21
|
+
|
22
|
+
@users = User.all
|
23
|
+
if @users != []
|
24
|
+
send options.template_engine, get_view_as_string("index.#{options.template_engine}"), :layout => use_layout?
|
25
|
+
else
|
26
|
+
redirect '/signup'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
app.get '/users/:id/?' do
|
31
|
+
login_required
|
32
|
+
|
33
|
+
@user = User.get(:id => params[:id])
|
34
|
+
send options.template_engine, get_view_as_string("show.#{options.template_engine}"), :layout => use_layout?
|
35
|
+
end
|
36
|
+
|
37
|
+
#convenience for ajax but maybe entirely stupid and unnecesary
|
38
|
+
app.get '/logged_in' do
|
39
|
+
if session[:user]
|
40
|
+
"true"
|
41
|
+
else
|
42
|
+
"false"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
app.get '/login/?' do
|
47
|
+
if session[:user]
|
48
|
+
redirect '/'
|
49
|
+
else
|
50
|
+
send options.template_engine, get_view_as_string("login.#{options.template_engine}"), :layout => use_layout?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
app.post '/login/?' do
|
55
|
+
if user = User.authenticate(params[:name], params[:password])
|
56
|
+
session[:user] = user.id
|
57
|
+
|
58
|
+
if Rack.const_defined?('Flash')
|
59
|
+
flash[:notice] = "Login successful."
|
60
|
+
end
|
61
|
+
|
62
|
+
if session[:return_to]
|
63
|
+
redirect_url = session[:return_to]
|
64
|
+
session[:return_to] = false
|
65
|
+
redirect redirect_url
|
66
|
+
else
|
67
|
+
redirect '/'
|
68
|
+
end
|
69
|
+
else
|
70
|
+
if Rack.const_defined?('Flash')
|
71
|
+
flash[:error] = "The email or password you entered is incorrect."
|
72
|
+
end
|
73
|
+
redirect '/login'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
app.get '/logout/?' do
|
78
|
+
session[:user] = nil
|
79
|
+
if Rack.const_defined?('Flash')
|
80
|
+
flash[:notice] = "Logout successful."
|
81
|
+
end
|
82
|
+
return_to = ( session[:return_to] ? session[:return_to] : '/' )
|
83
|
+
redirect return_to
|
84
|
+
end
|
85
|
+
|
86
|
+
app.get '/signup/?' do
|
87
|
+
if session[:user]
|
88
|
+
redirect '/'
|
89
|
+
else
|
90
|
+
send options.template_engine, get_view_as_string("signup.#{options.template_engine}"), :layout => use_layout?
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
app.post '/signup/?' do
|
95
|
+
@user = User.set(params[:user])
|
96
|
+
if @user.valid && @user.id
|
97
|
+
session[:user] = @user.id
|
98
|
+
if Rack.const_defined?('Flash')
|
99
|
+
flash[:notice] = "Account created."
|
100
|
+
end
|
101
|
+
redirect '/'
|
102
|
+
else
|
103
|
+
if Rack.const_defined?('Flash')
|
104
|
+
flash[:error] = "There were some problems creating your account: #{@user.errors}."
|
105
|
+
end
|
106
|
+
redirect '/signup?' + hash_to_query_string(params['user'])
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
app.get '/users/:id/edit/?' do
|
111
|
+
login_required
|
112
|
+
redirect "/users" unless current_user.admin? || current_user.id.to_s == params[:id]
|
113
|
+
@user = User.get(:id => params[:id])
|
114
|
+
send options.template_engine, get_view_as_string("edit.#{options.template_engine}"), :layout => use_layout?
|
115
|
+
end
|
116
|
+
|
117
|
+
app.post '/users/:id/edit/?' do
|
118
|
+
login_required
|
119
|
+
redirect "/users" unless current_user.admin? || current_user.id.to_s == params[:id]
|
120
|
+
|
121
|
+
user = User.get(:id => params[:id])
|
122
|
+
user_attributes = params[:user]
|
123
|
+
if params[:user][:password] == ""
|
124
|
+
user_attributes.delete("password")
|
125
|
+
user_attributes.delete("password_confirmation")
|
126
|
+
end
|
127
|
+
|
128
|
+
if user.update(user_attributes)
|
129
|
+
if Rack.const_defined?('Flash')
|
130
|
+
flash[:notice] = 'Account updated.'
|
131
|
+
end
|
132
|
+
redirect '/'
|
133
|
+
else
|
134
|
+
if Rack.const_defined?('Flash')
|
135
|
+
flash[:error] = "Whoops, looks like there were some problems with your updates: #{user.errors}."
|
136
|
+
end
|
137
|
+
redirect "/users/#{user.id}/edit?" + hash_to_query_string(user_attributes)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
app.get '/users/:id/delete/?' do
|
142
|
+
login_required
|
143
|
+
redirect "/users" unless current_user.admin? || current_user.id.to_s == params[:id]
|
144
|
+
|
145
|
+
if User.delete(params[:id])
|
146
|
+
if Rack.const_defined?('Flash')
|
147
|
+
flash[:notice] = "User deleted."
|
148
|
+
end
|
149
|
+
else
|
150
|
+
if Rack.const_defined?('Flash')
|
151
|
+
flash[:error] = "Deletion failed."
|
152
|
+
end
|
153
|
+
end
|
154
|
+
redirect '/'
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
if Sinatra.const_defined?('FacebookObject')
|
159
|
+
app.get '/connect/?' do
|
160
|
+
if fb[:user]
|
161
|
+
if current_user.class != GuestUser
|
162
|
+
user = current_user
|
163
|
+
else
|
164
|
+
user = User.get(:fb_uid => fb[:user])
|
165
|
+
end
|
166
|
+
|
167
|
+
if user
|
168
|
+
if !user.fb_uid || user.fb_uid != fb[:user]
|
169
|
+
user.update :fb_uid => fb[:user]
|
170
|
+
end
|
171
|
+
session[:user] = user.id
|
172
|
+
else
|
173
|
+
user = User.set!(:fb_uid => fb[:user])
|
174
|
+
session[:user] = user.id
|
175
|
+
end
|
176
|
+
end
|
177
|
+
redirect '/'
|
178
|
+
end
|
179
|
+
|
180
|
+
app.get '/receiver' do
|
181
|
+
%[<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
182
|
+
<html xmlns="http://www.w3.org/1999/xhtml" >
|
183
|
+
<body>
|
184
|
+
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.js" type="text/javascript"></script>
|
185
|
+
</body>
|
186
|
+
</html>]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
module Helpers
|
193
|
+
def hash_to_query_string(hash)
|
194
|
+
hash.collect {|k,v| "#{k}=#{v}"}.join('&')
|
195
|
+
end
|
196
|
+
|
197
|
+
def login_required
|
198
|
+
#not as efficient as checking the session. but this inits the fb_user if they are logged in
|
199
|
+
if current_user.class != GuestUser
|
200
|
+
return true
|
201
|
+
else
|
202
|
+
session[:return_to] = request.fullpath
|
203
|
+
redirect '/login'
|
204
|
+
return false
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def current_user
|
209
|
+
if session[:user]
|
210
|
+
User.get(:id => session[:user])
|
211
|
+
else
|
212
|
+
GuestUser.new
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def logged_in?
|
217
|
+
!!session[:user]
|
218
|
+
end
|
219
|
+
|
220
|
+
def use_layout?
|
221
|
+
!request.xhr?
|
222
|
+
end
|
223
|
+
|
224
|
+
#BECAUSE sinatra 9.1.1 can't load views from different paths properly
|
225
|
+
def get_view_as_string(filename)
|
226
|
+
view = File.join(settings.sinatra_authentication_view_path, filename)
|
227
|
+
data = ""
|
228
|
+
f = File.open(view, "r")
|
229
|
+
f.each_line do |line|
|
230
|
+
data += line
|
231
|
+
end
|
232
|
+
return data
|
233
|
+
end
|
234
|
+
|
235
|
+
def render_login_logout(html_attributes = {:class => ""})
|
236
|
+
css_classes = html_attributes.delete(:class)
|
237
|
+
parameters = ''
|
238
|
+
html_attributes.each_pair do |attribute, value|
|
239
|
+
parameters += "#{attribute}=\"#{value}\" "
|
240
|
+
end
|
241
|
+
|
242
|
+
result = "<div id='sinatra-authentication-login-logout' >"
|
243
|
+
if logged_in?
|
244
|
+
logout_parameters = html_attributes
|
245
|
+
# a tad janky?
|
246
|
+
logout_parameters.delete(:rel)
|
247
|
+
result += "<a href='/users/#{current_user.id}/edit' class='#{css_classes} sinatra-authentication-edit' #{parameters}>Edit account</a> "
|
248
|
+
if Sinatra.const_defined?('FacebookObject')
|
249
|
+
if fb[:user]
|
250
|
+
result += "<a href='javascript:FB.Connect.logoutAndRedirect(\"/logout\");' class='#{css_classes} sinatra-authentication-logout' #{logout_parameters}>Logout</a>"
|
251
|
+
else
|
252
|
+
result += "<a href='/logout' class='#{css_classes} sinatra-authentication-logout' #{logout_parameters}>Logout</a>"
|
253
|
+
end
|
254
|
+
else
|
255
|
+
result += "<a href='/logout' class='#{css_classes} sinatra-authentication-logout' #{logout_parameters}>Logout</a>"
|
256
|
+
end
|
257
|
+
else
|
258
|
+
result += "<a href='/signup' class='#{css_classes} sinatra-authentication-signup' #{parameters}>Signup</a> "
|
259
|
+
result += "<a href='/login' class='#{css_classes} sinatra-authentication-login' #{parameters}>Login</a>"
|
260
|
+
end
|
261
|
+
|
262
|
+
result += "</div>"
|
263
|
+
end
|
264
|
+
|
265
|
+
if Sinatra.const_defined?('FacebookObject')
|
266
|
+
def render_facebook_connect_link(text = 'Login using facebook', options = {:size => 'small'})
|
267
|
+
if options[:size] == 'small'
|
268
|
+
size = 'Small'
|
269
|
+
elsif options[:size] == 'medium'
|
270
|
+
size = 'Medium'
|
271
|
+
elsif options[:size] == 'large'
|
272
|
+
size = 'Large'
|
273
|
+
elsif options[:size] == 'xlarge'
|
274
|
+
size = 'BigPun'
|
275
|
+
else
|
276
|
+
size = 'Small'
|
277
|
+
end
|
278
|
+
|
279
|
+
%[<a href="#" onclick="FB.Connect.requireSession(function(){document.location = '/connect';}); return false;" class="fbconnect_login_button FBConnectButton FBConnectButton_#{size}">
|
280
|
+
<span id="RES_ID_fb_login_text" class="FBConnectButton_Text">
|
281
|
+
#{text}
|
282
|
+
</span>
|
283
|
+
</a>]
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
register SinatraAuthentication
|
289
|
+
end
|
290
|
+
|
291
|
+
class GuestUser
|
292
|
+
def guest?
|
293
|
+
true
|
294
|
+
end
|
295
|
+
|
296
|
+
def permission_level
|
297
|
+
0
|
298
|
+
end
|
299
|
+
|
300
|
+
# current_user.admin? returns false. current_user.has_a_baby? returns false.
|
301
|
+
# (which is a bit of an assumption I suppose)
|
302
|
+
def method_missing(m, *args)
|
303
|
+
return false
|
304
|
+
end
|
305
|
+
end
|
@@ -0,0 +1,305 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require File.expand_path("../models/abstract_user", __FILE__)
|
3
|
+
|
4
|
+
module Sinatra
|
5
|
+
module SinatraAuthentication
|
6
|
+
def self.registered(app)
|
7
|
+
#INVESTIGATE
|
8
|
+
#the possibility of sinatra having an array of view_paths to load from
|
9
|
+
#PROBLEM
|
10
|
+
#sinatra 9.1.1 doesn't have multiple view capability anywhere
|
11
|
+
#so to get around I have to do it totally manually by
|
12
|
+
#loading the view from this path into a string and rendering it
|
13
|
+
app.set :sinatra_authentication_view_path, File.expand_path('../views/', __FILE__)
|
14
|
+
unless defined?(options.template_engine)
|
15
|
+
app.set :template_engine, :slim
|
16
|
+
end
|
17
|
+
|
18
|
+
app.get '/users/?' do
|
19
|
+
login_required
|
20
|
+
redirect "/" unless current_user.admin?
|
21
|
+
|
22
|
+
@users = User.all
|
23
|
+
if @users != []
|
24
|
+
send options.template_engine, get_view_as_string("index.#{options.template_engine}"), :layout => use_layout?
|
25
|
+
else
|
26
|
+
redirect '/signup'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
app.get '/users/:id/?' do
|
31
|
+
login_required
|
32
|
+
|
33
|
+
@user = User.get(:id => params[:id])
|
34
|
+
send options.template_engine, get_view_as_string("show.#{options.template_engine}"), :layout => use_layout?
|
35
|
+
end
|
36
|
+
|
37
|
+
#convenience for ajax but maybe entirely stupid and unnecesary
|
38
|
+
app.get '/logged_in' do
|
39
|
+
if session[:user]
|
40
|
+
"true"
|
41
|
+
else
|
42
|
+
"false"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
app.get '/login/?' do
|
47
|
+
if session[:user]
|
48
|
+
redirect '/'
|
49
|
+
else
|
50
|
+
send options.template_engine, get_view_as_string("login.#{options.template_engine}"), :layout => use_layout?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
app.post '/login/?' do
|
55
|
+
if user = User.authenticate(params[:name], params[:password])
|
56
|
+
session[:user] = user.id
|
57
|
+
|
58
|
+
if Rack.const_defined?('Flash')
|
59
|
+
flash[:notice] = "Login successful."
|
60
|
+
end
|
61
|
+
|
62
|
+
if session[:return_to]
|
63
|
+
redirect_url = session[:return_to]
|
64
|
+
session[:return_to] = false
|
65
|
+
redirect redirect_url
|
66
|
+
else
|
67
|
+
redirect '/'
|
68
|
+
end
|
69
|
+
else
|
70
|
+
if Rack.const_defined?('Flash')
|
71
|
+
flash[:error] = "The email or password you entered is incorrect."
|
72
|
+
end
|
73
|
+
redirect '/login'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
app.get '/logout/?' do
|
78
|
+
session[:user] = nil
|
79
|
+
if Rack.const_defined?('Flash')
|
80
|
+
flash[:notice] = "Logout successful."
|
81
|
+
end
|
82
|
+
return_to = ( session[:return_to] ? session[:return_to] : '/' )
|
83
|
+
redirect return_to
|
84
|
+
end
|
85
|
+
|
86
|
+
app.get '/signup/?' do
|
87
|
+
if session[:user]
|
88
|
+
redirect '/'
|
89
|
+
else
|
90
|
+
send options.template_engine, get_view_as_string("signup.#{options.template_engine}"), :layout => use_layout?
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
app.post '/signup/?' do
|
95
|
+
@user = User.set(params[:user])
|
96
|
+
if @user.valid && @user.id
|
97
|
+
session[:user] = @user.id
|
98
|
+
if Rack.const_defined?('Flash')
|
99
|
+
flash[:notice] = "Account created."
|
100
|
+
end
|
101
|
+
redirect '/'
|
102
|
+
else
|
103
|
+
if Rack.const_defined?('Flash')
|
104
|
+
flash[:error] = "There were some problems creating your account: #{@user.errors}."
|
105
|
+
end
|
106
|
+
redirect '/signup?' + hash_to_query_string(params['user'])
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
app.get '/users/:id/edit/?' do
|
111
|
+
login_required
|
112
|
+
redirect "/users" unless current_user.admin? || current_user.id.to_s == params[:id]
|
113
|
+
@user = User.get(:id => params[:id])
|
114
|
+
send options.template_engine, get_view_as_string("edit.#{options.template_engine}"), :layout => use_layout?
|
115
|
+
end
|
116
|
+
|
117
|
+
app.post '/users/:id/edit/?' do
|
118
|
+
login_required
|
119
|
+
redirect "/users" unless current_user.admin? || current_user.id.to_s == params[:id]
|
120
|
+
|
121
|
+
user = User.get(:id => params[:id])
|
122
|
+
user_attributes = params[:user]
|
123
|
+
if params[:user][:password] == ""
|
124
|
+
user_attributes.delete("password")
|
125
|
+
user_attributes.delete("password_confirmation")
|
126
|
+
end
|
127
|
+
|
128
|
+
if user.update(user_attributes)
|
129
|
+
if Rack.const_defined?('Flash')
|
130
|
+
flash[:notice] = 'Account updated.'
|
131
|
+
end
|
132
|
+
redirect '/'
|
133
|
+
else
|
134
|
+
if Rack.const_defined?('Flash')
|
135
|
+
flash[:error] = "Whoops, looks like there were some problems with your updates: #{user.errors}."
|
136
|
+
end
|
137
|
+
redirect "/users/#{user.id}/edit?" + hash_to_query_string(user_attributes)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
app.get '/users/:id/delete/?' do
|
142
|
+
login_required
|
143
|
+
redirect "/users" unless current_user.admin? || current_user.id.to_s == params[:id]
|
144
|
+
|
145
|
+
if User.delete(params[:id])
|
146
|
+
if Rack.const_defined?('Flash')
|
147
|
+
flash[:notice] = "User deleted."
|
148
|
+
end
|
149
|
+
else
|
150
|
+
if Rack.const_defined?('Flash')
|
151
|
+
flash[:error] = "Deletion failed."
|
152
|
+
end
|
153
|
+
end
|
154
|
+
redirect '/'
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
if Sinatra.const_defined?('FacebookObject')
|
159
|
+
app.get '/connect/?' do
|
160
|
+
if fb[:user]
|
161
|
+
if current_user.class != GuestUser
|
162
|
+
user = current_user
|
163
|
+
else
|
164
|
+
user = User.get(:fb_uid => fb[:user])
|
165
|
+
end
|
166
|
+
|
167
|
+
if user
|
168
|
+
if !user.fb_uid || user.fb_uid != fb[:user]
|
169
|
+
user.update :fb_uid => fb[:user]
|
170
|
+
end
|
171
|
+
session[:user] = user.id
|
172
|
+
else
|
173
|
+
user = User.set!(:fb_uid => fb[:user])
|
174
|
+
session[:user] = user.id
|
175
|
+
end
|
176
|
+
end
|
177
|
+
redirect '/'
|
178
|
+
end
|
179
|
+
|
180
|
+
app.get '/receiver' do
|
181
|
+
%[<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
182
|
+
<html xmlns="http://www.w3.org/1999/xhtml" >
|
183
|
+
<body>
|
184
|
+
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.js" type="text/javascript"></script>
|
185
|
+
</body>
|
186
|
+
</html>]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
module Helpers
|
193
|
+
def hash_to_query_string(hash)
|
194
|
+
hash.collect {|k,v| "#{k}=#{v}"}.join('&')
|
195
|
+
end
|
196
|
+
|
197
|
+
def login_required
|
198
|
+
#not as efficient as checking the session. but this inits the fb_user if they are logged in
|
199
|
+
if current_user.class != GuestUser
|
200
|
+
return true
|
201
|
+
else
|
202
|
+
session[:return_to] = request.fullpath
|
203
|
+
redirect '/login'
|
204
|
+
return false
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def current_user
|
209
|
+
if session[:user]
|
210
|
+
User.get(:id => session[:user])
|
211
|
+
else
|
212
|
+
GuestUser.new
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def logged_in?
|
217
|
+
!!session[:user]
|
218
|
+
end
|
219
|
+
|
220
|
+
def use_layout?
|
221
|
+
!request.xhr?
|
222
|
+
end
|
223
|
+
|
224
|
+
#BECAUSE sinatra 9.1.1 can't load views from different paths properly
|
225
|
+
def get_view_as_string(filename)
|
226
|
+
view = File.join(settings.sinatra_authentication_view_path, filename)
|
227
|
+
data = ""
|
228
|
+
f = File.open(view, "r")
|
229
|
+
f.each_line do |line|
|
230
|
+
data += line
|
231
|
+
end
|
232
|
+
return data
|
233
|
+
end
|
234
|
+
|
235
|
+
def render_login_logout(html_attributes = {:class => ""})
|
236
|
+
css_classes = html_attributes.delete(:class)
|
237
|
+
parameters = ''
|
238
|
+
html_attributes.each_pair do |attribute, value|
|
239
|
+
parameters += "#{attribute}=\"#{value}\" "
|
240
|
+
end
|
241
|
+
|
242
|
+
result = "<div id='sinatra-authentication-login-logout' >"
|
243
|
+
if logged_in?
|
244
|
+
logout_parameters = html_attributes
|
245
|
+
# a tad janky?
|
246
|
+
logout_parameters.delete(:rel)
|
247
|
+
result += "<a href='/users/#{current_user.id}/edit' class='#{css_classes} sinatra-authentication-edit' #{parameters}>Edit account</a> "
|
248
|
+
if Sinatra.const_defined?('FacebookObject')
|
249
|
+
if fb[:user]
|
250
|
+
result += "<a href='javascript:FB.Connect.logoutAndRedirect(\"/logout\");' class='#{css_classes} sinatra-authentication-logout' #{logout_parameters}>Logout</a>"
|
251
|
+
else
|
252
|
+
result += "<a href='/logout' class='#{css_classes} sinatra-authentication-logout' #{logout_parameters}>Logout</a>"
|
253
|
+
end
|
254
|
+
else
|
255
|
+
result += "<a href='/logout' class='#{css_classes} sinatra-authentication-logout' #{logout_parameters}>Logout</a>"
|
256
|
+
end
|
257
|
+
else
|
258
|
+
result += "<a href='/signup' class='#{css_classes} sinatra-authentication-signup' #{parameters}>Signup</a> "
|
259
|
+
result += "<a href='/login' class='#{css_classes} sinatra-authentication-login' #{parameters}>Login</a>"
|
260
|
+
end
|
261
|
+
|
262
|
+
result += "</div>"
|
263
|
+
end
|
264
|
+
|
265
|
+
if Sinatra.const_defined?('FacebookObject')
|
266
|
+
def render_facebook_connect_link(text = 'Login using facebook', options = {:size => 'small'})
|
267
|
+
if options[:size] == 'small'
|
268
|
+
size = 'Small'
|
269
|
+
elsif options[:size] == 'medium'
|
270
|
+
size = 'Medium'
|
271
|
+
elsif options[:size] == 'large'
|
272
|
+
size = 'Large'
|
273
|
+
elsif options[:size] == 'xlarge'
|
274
|
+
size = 'BigPun'
|
275
|
+
else
|
276
|
+
size = 'Small'
|
277
|
+
end
|
278
|
+
|
279
|
+
%[<a href="#" onclick="FB.Connect.requireSession(function(){document.location = '/connect';}); return false;" class="fbconnect_login_button FBConnectButton FBConnectButton_#{size}">
|
280
|
+
<span id="RES_ID_fb_login_text" class="FBConnectButton_Text">
|
281
|
+
#{text}
|
282
|
+
</span>
|
283
|
+
</a>]
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
register SinatraAuthentication
|
289
|
+
end
|
290
|
+
|
291
|
+
class GuestUser
|
292
|
+
def guest?
|
293
|
+
true
|
294
|
+
end
|
295
|
+
|
296
|
+
def permission_level
|
297
|
+
0
|
298
|
+
end
|
299
|
+
|
300
|
+
# current_user.admin? returns false. current_user.has_a_baby? returns false.
|
301
|
+
# (which is a bit of an assumption I suppose)
|
302
|
+
def method_missing(m, *args)
|
303
|
+
return false
|
304
|
+
end
|
305
|
+
end
|