ae_users 0.6.0

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