boilerplate_generator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. data/History.txt +3 -0
  2. data/Manifest.txt +32 -0
  3. data/README.txt +152 -0
  4. data/USAGE +30 -0
  5. data/boilerplate_generator.rb +69 -0
  6. data/lib/boilerplate_generator/version.rb +9 -0
  7. data/templates/app/controllers/account_controller.rb +19 -0
  8. data/templates/app/controllers/application.rb +6 -0
  9. data/templates/app/controllers/user_controller.rb +34 -0
  10. data/templates/app/helpers/account_helper.rb +2 -0
  11. data/templates/app/helpers/user_helper.rb +2 -0
  12. data/templates/app/models/user.rb +71 -0
  13. data/templates/app/views/account/login.haml +16 -0
  14. data/templates/app/views/account/login.html.erb +17 -0
  15. data/templates/app/views/layouts/application.haml +11 -0
  16. data/templates/app/views/layouts/application.html.erb +17 -0
  17. data/templates/app/views/user/_form.haml +17 -0
  18. data/templates/app/views/user/_form.html.erb +13 -0
  19. data/templates/app/views/user/edit.haml +7 -0
  20. data/templates/app/views/user/edit.html.erb +8 -0
  21. data/templates/app/views/user/new.haml +11 -0
  22. data/templates/app/views/user/new.html.erb +11 -0
  23. data/templates/app/views/user/show.haml +4 -0
  24. data/templates/app/views/user/show.html.erb +4 -0
  25. data/templates/config/routes.rb +12 -0
  26. data/templates/db/migrate/create_users.rb +18 -0
  27. data/templates/lib/authentication_system.rb +167 -0
  28. data/templates/test/fixtures/users.yml +15 -0
  29. data/templates/test/functional/account_controller_test.rb +77 -0
  30. data/templates/test/functional/user_controller_test.rb +119 -0
  31. data/templates/test/test_helper.rb +37 -0
  32. data/templates/test/unit/user_test.rb +116 -0
  33. metadata +77 -0
