voyage 1.44.0.9 → 1.44.0.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 34805db52fd3603e41eb324e307c4c5fca0e05af
4
- data.tar.gz: 62e934b8eb5fae05b49f229c0795888d41fa1c96
3
+ metadata.gz: d2d85038fd4f02fe75a941bfbeb66bfb7c1ae2fc
4
+ data.tar.gz: 00f7aa3152f0e7ec2bc036420d0f96a87926690b
5
5
  SHA512:
6
- metadata.gz: a41c3764da14b591fd920a1c44c59bd7576351ad6b967120609d930f3975c5498db0d671f99c060420bf9f762c43b588ece957abf6752559d486eb1f53946585
7
- data.tar.gz: 0ab410d991d66a534598e5b285f986f4301bc273ef24b8c6793babb308f1af6886c70bbc9f2ce9b58883c1b511504db09997bb37fef7a71a2236a78bc70f9688
6
+ metadata.gz: 60ea2891a535d8abc0f216f5801f3cadbf37a97541b1fb5deaa2b9dae70d390d919e6fafe930b22145b9f6b6253881b72c4f85ee81aadf51920439187a413357
7
+ data.tar.gz: 3309b6cefdefdc3696329becf3c23960fdd590f0ffd046f3122ca806ddf91db4e91c65f6c5c34752f61ab44da5f4250ab264494ab474c06636f21db52bc1c3e8
@@ -86,6 +86,11 @@ module Suspenders
86
86
  def install_devise
87
87
  if @@accept_defaults || agree?('Would you like to install Devise? (Y/n)')
88
88
  @@use_devise = true
89
+
90
+ if @@accept_defaults || agree?('Would you like to install Devise token authentication? (Y/n)')
91
+ devise_token_auth = true
92
+ end
93
+
89
94
  bundle_command 'exec rails generate devise:install'
90
95
 
91
96
  if @@accept_defaults || agree?("Would you like to add first_name and last_name to the devise model? (Y/n)")
@@ -112,7 +117,7 @@ module Suspenders
112
117
  end
113
118
 
114
119
  customize_devise_views if adding_first_and_last_name
115
- customize_application_controller_for_devise(adding_first_and_last_name)
120
+ customize_application_controller_for_devise(adding_first_and_last_name, devise_token_auth)
116
121
  add_devise_registrations_controller
117
122
  customize_resource_controller_for_devise(adding_first_and_last_name)
118
123
  add_admin_views_for_devise_resource(adding_first_and_last_name)
@@ -124,6 +129,7 @@ module Suspenders
124
129
  customize_user_factory(adding_first_and_last_name)
125
130
  generate_seeder_templates(using_devise: true)
126
131
  customize_user_spec
132
+ add_token_auth
127
133
  else
128
134
  generate_seeder_templates(using_devise: false)
129
135
  end
@@ -149,7 +155,7 @@ module Suspenders
149
155
  end
150
156
  end
151
157
 
152
- def customize_application_controller_for_devise(adding_first_and_last_name)
158
+ def customize_application_controller_for_devise(adding_first_and_last_name, devise_token_auth)
153
159
  inject_into_file 'app/controllers/application_controller.rb', before: "class ApplicationController < ActionController::Base" do <<-RUBY.gsub(/^ {8}/, '')
154
160
  # rubocop:disable Metrics/ClassLength, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/LineLength
155
161
  RUBY
@@ -159,6 +165,7 @@ module Suspenders
159
165
 
160
166
  check_authorization unless: :devise_or_pages_controller?
161
167
  impersonates :user
168
+ #{'acts_as_token_authentication_handler_for User' if devise_token_auth}
162
169
 
163
170
  before_action :configure_permitted_parameters, if: :devise_controller?
164
171
  before_action :authenticate_user!, unless: -> { is_a?(HighVoltage::PagesController) }
@@ -316,6 +323,7 @@ module Suspenders
316
323
  end
317
324
 
318
325
  template '../templates/admin_users_controller.rb', 'app/controllers/admin/users_controller.rb'
326
+ template '../templates/admin_controller.rb', 'app/controllers/admin/admin_controller.rb'
319
327
  end
320
328
 
