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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -1
  4. data/README.md +61 -35
  5. data/bin/katapult +24 -34
  6. data/features/authenticate.feature +344 -0
  7. data/features/basics.feature +590 -0
  8. data/features/binary.feature +33 -1
  9. data/features/model.feature +9 -13
  10. data/features/step_definitions/rails_steps.rb +3 -2
  11. data/features/wui.feature +49 -4
  12. data/lib/generators/katapult/basics/basics_generator.rb +63 -17
  13. data/lib/generators/katapult/basics/templates/.gitignore +1 -0
  14. data/lib/generators/katapult/basics/templates/.ruby-version +1 -1
  15. data/lib/generators/katapult/basics/templates/Capfile +25 -0
  16. data/lib/generators/katapult/basics/templates/Gemfile +14 -6
  17. data/lib/generators/katapult/basics/templates/Guardfile +44 -0
  18. data/lib/generators/katapult/basics/templates/config/database.sample.yml +3 -2
  19. data/lib/generators/katapult/basics/templates/config/database.yml +3 -2
  20. data/lib/generators/katapult/basics/templates/config/deploy/production.rb +8 -0
  21. data/lib/generators/katapult/basics/templates/config/deploy/staging.rb +7 -0
  22. data/lib/generators/katapult/basics/templates/config/deploy.rb +37 -0
  23. data/lib/generators/katapult/basics/templates/config/initializers/ext.rb +3 -0
  24. data/lib/generators/katapult/basics/templates/features/support/factory_girl.rb +1 -0
  25. data/lib/generators/katapult/basics/templates/features/support/paths.rb +6 -0
  26. data/lib/generators/katapult/basics/templates/lib/capistrano/tasks/db.rake +28 -0
  27. data/lib/generators/katapult/basics/templates/lib/capistrano/tasks/deploy.rake +15 -0
  28. data/lib/generators/katapult/basics/templates/lib/capistrano/tasks/passenger.rake +8 -0
  29. data/lib/generators/katapult/basics/templates/{config/initializers → lib/ext/action_view}/form_for_with_development_errors.rb +0 -2
  30. data/lib/generators/katapult/basics/templates/lib/ext/action_view/spec_label.rb +46 -0
  31. data/lib/generators/katapult/basics/templates/{config/initializers → lib/ext/active_record}/find_by_anything.rb +0 -0
  32. data/lib/generators/katapult/basics/templates/lib/ext/active_record/these.rb +7 -0
  33. data/lib/generators/katapult/basics/templates/lib/ext/array/xss_aware_join.rb +10 -0
  34. data/lib/generators/katapult/basics/templates/lib/ext/enumerable/natural_sort.rb +15 -0
  35. data/lib/generators/katapult/basics/templates/lib/ext/hash/infinite.rb +7 -0
  36. data/lib/generators/katapult/basics/templates/lib/ext/string/html_entities.rb +11 -0
  37. data/lib/generators/katapult/basics/templates/lib/ext/string/to_sort_atoms.rb +52 -0
  38. data/lib/generators/katapult/basics/templates/lib/tasks/pending_migrations.rake +24 -0
  39. data/lib/generators/katapult/basics/templates/spec/factories/factories.rb +9 -0
  40. data/lib/generators/katapult/basics/templates/spec/support/factory_girl.rb +3 -0
  41. data/lib/generators/katapult/clearance/clearance_generator.rb +125 -0
  42. data/lib/generators/katapult/clearance/templates/app/controllers/passwords_controller.rb +16 -0
  43. data/lib/generators/katapult/clearance/templates/app/views/clearance_mailer/change_password.html.haml +6 -0
  44. data/lib/generators/katapult/clearance/templates/app/views/clearance_mailer/change_password.text.erb +3 -0
  45. data/lib/generators/katapult/clearance/templates/app/views/passwords/create.html.haml +5 -0
  46. data/lib/generators/katapult/clearance/templates/app/views/passwords/edit.html.haml +16 -0
  47. data/lib/generators/katapult/clearance/templates/app/views/passwords/new.html.haml +14 -0
  48. data/lib/generators/katapult/clearance/templates/app/views/sessions/new.html.haml +19 -0
  49. data/lib/generators/katapult/clearance/templates/config/initializers/clearance.rb +15 -0
  50. data/lib/generators/katapult/clearance/templates/config/locales/clearance.en.yml +59 -0
  51. data/lib/generators/katapult/clearance/templates/features/authentication.feature +94 -0
  52. data/lib/generators/katapult/clearance/templates/features/step_definitions/authentication_steps.rb +4 -0
  53. data/lib/generators/katapult/cucumber_features/templates/feature.feature +11 -7
  54. data/lib/generators/katapult/haml/haml_generator.rb +5 -0
  55. data/lib/generators/katapult/haml/templates/_form.html.haml +4 -4
  56. data/lib/generators/katapult/haml/templates/app/views/layouts/_flashes.html.haml +3 -0
  57. data/lib/generators/katapult/haml/templates/app/views/layouts/application.html.haml +9 -3
  58. data/lib/generators/katapult/haml/templates/index.html.haml +1 -1
  59. data/lib/generators/katapult/haml/templates/show.html.haml +2 -4
  60. data/lib/generators/katapult/install/templates/lib/katapult/application_model.rb +9 -7
  61. data/lib/generators/katapult/model/model_generator.rb +1 -1
  62. data/lib/generators/katapult/w_u_i/templates/controller.rb +1 -1
  63. data/lib/generators/katapult/w_u_i/w_u_i_generator.rb +4 -2
  64. data/lib/katapult/application_model.rb +8 -1
  65. data/lib/katapult/attribute.rb +10 -11
  66. data/lib/katapult/authentication.rb +25 -0
  67. data/lib/katapult/binary_util.rb +37 -0
  68. data/lib/katapult/element.rb +1 -1
  69. data/lib/katapult/generator.rb +6 -0
  70. data/lib/katapult/model.rb +13 -1
  71. data/lib/katapult/parser.rb +7 -0
  72. data/lib/katapult/version.rb +1 -1
  73. data/lib/katapult/wui.rb +4 -0
  74. data/lib/katapult.rb +2 -0
  75. data/spec/attribute_spec.rb +13 -0
  76. data/spec/element_spec.rb +5 -0
  77. data/spec/model_spec.rb +5 -4
  78. data/spec/util_spec.rb +8 -8
  79. data/spec/wui_spec.rb +19 -0
  80. metadata +44 -8
  81. data/features/katapult.feature +0 -271
  82. data/lib/katapult/util.rb +0 -16
