ae_users 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/README +47 -0
  2. data/Rakefile +36 -0
  3. data/VERSION +1 -0
  4. data/ae_users.gemspec +117 -0
  5. data/app/controllers/account_controller.rb +167 -0
  6. data/app/controllers/auth_controller.rb +202 -0
  7. data/app/controllers/permission_controller.rb +172 -0
  8. data/app/helpers/account_helper.rb +2 -0
  9. data/app/helpers/auth_helper.rb +5 -0
  10. data/app/helpers/permission_helper.rb +2 -0
  11. data/app/models/account.rb +50 -0
  12. data/app/models/auth_notifier.rb +34 -0
  13. data/app/models/auth_ticket.rb +39 -0
  14. data/app/models/email_address.rb +17 -0
  15. data/app/models/login.rb +23 -0
  16. data/app/models/open_id_identity.rb +5 -0
  17. data/app/models/permission.rb +57 -0
  18. data/app/models/person.rb +156 -0
  19. data/app/models/role.rb +7 -0
  20. data/app/views/account/_personal_info.rhtml +35 -0
  21. data/app/views/account/_procon_profile.rhtml +3 -0
  22. data/app/views/account/_signup_form.html.erb +39 -0
  23. data/app/views/account/activate.rhtml +6 -0
  24. data/app/views/account/activation_error.rhtml +11 -0
  25. data/app/views/account/change_password.rhtml +3 -0
  26. data/app/views/account/edit_profile.rhtml +117 -0
  27. data/app/views/account/signup.rhtml +9 -0
  28. data/app/views/account/signup_noactivation.rhtml +7 -0
  29. data/app/views/account/signup_success.rhtml +8 -0
  30. data/app/views/auth/_auth_form.rhtml +54 -0
  31. data/app/views/auth/_forgot_form.html.erb +12 -0
  32. data/app/views/auth/_mini_auth_form.rhtml +17 -0
  33. data/app/views/auth/_openid_auth_form.html.erb +14 -0
  34. data/app/views/auth/_other_login_options.html.erb +24 -0
  35. data/app/views/auth/auth_form.js.erb +63 -0
  36. data/app/views/auth/forgot.rhtml +3 -0
  37. data/app/views/auth/forgot_form.rhtml +6 -0
  38. data/app/views/auth/index.css.erb +23 -0
  39. data/app/views/auth/login.rhtml +6 -0
  40. data/app/views/auth/needs_activation.rhtml +6 -0
  41. data/app/views/auth/needs_person.html.erb +32 -0
  42. data/app/views/auth/needs_profile.rhtml +14 -0
  43. data/app/views/auth/openid_login.html.erb +6 -0
  44. data/app/views/auth/resend_activation.rhtml +3 -0
  45. data/app/views/auth_notifier/account_activation.rhtml +13 -0
  46. data/app/views/auth_notifier/generated_password.rhtml +10 -0
  47. data/app/views/permission/_add_grantee.rhtml +47 -0
  48. data/app/views/permission/_role_member.rhtml +8 -0
  49. data/app/views/permission/_show.rhtml +81 -0
  50. data/app/views/permission/_userpicker.rhtml +0 -0
  51. data/app/views/permission/add_role_member.rhtml +3 -0
  52. data/app/views/permission/admin.rhtml +45 -0
  53. data/app/views/permission/edit.rhtml +9 -0
  54. data/app/views/permission/edit_role.rhtml +63 -0
  55. data/app/views/permission/grant.rhtml +10 -0
  56. data/db/migrate/002_create_accounts.rb +17 -0
  57. data/db/migrate/003_create_email_addresses.rb +17 -0
  58. data/db/migrate/004_create_people.rb +24 -0
  59. data/db/migrate/013_simplify_signup.rb +15 -0
  60. data/db/migrate/014_create_permissions.rb +16 -0
  61. data/db/migrate/015_create_roles.rb +18 -0
  62. data/db/migrate/016_refactor_people.rb +36 -0
  63. data/db/migrate/017_people_permissions.rb +9 -0
  64. data/generators/ae_users/USAGE +14 -0
  65. data/generators/ae_users/ae_users_generator.rb +12 -0
  66. data/generators/ae_users/templates/add.png +0 -0
  67. data/generators/ae_users/templates/admin.png +0 -0
  68. data/generators/ae_users/templates/group.png +0 -0
  69. data/generators/ae_users/templates/logout.png +0 -0
  70. data/generators/ae_users/templates/migration.rb +25 -0
  71. data/generators/ae_users/templates/openid.gif +0 -0
  72. data/generators/ae_users/templates/remove.png +0 -0
  73. data/generators/ae_users/templates/user.png +0 -0
  74. data/init.rb +1 -0
  75. data/install.rb +1 -0
  76. data/lib/ae_users.rb +781 -0
  77. data/rails/init.rb +20 -0
  78. data/tasks/ae_users_tasks.rake +4 -0
  79. data/test/ae_users_test.rb +8 -0
  80. data/uninstall.rb +1 -0
  81. metadata +134 -0