321
329
  def authorize_devise_resource_for_index_action
@@ -508,11 +516,45 @@ module Suspenders
508
516
  expect(user.tester?).to eq(false)
509
517
  end
510
518
  end
519
+
520
+ context 'new user creation' do
521
+ it 'ensures uniqueness of the uuid' do
522
+ allow(User).to receive(:exists?).and_return(true, false)
523
+
524
+ expect do
525
+ create(:user)
526
+ end.to change { User.count }.by(1)
527
+
528
+ expect(User).to have_received(:exists?).exactly(2).times
529
+ end
530
+ end
511
531
  RUBY
512
532
 
513
533
  replace_in_file 'spec/models/user_spec.rb', find, replace
514
534
  end
515
535
 
536
+ def add_token_auth
537
+ inject_into_file 'app/models/user.rb', after: "class User < ApplicationRecord" do <<-'RUBY'.gsub(/^ {6}/, '')
538
+
539
+ acts_as_token_authenticatable
540
+ RUBY
541
+ end
542
+
543
+ generate 'migration add_authentication_token_to_users "authentication_token:string{30}:uniq"'
544
+
545
+ # specs
546
+ template '../templates/specs/features/user_impersonation_spec.rb', 'spec/features/user_impersonation_spec.rb', force: true
547
+ template '../templates/specs/features/user_list_spec.rb', 'spec/features/user_list_spec.rb', force: true
548
+ template '../templates/specs/features/user_signup_spec.rb', 'spec/features/user_signup_spec.rb', force: true
549
+ template '../templates/specs/requests/user_api_spec.rb', 'spec/requests/user_api_spec.rb', force: true
550
+ template '../templates/specs/support/api/schemas/user.json', 'spec/support/api/schemas/user.json', force: true
551
+ template '../templates/config_initializers_ams.rb', 'config/initializers/ams.rb', force: true
552
+ template '../templates/specs/support/matchers/api_schema_matcher.rb', 'spec/support/matchers/api_schema_matcher.rb', force: true
553
+ template '../templates/specs/mailers/application_mailer_spec.rb.erb', 'spec/mailers/application_mailer_spec.rb', force: true
554
+ template '../templates/specs/support/features/session_helpers.rb', 'spec/support/features/session_helpers.rb', force: true
555
+ template '../templates/specs/support/request_spec_helper.rb', 'spec/support/request_spec_helper.rb', force: true
556
+ end
557
+
516
558
  def customize_application_js
517
559
  template '../templates/application.js', 'app/assets/javascripts/application.js', force: true
518
560
 
@@ -712,6 +754,20 @@ module Suspenders
712
754
  template '../templates/favicon.ico', 'app/assets/images/favicon.ico', force: true
713
755
  end
714
756
 
757
+ def customize_application_mailer
758
+ template '../templates/application_mailer.rb.erb', 'app/mailers/application_mailer.rb', force: true
759
+ end
760
+
761
+ def add_specs
762
+ inject_into_file 'app/jobs/application_job.rb', before: "class ApplicationJob < ActiveJob::Base" do <<-RUBY.gsub(/^ {8}/, '')
763
+ # :nocov:
764
+ RUBY
765
+ end
766
+
767
+ template '../templates/specs/controllers/admin/users_controller_spec.rb', 'spec/controllers/admin/users_controller_spec.rb', force: true
768
+ template '../templates/specs/controllers/application_controller_spec.rb', 'spec/controllers/application_controller_spec.rb', force: true
769
+ end
770
+
715
771
  # Do this last
716
772
  def rake_db_setup
717
773
  rake 'db:migrate'
@@ -750,6 +806,7 @@ module Suspenders
750
806
  .zenflow-log
751
807
  errors.err
752
808
  .ctags
809
+ .cadre/coverage.vim
753
810
  RUBY
754
811
  end
755
812
  end
@@ -43,6 +43,8 @@ module Suspenders
43
43
  invoke :add_auto_annotate_models_rake_task
44
44
  invoke :update_delayed_job_migration_rails_5_1_specify_4_2
45
45
  invoke :add_favicon
46
+ invoke :customize_application_mailer
47
+ invoke :add_specs
46
48
 
