api_guardian 0.1.0.pre

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 (114) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +125 -0
  4. data/Rakefile +30 -0
  5. data/app/controllers/api_guardian/api_controller.rb +112 -0
  6. data/app/controllers/api_guardian/application_controller.rb +11 -0
  7. data/app/controllers/api_guardian/permissions_controller.rb +7 -0
  8. data/app/controllers/api_guardian/registration_controller.rb +38 -0
  9. data/app/controllers/api_guardian/roles_controller.rb +19 -0
  10. data/app/controllers/api_guardian/users_controller.rb +20 -0
  11. data/app/models/api_guardian/permission.rb +14 -0
  12. data/app/models/api_guardian/role.rb +97 -0
  13. data/app/models/api_guardian/role_permission.rb +8 -0
  14. data/app/models/api_guardian/user.rb +23 -0
  15. data/app/serializers/api_guardian/permission_serializer.rb +7 -0
  16. data/app/serializers/api_guardian/role_serializer.rb +7 -0
  17. data/app/serializers/api_guardian/user_serializer.rb +10 -0
  18. data/config/initializers/api_guardian.rb +10 -0
  19. data/config/initializers/doorkeeper.rb +143 -0
  20. data/config/routes.rb +20 -0
  21. data/db/migrate/20151117191338_api_guardian_enable_uuid_extension.rb +5 -0
  22. data/db/migrate/20151117191911_create_api_guardian_roles.rb +9 -0
  23. data/db/migrate/20151117195618_create_api_guardian_users.rb +25 -0
  24. data/db/migrate/20151117212826_create_api_guardian_permissions.rb +10 -0
  25. data/db/migrate/20151117213145_create_api_guardian_role_permissions.rb +11 -0
  26. data/db/migrate/20151117225238_create_doorkeeper_tables.rb +42 -0
  27. data/db/seeds.rb +32 -0
  28. data/lib/api_guardian.rb +80 -0
  29. data/lib/api_guardian/concerns/api_errors/handler.rb +145 -0
  30. data/lib/api_guardian/concerns/api_errors/renderer.rb +45 -0
  31. data/lib/api_guardian/concerns/api_request/validator.rb +66 -0
  32. data/lib/api_guardian/configuration.rb +171 -0
  33. data/lib/api_guardian/engine.rb +23 -0
  34. data/lib/api_guardian/errors/invalid_content_type_error.rb +6 -0
  35. data/lib/api_guardian/errors/invalid_permission_name_error.rb +6 -0
  36. data/lib/api_guardian/errors/invalid_request_body_error.rb +6 -0
  37. data/lib/api_guardian/errors/invalid_request_resource_id_error.rb +6 -0
  38. data/lib/api_guardian/errors/invalid_request_resource_type_error.rb +6 -0
  39. data/lib/api_guardian/errors/invalid_update_action_error.rb +6 -0
  40. data/lib/api_guardian/errors/reset_token_expired_error.rb +6 -0
  41. data/lib/api_guardian/errors/reset_token_user_mismatch_error.rb +6 -0
  42. data/lib/api_guardian/policies/application_policy.rb +65 -0
  43. data/lib/api_guardian/policies/permission_policy.rb +15 -0
  44. data/lib/api_guardian/policies/role_policy.rb +15 -0
  45. data/lib/api_guardian/policies/user_policy.rb +23 -0
  46. data/lib/api_guardian/stores/base.rb +53 -0
  47. data/lib/api_guardian/stores/permission_store.rb +6 -0
  48. data/lib/api_guardian/stores/role_store.rb +9 -0
  49. data/lib/api_guardian/stores/user_store.rb +86 -0
  50. data/lib/api_guardian/version.rb +3 -0
  51. data/lib/generators/api_guardian/install/USAGE +8 -0
  52. data/lib/generators/api_guardian/install/install_generator.rb +19 -0
  53. data/lib/generators/api_guardian/install/templates/README +1 -0
  54. data/lib/generators/api_guardian/install/templates/api_guardian.rb +5 -0
  55. data/lib/tasks/api_guardian_tasks.rake +4 -0
  56. data/spec/concerns/api_errors/handler_spec.rb +114 -0
  57. data/spec/concerns/api_request/validator_spec.rb +102 -0
  58. data/spec/dummy/README.rdoc +28 -0
  59. data/spec/dummy/Rakefile +6 -0
  60. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  61. data/spec/dummy/bin/bundle +3 -0
  62. data/spec/dummy/bin/rails +4 -0
  63. data/spec/dummy/bin/rake +4 -0
  64. data/spec/dummy/bin/setup +29 -0
  65. data/spec/dummy/config.ru +4 -0
  66. data/spec/dummy/config/application.rb +25 -0
  67. data/spec/dummy/config/boot.rb +5 -0
  68. data/spec/dummy/config/database.yml +13 -0
  69. data/spec/dummy/config/environment.rb +5 -0
  70. data/spec/dummy/config/environments/development.rb +41 -0
  71. data/spec/dummy/config/environments/production.rb +79 -0
  72. data/spec/dummy/config/environments/test.rb +42 -0
  73. data/spec/dummy/config/initializers/assets.rb +11 -0
  74. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  75. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  76. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  77. data/spec/dummy/config/initializers/inflections.rb +16 -0
  78. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  79. data/spec/dummy/config/initializers/session_store.rb +3 -0
  80. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  81. data/spec/dummy/config/locales/en.yml +23 -0
  82. data/spec/dummy/config/routes.rb +3 -0
  83. data/spec/dummy/config/secrets.yml +22 -0
  84. data/spec/dummy/db/schema.rb +104 -0
  85. data/spec/dummy/log/test.log +5031 -0
  86. data/spec/dummy/public/404.html +67 -0
  87. data/spec/dummy/public/422.html +67 -0
  88. data/spec/dummy/public/500.html +66 -0
  89. data/spec/dummy/public/favicon.ico +0 -0
  90. data/spec/factories/permissions.rb +6 -0
  91. data/spec/factories/role_permissions.rb +6 -0
  92. data/spec/factories/roles.rb +24 -0
  93. data/spec/factories/users.rb +11 -0
  94. data/spec/models/permission_spec.rb +28 -0
  95. data/spec/models/role_permission_spec.rb +27 -0
  96. data/spec/models/role_spec.rb +209 -0
  97. data/spec/models/user_spec.rb +44 -0
  98. data/spec/policies/application_policy_spec.rb +118 -0
  99. data/spec/policies/permission_policy_spec.rb +28 -0
  100. data/spec/policies/role_policy_spec.rb +28 -0
  101. data/spec/policies/user_policy_spec.rb +29 -0
  102. data/spec/requests/permissions_controller_spec.rb +19 -0
  103. data/spec/requests/registration_controller_spec.rb +151 -0
  104. data/spec/requests/roles_controller_spec.rb +75 -0
  105. data/spec/requests/users_controller_spec.rb +75 -0
  106. data/spec/spec_helper.rb +138 -0
  107. data/spec/stores/base_spec.rb +113 -0
  108. data/spec/stores/permission_store_spec.rb +2 -0
  109. data/spec/stores/role_store_spec.rb +12 -0
  110. data/spec/stores/user_store_spec.rb +144 -0
  111. data/spec/support/controller_concern_test_helpers.rb +21 -0
  112. data/spec/support/matchers.rb +37 -0
  113. data/spec/support/request_helpers.rb +111 -0
  114. metadata +508 -0