@@ -0,0 +1,10 @@
1
+ Array.class_eval do
2
+ def xss_aware_join(delimiter = '')
3
+ ''.html_safe.tap do |str|
4
+ each_with_index do |element, i|
5
+ str << delimiter if i > 0
6
+ str << element
7
+ end
8
+ end
9
+ end
10
+ end
@@ -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,7 @@
1
+ class Hash
2
+
3
+ def self.infinite
4
+ new { |h, k| h[k] = new(&h.default_proc) }
5
+ end
6
+
7
+ end
@@ -0,0 +1,11 @@
1
+ class String
2
+
3
+ def self.nbsp
4
+ ' '
5
+ end
6
+
7
+ def self.ndash
8
+ '–'
9
+ end
10
+
11
+ 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,9 @@
1
+ FactoryGirl.define do
2
+
3
+ factory :EXAMPLE do
4
+ status 'pending'
5
+ uuid { SecureRandom.uuid }
6
+ sequence(:title) { |i| "Titel #{ i }"}
7
+ end
8
+
9
+ end
@@ -0,0 +1,3 @@
1
+ RSpec.configure do |config|
2
+ config.include FactoryGirl::Syntax::Methods
3
+ 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,6 @@
1
+ %p
2
+ To reset your password, please follow this link:
3
+
4
+ %p
5
+ = link_to 'Change password',
6
+ edit_user_password_url(@user, token: @user.confirmation_token.html_safe)
@@ -0,0 +1,3 @@
1
+ To reset your password, please follow this link:
2
+
3
+ <%= edit_user_password_url(@user, token: @user.confirmation_token.html_safe) %>
@@ -0,0 +1,5 @@
1
+ %h1
2
+ Password Reset Instructions Sent
3
+
4
+ %p
5
+ We've sent you an email with instructions on how to reset your password.
@@ -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
@@ -0,0 +1,4 @@
1
+ When /^I (?:am signed|sign) in as the user above$/ do
2
+ user = User.last!
3
+ visit root_path(as: user) # Using Clearance::BackDoor
4
+ end
@@ -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(:variable) %>"
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, :markdown, :datetime -%>
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, :markdown -%>
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, :markdown, :datetime -%>
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 # do not crash when the model has no 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.attrs.each do |attribute| -%>
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.datetime_field <%= attribute.name(:symbol) %>
30
+ = form.date_field <%= attribute.name(:symbol) %>
31
31
  <%- end -%>
32
32
  <%- end -%>
33
33
  <% end -%>
@@ -0,0 +1,3 @@
1
+ - flash.each do |level, message|
2
+ .flash.alert.alert-info
3
+ = message
@@ -15,12 +15,18 @@
15
15
 
16
16
  .layout__head
17
17
  %h2 <%= app_name.titlecase %>
18
- <%- if navigation -%>
18
+ <%- if navigation -%>
19
19
  = render_navigation Navigation.<%= navigation.name(:variable) %>
20
- <%- end -%>
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
- =# render 'layouts/flashes'
29
+ = render 'layouts/flashes'
24
30
  = yield
25
31
 
26
32
  .layout__tail