47
49
 
48
50
  # Do these last
@@ -137,6 +139,14 @@ module Suspenders
137
139
  build :add_favicon
138
140
  end
139
141
 
142
+ def customize_application_mailer
143
+ build :customize_application_mailer
144
+ end
145
+
146
+ def add_specs
147
+ build :add_specs
148
+ end
149
+
140
150
  def spin_up_webpacker
141
151
  build :spin_up_webpacker
142
152
  end
@@ -41,8 +41,10 @@ gem 'canard', git: 'https://github.com/jondkinney/canard.git', branch: 'feature/
41
41
  gem 'cancancan' # authorization library
42
42
  gem 'devise'
43
43
  gem 'pretender' # impersonate users as an admin
44
+ gem 'simple_token_authentication', '~> 1.0' # adds token authentication to Devise
44
45
 
45
46
  # Database Tweaks
47
+ gem 'active_model_serializers', '~> 0.10.0'
46
48
  gem 'dynamic_form' # for custom messages without the database column
47
49
  gem 'friendly_id' # slugs in the url auto-generated
48
50
  gem 'nested_form_fields' # Dynamically add and remove nested has_many association fields in a Ruby on Rails form
@@ -80,7 +82,6 @@ group :development do
80
82
  gem 'fix-db-schema-conflicts' # when working with multiple developers schema order of columns is standardized.
81
83
  gem 'meta_request' # for chrome rails console plugin found here: https://chrome.google.com/webstore/detail/railspanel/gjpfobpafnhjhbajcjgccbbdofdckggg?hl=en-US
82
84
  gem 'rails-erd' # auto gen ERD Diagram of models in the app on rake db:migrate
83
- gem 'redcarpet' # used to render the readme inside a static welcome page from the high_voltage gem
84
85
  gem 'zenflow', git: 'https://github.com/zencoder/zenflow.git'
85
86
  end
86
87
 
@@ -89,16 +90,16 @@ group :development, :test do
89
90
  gem "bullet"
90
91
  gem "bundler-audit", ">= 0.5.0", require: false
91
92
  gem "dotenv-rails"
92
- gem "factory_girl_rails"
93
+ <%# gem "factory_girl_rails" %>
93
94
  <%# gem "pry-byebug" %>
94
95
  <%# gem "pry-rails" %>
95
96
  gem "rspec-rails", "~> 3.5"
96
97
 
97
98
  # Customizations
98
- gem 'faker' # provides auto generated names for factories, can be customized
99
99
  gem 'letter_opener' # auto-open emails when they're sent
100
100
  gem 'rubocop'
101
101
  gem 'rubocop-rspec', require: false
102
+ gem 'redcarpet' # used to render the readme inside a static welcome page from the high_voltage gem
102
103
  end
103
104
 
104
105
  group :development, :staging do
@@ -118,10 +119,17 @@ group :test do
118
119
  # Customizations
119
120
  gem 'cadre' # highlights code coverage in vim
120
121
  gem 'capybara' # DSL for finding elements on a page during integration testing
122
+ gem 'json-schema' # Allows testing API responses against JSON schema
121
123
  gem 'poltergeist' # Headless browser, used in integration tests
124
+ gem 'rspec_junit_formatter' # Creates JUnit style XML for use in CircleCI
122
125
  gem 'selenium-webdriver' # `brew install chromedriver`, used for acceptance tests in an actual browser.
123
126
  end
124
127
 
128
+ group :development, :test, :staging do
129
+ gem 'factory_girl_rails'
130
+ gem 'faker' # provides auto generated names for factories, can be customized
131
+ end
132
+
125
133
  group :staging, :production do
126
134
  gem "rack-timeout"
127
135
  end
@@ -0,0 +1,13 @@
1
+ module Admin
2
+ class AdminController < ApplicationController
3
+ before_action :require_admin!
4
+ skip_authorization_check
5
+
6
+ private
7
+
8
+ def require_admin!
9
+ txt = 'You must be an admin to perform that action'
10
+ redirect_to root_path, alert: txt unless current_user.admin?
11
+ end
12
+ end
13
+ end
@@ -1,10 +1,12 @@
1
1
  module Admin
