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