data/History.txt ADDED
@@ -0,0 +1,3 @@
1
+ +++ 0.0.1 2007-05-07
2
+
3
+ + Initial gem release
data/Manifest.txt ADDED
@@ -0,0 +1,32 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ USAGE
5
+ boilerplate_generator.rb
6
+ lib/boilerplate_generator/version.rb
7
+ templates/app/controllers/account_controller.rb
8
+ templates/app/controllers/application.rb
9
+ templates/app/controllers/user_controller.rb
10
+ templates/app/helpers/account_helper.rb
11
+ templates/app/helpers/user_helper.rb
12
+ templates/app/models/user.rb
13
+ templates/app/views/account/login.haml
14
+ templates/app/views/account/login.html.erb
15
+ templates/app/views/layouts/application.haml
16
+ templates/app/views/layouts/application.html.erb
17
+ templates/app/views/user/_form.haml
18
+ templates/app/views/user/_form.html.erb
19
+ templates/app/views/user/edit.haml
20
+ templates/app/views/user/edit.html.erb
21
+ templates/app/views/user/new.haml
22
+ templates/app/views/user/new.html.erb
23
+ templates/app/views/user/show.haml
24
+ templates/app/views/user/show.html.erb
25
+ templates/config/routes.rb
26
+ templates/db/migrate/create_users.rb
27
+ templates/lib/authentication_system.rb
28
+ templates/test/fixtures/users.yml
29
+ templates/test/functional/account_controller_test.rb
30
+ templates/test/functional/user_controller_test.rb
31
+ templates/test/test_helper.rb
32
+ templates/test/unit/user_test.rb
data/README.txt ADDED
@@ -0,0 +1,152 @@
1
+ = Boilerplate Generator
2
+
3
+ Boilerplate is a generator for new Rails projects. It automatically creates a
4
+ working account system for user login and registration, a basic layout, some
5
+ named routes, and (of course) a comprehensive suite of tests.
6
+
7
+ If you have any questions, comments, criticisms, or unmelted chocolate
8
+ sundaes, please contact me via electronic mail. My address is
9
+ packagetheif@gmail.com
10
+
11
+ == Why?
12
+
13
+ Because I get tired of creating the same basic things each time I start a new
14
+ project. Steeped in frustration, I extracted all the preliminary code from last
15
+ project I created and packaged it up for posterity.
16
+
17
+ == What's included?
18
+
19
+ Nothing fancy, really. That's the whole idea: no smoke, no mirrors. Just simple
20
+ code that's easy to modify and/or extend.
21
+
22
+ models
23
+ A User model with support for hashed (and salted) passwords, all the necessary
24
+ validations, and an authenticate class method. Take a look at
25
+ db/migrate/###_create_users.rb if you want to see the schema definition
26
+
27
+ views
28
+ Views for login and signup, plus a simple xhtml layout that includes
29
+ the default javascript libraries
30
+
31
+ controllers
32
+ An account controller with index, login, signup, and logout actions; a
33
+ modified application_controller that mixes in the AuthenticationSystem module.
34
+ The current_user method returns a User object provided a User with an id equal
35
+ to session[:user] can be found; the authenticate method redirects to the
36
+ login_url if current_user returns false
37
+
38
+ routes
39
+ Named routes for signup_url, login_url, and logout_url and a resource route
40
+ for users (map.resource :user)
41
+
42
+ migrations
43
+ A migration to create the Users table
44
+
45
+ tests
46
+ A comprehensive suite of tests covering the User model, and the all the
47
+ Account and User actions
48
+
49
+ == Test Specs
50
+
51
+ Account controller should:
52
+ * login user and redirect
53
+ * not login invalid user
54
+ * logout and redirect
55
+ * remember login if remember me is set
56
+ * not remember login if remember me is not set
57
+ * delete token on logout
58
+ * login automatically from cookie
59
+ * fail cookie login with expired cookie
60
+ * fail cookie login with invalid cookie
61
+
62
+ User controller should:
63
+ * create user
64
+ * require login on create
65
+ * require unique login on create
66
+ * require password on create
67
+ * require password confirmation on create
68
+ * require email on create
69
+ * require valid email on create
70
+ * require authentication for show
71
+ * require authentication for edit
72
+ * require authentication for update
73
+ * accept http basic authentication
74
+
75
+ User should:
76
+ * create user
77
+ * update user
78
+ * destroy user
79
+ * accept valid emails
80
+ * not allow invalid emails
81
+ * not allow spaces or dots in login
82
+ * reset password
83
+ * not rehash password when unchanged
84
+ * authenticate user
85
+ * set remember token
86
+ * unset remember token
87
+ * remember login for one week
88
+ * remember login until one week from now
89
+ * remember login for default two weeks
90
+
91
+ == Usage
92
+
93
+ Boilerplate is intended to be used on a fresh Rails application. You're free to
94
+ use it on an app with code in it already; it will prompt you before it tries
95
+ to overwrite any existing files.
96
+
97
+ To generate the boilerplate code for your application, use the generate script:
98
+
99
+ $ ./script/generate boilerplate
100
+
101
+ Assuming you have the databases set up for your application, run the migration
102
+ script which will create the User table:
103
+
104
+ $ rake db:migrate
105
+
106
+ Run the test suite to make sure everything is kosher:
107
+
108
+ $ rake test
109
+
110
+ == Generated files
111
+
112
+ The following files are generated:
113
+
114
+ +-- app
115
+ | |-- controllers
116
+ | | |-- account_controller.rb
117
+ | | |-- user_controller.rb
118
+ | | `-- application.rb
119
+ | |-- models
120
+ | | `-- user.rb
121
+ | `-- views
122
+ | |-- account
123
+ | | |-- index.rhtml
124
+ | | |-- login.rhtml
125
+ | | `-- signup.rhtml
126
+ | |-- user
127
+ | | |-- login.rhtml
128
+ | | |-- show.rhtml
129
+ | | `-- signup.rhtml
130
+ | `-- layouts
131
+ | `-- application.rhtml
132
+ |-- config
133
+ | `-- routes.rb
134
+ |-- db
135
+ | `-- migrate
136
+ | |-- ###_create_sessions.rb
137
+ | `-- ###_create_users.rb
138
+ |-- lib
139
+ | `-- authentication_system.rb
140
+ `-- test
141
+ |-- fixtures
142
+ | `-- users.yml
143
+ |-- functional
144
+ | |-- user_controller_test.rb
145
+ | `-- account_controller_test.rb
146
+ |-- test_helper.rb
147
+ `-- unit
148
+ `-- user_test.rb
149
+
150
+
151
+ ---
152
+ Copyright (c) 2007 Jeffrey Allan Hardy, released under the MIT license
data/USAGE ADDED
@@ -0,0 +1,30 @@
1
+ NAME
2
+ boilerplate - creates a working account system for user login and
3
+ registration
4
+
5
+ SYNOPSIS
6
+ boilerplate
7
+
8
+ DESCRIPTION
9
+ Automatically creates a working account system for user login and
10
+ registration, a basic layout, some named routes, and (of course) a
11
+ comprehensive suite of tests.
12
+
13
+ Boilerplate is intended to be used on a fresh Rails application.
14
+ You're free to use it on an app with code in it already; it will
15
+ prompt you before it tries to overwrite any existing files.
16
+
17
+ EXAMPLE
18
+ To generate the boilerplate code for your application, use the
19
+ generate script:
20
+
21
+ ./script/generate boilerplate
22
+
23
+ Assuming you have the databases set up for your application, run
24
+ the migration script which will create the User table:
25
+
26
+ rake db:migrate
27
+
28
+ Run the test suite to make sure everything is kosher:
29
+
30
+ rake test
@@ -0,0 +1,69 @@
1
+ class BoilerplateGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ # Set the file extension to use for templates
5
+ ext = (File.exist?('vendor/plugins/haml')) ? 'haml' : 'html.erb'
6
+
7
+ # Models
8
+ dir = 'app/models'
9
+ m.template File.join(dir, file = 'user.rb'), File.join(dir, file)
10
+
11
+ # Views
12
+ dir = 'app/views/account'
13
+ m.directory dir
14
+ m.template File.join(dir, file = "login.#{ext}"), File.join(dir, file)
15
+
16
+ dir = 'app/views/user'
17
+ m.directory dir
18
+ m.template File.join(dir, file = "_form.#{ext}"), File.join(dir, file)
19
+ m.template File.join(dir, file = "edit.#{ext}"), File.join(dir, file)
20
+ m.template File.join(dir, file = "show.#{ext}"), File.join(dir, file)
21
+ m.template File.join(dir, file = "new.#{ext}"), File.join(dir, file)
22
+
23
+ # Layouts
24
+ dir = 'app/views/layouts'
25
+ m.template File.join(dir, file = "application.#{ext}"), File.join(dir, file)
26
+
27
+ # Helpers
28
+ dir = 'app/helpers'
29
+ m.template File.join(dir, file = 'account_helper.rb'), File.join(dir, file)
30
+ m.template File.join(dir, file = 'user_helper.rb'), File.join(dir, file)
31
+
32
+ # Controllers
33
+ dir = 'app/controllers'
34
+ m.template File.join(dir, file = 'account_controller.rb'), File.join(dir, file)
35
+ m.template File.join(dir, file = 'user_controller.rb'), File.join(dir, file)
36
+ m.template File.join(dir, file = 'application.rb'), File.join(dir, file)
37
+
38
+ # Libraries
39
+ dir = 'lib'
40
+ m.template File.join(dir, file = 'authentication_system.rb'), File.join(dir, file)
41
+
42
+ # Routes
43
+ dir = 'config'
44
+ m.template File.join(dir, file = 'routes.rb'), File.join(dir, file)
45
+
46
+ # Migrations
47
+ dir = 'db/migrate'
48
+ m.directory dir
49
+ m.migration_template File.join(dir, file = 'create_users.rb'), dir, :migration_file_name => file.sub(/\.rb$/, '')
50
+
51
+ # Test Helpers
52
+ dir = 'test'
53
+ m.template File.join(dir, file = 'test_helper.rb'), File.join(dir, file)
54
+
55
+ # Fixtures
56
+ dir = 'test/fixtures'
57
+ m.template File.join(dir, file = 'users.yml'), File.join(dir, file)
58
+
59
+ # Functional Tests
60
+ dir = 'test/functional'
61
+ m.template File.join(dir, file = 'account_controller_test.rb'), File.join(dir, file)
62
+ m.template File.join(dir, file = 'user_controller_test.rb'), File.join(dir, file)
63
+
64
+ # Unit Tests
65
+ dir = 'test/unit'
66
+ m.template File.join(dir, file = 'user_test.rb'), File.join(dir, file)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,9 @@
1
+ module BoilerplateGenerator #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ class AccountController < ApplicationController
2
+ def login
3
+ if request.post?
4
+ if self.current_user = User.authenticate(params[:login], params[:password])
5
+ remember_current_user if params[:remember_me] == '1'
6
+ redirect_back_or_to user_url
7
+ else
8
+ flash[:error] = 'Invalid user/password combination'
9
+ redirect_to login_path
10
+ end
11
+ end
12
+ end
13
+
14
+ def logout
15
+ logout_current_user!
16
+ flash[:notice] = 'You have been logged out'
17
+ redirect_to login_path
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ class ApplicationController < ActionController::Base
2
+ include AuthenticationSystem
3
+ before_filter :authenticate_with_cookies
4
+
5
+ helper :all
6
+ end
@@ -0,0 +1,34 @@
1
+ class UserController < ApplicationController
2
+ before_filter :authenticate, :except => [:new, :create]
3
+
4
+ def show
5
+ @user = current_user
6
+ end
7
+
8
+ def new
9
+ @user = User.new
10
+ end
11
+
12
+ def create
13
+ @user = User.new(params[:user])
14
+ if @user.save
15
+ self.current_user = @user
16
+ flash[:notice] = 'Thanks for signing up!'
17
+ redirect_to root_url
18
+ else
19
+ render :action => 'new'
20
+ end
21
+ end
22
+
23
+ def edit
24
+ @user = current_user
25
+ end
26
+
27
+ def update
28
+ @user = current_user
29
+ if @user.update_attributes(params[:user])
30
+ flash[:notice] = 'Account information updated'
31
+ redirect_to edit_user_url
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,2 @@
1
+ module AccountHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module UserHelper
2
+ end
@@ -0,0 +1,71 @@
1
+ require 'digest/sha1'
2
+
3
+ class User < ActiveRecord::Base
4
+ attr_accessor :password
5
+
6
+ validates_presence_of :login
7
+ validates_length_of :login, :within => 3..40
8
+ validates_uniqueness_of :login, :case_sensitive => false
9
+ validates_format_of :login, :with => /^[\w-]+$/i, :message => 'cannot contain spaces or special characters'
10
+
11
+ validates_presence_of :email
12
+ validates_format_of :email, :with => /^[^@][\w.-]*@[\w.-]+[.][a-z]{2,4}$/i
13
+
14
+ validates_presence_of :password, :if => :password_required?
15
+ validates_length_of :password, :within => 4..40, :if => :password_required?
16
+ validates_presence_of :password_confirmation, :if => :password_required?
17
+ validates_confirmation_of :password, :if => :password_required?
18
+
19
+ validates_acceptance_of :terms_of_service
20
+
21
+ before_save :hash_password
22
+
23
+ attr_protected :hashed_password, :remember_token, :remember_token_expires_at
24
+
25
+ def self.authenticate(login, password)
26
+ user = find_by_login(login)
27
+ return user if user && user.authenticated?(password)
28
+ end
29
+
30
+ def authenticated?(password)
31
+ hashed_password == encrypt(password)
32
+ end
33
+
34
+ def remember
35
+ remember_for 2.weeks
36
+ end
37
+
38
+ def remember_for(time)
39
+ remember_until time.from_now.utc
40
+ end
41
+
42
+ def remember_until(time)
43
+ self.remember_token_expires_at = time
44
+ self.remember_token = encrypt("#{email}--#{remember_token_expires_at}")
45
+ save
46
+ end
47
+
48
+ def forget
49
+ self.remember_token_expires_at = nil
50
+ self.remember_token = nil
51
+ save
52
+ end
53
+
54
+ def to_s
55
+ login
56
+ end
57
+
58
+ protected
59
+ def hash_password
60
+ return if password.blank?
61
+ self.hashed_password = encrypt(password)
62
+ end
63
+
64
+ def password_required?
65
+ hashed_password.blank? || !password.blank?
66
+ end
67
+
68
+ def encrypt(string)
69
+ Digest::SHA1.hexdigest(string)
70
+ end
71
+ end
@@ -0,0 +1,16 @@
1
+ %h1 Login
2
+
3
+ - form_tag do
4
+ %fieldset
5
+ %p
6
+ Login:<br />
7
+ = text_field_tag :login
8
+ %p
9
+ Password:<br />
10
+ = password_field_tag :password
11
+ %p
12
+ = "#{check_box_tag :remember_me} Remember me for 2 weeks"
13
+ %p
14
+ = submit_tag 'Login'
15
+
16
+ %h2= "Don't have an account? You should #{link_to 'Sign up!', new_user_url}"
@@ -0,0 +1,17 @@
1
+ <h1>Login</h1>
2
+
3
+ <%% form_tag do -%>
4
+ <fieldset>
5
+ <p><label for="login">Login:</label><br />
6
+ <%%= text_field_tag :login %></p>
7
+
8
+ <p><label for="password">Password:</label><br />
9
+ <%%= password_field_tag :password %></p>
10
+
11
+ <p><label><%%= check_box_tag :remember_me %> Remember me for 2 weeks</label></p>
12
+
13
+ <p><%%= submit_tag 'Login' %></p>
14
+ </fieldset>
15
+ <%% end -%>
16
+
17
+ <h2>Don't have an account? You should <%%= link_to 'Sign up!', new_user_url %></h2>
@@ -0,0 +1,11 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title= controller.controller_name.capitalize
5
+ %meta{'http-equiv' => 'Content-Type', 'content' => 'text/html; charset=utf-8'}/
6
+ = javascript_include_tag :defaults
7
+ %body
8
+ #container
9
+ #content
10
+ = [:notice, :error].collect {|k| content_tag(:div, flash[k], :class => "flash #{k}") if flash[k] }.join
11
+ = yield
@@ -0,0 +1,17 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html>
3
+ <head>
4
+ <title><%%= controller.controller_name.capitalize %></title>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <%%= javascript_include_tag :defaults %>
7
+ </head>
8
+
9
+ <body>
10
+ <div id="container">
11
+ <div id="content">
12
+ <%%= [:notice, :error].collect {|k| content_tag(:div, flash[k], :class => "flash #{k}") if flash[k] }.join %>
13
+ <%%= yield %>
14
+ </div>
15
+ </div>
16
+ </body>
17
+ </html>
@@ -0,0 +1,17 @@
1
+ = error_messages_for 'user'
2
+
3
+ %p
4
+ Login:<br />
5
+ = text_field :user, :login
6
+
7
+ %p
8
+ Email:<br />
9
+ = text_field :user, :email
10
+
11
+ %p
12
+ Password:<br />
13
+ = password_field :user, :password
14
+
15
+ %p
16
+ Password confirmation:<br />
17
+ = password_field :user, :password_confirmation
@@ -0,0 +1,13 @@
1
+ <%%= error_messages_for 'user' %>
2
+
3
+ <p><label>Login:</label><br />
4
+ <%%= text_field :user, :login %></p>
5
+
6
+ <p><label>Email:</label><br />
7
+ <%%= text_field :user, :email %></p>
8
+
9
+ <p><label>Password:</label><br />
10
+ <%%= password_field :user, :password %></p>
11
+
12
+ <p><label>Password confirmation:</label><br />
13
+ <%%= password_field :user, :password_confirmation %></p>
@@ -0,0 +1,7 @@
1
+ %h1 Edit your account details
2
+
3
+ - form_tag user_path, :method => :put do
4
+ %fieldset
5
+ = render :partial => 'form'
6
+ %p
7
+ = submit_tag 'Save Changes'
@@ -0,0 +1,8 @@
1
+ <h1>Edit your account details</h1>
2
+
3
+ <%% form_tag user_path, :method => :put do -%>
4
+ <fieldset>
5
+ <%%= render :partial => 'form' %>
6
+ <p><%%= submit_tag 'Save Changes' %></p>
7
+ </fieldset>
8
+ <%% end -%>
@@ -0,0 +1,11 @@
1
+ %h1 Signup for an account
2
+
3
+ - form_tag user_path do
4
+ %fieldset
5
+ = render :partial => 'form'
6
+ %p
7
+ = "#{check_box :user, :terms_of_service} Yes, I have read and accept your #{link_to 'terms of service'}"
8
+ %p
9
+ = submit_tag 'Signup'
10
+
11
+ %h2= "Already have an account? #{link_to 'Log in', login_url}"
@@ -0,0 +1,11 @@
1
+ <h1>Signup for an account</h1>
2
+
3
+ <%% form_tag user_path do -%>
4
+ <fieldset>
5
+ <%%= render :partial => 'form' %>
6
+ <p><label><%%= check_box :user, :terms_of_service %> Yes, I have read and accept your</label> <%%= link_to 'terms of service', '#' %></p>
7
+ <p><%%= submit_tag 'Signup' %></p>
8
+ </fieldset>
9
+ <%% end -%>
10
+
11
+ <h2>Already have an account? <%%= link_to 'Log in', login_url %></h2>
@@ -0,0 +1,4 @@
1
+ %h1 You are logged in
2
+
3
+ = link_to 'logout', logout_url
4
+ = link_to 'edit your account information', edit_user_path
@@ -0,0 +1,4 @@
1
+ <h1>You are logged in</h1>
2
+
3
+ <%%= link_to 'logout', logout_url %> |
4
+ <%%= link_to 'edit your account information', edit_user_path %>
@@ -0,0 +1,12 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.root :controller => 'account', :action => 'login'
3
+
4
+ map.login 'login', :controller => 'account', :action => 'login'
5
+ map.logout 'logout', :controller => 'account', :action => 'logout'
6
+
7
+ map.resource :user
8
+
9
+ # Install the default routes as the lowest priority.
10
+ map.connect ':controller/:action/:id'
11
+ map.connect ':controller/:action/:id.:format'
12
+ end
@@ -0,0 +1,18 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :users do |t|
4
+ t.column :login, :string
5
+ t.column :email, :string
6
+ t.column :hashed_password, :string
7
+ t.column :remember_token, :string
8
+ t.column :remember_token_expires_at, :datetime
9
+ t.column :created_at, :datetime
10
+ t.column :updated_at, :datetime
11
+ end
12
+ add_index :users, [:login, :hashed_password]
13
+ end
14
+
15
+ def self.down
16
+ drop_table :users
17
+ end
18
+ end
@@ -0,0 +1,167 @@
1
+ # Heavily influenced by xal's original login_generator (circa 2004) and
2
+ # technoweenie's acts_as_authenticated.
3
+ #
4
+ # Provides a simple authentication system with support for HTTP Basic
5
+ # Authentication and remember-me goodness via cookies. To use simply
6
+ # mix in to ApplicationController.
7
+ #
8
+ # Assumes a named login route (login_url), a User model with the class
9
+ # method `authenticate(login, password)` and the following schema:
10
+ #
11
+ # create_table :users do |t|
12
+ # t.column :login, :string
13
+ # t.column :email, :string
14
+ # t.column :hashed_password, :string
15
+ # t.column :remember_token, :string
16
+ # t.column :remember_token_expires_at, :datetime
17
+ # end
18
+ #
19
+ # ---
20
+ # Copyright (c) 2006 Jeffrey Hardy (packagethief)
21
+ #
22
+ # Permission is hereby granted, free of charge, to any person obtaining
23
+ # a copy of this software and associated documentation files (the
24
+ # "Software"), to deal in the Software without restriction, including
25
+ # without limitation the rights to use, copy, modify, merge, publish,
26
+ # distribute, sublicense, and/or sell copies of the Software, and to
27
+ # permit persons to whom the Software is furnished to do so, subject to
28
+ # the following conditions:
29
+ #
30
+ # The above copyright notice and this permission notice shall be
31
+ # included in all copies or substantial portions of the Software.
32
+ #
33
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
34
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
35
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
36
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
37
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
38
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
39
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40
+ module AuthenticationSystem
41
+ protected
42
+
43
+ def self.included(controller)
44
+ controller.helper_method :current_user, :logged_in?
45
+ controller.filter_parameter_logging :password
46
+ end
47
+
48
+ def find_current_user
49
+ if session[:user_id]
50
+ User.find_by_id(session[:user_id])
51
+ else
52
+ authenticate_with_http_basic {|u, p| User.authenticate(u, p) }
53
+ end
54
+ end
55
+
56
+ def current_user
57
+ @current_user ||= find_current_user
58
+ end
59
+
60
+ def current_user=(user)
61
+ @current_user = user.is_a?(User) ? user : nil
62
+ session[:user_id] = @current_user ? @current_user.id : nil
63
+ end
64
+
65
+ def logged_in?
66
+ current_user.is_a?(User)
67
+ end
68
+
69
+ # Filter method to enforce a login requirement
70
+ # Apply as a before_filter on any controller you want to protect
71
+ def authenticate
72
+ (logged_in? && authorized?) ? true : access_denied
73
+ end
74
+
75
+ # Filter method to login a user using a cookie
76
+ # Apply as a before_filter on the application controller
77
+ def authenticate_with_cookies
78
+ return if logged_in? or cookies[:auth_token].nil?
79
+ self.current_user = User.find_by_remember_token(cookies[:auth_token])
80
+ end
81
+
82
+ # Overwrite in idividual controllers to control authorization
83
+ def authorized?
84
+ true
85
+ end
86
+
87
+ # Overwrite in idividual controllers to customize the flash message shown when authorization fails
88
+ def unauthorized_message
89
+ "Please login first and we'll send you right along"
90
+ end
91
+
92
+ # Sets the appropriate cookies to remember the current user
93
+ def remember_current_user
94
+ if logged_in?
95
+ current_user.remember
96
+ cookies[:auth_token] = { :value => current_user.remember_token, :expires => current_user.remember_token_expires_at }
97
+ end
98
+ end
99
+
100
+ # Logs out the current user by removing the session, cookie, and any HTTP auth data
101
+ def logout_current_user!
102
+ current_user.forget rescue nil
103
+ cookies.delete :auth_token
104
+ self.current_user = nil
105
+ request.env['HTTP_AUTHORIZATION'] = nil
106
+ end
107
+
108
+ def access_denied
109
+ respond_to do |format|
110
+ format.html do
111
+ store_location
112
+ flash[:notice] = unauthorized_message
113
+ redirect_to login_url
114
+ end
115
+ format.xml do
116
+ headers['Status'] = 'Unauthorized'
117
+ headers['WWW-Authenticate'] = 'Basic realm="Application"'
118
+ render :text => "401 Unauthorized\n", :status => :unauthorized
119
+ end
120
+ end
121
+ false
122
+ end
123
+
124
+ def store_location
125
+ session[:return_to] = request.request_uri
126
+ end
127
+
128
+ def redirect_back_or_to(options)
129
+ session[:return_to] ? redirect_to(session[:return_to]) : redirect_to(options)
130
+ session[:return_to] = nil
131
+ end
132
+
133
+ # Inspired by DHH's http_authentication plugin
134
+ # See http://dev.rubyonrails.org/svn/rails/plugins/http_authentication
135
+ def authenticate_with_http_basic(&login_procedure)
136
+ if authorization = request.env['HTTP_AUTHORIZATION'] || request.env['X-HTTP_AUTHORIZATION']
137
+ login_procedure.call(*Base64.decode64(authorization.split.last).split(/:/, 2))
138
+ end
139
+ end
140
+
141
+ # Helpers to make testing the functionality provided by this library
142
+ # easier. Include AuthenticationSystem::TestHelpers in RAILS_ROOT/test/test_helper.rb
143
+ module TestHelpers
144
+ def login_as(user)
145
+ @request.session[:user_id] = users(user.to_sym).id
146
+ end
147
+
148
+ def authenticate_as(login, password)
149
+ @request.env['HTTP_ACCEPT'] = @request.env['Content-Type'] = 'text/xml'
150
+ @request.env["HTTP_AUTHORIZATION"] = "Basic #{Base64.encode64("#{login}:#{password}")}"
151
+ end
152
+
153
+ def logout!
154
+ @request.session[:user_id] = nil
155
+ @controller.instance_variable_set('@current_user', nil)
156
+ @request.env['HTTP_AUTHORIZATION'] = nil
157
+ end
158
+
159
+ def auth_token(token)
160
+ CGI::Cookie.new('name' => 'auth_token', 'value' => token)
161
+ end
162
+
163
+ def cookie_for(user)
164
+ auth_token(users(user).remember_token)
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,15 @@
1
+ eugene:
2
+ id: 1
3
+ login: 'eugene'
4
+ email: 'eugene@example.com'
5
+ hashed_password: 'e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4' # => secret
6
+ created_at: <%%= Time.now.to_s :db %>
7
+ updated_at: <%%= Time.now.to_s :db %>
8
+
9
+ arthur:
10
+ id: 2
11
+ login: 'arthur'
12
+ email: 'arthur@example.com'
13
+ hashed_password: 'e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4' # => secret
14
+ created_at: <%%= Time.now.to_s :db %>
15
+ updated_at: <%%= Time.now.to_s :db %>
@@ -0,0 +1,77 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'account_controller'
3
+
4
+ # Re-raise errors caught by the controller.
5
+ class AccountController; def rescue_action(e) raise e end; end
6
+
7
+ class AccountControllerTest < Test::Unit::TestCase
8
+ fixtures :users
9
+
10
+ def setup
11
+ @controller = AccountController.new
12
+ @request = ActionController::TestRequest.new
13
+ @response = ActionController::TestResponse.new
14
+ end
15
+
16
+ def test_should_login_user_and_redirect
17
+ post :login, :login => 'eugene', :password => 'secret'
18
+ assert @controller.send(:logged_in?)
19
+ assert session[:user_id]
20
+ assert_response :redirect
21
+ end
22
+
23
+ def test_should_not_login_invalid_user
24
+ post :login, :login => 'eugene', :password => 'bad password'
25
+ assert !@controller.send(:logged_in?)
26
+ assert_nil session[:user_id]
27
+ assert flash[:error]
28
+ assert_response :redirect
29
+ end
30
+
31
+ def test_should_logout_and_redirect
32
+ login_as :eugene
33
+ get :logout
34
+ assert_nil session[:user_id]
35
+ assert flash[:notice]
36
+ assert_response :redirect
37
+ end
38
+
39
+ def test_should_remember_login_if_remember_me_is_set
40
+ post :login, :login => 'eugene', :password => 'secret', :remember_me => "1"
41
+ assert @controller.send(:logged_in?)
42
+ assert_not_nil @response.cookies["auth_token"]
43
+ end
44
+
45
+ def test_should_not_remember_login_if_remember_me_is_not_set
46
+ post :login, :login => 'eugene', :password => 'secret', :remember_me => "0"
47
+ assert_nil @response.cookies["auth_token"]
48
+ end
49
+
50
+ def test_should_delete_token_on_logout
51
+ login_as :eugene
52
+ get :logout
53
+ assert_equal @response.cookies['auth_token'], []
54
+ end
55
+
56
+ def test_should_login_automatically_from_cookie
57
+ users(:eugene).remember
58
+ @request.cookies['auth_token'] = cookie_for(:eugene)
59
+ get :login
60
+ assert @controller.send(:logged_in?)
61
+ end
62
+
63
+ def test_should_fail_cookie_login_with_expired_cookie
64
+ users(:eugene).remember
65
+ users(:eugene).update_attribute :remember_token_expires_at, 5.minutes.ago.utc
66
+ @request.cookies['auth_token'] = cookie_for(:eugene)
67
+ get :login
68
+ assert_equal false, !@controller.send(:logged_in?)
69
+ end
70
+
71
+ def test_should_fail_cookie_login_with_invalid_cookie
72
+ users(:eugene).remember
73
+ @request.cookies['auth_token'] = auth_token('invalid_auth_token')
74
+ get :login
75
+ assert !@controller.send(:logged_in?)
76
+ end
77
+ end
@@ -0,0 +1,119 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ require 'user_controller'
3
+
4
+ # Re-raise errors caught by the controller.
5
+ class UserController; def rescue_action(e) raise e end; end
6
+
7
+ class UserControllerTest < Test::Unit::TestCase
8
+ fixtures :users
9
+
10
+ def setup
11
+ @controller = UserController.new
12
+ @request = ActionController::TestRequest.new
13
+ @response = ActionController::TestResponse.new
14
+ end
15
+
16
+ def test_should_create_user
17
+ assert_difference 'User.count' do
18
+ post :create, :user => valid_user
19
+ assert assigns(:user)
20
+ assert flash[:notice]
21
+ assert_response :redirect
22
+ end
23
+ end
24
+
25
+ def test_should_require_login_on_create
26
+ assert_no_difference 'User.count' do
27
+ post :create, :user => valid_user(:login => nil)
28
+ assert assigns(:user).errors.on(:login)
29
+ assert_response :success
30
+ end
31
+ end
32
+
33
+ def test_should_require_unique_login_on_create
34
+ assert_no_difference 'User.count' do
35
+ post :create, :user => valid_user(:login => 'eugene')
36
+ assert assigns(:user).errors.on(:login)
37
+ assert_response :success
38
+ end
39
+ end
40
+
41
+ def test_should_require_password_on_create
42
+ assert_no_difference 'User.count' do
43
+ post :create, :user => valid_user(:password => nil)
44
+ assert assigns(:user).errors.on(:password)
45
+ assert_response :success
46
+ end
47
+ end
48
+
49
+ def test_should_require_password_confirmation_on_create
50
+ assert_no_difference 'User.count' do
51
+ post :create, :user => valid_user(:password_confirmation => nil)
52
+ assert_response :success
53
+ end
54
+ end
55
+
56
+ def test_should_require_email_on_create
57
+ assert_no_difference 'User.count' do
58
+ post :create, :user => valid_user(:email => nil)
59
+ assert assigns(:user).errors.on(:email)
60
+ assert_response :success
61
+ end
62
+ end
63
+
64
+ def test_should_require_valid_email_on_create
65
+ assert_no_difference 'User.count' do
66
+ post :create, :user => valid_user(:email => 'invalid@')
67
+ assert assigns(:user).errors.on(:email)
68
+ assert_response :success
69
+ end
70
+ end
71
+
72
+ def test_should_require_authentication_for_show
73
+ get :show
74
+ assert_redirected_to login_url
75
+
76
+ @request.env['HTTP_ACCEPT'] = @request.env['Content-Type'] = 'text/xml'
77
+ get :show
78
+ assert_response :unauthorized
79
+ end
80
+
81
+ def test_should_require_authentication_for_edit
82
+ get :edit
83
+ assert_redirected_to login_url
84
+
85
+ @request.env['HTTP_ACCEPT'] = @request.env['Content-Type'] = 'text/xml'
86
+ get :edit
87
+ assert_response :unauthorized
88
+ end
89
+
90
+ def test_should_require_authentication_for_update
91
+ post :update
92
+ assert_redirected_to login_url
93
+
94
+ @request.env['HTTP_ACCEPT'] = @request.env['Content-Type'] = 'text/xml'
95
+ post :update
96
+ assert_response :unauthorized
97
+ end
98
+
99
+ def test_should_accept_http_basic_authentication
100
+ login_as('eugene')
101
+ get :edit
102
+ assert_response :success
103
+
104
+ logout!
105
+
106
+ # HTTP_AUTH
107
+ authenticate_as('eugene', 'secret')
108
+ get :edit
109
+ assert_response :success
110
+ end
111
+
112
+ protected
113
+ def valid_user(overrides = {})
114
+ { :login => 'rusty',
115
+ :email => 'rusty@example.com',
116
+ :password => 'secret',
117
+ :password_confirmation => 'secret' }.merge(overrides)
118
+ end
119
+ end
@@ -0,0 +1,37 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
3
+ require 'test_help'
4
+
5
+ class Test::Unit::TestCase
6
+ # Transactional fixtures accelerate your tests by wrapping each test method
7
+ # in a transaction that's rolled back on completion. This ensures that the
8
+ # test database remains unchanged so your fixtures don't have to be reloaded
9
+ # between every test method. Fewer database queries means faster tests.
10
+ #
11
+ # Read Mike Clark's excellent walkthrough at
12
+ # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
13
+ #
14
+ # Every Active Record database supports transactions except MyISAM tables
15
+ # in MySQL. Turn off transactional fixtures in this case; however, if you
16
+ # don't care one way or the other, switching from MyISAM to InnoDB tables
17
+ # is recommended.
18
+ self.use_transactional_fixtures = true
19
+
20
+ # Instantiated fixtures are slow, but give you @david where otherwise you
21
+ # would need people(:david). If you don't want to migrate your existing
22
+ # test cases which use the @david style and don't mind the speed hit (each
23
+ # instantiated fixtures translates to a database query per test method),
24
+ # then set this back to true.
25
+ self.use_instantiated_fixtures = false
26
+
27
+ # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
28
+ # If you need to control the loading order (due to foreign key constraints etc), you'll
29
+ # need to change this line to explicitly name the order you desire.
30
+ #
31
+ # Note: You'll currently still have to declare fixtures explicitly in integration tests
32
+ # -- they do not yet inherent this setting
33
+ #fixtures :all
34
+
35
+ # Mixin the helpers provided by the authentication library
36
+ include AuthenticationSystem::TestHelpers
37
+ end
@@ -0,0 +1,116 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class UserTest < Test::Unit::TestCase
4
+ fixtures :users
5
+
6
+ def test_should_create_user
7
+ assert_difference 'User.count' do
8
+ user = User.create(valid_user)
9
+ assert !user.new_record?, "#{user.errors.full_messages.to_sentence}"
10
+ end
11
+ end
12
+
13
+ def test_should_update_user
14
+ u = users(:eugene)
15
+ attributes = {
16
+ :login => 'eugene_smith',
17
+ :email => 'eugene.smith@example.com',
18
+ :password => 'terces',
19
+ :password_confirmation => 'terces'
20
+ }
21
+ assert u.update_attributes(attributes), u.errors.full_messages
22
+ end
23
+
24
+ def test_should_destroy_user
25
+ assert_difference 'User.count', -1 do
26
+ User.find(:first).destroy
27
+ end
28
+ end
29
+
30
+ def test_should_accept_valid_emails
31
+ %w(user@example.com user@example.co.uk ab@cd.ef 1@example.ca john.q@example.com john_q-pub.lic@ex-ample.co.uk 8375309@90210.org).each do |email|
32
+ assert_valid User.new(valid_user(:email => email))
33
+ end
34
+ end
35
+
36
+ def test_should_not_allow_invalid_emails
37
+ user = User.new(valid_user)
38
+
39
+ %w(@foo.bar foo@ foo@bar @).each do |email|
40
+ user.email = email
41
+ assert !user.valid?
42
+ assert user.errors.on(:email)
43
+ end
44
+ end
45
+
46
+ def test_should_not_allow_spaces_or_dots_in_login
47
+ user = User.new(valid_user)
48
+
49
+ ['foo.bar', 'foo bar'].each do |login|
50
+ user.login = login
51
+ assert !user.valid?
52
+ assert user.errors.on(:login)
53
+ end
54
+ end
55
+
56
+ def test_should_reset_password
57
+ users(:eugene).update_attributes(:password => 'new password', :password_confirmation => 'new password')
58
+ assert_equal users(:eugene), User.authenticate('eugene', 'new password')
59
+ end
60
+
61
+ def test_should_not_rehash_password_when_unchanged
62
+ users(:eugene).update_attributes(:login => 'enegue')
63
+ assert_equal users(:eugene), User.authenticate('enegue', 'secret')
64
+ end
65
+
66
+ def test_should_authenticate_user
67
+ assert_equal users(:eugene), User.authenticate('eugene', 'secret')
68
+ end
69
+
70
+ def test_should_set_remember_token
71
+ users(:eugene).remember
72
+ assert_not_nil users(:eugene).remember_token
73
+ assert_not_nil users(:eugene).remember_token_expires_at
74
+ end
75
+
76
+ def test_should_unset_remember_token
77
+ users(:eugene).remember
78
+ assert_not_nil users(:eugene).remember_token
79
+ users(:eugene).forget
80
+ assert_nil users(:eugene).remember_token
81
+ end
82
+
83
+ def test_should_remember_login_for_one_week
84
+ before = 1.week.from_now.utc
85
+ users(:eugene).remember_for 1.week
86
+ after = 1.week.from_now.utc
87
+ assert_not_nil users(:eugene).remember_token
88
+ assert_not_nil users(:eugene).remember_token_expires_at
89
+ assert users(:eugene).remember_token_expires_at.between?(before, after)
90
+ end
91
+
92
+ def test_should_remember_login_until_one_week_from_now
93
+ time = 1.week.from_now.utc
94
+ users(:eugene).remember_until time
95
+ assert_not_nil users(:eugene).remember_token
96
+ assert_not_nil users(:eugene).remember_token_expires_at
97
+ assert_equal users(:eugene).remember_token_expires_at, time
98
+ end
99
+
100
+ def test_should_remember_login_for_default_two_weeks
101
+ before = 2.weeks.from_now.utc
102
+ users(:eugene).remember
103
+ after = 2.weeks.from_now.utc
104
+ assert_not_nil users(:eugene).remember_token
105
+ assert_not_nil users(:eugene).remember_token_expires_at
106
+ assert users(:eugene).remember_token_expires_at.between?(before, after)
107
+ end
108
+
109
+ protected
110
+ def valid_user(overrides={})
111
+ { :login => 'rusty',
112
+ :email => 'rusty@example.com',
113
+ :password => 'secret',
114
+ :password_confirmation => 'secret' }.merge(overrides)
115
+ end
116
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.2
3
+ specification_version: 1
4
+ name: boilerplate_generator
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2007-05-08 00:00:00 -04:00
8
+ summary: Boilerplate is a generator for new Rails projects
9
+ require_paths:
10
+ - lib
11
+ email: packagethief@gmail.com
12
+ homepage: http://boilerplate.rubyforge.org
13
+ rubyforge_project: boilerplate
14
+ description: Boilerplate is a generator for new Rails projects
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Jeffrey Hardy (packagethief)
31
+ files:
32
+ - History.txt
33
+ - Manifest.txt
34
+ - README.txt
35
+ - USAGE
36
+ - boilerplate_generator.rb
37
+ - lib/boilerplate_generator/version.rb
38
+ - templates/app/controllers/account_controller.rb
39
+ - templates/app/controllers/application.rb
40
+ - templates/app/controllers/user_controller.rb
41
+ - templates/app/helpers/account_helper.rb
42
+ - templates/app/helpers/user_helper.rb
43
+ - templates/app/models/user.rb
44
+ - templates/app/views/account/login.haml
45
+ - templates/app/views/account/login.html.erb
46
+ - templates/app/views/layouts/application.haml
47
+ - templates/app/views/layouts/application.html.erb
48
+ - templates/app/views/user/_form.haml
49
+ - templates/app/views/user/_form.html.erb
50
+ - templates/app/views/user/edit.haml
51
+ - templates/app/views/user/edit.html.erb
52
+ - templates/app/views/user/new.haml
53
+ - templates/app/views/user/new.html.erb
54
+ - templates/app/views/user/show.haml
55
+ - templates/app/views/user/show.html.erb
56
+ - templates/config/routes.rb
57
+ - templates/db/migrate/create_users.rb
58
+ - templates/lib/authentication_system.rb
59
+ - templates/test/fixtures/users.yml
60
+ - templates/test/functional/account_controller_test.rb
61
+ - templates/test/functional/user_controller_test.rb
62
+ - templates/test/test_helper.rb
63
+ - templates/test/unit/user_test.rb
64
+ test_files: []
65
+
66
+ rdoc_options: []
67
+
68
+ extra_rdoc_files: []
69
+
70
+ executables: []
71
+
72
+ extensions: []
73
+
74
+ requirements: []
75
+
76
+ dependencies: []
77
+