katapult 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,15 @@
|
|
1
|
+
module Enumerable
|
2
|
+
|
3
|
+
def natural_sort
|
4
|
+
natural_sort_by
|
5
|
+
end
|
6
|
+
|
7
|
+
def natural_sort_by(&stringifier)
|
8
|
+
sort_by do |element|
|
9
|
+
element = stringifier.call(element) if stringifier
|
10
|
+
element = element.to_s unless element.respond_to?(:to_sort_atoms)
|
11
|
+
element.to_sort_atoms
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class SmartSortAtom
|
2
|
+
|
3
|
+
attr_reader :value
|
4
|
+
|
5
|
+
def initialize(value)
|
6
|
+
@value = value
|
7
|
+
end
|
8
|
+
|
9
|
+
def <=>(other)
|
10
|
+
other.is_a?(self.class) or raise "Can only smart compare with other SmartSortAtom"
|
11
|
+
left_value = value
|
12
|
+
right_value = other.value
|
13
|
+
if left_value.class == right_value.class
|
14
|
+
left_value <=> right_value
|
15
|
+
elsif left_value.is_a?(Float)
|
16
|
+
-1
|
17
|
+
else
|
18
|
+
1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.parse(string)
|
23
|
+
# Loosely based on http://stackoverflow.com/a/4079031
|
24
|
+
string.scan(/[^\d\.]+|[\d\.]+/).collect do |atom|
|
25
|
+
if atom.match(/\d+(\.\d+)?/)
|
26
|
+
atom = atom.to_f
|
27
|
+
else
|
28
|
+
atom = normalize_string(atom)
|
29
|
+
end
|
30
|
+
new(atom)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def self.normalize_string(string)
|
38
|
+
string = ActiveSupport::Inflector.transliterate(string)
|
39
|
+
string = string.downcase
|
40
|
+
string
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
String.class_eval do
|
46
|
+
|
47
|
+
def to_sort_atoms
|
48
|
+
SmartSortAtom.parse(self)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
namespace :db do
|
2
|
+
|
3
|
+
desc 'Warns if there are pending migrations'
|
4
|
+
task :warn_if_pending_migrations => :environment do
|
5
|
+
if defined? ActiveRecord
|
6
|
+
all_migrations = ActiveRecord::Migrator.migrations('db/migrate')
|
7
|
+
pending_migrations = ActiveRecord::Migrator.new(:up, all_migrations).pending_migrations
|
8
|
+
|
9
|
+
if pending_migrations.any?
|
10
|
+
puts ''
|
11
|
+
puts '======================================================='
|
12
|
+
puts "You have #{ pending_migrations.size } pending migrations:"
|
13
|
+
pending_migrations.each do |pending_migration|
|
14
|
+
puts ' %4d %s' % [pending_migration.version, pending_migration.name]
|
15
|
+
end
|
16
|
+
puts 'Run cap <stage> deploy:migrations'
|
17
|
+
puts '======================================================='
|
18
|
+
puts ''
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# Generate authentication with Clearance
|
2
|
+
|
3
|
+
require 'katapult/generator'
|
4
|
+
|
5
|
+
module Katapult
|
6
|
+
module Generators
|
7
|
+
class ClearanceGenerator < Katapult::Generator
|
8
|
+
|
9
|
+
desc 'Generate authentication with Clearance'
|
10
|
+
|
11
|
+
check_class_collision
|
12
|
+
source_root File.expand_path('../templates', __FILE__)
|
13
|
+
|
14
|
+
|
15
|
+
def migrate
|
16
|
+
rake 'db:migrate' # Clearance must see the users table in the db
|
17
|
+
end
|
18
|
+
|
19
|
+
def install_clearance
|
20
|
+
insert_into_file 'Gemfile', <<-GEM, before: "gem 'katapult'"
|
21
|
+
gem 'clearance', '< 1.14.0' # Has broken InstallGenerator :(
|
22
|
+
|
23
|
+
GEM
|
24
|
+
run 'bundle install --quiet'
|
25
|
+
generate 'clearance:install'
|
26
|
+
end
|
27
|
+
|
28
|
+
def require_login
|
29
|
+
file = 'app/controllers/application_controller.rb'
|
30
|
+
insert_into_file file, <<-CONTENT, after: "Clearance::Controller\n"
|
31
|
+
|
32
|
+
before_action :require_login
|
33
|
+
CONTENT
|
34
|
+
end
|
35
|
+
|
36
|
+
def overwrite_clearance_controllers
|
37
|
+
template 'app/controllers/passwords_controller.rb'
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_clearance_views
|
41
|
+
directory 'app/views/clearance_mailer'
|
42
|
+
directory 'app/views/passwords'
|
43
|
+
directory 'app/views/sessions'
|
44
|
+
end
|
45
|
+
|
46
|
+
def install_backdoor
|
47
|
+
# This creepy indentation leads to correct formatting in the file
|
48
|
+
application <<-CONTENT, env: 'test'
|
49
|
+
# Enable quick-signin in tests: `visit homepage(as: User.last!)`
|
50
|
+
config.middleware.use Clearance::BackDoor
|
51
|
+
CONTENT
|
52
|
+
end
|
53
|
+
|
54
|
+
def create_initializer
|
55
|
+
template 'config/initializers/clearance.rb', force: true
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_translations
|
59
|
+
template 'config/locales/clearance.en.yml'
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_routes
|
63
|
+
route <<-ROUTES
|
64
|
+
resources :users do
|
65
|
+
resource :password, controller: 'passwords',
|
66
|
+
only: %i[edit update]
|
67
|
+
end
|
68
|
+
|
69
|
+
# Clearance
|
70
|
+
get '/login', to: 'clearance/sessions#new', as: 'sign_in'
|
71
|
+
resource :session, controller: 'clearance/sessions', only: [:create]
|
72
|
+
resources :passwords, controller: 'passwords', only: [:create, :new]
|
73
|
+
delete '/logout', to: 'clearance/sessions#destroy', as: 'sign_out'
|
74
|
+
ROUTES
|
75
|
+
end
|
76
|
+
|
77
|
+
def add_sign_in_background_to_all_features
|
78
|
+
Dir['features/*.feature'].each do |file|
|
79
|
+
inject_into_file file, <<-CONTENT, after: /^Feature: .*$/
|
80
|
+
|
81
|
+
|
82
|
+
Background:
|
83
|
+
Given there is a user
|
84
|
+
And I sign in as the user above
|
85
|
+
CONTENT
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def create_authentication_feature
|
90
|
+
template 'features/authentication.feature'
|
91
|
+
end
|
92
|
+
|
93
|
+
def create_authentication_steps
|
94
|
+
template 'features/step_definitions/authentication_steps.rb'
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_authentication_paths
|
98
|
+
inject_into_file 'features/support/paths.rb', <<-CONTENT, after: 'case page_name'
|
99
|
+
|
100
|
+
|
101
|
+
# Authentication
|
102
|
+
when 'the sign-in form'
|
103
|
+
sign_in_path
|
104
|
+
when 'the reset password page'
|
105
|
+
new_password_path
|
106
|
+
when 'the new password page for the user above'
|
107
|
+
edit_user_password_path(User.last!)
|
108
|
+
|
109
|
+
CONTENT
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_user_factory
|
113
|
+
inject_into_file 'spec/factories/factories.rb', <<-'CONTENT', after: 'FactoryGirl.define do'
|
114
|
+
|
115
|
+
factory :user do
|
116
|
+
sequence(:email) { |i| "user-#{ i }@example.com" }
|
117
|
+
password 'password'
|
118
|
+
end
|
119
|
+
|
120
|
+
CONTENT
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class PasswordsController < Clearance::PasswordsController
|
2
|
+
|
3
|
+
def update
|
4
|
+
@user = find_user_for_update
|
5
|
+
|
6
|
+
if @user.update_password password_reset_params
|
7
|
+
sign_in @user
|
8
|
+
flash[:notice] = 'Password successfully changed' # <<- added
|
9
|
+
redirect_to url_after_update
|
10
|
+
else
|
11
|
+
flash_failure_after_update
|
12
|
+
render template: 'passwords/edit'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
%h1
|
2
|
+
Reset Password
|
3
|
+
|
4
|
+
%p
|
5
|
+
Choose your new password:
|
6
|
+
|
7
|
+
= form_for :password_reset,
|
8
|
+
url: user_password_path(@user, token: @user.confirmation_token),
|
9
|
+
html: { method: :put } do |form|
|
10
|
+
|
11
|
+
.form-group
|
12
|
+
= form.label :password
|
13
|
+
= form.password_field :password, class: 'form-control',
|
14
|
+
placeholder: 'New Password'
|
15
|
+
|
16
|
+
= form.submit 'Update Password', class: 'btn btn-primary'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
%h1
|
2
|
+
Password Reset
|
3
|
+
|
4
|
+
%p
|
5
|
+
Please enter your email address. We will send you instructions on how
|
6
|
+
to reset your password.
|
7
|
+
|
8
|
+
= form_for :password, url: passwords_path do |form|
|
9
|
+
.form-group
|
10
|
+
= form.label :email
|
11
|
+
= form.email_field :email, class: 'form-control',
|
12
|
+
placeholder: 'Email Address'
|
13
|
+
|
14
|
+
= form.submit 'Request Instructions', class: 'btn btn-primary'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
%h1
|
2
|
+
Please sign in
|
3
|
+
|
4
|
+
= form_for :session, url: session_path do |form|
|
5
|
+
.form-group
|
6
|
+
= form.label :email
|
7
|
+
= form.email_field :email, class: 'form-control',
|
8
|
+
placeholder: 'Email Address', required: true, autofocus: true
|
9
|
+
|
10
|
+
.form-group
|
11
|
+
= form.label :password
|
12
|
+
= form.password_field :password, class: 'form-control', required: true,
|
13
|
+
placeholder: 'Password'
|
14
|
+
|
15
|
+
%p
|
16
|
+
= form.submit 'Sign in', class: 'btn btn-primary'
|
17
|
+
|
18
|
+
%p
|
19
|
+
= link_to 'Forgot password', new_password_path, class: 'text-muted'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Clearance.configure do |config|
|
2
|
+
config.allow_sign_up = false
|
3
|
+
# config.cookie_domain = '.example.com'
|
4
|
+
# config.cookie_expiration = lambda { |cookies| 1.year.from_now.utc }
|
5
|
+
# config.cookie_name = 'remember_token'
|
6
|
+
# config.cookie_path = '/'
|
7
|
+
config.routes = false
|
8
|
+
# config.httponly = true
|
9
|
+
config.mailer_sender = 'system@example.com'
|
10
|
+
# config.password_strategy = Clearance::PasswordStrategies::BCrypt
|
11
|
+
# config.redirect_url = '/'
|
12
|
+
# config.secure_cookie = true
|
13
|
+
# config.sign_in_guards = []
|
14
|
+
# config.user_model = User
|
15
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
---
|
2
|
+
en:
|
3
|
+
clearance:
|
4
|
+
models:
|
5
|
+
clearance_mailer:
|
6
|
+
change_password: Change your password
|
7
|
+
clearance_mailer:
|
8
|
+
change_password:
|
9
|
+
closing: If you didn't request this, ignore this email. Your password has
|
10
|
+
not been changed.
|
11
|
+
link_text: Change my password
|
12
|
+
opening: "Someone, hopefully you, requested we send you a link to change
|
13
|
+
your password:"
|
14
|
+
flashes:
|
15
|
+
failure_after_create: Bad email or password.
|
16
|
+
failure_after_update: Password can't be blank.
|
17
|
+
failure_when_forbidden: Please double check the URL or try submitting
|
18
|
+
the form again.
|
19
|
+
failure_when_not_signed_in: Please sign in to continue.
|
20
|
+
helpers:
|
21
|
+
label:
|
22
|
+
password:
|
23
|
+
email: Email address
|
24
|
+
password_reset:
|
25
|
+
password: Choose password
|
26
|
+
submit:
|
27
|
+
password:
|
28
|
+
submit: Reset password
|
29
|
+
password_reset:
|
30
|
+
submit: Save this password
|
31
|
+
session:
|
32
|
+
submit: Sign in
|
33
|
+
user:
|
34
|
+
create: Sign up
|
35
|
+
layouts:
|
36
|
+
application:
|
37
|
+
sign_in: Sign in
|
38
|
+
sign_out: Sign out
|
39
|
+
passwords:
|
40
|
+
create:
|
41
|
+
description: You will receive an email within the next few minutes. It
|
42
|
+
contains instructions for changing your password.
|
43
|
+
edit:
|
44
|
+
description: Your password has been reset. Choose a new password below.
|
45
|
+
title: Change your password
|
46
|
+
new:
|
47
|
+
description: To be emailed a link to reset your password, please enter
|
48
|
+
your email address.
|
49
|
+
title: Reset your password
|
50
|
+
sessions:
|
51
|
+
form:
|
52
|
+
forgot_password: Forgot password?
|
53
|
+
sign_up: Sign up
|
54
|
+
new:
|
55
|
+
title: Sign in
|
56
|
+
users:
|
57
|
+
new:
|
58
|
+
sign_in: Sign in
|
59
|
+
title: Sign up
|
@@ -0,0 +1,94 @@
|
|
1
|
+
Feature: Everything about user authentication
|
2
|
+
|
3
|
+
Scenario: Login is required to visit the homepage
|
4
|
+
When I go to the homepage
|
5
|
+
Then I should see "Please sign in to continue" within the flash
|
6
|
+
And I should be on the sign-in form
|
7
|
+
|
8
|
+
|
9
|
+
Scenario: Login
|
10
|
+
Given there is a user with the email "henry@example.com" and the password "password"
|
11
|
+
|
12
|
+
When I go to the homepage
|
13
|
+
Then I should be on the sign-in form
|
14
|
+
And I should see "Please sign in"
|
15
|
+
|
16
|
+
# Wrong email
|
17
|
+
When I fill in "Email" with "nonsense"
|
18
|
+
And I fill in "Password" with "password"
|
19
|
+
And I press "Sign in"
|
20
|
+
Then I should see "Bad email or password" within the flash
|
21
|
+
And I should see "Please sign in"
|
22
|
+
|
23
|
+
# Wrong password
|
24
|
+
When I fill in "Email" with "admin@example.com"
|
25
|
+
And I fill in "Password" with "wrong"
|
26
|
+
And I press "Sign in"
|
27
|
+
Then I should see "Bad email or password" within the flash
|
28
|
+
And I should see "Please sign in"
|
29
|
+
|
30
|
+
# Correct credentials
|
31
|
+
When I fill in "Email" with "henry@example.com"
|
32
|
+
And I fill in "Password" with "password"
|
33
|
+
And I press "Sign in"
|
34
|
+
Then I should be on the homepage
|
35
|
+
|
36
|
+
|
37
|
+
Scenario: Logout
|
38
|
+
Given there is a user
|
39
|
+
And I am signed in as the user above
|
40
|
+
|
41
|
+
When I follow "Sign out"
|
42
|
+
Then I should be on the sign-in form
|
43
|
+
|
44
|
+
# Logged out
|
45
|
+
When I go to the homepage
|
46
|
+
Then I should be on the sign-in form
|
47
|
+
|
48
|
+
|
49
|
+
Scenario: Reset password as a signed-in user
|
50
|
+
Given there is a user with the email "henry@example.com"
|
51
|
+
And I sign in as the user above
|
52
|
+
|
53
|
+
When I go to the homepage
|
54
|
+
And I follow "henry@example.com" within the current user
|
55
|
+
Then I should be on the form for the user above
|
56
|
+
|
57
|
+
When I fill in "Password" with "new-password"
|
58
|
+
And I press "Save"
|
59
|
+
Then I should be on the page for the user above
|
60
|
+
|
61
|
+
When I follow "Sign out"
|
62
|
+
And I fill in "Email" with "henry@example.com"
|
63
|
+
And I fill in "Password" with "new-password"
|
64
|
+
And I press "Sign in"
|
65
|
+
Then I should be on the homepage
|
66
|
+
|
67
|
+
|
68
|
+
Scenario: Reset password as a signed-out user
|
69
|
+
Given there is a user with the email "henry@example.com"
|
70
|
+
|
71
|
+
When I go to the sign-in form
|
72
|
+
And I follow "Forgot password"
|
73
|
+
Then I should be on the reset password page
|
74
|
+
And I should see "Password Reset"
|
75
|
+
|
76
|
+
When I fill in "Email" with "henry@example.com"
|
77
|
+
And I press "Request Instructions"
|
78
|
+
Then an email should have been sent with:
|
79
|
+
"""
|
80
|
+
From: system@example.com
|
81
|
+
To: henry@example.com
|
82
|
+
Subject: Change your password
|
83
|
+
|
84
|
+
To reset your password, please follow this link:
|
85
|
+
"""
|
86
|
+
|
87
|
+
When I follow the first link in the email
|
88
|
+
Then I should be on the new password page for the user above
|
89
|
+
And I should see "Reset Password"
|
90
|
+
|
91
|
+
When I fill in "Choose password" with "new-password"
|
92
|
+
And I press "Update Password"
|
93
|
+
Then I should see "Password successfully changed" within the flash
|
94
|
+
And I should be on the homepage
|
@@ -4,16 +4,18 @@ Feature: <%= model.name(:humans).titleize %>
|
|
4
4
|
Given I am on the list of <%= model.name(:variables) %>
|
5
5
|
|
6
6
|
# create
|
7
|
-
When I follow "Add <%= model.name(:
|
7
|
+
When I follow "Add <%= model.name(:human) %>"
|
8
8
|
<% model.attrs.each do |attr| -%>
|
9
9
|
<%- if attr.assignable_values -%>
|
10
10
|
And I select "<%= attr.test_value %>" from "<%= attr.name.humanize %>"
|
11
11
|
<%- else -%>
|
12
12
|
<%- case attr.type -%>
|
13
|
-
<%- when :string, :email, :url, :integer, :money, :text, :
|
13
|
+
<%- when :string, :email, :url, :integer, :money, :text, :password -%>
|
14
14
|
And I fill in "<%= attr.name.humanize %>" with "<%= attr.test_value %>"
|
15
15
|
<%- when :flag -%>
|
16
16
|
And I check "<%= attr.name.humanize %>"
|
17
|
+
<%- when :datetime -%>
|
18
|
+
And I fill in "<%= attr.name.humanize %>" with "<%= attr.test_value.to_date %>"
|
17
19
|
<%- end -%>
|
18
20
|
<%- end -%>
|
19
21
|
<% end -%>
|
@@ -23,12 +25,12 @@ Feature: <%= model.name(:humans).titleize %>
|
|
23
25
|
Then I should be on the page for the <%= model.name(:variable) %> above
|
24
26
|
<% model.attrs.each do |attr| -%>
|
25
27
|
<%- case attr.type -%>
|
26
|
-
<%- when :string, :email, :url, :integer, :money, :text
|
28
|
+
<%- when :string, :email, :url, :integer, :money, :text -%>
|
27
29
|
And I should see "<%= attr.test_value %>"
|
28
30
|
<%- when :flag -%>
|
29
31
|
And I should see "<%= attr.name.humanize %> Yes"
|
30
32
|
<%- when :datetime -%>
|
31
|
-
And I should see "<%= I18n.localize(attr.test_value) %>"
|
33
|
+
And I should see "<%= I18n.localize(attr.test_value.to_date) %>"
|
32
34
|
<%- end -%>
|
33
35
|
<% end -%>
|
34
36
|
|
@@ -40,20 +42,22 @@ Feature: <%= model.name(:humans).titleize %>
|
|
40
42
|
And "<%= attr.test_value %>" should be selected for "<%= attr.name.humanize %>"
|
41
43
|
<%- else -%>
|
42
44
|
<%- case attr.type -%>
|
43
|
-
<%- when :string, :email, :url, :integer, :money, :text
|
45
|
+
<%- when :string, :email, :url, :integer, :money, :text -%>
|
44
46
|
And the "<%= attr.name.humanize %>" field should contain "<%= attr.test_value %>"
|
45
47
|
<%- when :flag -%>
|
46
48
|
And the "<%= attr.name.humanize %>" checkbox should be checked
|
49
|
+
<%- when :datetime -%>
|
50
|
+
And the "<%= attr.name.humanize %>" field should contain "<%= attr.test_value.to_date %>"
|
47
51
|
<%- end -%>
|
48
52
|
<%- end -%>
|
49
53
|
<% end -%>
|
50
54
|
|
51
|
-
<% if model.label_attr
|
55
|
+
<% if model.label_attr -%>
|
52
56
|
# destroy
|
53
57
|
When I go to the list of <%= model.name(:variables) %>
|
54
58
|
Then I should see "<%= model.label_attr.test_value %>"
|
55
59
|
|
56
|
-
When I follow "Destroy"
|
60
|
+
When I follow "Destroy <%= model.label_attr.test_value %>"
|
57
61
|
Then I should be on the list of <%= model.name(:variables) %>
|
58
62
|
But I should not see "<%= model.label_attr.test_value %>"
|
59
63
|
<% end -%>
|
@@ -14,6 +14,7 @@ module Katapult
|
|
14
14
|
def install_application_layout
|
15
15
|
remove_file 'app/views/layouts/application.html.erb'
|
16
16
|
template 'app/views/layouts/application.html.haml'
|
17
|
+
template 'app/views/layouts/_flashes.html.haml'
|
17
18
|
end
|
18
19
|
|
19
20
|
def create_views_directory
|
@@ -63,6 +64,10 @@ module Katapult
|
|
63
64
|
def navigation
|
64
65
|
wui.application_model.navigation
|
65
66
|
end
|
67
|
+
|
68
|
+
def authentication
|
69
|
+
wui.application_model.authentication
|
70
|
+
end
|
66
71
|
end
|
67
72
|
|
68
73
|
private
|
@@ -1,7 +1,7 @@
|
|
1
1
|
= form_for <%= model_name(:ivar) %> do |form|
|
2
2
|
|
3
3
|
%dl.controls
|
4
|
-
<% wui.model.
|
4
|
+
<% wui.model.editable_attrs.each do |attribute| -%>
|
5
5
|
%dt
|
6
6
|
= form.label <%= attribute.name(:symbol) %>
|
7
7
|
%dd
|
@@ -13,6 +13,8 @@
|
|
13
13
|
= form.text_field <%= attribute.name(:symbol) %>
|
14
14
|
<%- when :email -%>
|
15
15
|
= form.email_field <%= attribute.name(:symbol) %>
|
16
|
+
<%- when :password -%>
|
17
|
+
= form.password_field <%= attribute.name(:symbol) %>
|
16
18
|
<%- when :url -%>
|
17
19
|
= form.url_field <%= attribute.name(:symbol) %>
|
18
20
|
<%- when :integer -%>
|
@@ -22,12 +24,10 @@
|
|
22
24
|
€
|
23
25
|
<%- when :text -%>
|
24
26
|
= form.text_area <%= attribute.name(:symbol) %>, rows: 5
|
25
|
-
<%- when :markdown -%>
|
26
|
-
= form.text_area <%= attribute.name(:symbol) %>, rows: 15
|
27
27
|
<%- when :flag -%>
|
28
28
|
= form.check_box <%= attribute.name(:symbol) %>
|
29
29
|
<%- when :datetime -%>
|
30
|
-
= form.
|
30
|
+
= form.date_field <%= attribute.name(:symbol) %>
|
31
31
|
<%- end -%>
|
32
32
|
<%- end -%>
|
33
33
|
<% end -%>
|
@@ -15,12 +15,18 @@
|
|
15
15
|
|
16
16
|
.layout__head
|
17
17
|
%h2 <%= app_name.titlecase %>
|
18
|
-
|
18
|
+
<%- if navigation -%>
|
19
19
|
= render_navigation Navigation.<%= navigation.name(:variable) %>
|
20
|
-
|
20
|
+
<%- end -%>
|
21
|
+
<%- if authentication -%>
|
22
|
+
- if signed_in?
|
23
|
+
.current-user
|
24
|
+
= link_to current_user.email, edit_user_path(current_user)
|
25
|
+
= link_to 'Sign out', sign_out_path, method: :delete
|
26
|
+
<%- end -%>
|
21
27
|
|
22
28
|
.layout__main
|
23
|
-
|
29
|
+
= render 'layouts/flashes'
|
24
30
|
= yield
|
25
31
|
|
26
32
|
.layout__tail
|