@@ -0,0 +1,75 @@
1
+ describe 'ApiGuardian::UsersController' do
2
+ # Authentication and permissions are tested elsewhere
3
+ before(:each) { @routes = ApiGuardian::Engine.routes }
4
+ before(:each) { seed_permissions('user') }
5
+ before(:each) { auth_user }
6
+ after(:each) { destroy_user }
7
+
8
+ describe 'RESOURCE /users' do
9
+ describe 'GET /' do
10
+ it 'returns a list of users' do
11
+ add_user_permission('user:read')
12
+
13
+ get '/users', {}, get_headers
14
+
15
+ expect(response).to have_http_status(:ok)
16
+ end
17
+ end
18
+
19
+ describe 'POST /' do
20
+ it 'creates a new user' do
21
+ add_user_permission('user:create')
22
+ user = create(:user)
23
+
24
+ allow_any_instance_of(ApiGuardian::Stores::UserStore).to receive(:create).and_return(user)
25
+
26
+ data = { data: { type: 'users', attributes: { name: '', default: false, permissions: [] } } }
27
+
28
+ post '/users', data.to_json, get_headers
29
+
30
+ expect(response).to have_http_status(:created)
31
+ end
32
+ end
33
+
34
+ describe 'GET /{:permission_id}' do
35
+ it 'gets a user by id' do
36
+ add_user_permission('user:read')
37
+ user = create(:user)
38
+
39
+ allow_any_instance_of(ApiGuardian::Stores::UserStore).to receive(:find).and_return(user)
40
+
41
+ get "/users/#{user.id}", {}, get_headers
42
+
43
+ expect(response).to have_http_status(:ok)
44
+ end
45
+ end
46
+
47
+ describe 'PATCH /{:permission_id}' do
48
+ it 'updates a user by id' do
49
+ add_user_permission('user:update')
50
+ user = create(:user)
51
+
52
+ allow_any_instance_of(ApiGuardian::Stores::UserStore).to receive(:update).and_return(user)
53
+
54
+ data = { data: { type: 'users', id: "#{user.id}", attributes: { name: Faker::Lorem.word, default: false } } }
55
+
56
+ patch "/users/#{user.id}", data.to_json, get_headers
57
+
58
+ expect(response).to have_http_status(:ok)
59
+ end
60
+ end
61
+
62
+ describe 'DELETE /{:permission_id}' do
63
+ it 'deletes a user by id' do
64
+ add_user_permission('user:delete')
65
+ user = create(:user)
66
+
67
+ allow_any_instance_of(ApiGuardian::Stores::UserStore).to receive(:destroy).and_return(user)
68
+
69
+ delete "/users/#{user.id}", {}, get_headers
70
+
71
+ expect(response).to have_http_status(:no_content)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,138 @@
1
+ # Configure Rails Environment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require 'capybara/rspec'
6
+ require 'pundit/rspec'
7
+ require 'rspec/rails'
8
+ require 'factory_girl_rails'
9
+ require 'simplecov'
10
+ require 'coveralls'
11
+ require 'faker'
12
+ require 'database_cleaner'
13
+ require "shoulda/matchers"
14
+ require 'support/matchers'
15
+ require 'support/request_helpers'
16
+ require 'rspec-activemodel-mocks'
17
+
18
+ Rails.backtrace_cleaner.remove_silencers!
19
+ ActiveRecord::Migration.maintain_test_schema!
20
+
21
+ if ENV['IS_CODESHIP']
22
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
23
+ Coveralls.wear!('rails')
24
+ end
25
+
26
+ SimpleCov.start do
27
+ add_group 'Controllers', 'app/controllers'
28
+ add_group 'Models', 'app/models'
29
+ add_group 'Serializers', 'app/serializers'
30
+ add_group 'Engine::Concerns', 'lib/api_guardian/concerns'
31
+ add_group 'Engine::Policies', 'lib/api_guardian/policies'
32
+ add_group 'Engine::Errors', 'lib/api_guardian/errors'
33
+ add_group 'Engine::Stores', 'lib/api_guardian/stores'
34
+ add_filter 'db'
35
+ add_filter 'spec'
36
+ end
37
+
38
+ # Eager load for code coverages purposes
39
+ Dir[Rails.root.parent.parent.join('app/controllers/**/*.rb')].each { |f| require f }
40
+ Dir[Rails.root.parent.parent.join('app/models/**/*.rb')].each { |f| require f }
41
+ Dir[Rails.root.parent.parent.join('app/serializers/**/*.rb')].each { |f| require f }
42
+ Dir[Rails.root.parent.parent.join('lib/**/*.rb')].each { |f| require f }
43
+
44
+ # Load support files
45
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
46
+
47
+ RSpec.configure do |config|
48
+ config.include Rails.application.routes.url_helpers
49
+
50
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
51
+ # examples within a transaction, remove the following line or assign false
52
+ # instead of true.
53
+ config.use_transactional_fixtures = false
54
+
55
+ # RSpec Rails can automatically mix in different behaviours to your tests
56
+ # based on their file location, for example enabling you to call `get` and
57
+ # `post` in specs under `spec/controllers`.
58
+ #
59
+ # You can disable this behaviour by removing the line below, and instead
60
+ # explicitly tag your specs with their type, e.g.:
61
+ #
62
+ # RSpec.describe UsersController, :type => :controller do
63
+ # # ...
64
+ # end
65
+ #
66
+ # The different available types are documented in the features, such as in
67
+ # https://relishapp.com/rspec/rspec-rails/docs
68
+ config.infer_spec_type_from_file_location!
69
+
70
+ # rspec-expectations config goes here. You can use an alternate
71
+ # assertion/expectation library such as wrong or the stdlib/minitest
72
+ # assertions if you prefer.
73
+ config.expect_with :rspec do |expectations|
74
+ # This option will default to `true` in RSpec 4. It makes the `description`
75
+ # and `failure_message` of custom matchers include text for helper methods
76
+ # defined using `chain`, e.g.:
77
+ # be_bigger_than(2).and_smaller_than(4).description
78
+ # # => "be bigger than 2 and smaller than 4"
79
+ # ...rather than:
80
+ # # => "be bigger than 2"
81
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
82
+ end
83
+
84
+ # rspec-mocks config goes here. You can use an alternate test double
85
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
86
+ config.mock_with :rspec do |mocks|
87
+ # Prevents you from mocking or stubbing a method that does not exist on
88
+ # a real object. This is generally recommended, and will default to
89
+ # `true` in RSpec 4.
90
+ mocks.verify_partial_doubles = true
91
+ end
92
+
93
+ # Use color in STDOUT
94
+ config.color = true
95
+
96
+ # Use color not only in STDOUT but also in pagers and files
97
+ config.tty = true
98
+
99
+ # Use the specified formatter
100
+ config.formatter = 'Fuubar' # :progress, :html, :textmate
101
+
102
+ config.order = "random"
103
+
104
+ config.before(:suite) do
105
+ DatabaseCleaner.clean_with(:truncation)
106
+ end
107
+
108
+ config.before(:each) do
109
+ DatabaseCleaner.strategy = :transaction
110
+ end
111
+
112
+ config.before(:each, js: true) do
113
+ DatabaseCleaner.strategy = :truncation
114
+ end
115
+
116
+ config.before(:each) do
117
+ DatabaseCleaner.start
118
+ end
119
+
120
+ config.after(:each) do
121
+ DatabaseCleaner.clean
122
+ end
123
+
124
+ config.include FactoryGirl::Syntax::Methods
125
+ config.include Requests::JsonHelpers, type: :request
126
+ config.include Requests::AuthHelpers, type: :request
127
+ config.include Requests::ErrorHelpers, type: :request
128
+ end
129
+
130
+ Shoulda::Matchers.configure do |config|
131
+ config.integrate do |with|
132
+ # Choose a test framework:
133
+ with.test_framework :rspec
134
+
135
+ # Choose one or more libraries:
136
+ with.library :rails
137
+ end
138
+ end
@@ -0,0 +1,113 @@
1
+ describe ApiGuardian::Stores::Base do
2
+ subject { ApiGuardian::Stores::Base.new(scope) }
3
+
4
+ let(:scope) { double(ApiGuardian::Policies::ApplicationPolicy::Scope) }
5
+
6
+ # Delegates
7
+ describe 'delegates' do
8
+ it { should delegate_method(:new).to(:resource_class) }
9
+ end
10
+
11
+ # Methods
12
+ describe 'methods' do
13
+ # using the user model to test the base store
14
+ let(:user) { double(ApiGuardian::User) }
15
+
16
+ before(:each) do
17
+ allow_any_instance_of(ApiGuardian::Stores::Base).to receive(:resource_class).and_return(user)
18
+ end
19
+
20
+ describe '#all' do
21
+ it 'returns objects via scope' do
22
+ expect(scope).to receive(:all)
23
+ subject.all
24
+ end
25
+ end
26
+
27
+ describe '#paginate' do
28
+ context 'returns objects via scope with pagination' do
29
+ it 'without arguments' do
30
+ expect(scope).to receive(:page).with(1).and_return(scope)
31
+ expect(scope).to receive(:per).with(25)
32
+
33
+ subject.paginate
34
+ end
35
+
36
+ it 'with arguments' do
37
+ expect(scope).to receive(:page).with(10).and_return(scope)
38
+ expect(scope).to receive(:per).with(50)
39
+
40
+ subject.paginate(10, 50)
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '#find' do
46
+ it 'errors on missing record' do
47
+ expect(user).to receive(:find).and_return(nil)
48
+
49
+ expect { subject.find(1) }.to raise_error ActiveRecord::RecordNotFound
50
+ end
51
+
52
+ it 'returns record if found' do
53
+ a_user = double(ApiGuardian::User)
54
+ expect(user).to receive(:find).and_return(a_user)
55
+
56
+ result = subject.find(1)
57
+
58
+ expect(result).to eq a_user
59
+ end
60
+ end
61
+
62
+ describe '#save' do
63
+ it 'saves a record' do
64
+ a_user = instance_double(ApiGuardian::User)
65
+ expect(a_user).to receive(:save!)
66
+
67
+ subject.save(a_user)
68
+ end
69
+ end
70
+
71
+ describe '#create' do
72
+ it 'errors on invalid record' do
73
+ attributes = {}
74
+ new_user = mock_model(ApiGuardian::User)
75
+ expect(new_user).to receive(:valid?).and_return(false)
76
+ expect(user).to receive(:new).with(attributes).and_return(new_user)
77
+
78
+ expect { subject.create(attributes) }.to raise_error ActiveRecord::RecordInvalid
79
+ end
80
+
81
+ it 'creates a record' do
82
+ attributes = {}
83
+ new_user = mock_model(ApiGuardian::User)
84
+ expect(new_user).to receive(:valid?).and_return(true)
85
+ expect(user).to receive(:new).with(attributes).and_return(new_user)
86
+ expect(subject).to receive(:save).with(new_user)
87
+
88
+ result = subject.create(attributes)
89
+
90
+ expect(result).to eq new_user
91
+ end
92
+ end
93
+
94
+ describe '#update' do
95
+ it 'updates a record' do
96
+ attributes = {}
97
+ a_user = instance_double(ApiGuardian::User)
98
+ expect(a_user).to receive(:update_attributes!).with(attributes)
99
+
100
+ subject.update(a_user, attributes)
101
+ end
102
+ end
103
+
104
+ describe '#destroy' do
105
+ it 'destroys a record' do
106
+ a_user = instance_double(ApiGuardian::User)
107
+ expect(a_user).to receive(:destroy!)
108
+
109
+ subject.destroy(a_user)
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,2 @@
1
+ describe ApiGuardian::Stores::PermissionStore do
2
+ end
@@ -0,0 +1,12 @@
1
+ describe ApiGuardian::Stores::RoleStore do
2
+ # Methods
3
+ describe 'methods' do
4
+ describe '.default_role' do
5
+ it 'should return the default role' do
6
+ expect(ApiGuardian::Role).to receive(:default_role)
7
+
8
+ ApiGuardian::Stores::RoleStore.default_role
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,144 @@
1
+ describe ApiGuardian::Stores::UserStore do
2
+ # Methods
3
+ describe 'methods' do
4
+ describe '#find_by_email' do
5
+ it 'should find user by email' do
6
+ expect(ApiGuardian::User).to receive(:find_by_email).with('test')
7
+
8
+ subject.find_by_email('test')
9
+ end
10
+ end
11
+
12
+ describe '#find_by_reset_password_token' do
13
+ it 'should find user by reset password token' do
14
+ expect(ApiGuardian::User).to receive(:find_by_reset_password_token).with('test')
15
+
16
+ subject.find_by_reset_password_token('test')
17
+ end
18
+ end
19
+
20
+ describe '#create' do
21
+ it 'should set default attributes before saving' do
22
+ attributes = {}
23
+ role = mock_model(ApiGuardian::Role)
24
+ expect(role).to receive(:id).and_return(1)
25
+ expect(ApiGuardian::Stores::RoleStore).to receive(:default_role).and_return(role)
26
+ expect_any_instance_of(ApiGuardian::User).to receive(:valid?).and_return(true)
27
+ expect_any_instance_of(ApiGuardian::User).to receive(:save!).and_return(true)
28
+
29
+ subject.create(attributes)
30
+
31
+ expect(attributes[:role_id]).to eq 1
32
+ expect(attributes[:email_confirmed_at]).to be_a(DateTime)
33
+ expect(attributes[:active]).to eq true
34
+ end
35
+ end
36
+
37
+ describe '.register' do
38
+ it 'fails on invalid attributes' do
39
+ role = mock_model(ApiGuardian::Role)
40
+ expect(role).to receive(:id).and_return(1)
41
+ expect(ApiGuardian::Stores::RoleStore).to receive(:default_role).and_return(role)
42
+ allow_any_instance_of(ApiGuardian::User).to receive(:valid?).and_return(false)
43
+
44
+ expect { ApiGuardian::Stores::UserStore.register({}) }.to raise_error ActiveRecord::RecordInvalid
45
+ end
46
+
47
+ it 'creates inactive user with unconfirmed email and default role' do
48
+ role = mock_model(ApiGuardian::Role)
49
+ user = create(:user)
50
+ expect(role).to receive(:id).and_return(1)
51
+ expect(ApiGuardian::Stores::RoleStore).to receive(:default_role).and_return(role)
52
+ expect(ApiGuardian::User).to receive(:new).and_return(user)
53
+ expect_any_instance_of(ApiGuardian::User).to receive(:valid?).and_return(true)
54
+ expect_any_instance_of(ApiGuardian::User).to receive(:save!).and_return(true)
55
+
56
+ result = ApiGuardian::Stores::UserStore.register({})
57
+
58
+ expect(result.role_id).to eq user.role_id
59
+ expect(result.active).to be false
60
+ expect(result.email_confirmed_at).to be nil
61
+ end
62
+ end
63
+
64
+ describe '.reset_password' do
65
+ it 'resets on valid email' do
66
+ user = mock_model(ApiGuardian::User)
67
+ expect(user).to receive(:reset_password_token=)
68
+ expect(user).to receive(:reset_password_sent_at=)
69
+ expect(user).to receive(:save)
70
+
71
+ allow_any_instance_of(ApiGuardian::Stores::UserStore).to receive(:find_by_email).and_return(user)
72
+
73
+ result = ApiGuardian::Stores::UserStore.reset_password('email')
74
+
75
+ expect(result).to be true
76
+ end
77
+
78
+ it 'fails on invalid email' do
79
+ allow_any_instance_of(ApiGuardian::Stores::UserStore).to receive(:find_by_email).and_return(nil)
80
+
81
+ result = ApiGuardian::Stores::UserStore.reset_password('email')
82
+
83
+ expect(result).to be false
84
+ end
85
+ end
86
+
87
+ describe '.complete_reset_password' do
88
+ it 'fails on missing user' do
89
+ allow_any_instance_of(ApiGuardian::Stores::UserStore).to receive(:find_by_reset_password_token).and_return(nil)
90
+ expect(ApiGuardian::Stores::UserStore.complete_reset_password({})).to be false
91
+ end
92
+
93
+ it 'fails if token doesn\'t match user email' do
94
+ user = mock_model(ApiGuardian::User)
95
+ expect(user).to receive(:email).and_return('bar')
96
+ allow_any_instance_of(ApiGuardian::Stores::UserStore).to receive(:find_by_reset_password_token).and_return(user)
97
+
98
+ expect { ApiGuardian::Stores::UserStore.complete_reset_password(email: 'foo') }.to raise_error ApiGuardian::Errors::ResetTokenUserMismatchError
99
+ end
100
+
101
+ it 'fails if token is expired' do
102
+ user = mock_model(ApiGuardian::User)
103
+ expect(user).to receive(:email).and_return('bar')
104
+ expect(user).to receive(:reset_password_token_valid?).and_return(false)
105
+ allow_any_instance_of(ApiGuardian::Stores::UserStore).to receive(:find_by_reset_password_token).and_return(user)
106
+
107
+ expect { ApiGuardian::Stores::UserStore.complete_reset_password(email: 'bar') }.to raise_error ApiGuardian::Errors::ResetTokenExpiredError
108
+ end
109
+
110
+ it 'fails if the new password is missing' do
111
+ user = mock_model(ApiGuardian::User)
112
+ allow_any_instance_of(ApiGuardian::Stores::UserStore).to receive(:find_by_reset_password_token).and_return(user)
113
+ expect(user).to receive(:email).and_return('foo')
114
+ expect(user).to receive(:reset_password_token_valid?).and_return(true)
115
+ expect(user).to receive(:password)
116
+ expect_any_instance_of(ActionController::Parameters).to receive(:fetch).with(:password, nil).and_return(nil)
117
+ expect { ApiGuardian::Stores::UserStore.complete_reset_password(ActionController::Parameters.new(email: 'foo')) }.to raise_error ActiveRecord::RecordInvalid
118
+ end
119
+
120
+ it 'resets on valid attributes' do
121
+ user = mock_model(ApiGuardian::User)
122
+ allow_any_instance_of(ApiGuardian::Stores::UserStore).to receive(:find_by_reset_password_token).and_return(user)
123
+ expect(user).to receive(:email).and_return('foo')
124
+ expect(user).to receive(:reset_password_token_valid?).and_return(true)
125
+ expect_any_instance_of(ActionController::Parameters).to receive(:fetch).with(:password, nil).and_return('password')
126
+ expect(user).to receive(:assign_attributes)
127
+ expect(user).to receive(:save!)
128
+ expect(user).to receive(:reset_password_token=)
129
+ expect(user).to receive(:reset_password_sent_at=)
130
+ expect(user).to receive(:save)
131
+
132
+ attributes = ActionController::Parameters.new(
133
+ email: 'foo',
134
+ password: 'password',
135
+ password_confirmation: 'password'
136
+ )
137
+
138
+ expect(ApiGuardian::Stores::UserStore.complete_reset_password(attributes)).to be true
139
+ expect(user.reset_password_token).to be nil
140
+ expect(user.reset_password_sent_at).to be nil
141
+ end
142
+ end
143
+ end
144
+ end