voyage 1.44.0.9 → 1.44.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/voyage/app_builder.rb +59 -2
- data/lib/voyage/generators/app_generator.rb +10 -0
- data/lib/voyage/templates/Gemfile.erb +11 -3
- data/lib/voyage/templates/admin_controller.rb +13 -0
- data/lib/voyage/templates/admin_users_controller.rb +5 -8
- data/lib/voyage/templates/application_mailer.rb.erb +11 -0
- data/lib/voyage/templates/config_initializers_ams.rb +1 -0
- data/lib/voyage/templates/devise_registrations_controller.rb +1 -5
- data/lib/voyage/templates/rails_helper.rb.erb +3 -2
- data/lib/voyage/templates/rubocop.yml +14 -0
- data/lib/voyage/templates/simplecov.rb +6 -1
- data/lib/voyage/templates/specs/controllers/admin/users_controller_spec.rb +69 -0
- data/lib/voyage/templates/specs/controllers/application_controller_spec.rb +81 -0
- data/lib/voyage/templates/specs/features/user_impersonation_spec.rb +38 -0
- data/lib/voyage/templates/specs/features/user_list_spec.rb +21 -0
- data/lib/voyage/templates/specs/features/user_signup_spec.rb +18 -0
- data/lib/voyage/templates/specs/mailers/application_mailer_spec.rb.erb +26 -0
- data/lib/voyage/templates/specs/requests/user_api_spec.rb +44 -0
- data/lib/voyage/templates/specs/support/api/schemas/user.json +58 -0
- data/lib/voyage/templates/specs/support/features/session_helpers.rb +27 -0
- data/lib/voyage/templates/specs/support/matchers/api_schema_matcher.rb +7 -0
- data/lib/voyage/templates/specs/support/request_spec_helper.rb +22 -0
- data/lib/voyage/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d2d85038fd4f02fe75a941bfbeb66bfb7c1ae2fc
|
4
|
+
data.tar.gz: 00f7aa3152f0e7ec2bc036420d0f96a87926690b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60ea2891a535d8abc0f216f5801f3cadbf37a97541b1fb5deaa2b9dae70d390d919e6fafe930b22145b9f6b6253881b72c4f85ee81aadf51920439187a413357
|
7
|
+
data.tar.gz: 3309b6cefdefdc3696329becf3c23960fdd590f0ffd046f3122ca806ddf91db4e91c65f6c5c34752f61ab44da5f4250ab264494ab474c06636f21db52bc1c3e8
|
data/lib/voyage/app_builder.rb
CHANGED
@@ -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 <
|
3
|
-
|
4
|
-
|
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
|
@@ -37,8 +37,9 @@ RSpec.configure do |config|
|
|
37
37
|
|
38
38
|
config.use_transactional_fixtures = false
|
39
39
|
|
40
|
-
config.include Devise::
|
41
|
-
config.include
|
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
|
data/lib/voyage/version.rb
CHANGED
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.
|
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-
|
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
|