katapult 0.1.2 → 0.2.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/README.md +61 -35
- data/bin/katapult +24 -34
- data/features/authenticate.feature +344 -0
- data/features/basics.feature +590 -0
- data/features/binary.feature +33 -1
- data/features/model.feature +9 -13
- data/features/step_definitions/rails_steps.rb +3 -2
- data/features/wui.feature +49 -4
- data/lib/generators/katapult/basics/basics_generator.rb +63 -17
- data/lib/generators/katapult/basics/templates/.gitignore +1 -0
- data/lib/generators/katapult/basics/templates/.ruby-version +1 -1
- data/lib/generators/katapult/basics/templates/Capfile +25 -0
- data/lib/generators/katapult/basics/templates/Gemfile +14 -6
- data/lib/generators/katapult/basics/templates/Guardfile +44 -0
- data/lib/generators/katapult/basics/templates/config/database.sample.yml +3 -2
- data/lib/generators/katapult/basics/templates/config/database.yml +3 -2
- data/lib/generators/katapult/basics/templates/config/deploy/production.rb +8 -0
- data/lib/generators/katapult/basics/templates/config/deploy/staging.rb +7 -0
- data/lib/generators/katapult/basics/templates/config/deploy.rb +37 -0
- data/lib/generators/katapult/basics/templates/config/initializers/ext.rb +3 -0
- data/lib/generators/katapult/basics/templates/features/support/factory_girl.rb +1 -0
- data/lib/generators/katapult/basics/templates/features/support/paths.rb +6 -0
- data/lib/generators/katapult/basics/templates/lib/capistrano/tasks/db.rake +28 -0
- data/lib/generators/katapult/basics/templates/lib/capistrano/tasks/deploy.rake +15 -0
- data/lib/generators/katapult/basics/templates/lib/capistrano/tasks/passenger.rake +8 -0
- data/lib/generators/katapult/basics/templates/{config/initializers → lib/ext/action_view}/form_for_with_development_errors.rb +0 -2
- data/lib/generators/katapult/basics/templates/lib/ext/action_view/spec_label.rb +46 -0
- data/lib/generators/katapult/basics/templates/{config/initializers → lib/ext/active_record}/find_by_anything.rb +0 -0
- data/lib/generators/katapult/basics/templates/lib/ext/active_record/these.rb +7 -0
- data/lib/generators/katapult/basics/templates/lib/ext/array/xss_aware_join.rb +10 -0
- data/lib/generators/katapult/basics/templates/lib/ext/enumerable/natural_sort.rb +15 -0
- data/lib/generators/katapult/basics/templates/lib/ext/hash/infinite.rb +7 -0
- data/lib/generators/katapult/basics/templates/lib/ext/string/html_entities.rb +11 -0
- data/lib/generators/katapult/basics/templates/lib/ext/string/to_sort_atoms.rb +52 -0
- data/lib/generators/katapult/basics/templates/lib/tasks/pending_migrations.rake +24 -0
- data/lib/generators/katapult/basics/templates/spec/factories/factories.rb +9 -0
- data/lib/generators/katapult/basics/templates/spec/support/factory_girl.rb +3 -0
- data/lib/generators/katapult/clearance/clearance_generator.rb +125 -0
- data/lib/generators/katapult/clearance/templates/app/controllers/passwords_controller.rb +16 -0
- data/lib/generators/katapult/clearance/templates/app/views/clearance_mailer/change_password.html.haml +6 -0
- data/lib/generators/katapult/clearance/templates/app/views/clearance_mailer/change_password.text.erb +3 -0
- data/lib/generators/katapult/clearance/templates/app/views/passwords/create.html.haml +5 -0
- data/lib/generators/katapult/clearance/templates/app/views/passwords/edit.html.haml +16 -0
- data/lib/generators/katapult/clearance/templates/app/views/passwords/new.html.haml +14 -0
- data/lib/generators/katapult/clearance/templates/app/views/sessions/new.html.haml +19 -0
- data/lib/generators/katapult/clearance/templates/config/initializers/clearance.rb +15 -0
- data/lib/generators/katapult/clearance/templates/config/locales/clearance.en.yml +59 -0
- data/lib/generators/katapult/clearance/templates/features/authentication.feature +94 -0
- data/lib/generators/katapult/clearance/templates/features/step_definitions/authentication_steps.rb +4 -0
- data/lib/generators/katapult/cucumber_features/templates/feature.feature +11 -7
- data/lib/generators/katapult/haml/haml_generator.rb +5 -0
- data/lib/generators/katapult/haml/templates/_form.html.haml +4 -4
- data/lib/generators/katapult/haml/templates/app/views/layouts/_flashes.html.haml +3 -0
- data/lib/generators/katapult/haml/templates/app/views/layouts/application.html.haml +9 -3
- data/lib/generators/katapult/haml/templates/index.html.haml +1 -1
- data/lib/generators/katapult/haml/templates/show.html.haml +2 -4
- data/lib/generators/katapult/install/templates/lib/katapult/application_model.rb +9 -7
- data/lib/generators/katapult/model/model_generator.rb +1 -1
- data/lib/generators/katapult/w_u_i/templates/controller.rb +1 -1
- data/lib/generators/katapult/w_u_i/w_u_i_generator.rb +4 -2
- data/lib/katapult/application_model.rb +8 -1
- data/lib/katapult/attribute.rb +10 -11
- data/lib/katapult/authentication.rb +25 -0
- data/lib/katapult/binary_util.rb +37 -0
- data/lib/katapult/element.rb +1 -1
- data/lib/katapult/generator.rb +6 -0
- data/lib/katapult/model.rb +13 -1
- data/lib/katapult/parser.rb +7 -0
- data/lib/katapult/version.rb +1 -1
- data/lib/katapult/wui.rb +4 -0
- data/lib/katapult.rb +2 -0
- data/spec/attribute_spec.rb +13 -0
- data/spec/element_spec.rb +5 -0
- data/spec/model_spec.rb +5 -4
- data/spec/util_spec.rb +8 -8
- data/spec/wui_spec.rb +19 -0
- metadata +44 -8
- data/features/katapult.feature +0 -271
- data/lib/katapult/util.rb +0 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a3cdc0f0b264fd596277340707b91532b302b8d2
|
|
4
|
+
data.tar.gz: 92f80d989c103b65434d22d9d33c0eb273f2dd40
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 708499a49443d9384eb273369a0e81bf2f6578e0520a9bc460abeefdc2c8c97ff5d310407e391ac80fc8517791c0c12f89652d60a3ff42b7d0228b9466130871
|
|
7
|
+
data.tar.gz: d122fd0af16935458dd2b06867fa86b5d545a74b8a2fb2f746c49cd61cada320b333426282a627cb5f41340b14dade12795724496a80c2404af42dfa76d0bd0f
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.3.0
|
data/README.md
CHANGED
|
@@ -3,13 +3,17 @@
|
|
|
3
3
|
<img src="katapult.png" width="200px" align="right" />
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
`Katapult` is a kickstart generator for Rails applications. It creates
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
`Katapult` is a kickstart generator for Rails applications. It creates new Rails
|
|
7
|
+
applications with [lots of pre-configuration](https://github.com/makandra/katapult/blob/master/lib/generators/katapult/basics/basics_generator.rb)
|
|
8
|
+
and offers ([makandra-flavored](https://leanpub.com/growing-rails)) code
|
|
9
|
+
generation from an application model.
|
|
10
|
+
These two features significally speed up the initial phase of a Rails project by
|
|
11
|
+
doing in minutes what took you weeks. After modeling your application, which
|
|
12
|
+
typically takes about an hour, you can instantly start implementing the meat of
|
|
13
|
+
your application.
|
|
10
14
|
|
|
11
|
-
`Katapult` will
|
|
12
|
-
Rails 4.2 and Ruby 2.
|
|
15
|
+
`Katapult` will only support current versions of Ruby and Rails, currently
|
|
16
|
+
Rails 4.2 and Ruby 2.3.
|
|
13
17
|
|
|
14
18
|
|
|
15
19
|
## Installation
|
|
@@ -18,15 +22,18 @@ Install the `katapult` gem with
|
|
|
18
22
|
|
|
19
23
|
gem install katapult
|
|
20
24
|
|
|
25
|
+
If you intend to extend an existing application, add it to the development group
|
|
26
|
+
in your Gemfile.
|
|
27
|
+
|
|
21
28
|
|
|
22
29
|
## Usage
|
|
23
30
|
|
|
24
31
|
`Katapult` does two separate things:
|
|
25
32
|
|
|
26
|
-
1.
|
|
27
|
-
useful configuration, databases etc.
|
|
28
|
-
2.
|
|
29
|
-
controllers, routes, stylesheets
|
|
33
|
+
1. It creates a new Rails application, set up with many standard gems, snippets,
|
|
34
|
+
useful configuration, databases, testing libraries etc. See the [BasicsGenerator](https://github.com/makandra/katapult/blob/master/lib/generators/katapult/basics/basics_generator.rb) for details.
|
|
35
|
+
2. It generates code from an application model, i.e. creates files for models,
|
|
36
|
+
views, controllers, routes, stylesheets; see the
|
|
30
37
|
|
|
31
38
|
You may use both or only one of them.
|
|
32
39
|
|
|
@@ -37,28 +44,27 @@ Run the following command:
|
|
|
37
44
|
|
|
38
45
|
katapult new $APPLICATION_NAME
|
|
39
46
|
|
|
40
|
-
|
|
47
|
+
This will:
|
|
41
48
|
|
|
42
|
-
- create a new Rails application
|
|
43
|
-
- install common Gems
|
|
44
|
-
-
|
|
45
|
-
- set up a `database.yml` file (for MySQL)
|
|
49
|
+
- create a new Rails application
|
|
50
|
+
- install common Gems
|
|
51
|
+
- set up a `database.yml` file (for PostgreSQL)
|
|
46
52
|
- create basic styles
|
|
47
|
-
- install some handy initializers
|
|
48
53
|
- install RSpec and Cucumber to the application
|
|
49
|
-
-
|
|
54
|
+
- install Capistrano
|
|
55
|
+
- create `lib/katapult/application_model.rb` (needed for step 2)
|
|
50
56
|
|
|
51
|
-
See
|
|
57
|
+
See the [BasicsGenerator](https://github.com/makandra/katapult/blob/master/lib/generators/katapult/basics/basics_generator.rb)
|
|
58
|
+
for details: Its methods are executed one-by-one and their names are a
|
|
59
|
+
description of what it does.
|
|
52
60
|
|
|
53
|
-
### Using Katapult in existing Rails applications
|
|
61
|
+
### Alternative: Using Katapult in existing Rails applications
|
|
54
62
|
`katapult` expects a clean application (that it would usually generate itself).
|
|
55
63
|
If you have an existing Rails application, you *may* use `katapult`, but be
|
|
56
64
|
warned: it is not designed to respect existing files, although it will usually
|
|
57
|
-
ask before overwriting
|
|
65
|
+
ask before overwriting anything.
|
|
58
66
|
|
|
59
|
-
|
|
60
|
-
`gem 'katapult', group: :development` to the Gemfile. Then run any of the
|
|
61
|
-
following generators:
|
|
67
|
+
After adding it to the Gemfile (see above), run any of the following generators:
|
|
62
68
|
|
|
63
69
|
rails generate katapult:basics # Prepare the app with useful defaults
|
|
64
70
|
rails generate katapult:install # Create application model file
|
|
@@ -72,16 +78,20 @@ following generators:
|
|
|
72
78
|
> install it with `rails generate katapult:install`. See above.
|
|
73
79
|
|
|
74
80
|
After installation, you will find a file `lib/katapult/application_model.rb`
|
|
75
|
-
where you will define the properties of your application.
|
|
81
|
+
where you will define the properties of your application. You're free to create
|
|
82
|
+
more than one application model, however, you'll need to specify their location
|
|
83
|
+
when running the transform.
|
|
76
84
|
|
|
77
|
-
Inside
|
|
78
|
-
express yourself. When you are done developing the
|
|
85
|
+
Inside the application model, use `katapult`'s simple DSL (domain specific
|
|
86
|
+
language) to express yourself. When you are done developing the model, transform
|
|
79
87
|
it into code with:
|
|
80
88
|
|
|
81
|
-
katapult fire
|
|
89
|
+
katapult fire [path/to/application_model]
|
|
82
90
|
|
|
83
91
|
See an overview of the DSL below. The respective sections hold examples of what
|
|
84
|
-
options are available to each element.
|
|
92
|
+
options are available to each element. For details, dive into
|
|
93
|
+
`lib/generators/katapult` where all generators are stored. The method names
|
|
94
|
+
inside a generator tell what it does.
|
|
85
95
|
|
|
86
96
|
### Generic DSL syntax example
|
|
87
97
|
The DSL consists of _elements_, e.g. `Model` or `WUI` (Web User Interface). Each
|
|
@@ -108,6 +118,10 @@ Defined on Model. Takes a name and options:
|
|
|
108
118
|
|
|
109
119
|
# Inferred type :email (when attr name matches /email/)
|
|
110
120
|
model.attr :email
|
|
121
|
+
|
|
122
|
+
# Inferred type :password. Password fields are rendered as password_field in
|
|
123
|
+
# forms, but never rendered in show views.
|
|
124
|
+
model.attr :password
|
|
111
125
|
|
|
112
126
|
# Specify assignable values. Available options: allow_blank, default
|
|
113
127
|
model.attr :age, type: :integer, assignable_values: 18..99, allow_blank: true
|
|
@@ -121,6 +135,10 @@ Defined on Model. Takes a name and options:
|
|
|
121
135
|
# Boolean fields are modeled as flags. Default required!
|
|
122
136
|
model.attr :locked, type: :flag, default: false
|
|
123
137
|
|
|
138
|
+
# JSON fields are supported
|
|
139
|
+
model.attr :prefer, type: :json # PostgreSQL "jsonb"
|
|
140
|
+
model.attr :avoid, type: :plain_json # PostgreSQL "json"
|
|
141
|
+
|
|
124
142
|
|
|
125
143
|
### WUI (Web User Interface)
|
|
126
144
|
Takes a name, options and a block:
|
|
@@ -160,6 +178,16 @@ WUIs.
|
|
|
160
178
|
navigation :main
|
|
161
179
|
|
|
162
180
|
|
|
181
|
+
### Authenticate
|
|
182
|
+
Takes the name of the user model (currently only `User` (case-insensitive) is
|
|
183
|
+
supported) and an email address. Generates authentication with [Clearance](https://github.com/thoughtbot/clearance).
|
|
184
|
+
|
|
185
|
+
authenticate 'User', system_email: 'system@example.com'
|
|
186
|
+
|
|
187
|
+
The email address will be the sender for Clearance mails like password reset
|
|
188
|
+
requests.
|
|
189
|
+
|
|
190
|
+
|
|
163
191
|
## Development
|
|
164
192
|
|
|
165
193
|
### Basic information
|
|
@@ -171,14 +199,12 @@ It caches a pristine Rails application inside its `tmp/` directory to
|
|
|
171
199
|
speed up test runs. Keep this in mind, as it may lead to caching issues when
|
|
172
200
|
switching Ruby versions or installing a new version of the Rails gem.
|
|
173
201
|
|
|
174
|
-
Since `katapult` has full-stack integration tests, it requires a
|
|
175
|
-
Create a dedicated account on your local
|
|
176
|
-
a MySQL console (as-is):
|
|
177
|
-
|
|
178
|
-
GRANT ALL ON *.* TO 'katapult'@'localhost' IDENTIFIED BY 'secret';
|
|
202
|
+
Since `katapult` has full-stack integration tests, it requires a PostgreSQL
|
|
203
|
+
account. Create a dedicated account on your local PostgreSQL server:
|
|
179
204
|
|
|
180
|
-
|
|
181
|
-
|
|
205
|
+
$> sudo -iu postgres
|
|
206
|
+
postgres $> psql
|
|
207
|
+
postgres=# CREATE ROLE katapult WITH createdb LOGIN;
|
|
182
208
|
|
|
183
209
|
### Continuing development
|
|
184
210
|
When you continue development on `katapult`, remove its `tmp/` directory first.
|
data/bin/katapult
CHANGED
|
@@ -4,18 +4,8 @@
|
|
|
4
4
|
# that the user else had to perform manually.
|
|
5
5
|
# See bottom for USAGE.
|
|
6
6
|
|
|
7
|
-
require_relative '../lib/katapult/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def pink_puts(*args)
|
|
11
|
-
message = "\n> #{ args.join ' ' }"
|
|
12
|
-
Kernel.puts "\e[35m#{ message }\e[0m" # pink
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
# With clean Bundler env
|
|
16
|
-
def run(command)
|
|
17
|
-
Bundler.with_clean_env { system command }
|
|
18
|
-
end
|
|
7
|
+
require_relative '../lib/katapult/binary_util'
|
|
8
|
+
util = Katapult::BinaryUtil
|
|
19
9
|
|
|
20
10
|
case (transform_command = ARGV.shift)
|
|
21
11
|
when 'new'
|
|
@@ -24,35 +14,35 @@ when 'new'
|
|
|
24
14
|
basics_command = 'bundle exec rails generate katapult:basics'
|
|
25
15
|
|
|
26
16
|
if interactive
|
|
27
|
-
|
|
17
|
+
util.puts 'Please enter your database user: '
|
|
28
18
|
basics_command << ' --db-user ' << gets.chomp
|
|
29
19
|
|
|
30
|
-
|
|
20
|
+
util.puts 'Please enter your database password: '
|
|
31
21
|
basics_command << ' --db-password ' << gets.chomp
|
|
32
22
|
end
|
|
33
23
|
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
util.puts 'Creating new Rails application ...'
|
|
25
|
+
util.create_rails_app app_name
|
|
36
26
|
|
|
37
27
|
Dir.chdir app_name
|
|
38
28
|
|
|
39
|
-
|
|
40
|
-
run 'git init'
|
|
41
|
-
|
|
29
|
+
util.puts 'Initializing git repository ...'
|
|
30
|
+
util.run 'git init --quiet'
|
|
31
|
+
util.git_commit "rails new #{ app_name }", '--quiet'
|
|
42
32
|
|
|
43
|
-
|
|
33
|
+
util.puts 'Installing katapult ...'
|
|
44
34
|
File.open('Gemfile', 'a') do |file|
|
|
45
35
|
file.puts "gem 'katapult'#{ ENV['KATAPULT_GEMFILE_OPTIONS'] }, group: :development"
|
|
46
36
|
end
|
|
47
|
-
run 'bundle install'
|
|
48
|
-
run 'bundle exec rails generate katapult:install'
|
|
49
|
-
|
|
37
|
+
util.run 'bundle install --quiet'
|
|
38
|
+
util.run 'bundle exec rails generate katapult:install'
|
|
39
|
+
util.git_commit 'rails generate katapult:install', '--quiet'
|
|
50
40
|
|
|
51
|
-
|
|
52
|
-
run basics_command
|
|
53
|
-
|
|
41
|
+
util.puts 'Generating katapult basics ...'
|
|
42
|
+
util.run basics_command
|
|
43
|
+
util.git_commit 'rails generate katapult:basics', '--quiet'
|
|
54
44
|
|
|
55
|
-
|
|
45
|
+
util.puts <<-INSTRUCTIONS
|
|
56
46
|
Application initialization done.
|
|
57
47
|
|
|
58
48
|
Next step: Model your application in lib/katapult/application_model.rb and
|
|
@@ -60,14 +50,14 @@ transform it into code by running `katapult fire`.
|
|
|
60
50
|
INSTRUCTIONS
|
|
61
51
|
|
|
62
52
|
when 'fire'
|
|
63
|
-
app_model_path = 'lib/katapult/application_model.rb'
|
|
53
|
+
app_model_path = ARGV.shift || 'lib/katapult/application_model.rb'
|
|
64
54
|
transform_command = 'bin/rails generate katapult:transform ' + app_model_path
|
|
65
55
|
|
|
66
|
-
|
|
67
|
-
run transform_command
|
|
68
|
-
|
|
56
|
+
util.puts 'Loading katapult ...'
|
|
57
|
+
util.run transform_command
|
|
58
|
+
util.git_commit transform_command
|
|
69
59
|
|
|
70
|
-
|
|
60
|
+
util.puts <<-INSTRUCTIONS
|
|
71
61
|
Model transformation done.
|
|
72
62
|
|
|
73
63
|
Now boot up your development server (e.g. with `rails server`) and try your
|
|
@@ -76,7 +66,7 @@ kickstarted application in the browser!
|
|
|
76
66
|
|
|
77
67
|
else
|
|
78
68
|
puts <<-USAGE
|
|
79
|
-
Usage: katapult [new APP_NAME | fire]
|
|
80
|
-
|
|
69
|
+
Usage: katapult [new APP_NAME | fire [path/to/model] ]
|
|
70
|
+
Suppress database credentials prompt with `--non-interactive`
|
|
81
71
|
USAGE
|
|
82
72
|
end
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
Feature: Add authentication to an application
|
|
2
|
+
|
|
3
|
+
Background:
|
|
4
|
+
Given a pristine Rails application
|
|
5
|
+
And I install katapult
|
|
6
|
+
And I generate katapult basics
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Scenario: Authenticate with the User model
|
|
10
|
+
When I overwrite "lib/katapult/application_model.rb" with:
|
|
11
|
+
"""
|
|
12
|
+
model 'user'
|
|
13
|
+
wui('user') { |w| w.crud }
|
|
14
|
+
authenticate 'user', system_email: 'system@example.com'
|
|
15
|
+
"""
|
|
16
|
+
And I successfully transform the application model
|
|
17
|
+
Then the file "Gemfile" should contain "gem 'clearance'"
|
|
18
|
+
And the file "app/controllers/application_controller.rb" should contain:
|
|
19
|
+
"""
|
|
20
|
+
include Clearance::Controller
|
|
21
|
+
|
|
22
|
+
before_action :require_login
|
|
23
|
+
"""
|
|
24
|
+
And the file "app/controllers/passwords_controller.rb" should contain exactly:
|
|
25
|
+
"""
|
|
26
|
+
class PasswordsController < Clearance::PasswordsController
|
|
27
|
+
|
|
28
|
+
def update
|
|
29
|
+
@user = find_user_for_update
|
|
30
|
+
|
|
31
|
+
if @user.update_password password_reset_params
|
|
32
|
+
sign_in @user
|
|
33
|
+
flash[:notice] = 'Password successfully changed' # <<- added
|
|
34
|
+
redirect_to url_after_update
|
|
35
|
+
else
|
|
36
|
+
flash_failure_after_update
|
|
37
|
+
render template: 'passwords/edit'
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
"""
|
|
43
|
+
And the file "app/controllers/users_controller.rb" should match /permit.*email.*password/
|
|
44
|
+
And the file "app/views/users/_form.html.haml" should contain:
|
|
45
|
+
"""
|
|
46
|
+
%dt
|
|
47
|
+
= form.label :email
|
|
48
|
+
%dd
|
|
49
|
+
= form.email_field :email
|
|
50
|
+
"""
|
|
51
|
+
And the file "app/views/users/_form.html.haml" should contain:
|
|
52
|
+
"""
|
|
53
|
+
%dt
|
|
54
|
+
= form.label :password
|
|
55
|
+
%dd
|
|
56
|
+
= form.password_field :password
|
|
57
|
+
"""
|
|
58
|
+
And the file "app/views/clearance_mailer/change_password.html.haml" should contain exactly:
|
|
59
|
+
"""
|
|
60
|
+
%p
|
|
61
|
+
To reset your password, please follow this link:
|
|
62
|
+
|
|
63
|
+
%p
|
|
64
|
+
= link_to 'Change password',
|
|
65
|
+
edit_user_password_url(@user, token: @user.confirmation_token.html_safe)
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
And the file "app/views/clearance_mailer/change_password.text.erb" should contain exactly:
|
|
69
|
+
"""
|
|
70
|
+
To reset your password, please follow this link:
|
|
71
|
+
|
|
72
|
+
<%= edit_user_password_url(@user, token: @user.confirmation_token.html_safe) %>
|
|
73
|
+
"""
|
|
74
|
+
And the file "app/views/passwords/create.html.haml" should contain exactly:
|
|
75
|
+
"""
|
|
76
|
+
%h1
|
|
77
|
+
Password Reset Instructions Sent
|
|
78
|
+
|
|
79
|
+
%p
|
|
80
|
+
We've sent you an email with instructions on how to reset your password.
|
|
81
|
+
"""
|
|
82
|
+
And the file "app/views/passwords/edit.html.haml" should contain exactly:
|
|
83
|
+
"""
|
|
84
|
+
%h1
|
|
85
|
+
Reset Password
|
|
86
|
+
|
|
87
|
+
%p
|
|
88
|
+
Choose your new password:
|
|
89
|
+
|
|
90
|
+
= form_for :password_reset,
|
|
91
|
+
url: user_password_path(@user, token: @user.confirmation_token),
|
|
92
|
+
html: { method: :put } do |form|
|
|
93
|
+
|
|
94
|
+
.form-group
|
|
95
|
+
= form.label :password
|
|
96
|
+
= form.password_field :password, class: 'form-control',
|
|
97
|
+
placeholder: 'New Password'
|
|
98
|
+
|
|
99
|
+
= form.submit 'Update Password', class: 'btn btn-primary'
|
|
100
|
+
"""
|
|
101
|
+
And the file "app/views/passwords/new.html.haml" should contain exactly:
|
|
102
|
+
"""
|
|
103
|
+
%h1
|
|
104
|
+
Password Reset
|
|
105
|
+
|
|
106
|
+
%p
|
|
107
|
+
Please enter your email address. We will send you instructions on how
|
|
108
|
+
to reset your password.
|
|
109
|
+
|
|
110
|
+
= form_for :password, url: passwords_path do |form|
|
|
111
|
+
.form-group
|
|
112
|
+
= form.label :email
|
|
113
|
+
= form.email_field :email, class: 'form-control',
|
|
114
|
+
placeholder: 'Email Address'
|
|
115
|
+
|
|
116
|
+
= form.submit 'Request Instructions', class: 'btn btn-primary'
|
|
117
|
+
"""
|
|
118
|
+
And the file "app/views/sessions/new.html.haml" should contain exactly:
|
|
119
|
+
"""
|
|
120
|
+
%h1
|
|
121
|
+
Please sign in
|
|
122
|
+
|
|
123
|
+
= form_for :session, url: session_path do |form|
|
|
124
|
+
.form-group
|
|
125
|
+
= form.label :email
|
|
126
|
+
= form.email_field :email, class: 'form-control',
|
|
127
|
+
placeholder: 'Email Address', required: true, autofocus: true
|
|
128
|
+
|
|
129
|
+
.form-group
|
|
130
|
+
= form.label :password
|
|
131
|
+
= form.password_field :password, class: 'form-control', required: true,
|
|
132
|
+
placeholder: 'Password'
|
|
133
|
+
|
|
134
|
+
%p
|
|
135
|
+
= form.submit 'Sign in', class: 'btn btn-primary'
|
|
136
|
+
|
|
137
|
+
%p
|
|
138
|
+
= link_to 'Forgot password', new_password_path, class: 'text-muted'
|
|
139
|
+
"""
|
|
140
|
+
And the file "config/environments/test.rb" should contain:
|
|
141
|
+
"""
|
|
142
|
+
# Enable quick-signin in tests: `visit homepage(as: User.last!)`
|
|
143
|
+
config.middleware.use Clearance::BackDoor
|
|
144
|
+
|
|
145
|
+
"""
|
|
146
|
+
And the file "config/initializers/clearance.rb" should contain exactly:
|
|
147
|
+
"""
|
|
148
|
+
Clearance.configure do |config|
|
|
149
|
+
config.allow_sign_up = false
|
|
150
|
+
# config.cookie_domain = '.example.com'
|
|
151
|
+
# config.cookie_expiration = lambda { |cookies| 1.year.from_now.utc }
|
|
152
|
+
# config.cookie_name = 'remember_token'
|
|
153
|
+
# config.cookie_path = '/'
|
|
154
|
+
config.routes = false
|
|
155
|
+
# config.httponly = true
|
|
156
|
+
config.mailer_sender = 'system@example.com'
|
|
157
|
+
# config.password_strategy = Clearance::PasswordStrategies::BCrypt
|
|
158
|
+
# config.redirect_url = '/'
|
|
159
|
+
# config.secure_cookie = true
|
|
160
|
+
# config.sign_in_guards = []
|
|
161
|
+
# config.user_model = User
|
|
162
|
+
end
|
|
163
|
+
"""
|
|
164
|
+
And a file named "config/locales/clearance.en.yml" should exist
|
|
165
|
+
And the file "config/routes.rb" should contain:
|
|
166
|
+
"""
|
|
167
|
+
resources :users do
|
|
168
|
+
resource :password, controller: 'passwords',
|
|
169
|
+
only: %i[edit update]
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Clearance
|
|
173
|
+
get '/login', to: 'clearance/sessions#new', as: 'sign_in'
|
|
174
|
+
resource :session, controller: 'clearance/sessions', only: [:create]
|
|
175
|
+
resources :passwords, controller: 'passwords', only: [:create, :new]
|
|
176
|
+
delete '/logout', to: 'clearance/sessions#destroy', as: 'sign_out'
|
|
177
|
+
"""
|
|
178
|
+
And there should be a migration with:
|
|
179
|
+
"""
|
|
180
|
+
class AddClearanceToUsers < ActiveRecord::Migration
|
|
181
|
+
def self.up
|
|
182
|
+
change_table :users do |t|
|
|
183
|
+
t.string :encrypted_password, limit: 128
|
|
184
|
+
t.string :confirmation_token, limit: 128
|
|
185
|
+
t.string :remember_token, limit: 128
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
add_index :users, :email
|
|
189
|
+
add_index :users, :remember_token
|
|
190
|
+
|
|
191
|
+
users = select_all("SELECT id FROM users WHERE remember_token IS NULL")
|
|
192
|
+
|
|
193
|
+
users.each do |user|
|
|
194
|
+
update <<-SQL
|
|
195
|
+
UPDATE users
|
|
196
|
+
SET remember_token = '#{Clearance::Token.new}'
|
|
197
|
+
WHERE id = '#{user['id']}'
|
|
198
|
+
SQL
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def self.down
|
|
203
|
+
change_table :users do |t|
|
|
204
|
+
t.remove :encrypted_password, :confirmation_token, :remember_token
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
"""
|
|
209
|
+
And the file "features/authentication.feature" should contain exactly:
|
|
210
|
+
"""
|
|
211
|
+
Feature: Everything about user authentication
|
|
212
|
+
|
|
213
|
+
Scenario: Login is required to visit the homepage
|
|
214
|
+
When I go to the homepage
|
|
215
|
+
Then I should see "Please sign in to continue" within the flash
|
|
216
|
+
And I should be on the sign-in form
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
Scenario: Login
|
|
220
|
+
Given there is a user with the email "henry@example.com" and the password "password"
|
|
221
|
+
|
|
222
|
+
When I go to the homepage
|
|
223
|
+
Then I should be on the sign-in form
|
|
224
|
+
And I should see "Please sign in"
|
|
225
|
+
|
|
226
|
+
# Wrong email
|
|
227
|
+
When I fill in "Email" with "nonsense"
|
|
228
|
+
And I fill in "Password" with "password"
|
|
229
|
+
And I press "Sign in"
|
|
230
|
+
Then I should see "Bad email or password" within the flash
|
|
231
|
+
And I should see "Please sign in"
|
|
232
|
+
|
|
233
|
+
# Wrong password
|
|
234
|
+
When I fill in "Email" with "admin@example.com"
|
|
235
|
+
And I fill in "Password" with "wrong"
|
|
236
|
+
And I press "Sign in"
|
|
237
|
+
Then I should see "Bad email or password" within the flash
|
|
238
|
+
And I should see "Please sign in"
|
|
239
|
+
|
|
240
|
+
# Correct credentials
|
|
241
|
+
When I fill in "Email" with "henry@example.com"
|
|
242
|
+
And I fill in "Password" with "password"
|
|
243
|
+
And I press "Sign in"
|
|
244
|
+
Then I should be on the homepage
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
Scenario: Logout
|
|
248
|
+
Given there is a user
|
|
249
|
+
And I am signed in as the user above
|
|
250
|
+
|
|
251
|
+
When I follow "Sign out"
|
|
252
|
+
Then I should be on the sign-in form
|
|
253
|
+
|
|
254
|
+
# Logged out
|
|
255
|
+
When I go to the homepage
|
|
256
|
+
Then I should be on the sign-in form
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
Scenario: Reset password as a signed-in user
|
|
260
|
+
Given there is a user with the email "henry@example.com"
|
|
261
|
+
And I sign in as the user above
|
|
262
|
+
|
|
263
|
+
When I go to the homepage
|
|
264
|
+
And I follow "henry@example.com" within the current user
|
|
265
|
+
Then I should be on the form for the user above
|
|
266
|
+
|
|
267
|
+
When I fill in "Password" with "new-password"
|
|
268
|
+
And I press "Save"
|
|
269
|
+
Then I should be on the page for the user above
|
|
270
|
+
|
|
271
|
+
When I follow "Sign out"
|
|
272
|
+
And I fill in "Email" with "henry@example.com"
|
|
273
|
+
And I fill in "Password" with "new-password"
|
|
274
|
+
And I press "Sign in"
|
|
275
|
+
Then I should be on the homepage
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
Scenario: Reset password as a signed-out user
|
|
279
|
+
Given there is a user with the email "henry@example.com"
|
|
280
|
+
|
|
281
|
+
When I go to the sign-in form
|
|
282
|
+
And I follow "Forgot password"
|
|
283
|
+
Then I should be on the reset password page
|
|
284
|
+
And I should see "Password Reset"
|
|
285
|
+
|
|
286
|
+
When I fill in "Email" with "henry@example.com"
|
|
287
|
+
And I press "Request Instructions"
|
|
288
|
+
Then an email should have been sent with:
|
|
289
|
+
\"\"\"
|
|
290
|
+
From: system@example.com
|
|
291
|
+
To: henry@example.com
|
|
292
|
+
Subject: Change your password
|
|
293
|
+
|
|
294
|
+
To reset your password, please follow this link:
|
|
295
|
+
\"\"\"
|
|
296
|
+
|
|
297
|
+
When I follow the first link in the email
|
|
298
|
+
Then I should be on the new password page for the user above
|
|
299
|
+
And I should see "Reset Password"
|
|
300
|
+
|
|
301
|
+
When I fill in "Choose password" with "new-password"
|
|
302
|
+
And I press "Update Password"
|
|
303
|
+
Then I should see "Password successfully changed" within the flash
|
|
304
|
+
And I should be on the homepage
|
|
305
|
+
"""
|
|
306
|
+
And the file "features/users.feature" should contain:
|
|
307
|
+
"""
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
Background:
|
|
311
|
+
Given there is a user
|
|
312
|
+
And I sign in as the user above
|
|
313
|
+
|
|
314
|
+
"""
|
|
315
|
+
And the file "features/step_definitions/authentication_steps.rb" should contain exactly:
|
|
316
|
+
"""
|
|
317
|
+
When /^I (?:am signed|sign) in as the user above$/ do
|
|
318
|
+
user = User.last!
|
|
319
|
+
visit root_path(as: user) # Using Clearance::BackDoor
|
|
320
|
+
end
|
|
321
|
+
"""
|
|
322
|
+
And the file "features/support/paths.rb" should contain:
|
|
323
|
+
"""
|
|
324
|
+
|
|
325
|
+
# Authentication
|
|
326
|
+
when 'the sign-in form'
|
|
327
|
+
sign_in_path
|
|
328
|
+
when 'the reset password page'
|
|
329
|
+
new_password_path
|
|
330
|
+
when 'the new password page for the user above'
|
|
331
|
+
edit_user_password_path(User.last!)
|
|
332
|
+
|
|
333
|
+
"""
|
|
334
|
+
And the file "spec/factories/factories.rb" should contain:
|
|
335
|
+
"""
|
|
336
|
+
factory :user do
|
|
337
|
+
sequence(:email) { |i| "user-#{ i }@example.com" }
|
|
338
|
+
password 'password'
|
|
339
|
+
end
|
|
340
|
+
"""
|
|
341
|
+
|
|
342
|
+
When I run cucumber
|
|
343
|
+
Then the features should pass
|
|
344
|
+
|