adva_user 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +22 -0
  5. data/README +114 -0
  6. data/README.md +29 -0
  7. data/Rakefile +2 -0
  8. data/adva_user.gemspec +17 -0
  9. data/app/controllers/admin/base_account_controller.rb +13 -0
  10. data/app/controllers/admin/users_controller.rb +95 -0
  11. data/app/controllers/password_controller.rb +36 -0
  12. data/app/controllers/session_controller.rb +30 -0
  13. data/app/helpers/users_helper.rb +27 -0
  14. data/app/models/account.rb +7 -0
  15. data/app/models/membership.rb +16 -0
  16. data/app/models/password_mailer.rb +43 -0
  17. data/app/models/user.rb +106 -0
  18. data/app/views/admin/users/_form.html.erb +29 -0
  19. data/app/views/admin/users/_sidebar.html.erb +8 -0
  20. data/app/views/admin/users/edit.html.erb +7 -0
  21. data/app/views/admin/users/index.html.erb +13 -0
  22. data/app/views/admin/users/new.html.erb +5 -0
  23. data/app/views/admin/users/show.html.erb +27 -0
  24. data/app/views/layouts/login.html.erb +24 -0
  25. data/app/views/password/edit.html.erb +14 -0
  26. data/app/views/password/new.html.erb +13 -0
  27. data/app/views/password_mailer/reset_password_email.html.erb +3 -0
  28. data/app/views/password_mailer/updated_password_email.html.erb +1 -0
  29. data/app/views/session/new.html.erb +17 -0
  30. data/config/initializers/menus.rb +25 -0
  31. data/config/routes.rb +14 -0
  32. data/db/migrate/20080402000001_create_users_table.rb +33 -0
  33. data/db/migrate/20080402000005_create_memberships_table.rb +13 -0
  34. data/db/migrate/20090625124502_create_accounts.rb +13 -0
  35. data/db/migrate/20090625133231_add_account_to_user.rb +10 -0
  36. data/lib/action_controller/authenticate_anonymous.rb +70 -0
  37. data/lib/action_controller/authenticate_user.rb +201 -0
  38. data/lib/active_record/belongs_to_author.rb +37 -0
  39. data/lib/adva_user.rb +28 -0
  40. data/lib/adva_user/version.rb +3 -0
  41. data/lib/login/helper_integration.rb +11 -0
  42. data/lib/login/mail_config.rb +39 -0
  43. data/test/contexts.rb +42 -0
  44. data/test/fixtures.rb +18 -0
  45. data/test/functional/admin/users_controller_test.rb +176 -0
  46. data/test/functional/password_controller_test.rb +96 -0
  47. data/test/functional/session_controller_test.rb +1 -0
  48. data/test/functional/user_controller_test.rb +95 -0
  49. data/test/integration/anonymous_login_test.rb +39 -0
  50. data/test/integration/edit_user_test.rb +44 -0
  51. data/test/integration/memberships_test.rb +52 -0
  52. data/test/integration/user_deletion_test.rb +27 -0
  53. data/test/integration/user_login_test.rb +53 -0
  54. data/test/integration/user_login_with_remember_me_test.rb +20 -0
  55. data/test/integration/user_registration_test.rb +64 -0
  56. data/test/test_helper.rb +1 -0
  57. data/test/unit/cells/user_cell_test.rb +13 -0
  58. data/test/unit/helpers/users_helper_test.rb +52 -0
  59. data/test/unit/models/account_test.rb +21 -0
  60. data/test/unit/models/anonymous_test.rb +54 -0
  61. data/test/unit/models/password_mailer_test.rb +26 -0
  62. data/test/unit/models/user_mailer_test.rb +16 -0
  63. data/test/unit/models/user_test.rb +173 -0
  64. data/vendor/gems/authentication/.gitignore +17 -0
  65. data/vendor/gems/authentication/Gemfile +4 -0
  66. data/vendor/gems/authentication/LICENSE +22 -0
  67. data/vendor/gems/authentication/MIT-LICENSE +38 -0
  68. data/vendor/gems/authentication/README +39 -0
  69. data/vendor/gems/authentication/README.md +29 -0
  70. data/vendor/gems/authentication/RUNNING_UNIT_TESTS +13 -0
  71. data/vendor/gems/authentication/Rakefile +61 -0
  72. data/vendor/gems/authentication/authentication.gemspec +17 -0
  73. data/vendor/gems/authentication/lib/authentication.rb +270 -0
  74. data/vendor/gems/authentication/lib/authentication/active_record_extensions.rb +11 -0
  75. data/vendor/gems/authentication/lib/authentication/bogus.rb +13 -0
  76. data/vendor/gems/authentication/lib/authentication/hash_helper.rb +26 -0
  77. data/vendor/gems/authentication/lib/authentication/ldap.rb +49 -0
  78. data/vendor/gems/authentication/lib/authentication/remember_me.rb +52 -0
  79. data/vendor/gems/authentication/lib/authentication/salted_hash.rb +53 -0
  80. data/vendor/gems/authentication/lib/authentication/single_token.rb +53 -0
  81. data/vendor/gems/authentication/lib/authentication/version.rb +3 -0
  82. data/vendor/gems/authentication/lib/radius/dictionary +207 -0
  83. data/vendor/gems/authentication/test_backup/abstract_unit.rb +30 -0
  84. data/vendor/gems/authentication/test_backup/active_record_extension_test.rb +17 -0
  85. data/vendor/gems/authentication/test_backup/authentication_test.rb +231 -0
  86. data/vendor/gems/authentication/test_backup/database.yml +12 -0
  87. data/vendor/gems/authentication/test_backup/fixtures/user.rb +3 -0
  88. data/vendor/gems/authentication/test_backup/fixtures/users.yml +3 -0
  89. data/vendor/gems/authentication/test_backup/options_test.rb +100 -0
  90. data/vendor/gems/authentication/test_backup/remember_me_test.rb +41 -0
  91. data/vendor/gems/authentication/test_backup/salted_hash_test.rb +38 -0
  92. data/vendor/gems/authentication/test_backup/schema.rb +10 -0
  93. data/vendor/gems/authentication/test_backup/single_token_test.rb +44 -0
  94. data/vendor/gems/authentication/test_backup/test_helper.rb +8 -0
  95. metadata +157 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3146f0136b688fa7c5c4f1322192e36870cceba8