@@ -0,0 +1,24 @@
1
+ class CreatePeople < ActiveRecord::Migration
2
+ def self.up
3
+ ActiveRecord::Base.establish_connection :users
4
+ create_table :people do |t|
5
+ t.column :firstname, :string
6
+ t.column :lastname, :string
7
+ t.column :gender, :string
8
+ t.column :nickname, :string
9
+ t.column :address, :string
10
+ t.column :home_phone, :string
11
+ t.column :work_phone, :string
12
+ t.column :best_call_time, :string
13
+ t.column :birthdate, :datetime
14
+ t.column :account_id, :integer
15
+ t.column :created_at, :datetime
16
+ t.column :updated_at, :datetime
17
+ end
18
+ end
19
+
20
+ def self.down
21
+ ActiveRecord::Base.establish_connection :users
22
+ drop_table :people
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ class SimplifySignup < ActiveRecord::Migration
2
+ def self.up
3
+ ActiveRecord::Base.establish_connection :users
4
+ rename_column "people", "home_phone", "phone"
5
+ remove_column "people", "work_phone"
6
+ remove_column "people", "address"
7
+ end
8
+
9
+ def self.down
10
+ ActiveRecord::Base.establish_connection :users
11
+ rename_column "people", "phone", "home_phone"
12
+ add_column "people", "work_phone", :string
13
+ add_column "people", "address", :string
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ class CreatePermissions < ActiveRecord::Migration
2
+ def self.up
3
+ ActiveRecord::Base.establish_connection :users
4
+ create_table :permissions do |t|
5
+ t.column :role_id, :integer, :null => false
6
+ t.column :permission, :string
7
+ t.column :permissioned_id, :integer
8
+ t.column :permissioned_type, :string
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ ActiveRecord::Base.establish_connection :users
14
+ drop_table :permissions
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ class CreateRoles < ActiveRecord::Migration
2
+ def self.up
3
+ ActiveRecord::Base.establish_connection :users
4
+ create_table :roles do |t|
5
+ t.column :name, :string, :null => false
6
+ end
7
+ create_table :people_roles, :id => false do |t|
8
+ t.column :person_id, :integer, :null => false
9
+ t.column :role_id, :integer, :null => false
10
+ end
11
+ end
12
+
13
+ def self.down
14
+ ActiveRecord::Base.establish_connection :users
15
+ drop_table :roles
16
+ drop_table :people_roles
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ class RefactorPeople < ActiveRecord::Migration
2
+ def self.up
3
+ ActiveRecord::Base.establish_connection :users
4
+ create_table :procon_profiles do |t|
5
+ t.column :person_id, :integer, :null => false
6
+ t.column :nickname, :string
7
+ t.column :phone, :string
8
+ t.column :best_call_time, :string
9
+ end
10
+ Person.find(:all).each do |person|
11
+ prof = ProconProfile.new :person => person
12
+ prof.nickname = person.nickname
13
+ prof.phone = person.phone
14
+ prof.best_call_time = person.best_call_time
15
+ prof.save
16
+ end
17
+ remove_column "people", "nickname"
18
+ remove_column "people", "phone"
19
+ remove_column "people", "best_call_time"
20
+ end
21
+
22
+ def self.down
23
+ ActiveRecord::Base.establish_connection :users
24
+ add_column "people", "nickname", :string
25
+ add_column "people", "phone", :string
26
+ add_column "people", "best_call_time", :string
27
+ ProconProfile.find(:all).each do |prof|
28
+ person = prof.person
29
+ person.nickname = prof.nickname
30
+ person.phone = prof.phone
31
+ person.best_call_time = prof.best_call_time
32
+ person.save
33
+ end
34
+ drop_table :procon_profiles
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ class PeoplePermissions < ActiveRecord::Migration
2
+ def self.up
3
+ add_column "permissions", "person_id", :integer
4
+ end
5
+
6
+ def self.down
7
+ remove_column "permissions", "person_id"
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ Description:
2
+ Copies the ae_users resource files into the correct place in your Rails working directory.
3
+
4
+ Example:
5
+ ./script/generate ae_users
6
+
7
+ This will create:
8
+ public/images/ae_users/add.png
9
+ public/images/ae_users/admin.png
10
+ public/images/ae_users/group.png
11
+ public/images/ae_users/logout.png
12
+ public/images/ae_users/openid.gif
13
+ public/images/ae_users/remove.png
14
+ public/images/ae_users/user.png
@@ -0,0 +1,12 @@
1
+ class AeUsersGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.directory "public/images/ae_users"
5
+ %w{add admin group logout remove user}.each do |img|
6
+ m.file "#{img}.png", "public/images/ae_users/#{img}.png"
7
+ end
8
+ m.file "openid.gif", "public/images/ae_users/openid.gif"
9
+ m.migration_template 'migration.rb', "db/migrate", :migration_file_name => 'ae_users_local_tables'
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,25 @@
1
+ class AeUsersLocalTables < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :permissions do |t|
4
+ t.column :role_id, :integer
5
+ t.column :person_id, :integer
6
+ t.column :permission, :string
7
+ t.column :permissioned_id, :integer
8
+ t.column :permissioned_type, :string
9
+ end
10
+
11
+ create_table :auth_tickets do |t|
12
+ t.column :secret, :string
13
+ t.column :person_id, :integer
14
+ t.timestamps
15
+ t.column :expires_at, :datetime
16
+ end
17
+
18
+ add_index :auth_tickets, :secret, :unique => true
19
+ end
20
+
21
+ def self.down
22
+ drop_table :auth_tickets
23
+ drop_table :permissions
24
+ end
25
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rails/init'
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,781 @@
1
+ # AeUsers
2
+ require 'active_record'
3
+
4
+ module AeUsers
5
+ begin
6
+ @@db_name = Rails::Configuration.new.database_configuration["users"]["database"]
7
+ def self.db_name
8
+ @@db_name
9
+ end
10
+ rescue
11
+ end
12
+
13
+ @@signup_allowed = true
14
+ def self.signup_allowed?
15
+ @@signup_allowed
16
+ end
17
+
18
+ def self.disallow_signup
19
+ @@signup_allowed = false
20
+ end
21
+
22
+ @@permissioned_classes = []
23
+ def self.add_permissioned_class(klass)
24
+ if not @@permissioned_classes.include?(klass.name)
25
+ @@permissioned_classes.push(klass.name)
26
+ end
27
+ end
28
+
29
+ def self.permissioned_classes
30
+ return @@permissioned_classes.collect do |name|
31
+ eval(name)
32
+ end
33
+ end
34
+
35
+ def self.permissioned_class(name)
36
+ if @@permissioned_classes.include?(name)
37
+ return eval(name)
38
+ end
39
+ end
40
+
41
+ @@js_framework = "prototype"
42
+ def self.js_framework
43
+ @@js_framework
44
+ end
45
+
46
+ def self.js_framework=(framework)
47
+ @@js_framework = framework
48
+ end
49
+
50
+ # yeah, the following 2 functions are Incredibly Evil(tm). I couldn't find any other way
51
+ # to pass around an ActiveRecord class without having it be potentially overwritten on
52
+ # association access.
53
+ def self.profile_class
54
+ nil
55
+ end
56
+
57
+ def self.profile_class=(klass)
58
+ module_eval <<-END_FUNC
59
+ def self.profile_class
60
+ return #{klass.name}
61
+ end
62
+ END_FUNC
63
+ end
64
+
65
+ def self.map_openid(map)
66
+ map.open_id_complete 'auth', :controller => "auth", :action => "login", :requirements => { :method => :get }
67
+ end
68
+
69
+ class PermissionCache
70
+ def initialize
71
+ @cache = {}
72
+ end
73
+
74
+ def permitted?(person, permissioned, permission)
75
+ RAILS_DEFAULT_LOGGER.debug "Permission cache looking up result for #{person}, #{permissioned}, #{permission}"
76
+ pcache = person_cache(person)
77
+ key = pcache_key(permissioned, permission)
78
+ unless pcache.has_key?(key)
79
+ RAILS_DEFAULT_LOGGER.debug "Cache miss! Loading uncached permission."
80
+ pcache[key] = person.uncached_permitted?(permissioned, permission)
81
+ end
82
+ RAILS_DEFAULT_LOGGER.debug "Result is #{pcache[key]}"
83
+ return pcache[key]
84
+ end
85
+
86
+ def invalidate(person, permissioned, permission)
87
+ RAILS_DEFAULT_LOGGER.debug "Permission cache invalidating result for #{person}, #{permissioned}, #{permission}"
88
+ pcache = person_cache(person)
89
+ pcache.delete(pcache_key(permissioned, permission))
90
+ end
91
+
92
+ def invalidate_all(options={})
93
+ if options[:person]
94
+ RAILS_DEFAULT_LOGGER.debug "Permission cache invalidating all results for #{options[:person]}"
95
+ @cache.delete(options[:person])
96
+ elsif options[:permission] and options[:permissioned]
97
+ RAILS_DEFAULT_LOGGER.debug "Permission cache invalidating all results for #{options[:permissioned]}, #{options[:permission]}"
98
+ @cache.each_value do |pcache|
99
+ pcache.delete(pcache_key(options[:permissioned], options[:permission]))
100
+ end
101
+ else
102
+ RAILS_DEFAULT_LOGGER.debug "Permission cache invalidating all results!"
103
+ @cache = {}
104
+ end
105
+ end
106
+
107
+ private
108
+ def person_cache(person)
109
+ unless @cache.has_key?(person)
110
+ RAILS_DEFAULT_LOGGER.debug "Permission cache creating new pcache for #{person}"
111
+ @cache[person] = {}
112
+ end
113
+ @cache[person]
114
+ end
115
+
116
+ def pcache_key(permissioned, permission)
117
+ if permissioned
118
+ return "#{permissioned.id}_#{permission}"
119
+ else
120
+ return "nil_#{permission}"
121
+ end
122
+ end
123
+ end
124
+
125
+ @@cache_permissions = true
126
+ @@permission_cache = AeUsers::PermissionCache.new
127
+ def self.cache_permissions=(value)
128
+ @@cache_permissions = value
129
+ end
130
+
131
+ def self.cache_permissions?
132
+ @@cache_permissions
133
+ end
134
+
135
+ def self.permission_cache
136
+ @@permission_cache
137
+ end
138
+
139
+ module Acts
140
+ module Permissioned
141
+ def self.included(base)
142
+ base.extend ClassMethods
143
+ end
144
+
145
+ module ClassMethods
146
+ def acts_as_permissioned(options = {})
147
+ has_many :permissions, :as => :permissioned, :dependent => :destroy, :include => [:person, :role, :permissioned]
148
+
149
+ cattr_accessor :permission_names
150
+ self.permission_names = options[:permission_names] || [:show, :edit, :destroy]
151
+ self.permission_names = self.permission_names.collect do |perm|
152
+ perm.to_s
153
+ end
154
+ if not self.permission_names.include? "change_permissions"
155
+ self.permission_names.push "change_permissions"
156
+ end
157
+
158
+ self.permission_names.each do |perm|
159
+ define_method("permit_#{perm}?") do |person|
160
+ self.permitted?(person, perm)
161
+ end
162
+ end
163
+
164
+ AeUsers.add_permissioned_class(self)
165
+
166
+ extend AeUsers::Acts::Permissioned::SingletonMethods
167
+ include AeUsers::Acts::Permissioned::InstanceMethods
168
+ end
169
+ end
170
+
171
+ module SingletonMethods
172
+ end
173
+
174
+ module InstanceMethods
175
+ def permitted?(person, permission=nil)
176
+ person.permitted? self, permission
177
+ end
178
+
179
+ def permitted_people(permission)
180
+ grants = permissions.select { |perm| perm.permission == permission }
181
+ people = []
182
+ grants.collect {|grant| grant.grantee}.each do |grantee|
183
+ if grantee.kind_of? Person
184
+ if not people.include? grantee
185
+ people << grantee
186
+ end
187
+ elsif grantee.kind_of? Role
188
+ grantee.people.each do |person|
189
+ if not people.include? person
190
+ people << person
191
+ end
192
+ end
193
+ end
194
+ end
195
+ return people
196
+ end
197
+
198
+ def grant(grantees, permissions=nil)
199
+ if not grantees.kind_of?(Array)
200
+ grantees = [grantees]
201
+ end
202
+
203
+ if not permissions.kind_of?(Array)
204
+ if permissions.nil?
205
+ permissions = self.class.permission_names
206
+ else
207
+ permissions = [permissions]
208
+ end
209
+ end
210
+
211
+ grantees.each do |grantee|
212
+ if grantee.kind_of? Role
213
+ permissions.each do |perm|
214
+ if AeUsers.cache_permissions?
215
+ grantee.members.each do |person|
216
+ AeUsers.permission_cache.invalidate(person, self, perm)
217
+ end
218
+ end
219
+ Permission.create :role => grantee, :permission => perm, :permissioned => self
220
+ end
221
+ elsif grantee.kind_of? Person
222
+ permissions.each do |perm|
223
+ if AeUsers.cache_permissions?
224
+ AeUsers.permission_cache.invalidate(grantee, self, perm)
225
+ end
226
+ Permission.create :person => grantee, :permission => perm, :permissioned => self
227
+ end
228
+ end
229
+ end
230
+ end
231
+
232
+ def revoke(grantees, permissions=nil)
233
+ if not grantees.kind_of?(Array)
234
+ grantees = [grantees]
235
+ end
236
+
237
+ if not permissions.kind_of?(Array)
238
+ if permissions.nil?
239
+ permissions = self.class.permission_names
240
+ else
241
+ permissions = [permissions]
242
+ end
243
+ end
244
+
245
+ grantees.each do |grantee|
246
+ permissions.each do |perm|
247
+ existing = if grantee.kind_of? Role
248
+ if AeUsers.cache_permissions?
249
+ grantee.members.each do |person|
250
+ AeUsers.permission_cache.invalidate(person, self, perm)
251
+ end
252
+ end
253
+ Permission.find_by_role_and_permission_type(grantee, perm)
254
+ elsif grantee.kind_of? Person
255
+ if AeUsers.cache_permissions?
256
+ AeUsers.permission_cache.invalidate(pesron, self, perm)
257
+ end
258
+ Permission.find_by_person_and_permission_type(person, perm)
259
+ end
260
+
261
+ if existing
262
+ existing.destroy
263
+ end
264
+ end
265
+ end
266
+ end
267
+ end
268
+ end
269
+ end
270
+
271
+ module ControllerExtensions
272
+ module RequirePermission
273
+ def self.included(base)
274
+ base.extend ClassMethods
275
+ end
276
+
277
+ def access_denied(msg=nil, options={})
278
+ options = {
279
+ :layout => active_layout
280
+ }.update(options)
281
+ msg ||= "Sorry, you don't have access to view that page."
282
+ if logged_in?
283
+ body = "If you feel you've been denied access in error, please contact the administrator of this web site."
284
+ respond_to do |format|
285
+ format.html { render options.update({:inline => "<h1>#{msg}</h1>\n\n<div id=\"login\"><p><b>#{body}</b></p></div>"}) }
286
+ format.xml { render :xml => { :error => msg }.to_xml, :status => :forbidden }
287
+ format.js { render :json => msg, :status => :forbidden }
288
+ format.json { render :json => msg, :status => :forbidden }
289
+ end
290
+ else
291
+ flash[:error_messages] = msg
292
+ redirect_to :controller => 'auth', :action => 'login'
293
+ end
294
+ end
295
+
296
+ def logged_in?
297
+ if @logged_in_person
298
+ return @logged_in_person
299
+ end
300
+ if session[:person]
301
+ begin
302
+ @logged_in_person = Person.find(session[:person])
303
+ rescue ActiveRecord::RecordNotFound
304
+ end
305
+ elsif session[:account]
306
+ begin
307
+ acct = Account.find(session[:account])
308
+ session[:person] = acct.person.id
309
+ @logged_in_person = acct.person
310
+ rescue ActiveRecord::RecordNotFound
311
+ end
312
+ elsif attempt_login_from_params
313
+ return logged_in?
314
+ else
315
+ return @logged_in_person
316
+ end
317
+ end
318
+
319
+ def logged_in_person
320
+ return logged_in?
321
+ end
322
+
323
+ def attempt_login(login)
324
+ @account = Account.find_by_email_address(login.email)
325
+ if not @account.nil? and not @account.active
326
+ redirect_to :controller => 'auth', :action => :needs_activation, :account => @account, :email => login.email, :return_to => login.return_to
327
+ return false
328
+ elsif not @account.nil? and @account.check_password login.password
329
+ if (not AeUsers.profile_class.nil? and not @account.person.nil? and
330
+ AeUsers.profile_class.find_by_person_id(@account.person.id).nil?)
331
+
332
+ session[:provisional_person] = @account.person.id
333
+ redirect_to :controller => 'auth', :action => :needs_profile, :return_to => login.return_to
334
+ return false
335
+ else
336
+ session[:person] = @account.person.id
337
+ return true
338
+ end
339
+ else
340
+ flash[:error_messages] = ['Invalid email address or password.']
341
+ return false
342
+ end
343
+ end
344
+
345
+ def attempt_open_id_login(return_to)
346
+ if return_to
347
+ session[:return_to] = return_to
348
+ else
349
+ return_to = session[:return_to]
350
+ end
351
+
352
+ openid_url = params[:openid_url]
353
+ params.delete(:openid_url)
354
+
355
+ optional_fields = Person.sreg_map.keys
356
+ if AeUsers.profile_class and AeUsers.profile_class.respond_to?('sreg_map')
357
+ optional_fields += AeUsers.profile_class.sreg_map.keys
358
+ end
359
+ authenticate_with_open_id(openid_url, :optional => optional_fields) do |result, identity_url, registration|
360
+ if result.successful?
361
+ id = OpenIdIdentity.find_by_identity_url(identity_url)
362
+ if not id.nil?
363
+ @person = id.person
364
+ end
365
+ if id.nil? or @person.nil?
366
+ if AeUsers.signup_allowed?
367
+ session[:identity_url] = identity_url
368
+ redirect_to :controller => 'auth', :action => :needs_person, :return_to => return_to, :registration => registration.data
369
+ return false
370
+ else
371
+ flash[:error_messages] = ["Sorry, you are not registered with this site."]
372
+ return false
373
+ end
374
+ else
375
+ if (not AeUsers.profile_class.nil? and AeUsers.profile_class.find_by_person_id(@person.id).nil?)
376
+ session[:provisional_person] = @person.id
377
+ redirect_to :controller => 'auth', :action => :needs_profile, :return_to => return_to
378
+ return false
379
+ else
380
+ session[:person] = @person.id
381
+ return true
382
+ end
383
+ end
384
+ else
385
+ flash[:error_messages] = result.message
386
+ return false
387
+ end
388
+ end
389
+ return session[:person]
390
+ end
391
+
392
+ def attempt_ticket_login(secret)
393
+ t = AuthTicket.find_ticket(secret)
394
+ if t.nil?
395
+ flash[:error_messages] = ["Ticket not found"]
396
+ return false
397
+ else
398
+ session[:person] = t.person
399
+ t.destroy
400
+ return session[:person]
401
+ end
402
+ end
403
+
404
+ def attempt_login_from_params
405
+ return_to = request.request_uri
406
+ if not params[:ae_email].blank? and not params[:ae_password].blank?
407
+ login = Login.new(:email => params[:ae_email], :password => params[:ae_password], :return_to => return_to)
408
+ attempt_login(login)
409
+ elsif not params[:openid_url].blank?
410
+ attempt_open_id_login(return_to)
411
+ elsif not params[:ae_ticket].blank?
412
+ attempt_ticket_login(params[:ae_ticket])
413
+ end
414
+ end
415
+
416
+ def do_permission_check(obj, perm_name, fail_msg)
417
+ attempt_login_from_params
418
+ p = logged_in_person
419
+ if not (p and p.permitted?(obj, perm_name))
420
+ access_denied fail_msg
421
+ end
422
+ end
423
+
424
+ def create_account_and_person()
425
+ account = Account.new(:password => params[:password1])
426
+ person = Person.new(params[:person])
427
+ addr = EmailAddress.new :address => params[:email], :person => person, :primary => true
428
+ person.account = account
429
+
430
+ if not AeUsers.profile_class.nil?
431
+ app_profile = AeUsers.profile_class.send(:new, :person => person)
432
+ app_profile.attributes = params[:app_profile]
433
+ end
434
+
435
+ if request.post?
436
+ error_fields = []
437
+ error_messages = []
438
+
439
+ if Person.find_by_email_address(params[:email])
440
+ error_fields.push "email"
441
+ error_messages.push "An account at that email address already exists!"
442
+ end
443
+
444
+ if params[:password1] != params[:password2]
445
+ error_fields += ["password1", "password2"]
446
+ error_messages.push "Passwords do not match."
447
+ elsif params[:password1].length == 0
448
+ error_fields += ["password1", "password2"]
449
+ error_messages.push "You must enter a password."
450
+ end
451
+
452
+ ["firstname", "lastname", "email", "gender"].each do |field|
453
+ if (not params[field] or params[field].length == 0) and (not params[:person][field] or params[:person][field].length == 0)
454
+ error_fields.push field
455
+ error_messages.push "You must enter a value for #{field}."
456
+ end
457
+ end
458
+
459
+ if error_fields.size > 0 or error_messages.size > 0
460
+ flash[:error_fields] = error_fields
461
+ flash[:error_messages] = error_messages
462
+ else
463
+ account.save
464
+ addr.save
465
+ person.save
466
+ if app_profile
467
+ app_profile.save
468
+ end
469
+
470
+ @account = account
471
+ @addr = addr
472
+ @person = person
473
+ @app_profile = app_profile
474
+
475
+ begin
476
+ ActionMailer::Base.default_url_options[:host] = request.host
477
+ account.generate_activation
478
+ rescue
479
+ account.activation_key = nil
480
+ account.active = true
481
+ account.save
482
+ return :no_activation
483
+ end
484
+
485
+ return :success
486
+ end
487
+ end
488
+ end
489
+
490
+ module ClassMethods
491
+ def require_login(conditions = {})
492
+ before_filter conditions do |controller|
493
+ if not controller.logged_in?
494
+ controller.attempt_login_from_params
495
+ if not controller.logged_in?
496
+ controller.access_denied "Sorry, but you need to be logged in to view that page."
497
+ end
498
+ end
499
+ end
500
+ end
501
+
502
+ def require_class_permission(perm_name, conditions = {})
503
+ delegated = false
504
+ if conditions[:class_name]
505
+ cn = conditions[:class_name]
506
+ delegated = true
507
+ elsif conditions[:class_param]
508
+ cpn = conditions[:class_param]
509
+ end
510
+ before_filter conditions do |controller|
511
+ if cn.nil? and cpn
512
+ cn = controller.params[cpn]
513
+ delegated = true
514
+ end
515
+ controller_cn = controller.class.name.gsub(/Controller$/, "").singularize
516
+ cn ||= controller_cn
517
+ full_perm_name = "#{perm_name}_#{cn.tableize}"
518
+ if delegated
519
+ msg = "Sorry, but you are not permitted to #{perm_name} #{controller_cn.tableize.humanize.downcase} in this #{cn.tableize.humanize.singularize.downcase}."
520
+ else
521
+ msg = "Sorry, but you are not permitted to #{perm_name} #{cn.tableize.humanize.downcase}."
522
+ end
523
+ controller.do_permission_check(nil, full_perm_name, msg)
524
+ end
525
+ end
526
+
527
+ def require_permission(perm_name, conditions = {})
528
+ if conditions[:class_name]
529
+ cn = conditions[:class_name]
530
+ end
531
+ id_param = conditions[:id_param] || :id
532
+ before_filter conditions do |controller|
533
+ cn ||= controller.class.name.gsub(/Controller$/, "").singularize
534
+ o = eval(cn).find(controller.params[id_param])
535
+ if not o.nil?
536
+ controller.do_permission_check(o, perm_name, "Sorry, but you are not permitted to #{perm_name} this #{cn.tableize.singularize.humanize.downcase}.")
537
+ end
538
+ end
539
+ end
540
+
541
+ def rest_edit_permissions(options = {})
542
+ options = {
543
+ :restrict_create => false,
544
+ }.update(options)
545
+ restrict_create = options[:restrict_create]
546
+ options.delete(:restrict_create)
547
+ require_permission("edit", { :only => [:edit, :update] }.update(options))
548
+ if restrict_create
549
+ require_class_permission("create", { :only => [:new, :create] }.update(options))
550
+ end
551
+ require_permission("destroy", { :only => [:destroy] }.update(options))
552
+ end
553
+
554
+ def rest_view_permissions(options = {})
555
+ options = {
556
+ :restrict_list => false,
557
+ }.update(options)
558
+ restrict_list = options[:restrict_list]
559
+ options.delete(:restrict_list)
560
+ if restrict_list
561
+ require_class_permission("list", { :only => [:index] }.update(options))
562
+ elsif options[:class_name]
563
+ require_permission("show", { :only => [:index], :id_param => "#{options[:class_name].tableize}_id" }.update(options))
564
+ end
565
+ require_permission("show", { :only => [:show] }.update(options))
566
+ end
567
+
568
+ def rest_permissions(options = {})
569
+ rest_view_permissions(options)
570
+ rest_edit_permissions(options)
571
+ end
572
+ end
573
+ end
574
+ end
575
+
576
+ module HelperFunctions
577
+ def permission_names(item)
578
+ if item.kind_of? ActiveRecord::Base
579
+ return item.class.permission_names
580
+ else
581
+ return item.permission_names
582
+ end
583
+ end
584
+
585
+ def full_permission_name(item, perm)
586
+ if item.kind_of? ActiveRecord::Base
587
+ return perm
588
+ else
589
+ return "#{perm}_#{item.class.name.tableize}"
590
+ end
591
+ end
592
+
593
+ def permission_grants(item, perm)
594
+ if item.kind_of? ActiveRecord::Base
595
+ grants = item.permissions.select {|p| p.permission == perm }
596
+ else
597
+ full_perm_name = full_permission_name(item, perm)
598
+ grants = Permission.find_all_by_permission(full_perm_name)
599
+ end
600
+ return grants
601
+ end
602
+
603
+ def all_permitted?(item, perm)
604
+ if item
605
+ # try to short-circuit this with an eager load check
606
+ if item.permissions.select {|p| (p.permission == perm or p.permission.nil?) and p.role.nil? and p.person.nil? }.size > 0
607
+ return true
608
+ end
609
+ end
610
+ sql = "permission = ? and (role_id = 0 or role_id is null) and (person_id = 0 or person_id is null)"
611
+ return Permission.find(:all, :conditions => [sql, full_permission_name(item, perm)]).length > 0
612
+ end
613
+
614
+ def logged_in?
615
+ return controller.logged_in?
616
+ end
617
+
618
+ def logged_in_person
619
+ return controller.logged_in_person
620
+ end
621
+
622
+ def app_profile(person = nil)
623
+ if person.nil?
624
+ person = logged_in_person
625
+ end
626
+
627
+ AeUsers.profile_class.find_by_person_id(person.id)
628
+ end
629
+
630
+ def user_picker(field_name, options = {})
631
+ options = {
632
+ :people => true,
633
+ :roles => false,
634
+ :callback => nil,
635
+ :default => nil,
636
+ :clear_after => true
637
+ }.update(options)
638
+
639
+ domid = field_name.gsub(/\W/, "_").gsub(/__+/, "_").sub(/_$/, "").sub(/^_/, "")
640
+
641
+ default = options[:default]
642
+ rhtml = text_field_tag("#{field_name}_shim", default ? default.name : "", { :style => "width: 15em; display: inline; float: none;" })
643
+ rhtml << hidden_field_tag(field_name, default ? default.id : "")
644
+ auto_complete_url = url_for(:controller => "permission", :action => "auto_complete_for_permission_grantee",
645
+ :people => options[:people], :roles => options[:roles], :escape => false)
646
+
647
+ if AeUsers.js_framework == "prototype"
648
+ rhtml << <<-ENDRHTML
649
+ <div id="#{domid}_shim_auto_complete" class="auto_complete"></div>
650
+ <%= auto_complete_field('#{domid}_shim', :select => "grantee_id", :param_name => "q",
651
+ :after_update_element => "function (el, selected) {
652
+ kid = el.value.split(':');
653
+ klass = kid[0];
654
+ id = kid[1];
655
+ cb = function(klass, id) {
656
+ $('#{domid}').value = el.value;
657
+ #{options[:clear_after] ? "$('#{domid}_shim').value = '';" : "$('#{domid}_shim').value = selected.getAttribute('granteeName');"}
658
+ #{options[:callback]}
659
+ };
660
+ cb(klass, id);
661
+ }",
662
+ :url => "#{auto_complete_url}") %>
663
+ ENDRHTML
664
+ elsif AeUsers.js_framework == "jquery"
665
+ rhtml << <<-ENDRHTML
666
+ <script type="text/javascript">
667
+ jQuery(function() {
668
+ jq_domid = "\##{domid.gsub(/(\W)/, '\\\\\\\\\1')}";
669
+ jQuery(jq_domid + "_shim").autocomplete('#{auto_complete_url}',
670
+ {
671
+ formatItem: function(data, i, n, value) {
672
+ return value;
673
+ },
674
+ }).bind('result', function(e, data) {
675
+ jQuery(jq_domid).val(data[1]);
676
+ #{options[:callback]}
677
+ }
678
+ );
679
+ });
680
+ </script>
681
+ ENDRHTML
682
+ end
683
+
684
+ render :inline => rhtml
685
+ end
686
+ end
687
+
688
+ module InstanceTagExtensions
689
+ DEFAULT_USERPICKER_OPTIONS = {
690
+ "auto_complete_url_params" => {:controller => "permission", :action => "auto_complete_for_permission_grantee"}
691
+ }
692
+
693
+ def to_user_picker_tag(people, roles, options={})
694
+ options = options.stringify_keys
695
+ options = DEFAULT_USERPICKER_OPTIONS.merge(options)
696
+ add_default_name_and_id(options)
697
+
698
+ default = options["default"]
699
+ shim = tag("input", :type => "text", :id => "#{options["id"]}_shim", :value => default ? default.name : "",
700
+ :style => "width: 15em; display: inline; float: none;")
701
+ hidden = to_input_field_tag("hidden", options.update("value" => default ? default.id : ""))
702
+
703
+ url_params = options["auto_complete_url_params"].update(:people => people, :roles => roles,
704
+ :escape => false)
705
+ RAILS_DEFAULT_LOGGER.debug url_params.collect { |k, v| "#{k}: #{v}" }.join(", ")
706
+
707
+ options["auto_complete_url"] = @template_object.url_for(url_params)
708
+ shim + hidden + user_picker_extra_content(options) + user_picker_js(options)
709
+ end
710
+
711
+ private
712
+ def user_picker_js(options = {})
713
+ case AeUsers.js_framework
714
+ when "prototype"
715
+ user_picker_js_for_prototype(options)
716
+ when "jquery"
717
+ user_picker_js_for_jquery(options)
718
+ end
719
+ end
720
+
721
+ def user_picker_extra_content(options = {})
722
+ if AeUsers.js_framework == "prototype"
723
+ return @template_object.tag("div", :id => "#{options['id']}_shim_auto_complete", :class => "auto_complete")
724
+ end
725
+
726
+ return ""
727
+ end
728
+
729
+ def user_picker_js_for_prototype(options = {})
730
+ @template_object.auto_complete_field(:select => "grantee_id", :param_name => "q",
731
+ :after_update_element =>
732
+ "function (el, selected) {
733
+ kid = el.value.split(':');
734
+ klass = kid[0];
735
+ id = kid[1];
736
+ cb = function(klass, id) {
737
+ $('#{options['id']}').value = el.value;
738
+ #{options['clear_after'] ? "$('#{options['id']}_shim').value = '';" : "$('#{options['id']}_shim').value = selected.getAttribute('granteeName');"}
739
+ #{options['callback']}
740
+ };
741
+ cb(klass, id);
742
+ }",
743
+ :url => options['auto_complete_url'])
744
+ end
745
+
746
+ def user_picker_js_for_jquery(options = {})
747
+ <<-ENDRHTML
748
+ <script type="text/javascript">
749
+ jQuery(function() {
750
+ jQuery('\##{options['id']}_shim').autocomplete('#{options['auto_complete_url']}',
751
+ {
752
+ formatItem: function(data, i, n, value) {
753
+ return value;
754
+ },
755
+ }).bind('result', function(e, data) {
756
+ jQuery(jq_domid).val(data[1]);
757
+ #{options['callback']}
758
+ }
759
+ );
760
+ });
761
+ </script>
762
+ ENDRHTML
763
+ end
764
+ end
765
+
766
+ module FormHelperFunctions
767
+
768
+
769
+ def person_field(object_name, method, options={})
770
+ it = ActionView::Base::InstanceTag.new(object_name, method, self, options.delete(:object))
771
+ it.to_user_picker_tag(true, false, options)
772
+ end
773
+
774
+ end
775
+
776
+ module FormBuilderFunctions
777
+ def person_field(method, options = {})
778
+ @template.send("person_field", @object_name, method, objectify_options(options))
779
+ end
780
+ end
781
+ end