2
- class UsersController < ApplicationController
3
- before_action :require_admin!, except: [:stop_impersonating]
4
- skip_authorization_check
2
+ class UsersController < AdminController
3
+ skip_before_action :require_admin!, only: [:stop_impersonating]
4
+ respond_to :html, :json
5
5
 
6
6
  def index
7
7
  @users = User.all
8
+
9
+ respond_with(@users)
8
10
  end
9
11
 
10
12
  def impersonate
@@ -22,11 +24,6 @@ module Admin
22
24
 
23
25
  private
24
26
 
25
- def require_admin!
26
- txt = 'You must be an admin to perform that action'
27
- redirect_to root_path, notice: txt unless current_user.admin?
28
- end
29
-
30
27
  def track_impersonation(user, status)
31
28
  analytics_track(
32
29
  true_user,
@@ -0,0 +1,11 @@
1
+ class ApplicationMailer < ActionMailer::Base
2
+ default from: "no-reply@<%= app_name %>.com",
3
+ return_path: "contact@<%= app_name %>.com"
4
+
5
+ layout 'mailer'
6
+
7
+ def email(to_address, subject, body)
8
+ options = { to: to_address, subject: subject, body: body }
9
+ mail options
10
+ end
11
+ end
@@ -0,0 +1 @@
1
+ ActiveModelSerializers.config.adapter = :json_api
@@ -7,11 +7,7 @@ module DeviseCustomizations
7
7
  protected
8
8
 
9
9
  def after_sign_up_path_for(resource)
10
- if user_signed_in?
11
- analytics_alias_user_path(resource)
12
- else
13
- new_user_session_path(resource)
14
- end
10
+ analytics_alias_user_path(resource)
15
11
  end
16
12
  end
17
13
  end
@@ -37,8 +37,9 @@ RSpec.configure do |config|
37
37
 
38
38
  config.use_transactional_fixtures = false
39
39
 
40
- config.include Devise::TestHelpers, type: :controller
41
- config.include ControllerHelpers, type: :controller
40
+ config.include Devise::Test::ControllerHelpers, type: :controller
41
+ config.include RequestSpecHelper, type: :request
42
+ config.include Features::SessionHelpers, type: :feature
42
43
  # config.include Paperclip::Shoulda::Matchers
43
44
 
44
45
  Capybara.javascript_driver = :poltergeist
@@ -15,6 +15,19 @@ RSpec/FilePath:
15
15
  RSpec/LeadingSubject:
16
16
  Enabled: false
17
17
 
18
+ Metrics/BlockLength:
19
+ Exclude:
20
+ - 'spec/**/*'
21
+
22
+ RSpec/NestedGroups:
23
+ Max: 6
24
+
25
+ RSpec/MultipleExpectations:
26
+ Max: 2
27
+
28
+ RSpec/ExampleLength:
29
+ Max: 15
30
+
18
31
  Rails:
19
32
  Enabled: true
20
33
 
@@ -39,6 +52,7 @@ AllCops:
39
52
  - 'config/initializers/wrap_parameters.rb'
40
53
  - 'bin/**/*'
41
54
  - 'Rakefile'
55
+ - 'node_modules/**/*'
42
56
  Include:
43
57
  - 'Gemfile'
44
58
  - '.simplecov'
@@ -1,4 +1,4 @@
1
- if ENV['COVERAGE'].match?(/\Atrue\z/i)
1
+ if ENV['COVERAGE'] && ENV['COVERAGE'].match?(/\Atrue\z/i)
2
2
  require 'cadre/simplecov'
3
3
 
4
4
  SimpleCov.start do
@@ -9,6 +9,7 @@ if ENV['COVERAGE'].match?(/\Atrue\z/i)
9
9
  add_group 'Helpers', 'app/helpers'
10
10
  add_group 'Mailers', 'app/mailers'
11
11
  add_group 'Models', 'app/models'
12
+ add_group 'Abilities', 'app/abilities'
12
13
  add_group 'Serializers', 'app/serializers'
13
14
  add_group 'Services', 'app/services'
14
15
  add_group 'Workers', 'app/workers'
@@ -19,6 +20,10 @@ if ENV['COVERAGE'].match?(/\Atrue\z/i)
19
20
  add_group 'Ignored Code' do |src_file|
20
21
  File.readlines(src_file.filename).grep(/:nocov:/).any?
21
22
  end
23
+
24
+ add_filter 'app/channels'
25
+ add_filter 'lib/tasks'
26
+ add_filter 'lib/seeder'
22
27
  end
23
28
 
24
29
  SimpleCov.formatters = [
@@ -0,0 +1,69 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe Admin::UsersController, type: :request do
4
+ let(:admin_user) { create(:user, :admin) }
5
+ let(:user) { create(:user) }
6
+
7
+ describe '#index' do
8
+ context 'authenticated' do
9
+ context 'admin' do
10
+ it 'loads all users in the browser' do
11
+ sign_in(admin_user)
12
+ get admin_users_path
13
+ expect(response).to be_success
14
+ end
15
+
16
+ it 'lists all users as json' do
17
+ token_header_params = {
18
+ 'X-User-Email': admin_user.email,
19
+ 'X-User-Token': admin_user.authentication_token,
20
+ }
21
+
22
+ get admin_users_url, headers: token_header_params, as: :json
23
+
24
+ expect(response.content_type).to eq('application/json')
25
+ expect(response).to have_http_status(:success)
26
+ end
27
+ end
28
+
29
+ context 'user' do
30
+ it 'redirects with an alert that you need to be an admin' do
31
+ sign_in(user)
32
+ get admin_users_path
33
+ expect(response).to be_redirect
34
+
35
+ txt = 'You must be an admin to perform that action'
36
+ expect(flash[:alert]).to eq(txt)
37
+ end
38
+ end
39
+ end
40
+
41
+ context 'NOT authenticated' do
42
+ it 'redirects to sign in page with an alert' do
43
+ get admin_users_path
44
+ expect(response).to be_redirect
45
+
46
+ txt = 'You need to sign in or sign up before continuing.'
47
+ expect(flash[:alert]).to eq(txt)
48
+ end
49
+ end
50
+ end
51
+
52
+ describe '#impersonate' do
53
+ it 'changes the current user from admin to the specified user' do
54
+ sign_in(admin_user)
55
+ get impersonate_admin_user_path(user)
56
+ expect(controller.current_user).to eq(user)
57
+ end
58
+ end
59
+
60
+ describe '#stop_impersonating' do
61
+ it 'returns the current_user to the admin user' do
62
+ sign_in(admin_user)
63
+ get impersonate_admin_user_path(user)
64
+ expect(controller.current_user).to eq(user)
65
+ get stop_impersonating_admin_users_path
66
+ expect(controller.current_user).to eq(admin_user)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,81 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe ApplicationController, type: :controller do
4
+ let(:user) { create(:user) }
5
+ let(:admin_user) { create(:user, :admin) }
6
+
7
+ controller do
8
+ skip_authorization_check only: :show
9
+
10
+ def index
11
+ raise CanCan::AccessDenied
12
+ end
13
+
14
+ def show
15
+ render body: 'show called'
16
+ end
17
+ end
18
+
19
+ context 'errors' do
20
+ it 'rescues from cancan errors and redirects' do
21
+ sign_in(user)
22
+ get :index
23
+ expect(response).to be_redirect
24
+ end
25
+ end
26
+
27
+ context 'analytics' do
28
+ before do
29
+ allow(user).to receive(:tester?).and_return(false)
30
+ allow(Analytics).to receive(:track)
31
+ end
32
+
33
+ it 'tracks with some global defaults' do
34
+ controller.analytics_track(user, 'Signed In', page_name: 'Page')
35
+ expect(Analytics).to have_received(:track)
36
+ end
37
+
38
+ it 'trys to pull roles on a non-user object' do
39
+ allow(user).to receive(:roles).and_return(StandardError.new('bazinga'))
40
+ controller.analytics_track(user, 'Signed In', page_name: 'Page')
41
+ expect(Analytics).to have_received(:track)
42
+ end
43
+ end
44
+
45
+ context 'variants' do
46
+ it 'allows iPad variants' do
47
+ request.env['HTTP_USER_AGENT'] = 'iPad'
48
+ sign_in(user)
49
+ get :show, params: { id: 'anyid' }
50
+ expect(request.variant).to include(:tablet)
51
+ end
52
+
53
+ it 'allows iPhone variants' do
54
+ request.env['HTTP_USER_AGENT'] = 'iPhone'
55
+ sign_in(user)
56
+ get :show, params: { id: 'anyid' }
57
+ expect(request.variant).to include(:phone)
58
+ end
59
+
60
+ it 'allows Android phone variants' do
61
+ request.env['HTTP_USER_AGENT'] = 'Android mobile'
62
+ sign_in(user)
63
+ get :show, params: { id: 'anyid' }
64
+ expect(request.variant).to include(:phone)
65
+ end
66
+
67
+ it 'allows Android tablet variants' do
68
+ request.env['HTTP_USER_AGENT'] = 'Android'
69
+ sign_in(user)
70
+ get :show, params: { id: 'anyid' }
71
+ expect(request.variant).to include(:tablet)
72
+ end
73
+
74
+ it 'allows Windows phone variants' do
75
+ request.env['HTTP_USER_AGENT'] = 'Windows Phone'
76
+ sign_in(user)
77
+ get :show, params: { id: 'anyid' }
78
+ expect(request.variant).to include(:phone)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,38 @@
1
+ require 'rails_helper'
2
+
3
+ feature 'Impersonate user' do
4
+ given(:admin_user) { create(:user, :admin) }
5
+ given(:regular_user) { create(:user) }
6
+
7
+ scenario 'With admin privileges' do
8
+ sign_in(admin_user.email, admin_user.password)
9
+
10
+ visit impersonate_admin_user_path(id: regular_user.id)
11
+
12
+ expect(page).to have_content('Stop Impersonating')
13
+ end
14
+
15
+ scenario 'With admin privileges: End Impersonation' do
16
+ sign_in(admin_user.email, admin_user.password)
17
+
18
+ visit impersonate_admin_user_path(id: regular_user.id)
19
+ visit stop_impersonating_admin_users_path
20
+
21
+ expect(page).to_not have_content('Stop Impersonating')
22
+ end
23
+
24
+ scenario 'Without admin privileges' do
25
+ sign_in(regular_user.email, regular_user.password)
26
+
27
+ visit impersonate_admin_user_path(id: admin_user.id)
28
+
29
+ expect(page).to have_content('You must be an admin to perform that action')
30
+ end
31
+
32
+ scenario 'Stop impersonating when not impersonating' do
33
+ visit stop_impersonating_admin_users_path
34
+
35
+ expect(page)
36
+ .to have_content('You need to sign in or sign up before continuing.')
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ require 'rails_helper'
2
+
3
+ feature 'Retrieve user list from browser' do
4
+ scenario 'without admin privileges' do
5
+ user = create(:user)
6
+
7
+ sign_in(user.email, user.password)
8
+ visit admin_users_path
9
+
10
+ expect(page).to have_content('You must be an admin to perform that action')
11
+ end
12
+
13
+ scenario 'with admin privileges' do
14
+ user = create(:user, :admin)
15
+
16
+ sign_in(user.email, user.password)
17
+ visit admin_users_path
18
+
19
+ expect(page).to have_content(user.email)
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ require 'rails_helper'
2
+
3
+ feature 'User signup' do
4
+ scenario 'Valid user information' do
5
+ sign_up_with('First', 'Last', 'test@example.com', 'password', 'password')
6
+ expect(page).to have_content('Welcome! You have signed up successfully.')
7
+ end
8
+
9
+ scenario 'Passwords do not match' do
10
+ sign_up_with('First', 'Last', 'test@example.com', 'password', 'password2')
11
+ expect(page).to have_content("doesn't match Password")
12
+ end
13
+
14
+ scenario 'Email is invalid' do
15
+ sign_up_with('First', 'Last', 'test2example.com', 'password', 'password')
16
+ expect(page).to have_content('is invalid')
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ require 'rails_helper'
2
+
3
+ describe ApplicationMailer do
4
+ it 'sets the correct subject' do
5
+ subject = 'Test email subject'
6
+ mail = described_class.email('test@example.com',
7
+ subject, 'Test email body')
8
+
9
+ expect(mail.subject).to eq(subject)
10
+ end
11
+
12
+ it 'includes content in the body of the email' do
13
+ body = 'Test email body'
14
+ mail = described_class.email('test@example.com',
15
+ 'Test email subject', body)
16
+
17
+ expect(mail.body).to eq(body)
18
+ end
19
+
20
+ it 'sends from no-reply@<%= app_name %>.com' do
21
+ mail = described_class.email('test@example.com',
22
+ 'Test email subject', 'Test email body')
23
+
24
+ expect(mail.from).to include('no-reply@<%= app_name %>.com')
25
+ end
26
+ end
@@ -0,0 +1,44 @@
1
+ require 'rails_helper'
2
+
3
+ describe 'Retrieve user list from API', type: :request do
4
+ context 'with token authentication via query params' do
5
+ it 'returns status code 200' do
6
+ user = create(:user, :admin)
7
+
8
+ get admin_users_url(user_email: user.email,
9
+ user_token: user.authentication_token), as: :json
10
+
11
+ expect(response.status).to eq 200
12
+ end
13
+
14
+ it 'returns valid user JSON matching schema' do
15
+ user = create(:user, :admin)
16
+
17
+ get admin_users_url(user_email: user.email,
18
+ user_token: user.authentication_token), as: :json
19
+
20
+ expect(response).to match_response_schema('user')
21
+ end
22
+ end
23
+
24
+ context 'with token authentication via request headers' do
25
+ it 'returns status code 200' do
26
+ user = create(:user, :admin)
27
+ token_header_params = { 'X-User-Email': user.email,
28
+ 'X-User-Token': user.authentication_token }
29
+
30
+ get admin_users_url, headers: token_header_params, as: :json
31
+
32
+ expect(response.status).to eq 200
33
+ end
34
+ it 'returns value user JSON matching schema' do
35
+ user = create(:user, :admin)
36
+ token_header_params = { 'X-User-Email': user.email,
37
+ 'X-User-Token': user.authentication_token }
38
+
39
+ get admin_users_url, headers: token_header_params, as: :json
40
+
41
+ expect(response).to match_response_schema('user')
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,58 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-04/schema#",
3
+ "title": "Users schema based on JSON API",
4
+ "type": "object",
5
+ "required": [
6
+ "data"
7
+ ],
8
+ "data": {
9
+ "description": "List of user resources.",
10
+ "type": "array",
11
+ "items": {
12
+ "type": "object",
13
+ "required": [
14
+ "type",
15
+ "id"
16
+ ],
17
+ "properties": {
18
+ "type": {
19
+ "type": "string"
20
+ },
21
+ "id": {
22
+ "type": "integer"
23
+ },
24
+ "attributes": {
25
+ "required": [
26
+ "first-name",
27
+ "last-name",
28
+ "email",
29
+ "authentication-token"
30
+ ],
31
+ "properties": {
32
+ "first-name": {
33
+ "type": "string"
34
+ },
35
+ "last-name": {
36
+ "type": "string"
37
+ },
38
+ "email": {
39
+ "type": "string"
40
+ },
41
+ "authentication-token": {
42
+ "type": "string"
43
+ },
44
+ "created-at": {
45
+ "type": "string",
46
+ "format": "date-time"
47
+ },
48
+ "updated-at": {
49
+ "type": "string",
50
+ "format": "date-time"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ },
56
+ "uniqueItems": true
57
+ }
58
+ }
@@ -0,0 +1,27 @@
1
+ module Features
2
+ module SessionHelpers
3
+ def sign_in(email, password)
4
+ visit sign_in_path
5
+ within '.form-inputs' do
6
+ fill_in 'user_email', with: email
7
+ fill_in 'user_password', with: password
8
+ end
9
+
10
+ click_button 'Log in'
11
+ end
12
+
13
+ def sign_up_with(first, last, email, password, password_confirmation)
14
+ visit new_user_registration_path
15
+ within '.form-inputs' do
16
+ fill_in 'First name', with: first
17
+ fill_in 'Last name', with: last
18
+
19
+ fill_in 'Email', with: email
20
+ fill_in 'user_password', with: password
21
+ fill_in 'user_password_confirmation', with: password_confirmation
22
+ end
23
+
24
+ click_button 'Sign up'
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ RSpec::Matchers.define :match_response_schema do |schema|
2
+ match do |response|
3
+ schema_directory = "#{Dir.pwd}/spec/support/api/schemas"
4
+ schema_path = "#{schema_directory}/#{schema}.json"
5
+ JSON::Validator.validate!(schema_path, response.body, strict: true)
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ module RequestSpecHelper
2
+ include Warden::Test::Helpers
3
+
4
+ def self.included(base)
5
+ base.before(:each) { Warden.test_mode! }
6
+ base.after(:each) { Warden.test_reset! }
7
+ end
8
+
9
+ def sign_in(resource)
10
+ login_as(resource, scope: warden_scope(resource))
11
+ end
12
+
13
+ def sign_out(resource)
14
+ logout(warden_scope(resource))
15
+ end
16
+
17
+ private
18
+
19
+ def warden_scope(resource)
20
+ resource.class.name.underscore.to_sym
21
+ end
22
+ end
@@ -5,5 +5,5 @@ module Voyage
5
5
  .read("#{File.dirname(__FILE__)}/../../.ruby-version")
6
6
  .strip
7
7
  .freeze
8
- VERSION = '1.44.0.9'.freeze
8
+ VERSION = '1.44.0.10'.freeze
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: voyage
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.44.0.9
4
+ version: 1.44.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoughtbot, headway
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-02 00:00:00.000000000 Z
11
+ date: 2017-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bitters
@@ -109,13 +109,16 @@ files:
109
109
  - lib/voyage/templates/Gemfile.erb
110
110
  - lib/voyage/templates/README.md.erb
111
111
  - lib/voyage/templates/about.html.erb
112
+ - lib/voyage/templates/admin_controller.rb
112
113
  - lib/voyage/templates/admin_users_controller.rb
113
114
  - lib/voyage/templates/analytics_alias.html.erb.erb
114
115
  - lib/voyage/templates/analytics_identify.html.erb.erb
115
116
  - lib/voyage/templates/analytics_ruby_initializer.rb
116
117
  - lib/voyage/templates/application.js
118
+ - lib/voyage/templates/application_mailer.rb.erb
117
119
  - lib/voyage/templates/auto_annotate_models.rake
118
120
  - lib/voyage/templates/config_dj_rails5_patches.rb
121
+ - lib/voyage/templates/config_initializers_ams.rb
119
122
  - lib/voyage/templates/config_locales_en.yml.erb
120
123
  - lib/voyage/templates/controller_helpers.rb
121
124
  - lib/voyage/templates/custom_cancan_matchers.rb
@@ -126,6 +129,17 @@ files:
126
129
  - lib/voyage/templates/seeder.rb.erb
127
130
  - lib/voyage/templates/seeds.rb.erb
128
131
  - lib/voyage/templates/simplecov.rb
132
+ - lib/voyage/templates/specs/controllers/admin/users_controller_spec.rb
133
+ - lib/voyage/templates/specs/controllers/application_controller_spec.rb
134
+ - lib/voyage/templates/specs/features/user_impersonation_spec.rb
135
+ - lib/voyage/templates/specs/features/user_list_spec.rb
136
+ - lib/voyage/templates/specs/features/user_signup_spec.rb
137
+ - lib/voyage/templates/specs/mailers/application_mailer_spec.rb.erb
138
+ - lib/voyage/templates/specs/requests/user_api_spec.rb
139
+ - lib/voyage/templates/specs/support/api/schemas/user.json
140
+ - lib/voyage/templates/specs/support/features/session_helpers.rb
141
+ - lib/voyage/templates/specs/support/matchers/api_schema_matcher.rb
142
+ - lib/voyage/templates/specs/support/request_spec_helper.rb
129
143
  - lib/voyage/templates/users_index.html.erb
130
144
  - lib/voyage/templates/voyage_layout.html.erb.erb
131
145
  - lib/voyage/templates/welcome.html.erb