4
+ data.tar.gz: 0451a800ba3eabd0a49988c574594fa6694f6d97
5
+ SHA512:
6
+ metadata.gz: 0e562845d0556d547e81c7ba0520dc8b4a3c21cfb067b82b97cf8bbb08fe2f9de374c967752c9af4cc4f3d62670ee769aefabb1178bbf7ce48b4a6e90bb7075f
7
+ data.tar.gz: 698a604a2d145232556e6445d2723e3a5c3cbf82ad100b73d8a0e22ae7f387117b47f40638eaefb24faafdaa2257a319695f2457cfbd5804bb2dba7574c8dc2c
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in adva_user.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Micah Geisel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,114 @@
1
+ As suggested by the author of this plugin, Bart Duchesne, we've used the
2
+ loginui plugin as a scaffolding and modified it for our own needs.
3
+
4
+ See http://rubyforge.org/projects/loginui/ for more information about this
5
+ fantastic plugin.
6
+
7
+
8
+
9
+
10
+ - original readme file -------------------------------------------------------
11
+
12
+ = Login Plugin
13
+
14
+ Provides a basic user interface for allowing a user to accomplish the
15
+ following tasks:
16
+
17
+ * Login (with Remember Me)
18
+ * Logout
19
+
20
+ * Forgot Password
21
+ * Change Password
22
+
23
+ * Register (with email verification)
24
+ * Delete User
25
+ * Restore Deleted User
26
+
27
+ == Dependencies
28
+
29
+ This plugin is implemented with the help of the "Engine" plugin and
30
+ can either be considered reusable slice of an application or can
31
+ be considered scaffolding to your own login work you will add later
32
+ to your project.
33
+
34
+ This plugin also does not implement the actual authentication process
35
+ itself or even define the "User" object that is authenticated against.
36
+ It just assumes certain functionality is available and any application
37
+ that implements that functionality can use this plugin to provide the
38
+ UI for their authentication.
39
+
40
+ If you do not have your own backend authentication I highly suggest you
41
+ check out the authentication plugin by the same author of this plugin.
42
+ Although not required to go together they do together provide a
43
+ complete authentication system.
44
+
45
+ == Development Status
46
+
47
+ This code has been used on many sites so it is fairly reliable. But all
48
+ the sites it has been used on are very similar in design so some
49
+ aspects that our outside of this design may not be tested as well. For
50
+ example all the sites it is currently used on has email for the username.
51
+ So if you don't use email for username (or don't even have an email
52
+ field) it *should* work but has not received significant testing.
53
+
54
+ Another aspect is Rails 1.x vs. Rails 2.0 apps. This was developed under
55
+ Rails 1.x and 95% of sites using this plugin are on Rails 1.x. But it
56
+ has been taken to Rails 2.0 and seems to work well there.
57
+
58
+ I welcome patches towards making this plugin work in different
59
+ environments.
60
+
61
+ == Your User model
62
+
63
+ Regardless of if you use the authentication plugin or build your own
64
+ you will need a user model that this plugin assumes. The user model
65
+ must be named "User". Also your User model needs a field that can
66
+ serve as the username. "email" is prefered (because people can
67
+ remember that) but username and user_name will also be accepted. If
68
+ you have something completely different then implement a class method
69
+ on the user object called "username_field" this method should return
70
+ whatever field is being used as your username.
71
+
72
+ == Optional support
73
+
74
+ The email notifications will only be sent if a "email" field is
75
+ on the model. This is regardless of what you use for a username. There
76
+ is currently no way to disable email notifications if you have the
77
+ email field. Obviously the "forgot my password" feature will not work
78
+ without an email field on the User model as well.
79
+
80
+ == Providing your own authentication
81
+
82
+ If you want to provide your own authentication system instead of using
83
+ the authentication plugin you will need to implement the following
84
+ actions on your User model.
85
+
86
+ === Required methods
87
+
88
+ password=:: Will assign the model a new password
89
+ assign_token(name, expiration=nil)::
90
+ Will return a token that can be used to authenticate the user with.
91
+ This is used for URL token authentication (in email confirmation,
92
+ forgot password and restore deleted user) and also used in the
93
+ "Remember Me" authentication. The expiration can be considered
94
+ optional.
95
+ authenticate(password)::
96
+ Will authenticate the current user against the given password
97
+ returning true or false to indicate the success
98
+
99
+ === Optional methods
100
+
101
+ password_confirmation=::
102
+ Not required but if the model responds to this method then it
103
+ will receive a copy of the password when a user is updating
104
+ their password for verification purposes.
105
+ deleted_at and deleted_at=::
106
+ If the model responds to deleted_at and deleted_at then when
107
+ a user is removed it will just get a date/time value to indicate
108
+ the user has been removed. It will assume once a object has this
109
+ value it will not be found unless User.find_with_deleted is used.
110
+ This is compatible with acts_as_paraniod
111
+ User.find_with_deleted(*find_args)::
112
+ If the User class responds to then then this will be called when
113
+ attempting to restore a user. This is for compatibility with
114
+ acts_as_paranoid and anything else implementing that interface.
@@ -0,0 +1,29 @@
1
+ # AdvaUser
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'adva_user'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install adva_user
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/adva_user/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Micah Geisel"]
6
+ gem.email = ["micah@botandrose.com"]
7
+ gem.description = %q{Adva User}
8
+ gem.summary = %q{Engine for Adva CMS user accounts}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "adva_user"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = AdvaUser::VERSION
17
+ end
@@ -0,0 +1,13 @@
1
+ class Admin::BaseAccountController < Admin::BaseController
2
+ before_filter :set_account
3
+
4
+ def set_account
5
+ @account = current_user.account
6
+ end
7
+
8
+ def require_authentication
9
+ unless current_user and current_user.account
10
+ return redirect_to_login(t(:'adva.flash.authentication_required'))
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,95 @@
1
+ class Admin::UsersController < Admin::BaseController
2
+ before_filter :set_users, :only => [:index]
3
+ before_filter :set_user, :only => [:show, :edit, :update, :destroy]
4
+ before_filter :authorize_access
5
+ before_filter :authorize_params, :only => :update
6
+
7
+ # guards_permissions :user
8
+
9
+ def index
10
+ end
11
+
12
+ def show
13
+ end
14
+
15
+ def new
16
+ @user = User.new
17
+ end
18
+
19
+ def create
20
+ # yuck! rails' params parsing is broken
21
+ params[:user][:roles_attributes] = params[:user][:roles_attributes].map { |key, value| value } if params[:user][:roles_attributes]
22
+
23
+ @user = User.new(params[:user])
24
+ @user.memberships.build(:site => @site) if @site and !@user.has_role?(:superuser)
25
+
26
+ if @user.save
27
+ @user.verify! # TODO hu??
28
+ trigger_events(@user)
29
+ flash[:notice] = t(:'adva.users.flash.create.success')
30
+ redirect_to admin_user_url(@site, @user)
31
+ else
32
+ flash.now[:error] = t(:'adva.users.flash.create.failure')
33
+ render :action => :new
34
+ end
35
+ end
36
+
37
+ def edit
38
+ end
39
+
40
+ def update
41
+ # yuck! rails' params parsing is broken
42
+ params[:user][:roles_attributes] = params[:user][:roles_attributes].map { |key, value| value } if params[:user][:roles_attributes]
43
+
44
+ if @user.update_attributes(params[:user])
45
+ trigger_events(@user)
46
+ flash[:notice] = t(:'adva.users.flash.update.success')
47
+ redirect_to admin_user_url(@site, @user)
48
+ else
49
+ flash.now[:error] = t(:'adva.users.flash.update.failure')
50
+ render :action => :edit
51
+ end
52
+ end
53
+
54
+ def destroy
55
+ if @user.destroy
56
+ trigger_events(@user)
57
+ flash[:notice] = t(:'adva.users.flash.destroy.success')
58
+ redirect_to admin_users_url(@site)
59
+ else
60
+ flash.now[:error] = t(:'adva.users.flash.destroy.failure')
61
+ render :action => :edit
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def set_menu
68
+ @menu = Menus::Admin::Users.new
69
+ end
70
+
71
+ def set_users
72
+ @users = @site ? @site.users_and_superusers :
73
+ User.admins_and_superusers
74
+ end
75
+
76
+ def set_user
77
+ @user = User.find(params[:id])
78
+ end
79
+
80
+ # FIXME extract this and use Rbac contexts instead
81
+ def authorize_access
82
+ redirect_to admin_sites_url unless @site || current_user.has_role?(:superuser)
83
+ end
84
+
85
+ def authorize_params
86
+ return
87
+ return unless params[:user] && params[:user][:roles]
88
+
89
+ if params[:user][:roles].has_key?('superuser') && !current_user.has_role?(:superuser) ||
90
+ params[:user][:roles].has_key?('admin') && !current_user.has_role?(:admin, @site)
91
+ raise "unauthorized parameter" # TODO raise something more meaningful
92
+ end
93
+ # TODO as well check for membership site_id if !user.has_role?(:superuser)
94
+ end
95
+ end
@@ -0,0 +1,36 @@
1
+ class PasswordController < BaseController
2
+ renders_with_error_proc :below_field
3
+ layout 'login'
4
+
5
+ def new
6
+ end
7
+
8
+ def create
9
+ flash[:notice] = t(:'adva.passwords.flash.create.notification')
10
+ if user = User.find_by_email(params[:user][:email])
11
+ token = user.assign_token 'password'
12
+ user.save!
13
+ trigger_event user, :password_reset_requested, :token => "#{user.id};#{token}"
14
+ redirect_to edit_password_url
15
+ else
16
+ render :action => :new
17
+ end
18
+ end
19
+
20
+ def edit
21
+ params[:token] = nil unless current_user # TODO: maybe solve this nicer?
22
+ end
23
+
24
+ def update
25
+ if current_user && current_user.update_attributes(params[:user].slice(:password))
26
+ trigger_event current_user, :password_updated
27
+ flash[:notice] = t(:'adva.passwords.flash.update.success')
28
+ authenticate_user(:email => current_user.email, :password => params[:user][:password])
29
+ redirect_to root_url
30
+ else
31
+ params[:token] = nil # ugh
32
+ flash[:error] = t(:'adva.passwords.flash.update.failure')
33
+ render :action => :edit
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,30 @@
1
+ class SessionController < BaseController
2
+ renders_with_error_proc :below_field
3
+
4
+ skip_before_filter :verify_authenticity_token # disable forgery protection
5
+
6
+ layout 'login'
7
+
8
+ def new
9
+ @user = User.new
10
+ end
11
+
12
+ def create
13
+ if authenticate_user(params[:user])
14
+ remember_me! if params[:user][:remember_me]
15
+ flash[:notice] = t(:'adva.session.flash.create.success')
16
+ redirect_to return_from(:login)
17
+ else
18
+ @user = User.new(:email => params[:user][:email])
19
+ @remember_me = params[:user][:remember_me]
20
+ flash.now[:error] = t(:'adva.session.flash.create.failure')
21
+ render :action => 'new'
22
+ end
23
+ end
24
+
25
+ def destroy
26
+ logout
27
+ flash[:notice] = t(:'adva.session.flash.destroy.success')
28
+ redirect_to return_from(:logout)
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ module UsersHelper
2
+ def who(name)
3
+ name = name.name if name.is_a? User
4
+ return current_user && current_user.name == name ? t(:'adva.common.you') : name
5
+ end
6
+
7
+ def gravatar_img(user, options = {})
8
+ image_tag gravatar_url(user.email), {:class => 'avatar'}.merge(options)
9
+ end
10
+
11
+ def gravatar_url(email = nil, size = 80)
12
+ default = '/assets/adva_cms/avatar.gif'
13
+ return default if email.blank?
14
+ require 'digest/md5'
15
+ digest = Digest::MD5.hexdigest(email)
16
+ # TODO #{ActionController::AbstractRequest.relative_url_root} missing in Rails 2.2
17
+ "http://www.gravatar.com/avatar.php?size=#{size}&gravatar_id=#{digest}&default=http://#{request.host_with_port}/assets/adva_cms/avatar.gif"
18
+ end
19
+
20
+ def link_to_author resource, options = {}
21
+ include_email = options[:include_email] && resource.respond_to?(:author_email)
22
+ name = resource.author_name
23
+ text = resource.author_homepage.blank? ? name : link_to(h(name), h(resource.author_homepage))
24
+ text = "#{text} (#{resource.author_email})" if include_email
25
+ text.html_safe
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ class Account < ActiveRecord::Base
2
+ has_many :users
3
+
4
+ def members
5
+
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ class Membership < ActiveRecord::Base
2
+ belongs_to :site
3
+ belongs_to :user
4
+
5
+ validates_uniqueness_of :site_id, :scope => :user_id
6
+
7
+ # tentacle does this. is it a good idea to keep has_many :roles on the membership?
8
+ # before_create :set_first_user_admin
9
+ # def set_first_user_admin
10
+ # self.transaction do
11
+ # if group && group.members.count == 0
12
+ # self.admin = true
13
+ # end
14
+ # end
15
+ # end
16
+ end