omniauth-mlh 1.0.0 → 4.0.1

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
  SHA256:
3
- metadata.gz: 622c9053382357ade0f161e78ed3f13ae01ae9f939b9bae87b43ff3281b618e2
4
- data.tar.gz: bc057ee83655fcac77978e15a21891013981853cebc8e7c235d08601468d8156
3
+ metadata.gz: 354aa7b0fc62afc09143d95359d8d9ee5f414bb8f38fbf5e9ee501ad2d547c98
4
+ data.tar.gz: d21f4b91b2a41f297350a6adedf60b33adf3390c255f1254b4741713b0f75042
5
5
  SHA512:
6
- metadata.gz: b4cd23553337c4dc6537a4c432c61d00f84334cd0d0372d7c3148b0c85bf175834a97ac9e213623e17541349f16b15e4489bfe0f8658302ae7fc01d71e4ad76f
7
- data.tar.gz: fb197ac156fb8a6ff76c8ce5b7e01ba016ff3859ad3741cd10da11932c274c7dc33c0f1dffbc766e0479cc4607d29621267e942ed1d26f22df37bdbb8f432050
6
+ metadata.gz: a6302f3601f4338a87ccbdd0e77044742dd99b06cfe985af75373e089fe90102f3babb72a6fe22dacd674e9178f407d30baf34bb85bf3059fead97d466f7b2c6
7
+ data.tar.gz: 0302bfd088521db00c27954a7bc0454219f46acc1112166655b16e449342839fcb385a73c223296c9a0ad05997ebe41bf9b432fdbb4d1f529cc382cbf2fcdc05
@@ -0,0 +1,30 @@
1
+ name: Push Gem
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - v*
7
+
8
+ jobs:
9
+ build:
10
+ name: Build + Publish
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v3
15
+ - name: Set up Ruby 3.2
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: '3.2'
19
+ bundler-cache: true
20
+
21
+ - name: Publish to RubyGems
22
+ run: |
23
+ mkdir -p $HOME/.gem
24
+ touch $HOME/.gem/credentials
25
+ chmod 0600 $HOME/.gem/credentials
26
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
27
+ gem build *.gemspec
28
+ gem push *.gem
29
+ env:
30
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_API_KEY}}"
@@ -0,0 +1,30 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - 'main'
7
+ pull_request:
8
+ branches:
9
+ - 'main'
10
+
11
+ jobs:
12
+ test:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ matrix:
16
+ ruby: ['3.2']
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - name: Set up Ruby ${{ matrix.ruby }}
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby }}
23
+ - name: Install dependencies
24
+ run: |
25
+ gem install bundler
26
+ bundle install
27
+ - name: Run Spec
28
+ run: bundle exec rake spec
29
+ - name: Run Rubocop
30
+ run: bundle exec rake rubocop
data/.rubocop.yml CHANGED
@@ -1,12 +1,28 @@
1
- AllCops:
2
- TargetRubyVersion: '2.2.0'
1
+ require:
2
+ - rubocop-rspec
3
+ - rubocop-performance
3
4
 
4
- Naming/FileName:
5
+ AllCops:
6
+ # Ruby 2.7 is the MINIMUM Ruby version supported
7
+ TargetRubyVersion: '2.7.0'
5
8
  Exclude:
6
- - 'lib/omniauth-mlh.rb'
9
+ - vendor/**/*
7
10
 
8
- Metrics/BlockLength:
9
- Exclude:
10
- - 'Rakefile'
11
- - '**/*.rake'
12
- - 'spec/**/*'
11
+ Style/WordArray:
12
+ Description: Force arrays of words to use bracket notation instead of %w
13
+ EnforcedStyle: brackets
14
+ Enabled: true
15
+
16
+ Style/SymbolArray:
17
+ Description: Force symbol arrays to use bracket notation instead of %i
18
+ EnforcedStyle: brackets
19
+ Enabled: true
20
+
21
+ Style/RegexpLiteral:
22
+ Description: Allow forward slashes within regular expressions
23
+ AllowInnerSlashes: true
24
+ Enabled: true
25
+
26
+ RSpec/MultipleExpectations:
27
+ Description: Allow tests to contain multiple expectations
28
+ Enabled: false
data/.travis.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 3.0.5
3
+ - 2.2.0
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,27 @@
1
+ # Contributing Guidelines
2
+
3
+ Thank you for considering contributing to omniauth-mlh.
4
+
5
+ ## Contributor Checklist
6
+
7
+ - Fork the Repo ( https://github.com/mlh/omniauth-mlh/fork )
8
+ - Create your feature branch (`git checkout -b my-new-feature`)
9
+ - Commit your changes (`git commit -am 'Add some feature'`)
10
+ - Push to the branch (`git push origin my-new-feature`)
11
+ - Create a new Pull Request
12
+
13
+ ### Running tests
14
+
15
+ Following command can be used to run the test
16
+
17
+ ```bash
18
+ $ bundle exec rake spec
19
+ ```
20
+
21
+ ## Code quality tools
22
+
23
+ Code quality is enforced across the entire gem with Rubocop:
24
+
25
+ ```bash
26
+ $ bundle exec rubocop
27
+ ```
data/Gemfile CHANGED
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in omniauth-mlh.gemspec
4
6
  gemspec
7
+ gem 'activesupport'
data/README.md CHANGED
@@ -1,18 +1,19 @@
1
- # MLH/my-mlh-omniauth
1
+ # MLH/omniauth-mlh
2
2
 
3
- [![Build Status](https://travis-ci.org/MLH/my-mlh-omniauth.svg?branch=master)](https://travis-ci.org/MLH/my-mlh-omniauth)
3
+ [![Gem Version](https://badge.fury.io/rb/omniauth-mlh.svg)](https://badge.fury.io/rb/omniauth-mlh)
4
+ [![Test](https://github.com/MLH/omniauth-mlh/actions/workflows/test.yml/badge.svg)](https://github.com/MLH/omniauth-mlh/actions/workflows/test.yml)
4
5
 
5
6
  This is the official [OmniAuth](https://github.com/omniauth/omniauth) strategy for
6
- authenticating with [MyMLH](https://my.mlh.io). To use it, you'll need to
7
- [register an application](https://my.mlh.io/oauth/applications) and obtain a OAuth Application ID and Secret from MyMLH.
7
+ authenticating with [MyMLH](https://my.mlh.io) in Ruby applications. To use it, you'll need to
8
+ [register an application](https://my.mlh.io/developers) and obtain a OAuth Application ID and Secret from MyMLH.
8
9
 
9
- It now supports MyMLH API V3. [Read the MyMLH V3 docs here](https://my.mlh.io/docs).
10
+ It now supports MyMLH API V4. [Read the MyMLH V4 docs here](https://my.mlh.io/developers/docs).
10
11
 
11
12
  Once you have done so, you can follow the instructions below:
12
13
 
13
14
  ## Requirements
14
15
 
15
- You need to have at least Ruby 3.0.5 to use this gem.
16
+ This Gem requires your Ruby version to be at least `3.2.0`.
16
17
 
17
18
  ## Installation
18
19
 
@@ -32,9 +33,13 @@ Or install it yourself as:
32
33
 
33
34
  ## Usage (Rack)
34
35
 
36
+ You can find a list of potential scopes and expandable fields in the [docs](https://my.mlh.io/developers/docs). The below defaults are provided simply as an example.
37
+
35
38
  ```ruby
36
39
  use OmniAuth::Builder do
37
- provider :mlh, ENV['MY_MLH_KEY'], ENV['MY_MLH_SECRET'], scope: 'default email birthday'
40
+ provider :mlh, ENV['MY_MLH_KEY'], ENV['MY_MLH_SECRET'],
41
+ scope: 'public offline_access user:read:profile',
42
+ expand_fields: ['education']
38
43
  end
39
44
  ```
40
45
 
@@ -44,17 +49,30 @@ end
44
49
  # config/devise.rb
45
50
 
46
51
  Devise.setup do |config|
47
- config.provider :mlh, ENV['MY_MLH_KEY'], ENV['MY_MLH_SECRET'], scope: 'default email birthday'
52
+ config.provider :mlh, ENV['MY_MLH_KEY'], ENV['MY_MLH_SECRET'],
53
+ scope: 'public offline_access user:read:profile',
54
+ expand_fields: ['education']
48
55
  end
49
56
  ```
50
57
 
58
+ ## Accessing User Data
59
+ Once a user has been authorized and you have received a token in your callback, you may access the scoped information for that user via the info key on the request data, as per the below example from a simple Sinatra app:
60
+
61
+ ```ruby
62
+ get '/auth/mlh/callback' do
63
+ auth = request.env['omniauth.auth']
64
+ user_data = auth['info']
65
+ first_name = user_data['first_name']
66
+ erb "
67
+ <h1>Hello #{first_name}</h1>"
68
+ end
69
+ ```
70
+
71
+ You can find the full User object in the [docs](https://my.mlh.io/developers/docs).
72
+
51
73
  ## Contributing
52
74
 
53
- 1. Fork it ( https://github.com/mlh/my-mlh-omniauth/fork )
54
- 2. Create your feature branch (`git checkout -b my-new-feature`)
55
- 3. Commit your changes (`git commit -am 'Add some feature'`)
56
- 4. Push to the branch (`git push origin my-new-feature`)
57
- 5. Create a new Pull Request
75
+ For guidance on setting up a development environment and how to make a contribution to omniauth-mlh, see the [contributing guidelines](https://github.com/MLH/omniauth-mlh/blob/main/CONTRIBUTING.md).
58
76
 
59
77
  ## Credit
60
78
 
@@ -63,6 +81,6 @@ We used part of [datariot/omniauth-paypal](http://github.com/datariot/omniauth-p
63
81
  ## Questions?
64
82
 
65
83
  Have a question about the API or this library? Start by checking out the
66
- [official MyMLH documentation](https://my.mlh.io/docs). If you still can't
84
+ [official MyMLH documentation](https://my.mlh.io/developers/docs). If you still can't
67
85
  find an answer, tweet at [@MLHacks](http://twitter.com/mlhacks) or drop an
68
86
  email to [engineering@mlh.io](mailto:engineering@mlh.io).
data/Rakefile CHANGED
@@ -1,8 +1,12 @@
1
1
  #!/usr/bin/env rake
2
+ # frozen_string_literal: true
3
+
2
4
  require 'bundler/gem_tasks'
3
5
  require 'rspec/core/rake_task'
6
+ require 'rubocop/rake_task'
4
7
 
5
8
  RSpec::Core::RakeTask.new
9
+ RuboCop::RakeTask.new
6
10
 
7
11
  desc 'Run specs'
8
12
  task default: :spec
@@ -5,42 +5,99 @@ require 'ostruct'
5
5
 
6
6
  module OmniAuth
7
7
  module Strategies
8
+ # MLH OAuth2 Strategy
9
+ #
10
+ # @example Basic Usage
11
+ # use OmniAuth::Builder do
12
+ # provider :mlh, ENV['MLH_KEY'], ENV['MLH_SECRET']
13
+ # end
14
+ #
15
+ # @example With Expandable Fields
16
+ # use OmniAuth::Builder do
17
+ # provider :mlh, ENV['MLH_KEY'], ENV['MLH_SECRET'],
18
+ # expand_fields: ['education', 'professional_experience']
19
+ # end
20
+ #
21
+ # @example With Refresh Tokens (offline access)
22
+ # use OmniAuth::Builder do
23
+ # provider :mlh, ENV['MLH_KEY'], ENV['MLH_SECRET'],
24
+ # scope: 'user:read:profile offline_access'
25
+ # end
26
+ #
27
+ # When offline_access scope is requested, the strategy will include
28
+ # refresh_token in the credentials hash if provided by the server.
8
29
  class MLH < OmniAuth::Strategies::OAuth2 # :nodoc:
9
30
  option :name, :mlh
10
31
 
11
32
  option :client_options, {
12
33
  site: 'https://my.mlh.io',
13
34
  authorize_url: 'oauth/authorize',
14
- token_url: 'oauth/token'
35
+ token_url: 'oauth/token',
36
+ auth_scheme: :request_body # Change from basic auth to request body
15
37
  }
16
38
 
39
+ # Support expandable fields through options
40
+ option :expand_fields, []
41
+
17
42
  uid { data[:id] }
18
43
 
19
44
  info do
20
- data.slice(
21
- :email,
22
- :created_at,
23
- :updated_at,
24
- :first_name,
25
- :last_name,
26
- :level_of_study,
27
- :major,
28
- :date_of_birth,
29
- :gender,
30
- :phone_number,
31
- :profession_type,
32
- :company_name,
33
- :company_title,
34
- :scopes,
35
- :school
36
- )
45
+ {
46
+ # Basic fields
47
+ id: data[:id],
48
+ created_at: data[:created_at],
49
+ updated_at: data[:updated_at],
50
+ first_name: data[:first_name],
51
+ last_name: data[:last_name],
52
+ email: data[:email],
53
+ phone_number: data[:phone_number],
54
+ roles: data[:roles],
55
+
56
+ # Expandable fields
57
+ profile: data[:profile],
58
+ address: data[:address],
59
+ social_profiles: data[:social_profiles],
60
+ professional_experience: data[:professional_experience],
61
+ education: data[:education],
62
+ identifiers: data[:identifiers]
63
+ }
37
64
  end
38
65
 
39
66
  def data
40
- @data ||= begin
41
- access_token.get('/api/v3/user.json').parsed.deep_symbolize_keys[:data]
42
- rescue StandardError
43
- {}
67
+ @data ||= fetch_and_process_data.compact
68
+ rescue StandardError
69
+ {}
70
+ end
71
+
72
+ private
73
+
74
+ def fetch_and_process_data
75
+ response = access_token.get(build_api_url)
76
+ data = JSON.parse(response.body, symbolize_names: true)
77
+ return {} unless data.is_a?(Hash)
78
+
79
+ symbolize_nested_arrays(data)
80
+ end
81
+
82
+ def build_api_url
83
+ url = 'https://api.mlh.com/v4/users/me'
84
+ expand_fields = options[:expand_fields] || []
85
+ return url if expand_fields.empty?
86
+
87
+ expand_query = expand_fields.map { |f| "expand[]=#{f}" }.join('&')
88
+ "#{url}?#{expand_query}"
89
+ end
90
+
91
+ def symbolize_nested_arrays(hash)
92
+ hash.transform_values do |value|
93
+ case value
94
+ when Hash
95
+ symbolize_nested_arrays(value)
96
+ when Array
97
+ value.map { |item| item.is_a?(Hash) ? symbolize_nested_arrays(item) : item }
98
+ else
99
+ value
100
+ end
44
101
  end
45
102
  end
46
103
  end
@@ -48,5 +105,5 @@ module OmniAuth
48
105
  end
49
106
 
50
107
  OmniAuth.config.add_camelization 'mlh', 'MLH'
51
- OmniAuth.config.allowed_request_methods = %i[post get]
108
+ OmniAuth.config.allowed_request_methods = [:post, :get]
52
109
  OmniAuth.config.silence_get_warning = true
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OmniAuth
4
4
  module MLH
5
- VERSION = '1.0.0'
5
+ VERSION = '4.0.1'
6
6
  end
7
7
  end
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support'
4
3
  require 'omniauth-mlh/version'
5
4
  require 'omniauth/strategies/mlh'
data/omniauth-mlh.gemspec CHANGED
@@ -8,15 +8,15 @@ require 'omniauth-mlh/version'
8
8
  Gem::Specification.new do |spec|
9
9
  spec.name = 'omniauth-mlh'
10
10
  spec.version = OmniAuth::MLH::VERSION
11
- spec.authors = ['Swift']
12
- spec.email = ['swift@mlh.io']
11
+ spec.authors = ['Major League Hacking (MLH)']
12
+ spec.email = ['hi@mlh.io']
13
13
 
14
14
  spec.summary = 'Official OmniAuth strategy for MyMLH.'
15
15
  spec.description = 'Official OmniAuth strategy for MyMLH.'
16
16
  spec.homepage = 'http://github.com/mlh/omniauth-mlh'
17
17
  spec.license = 'MIT'
18
18
 
19
- spec.required_ruby_version = '>= 2.2.0'
19
+ spec.required_ruby_version = '>= 2.7.0'
20
20
 
21
21
  spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
22
22
  spec.files = `git ls-files`.split("\n")
@@ -26,13 +26,13 @@ Gem::Specification.new do |spec|
26
26
  spec.add_dependency 'oauth2', '~> 2.0.9'
27
27
  spec.add_dependency 'omniauth', '~> 2.1.1'
28
28
  spec.add_dependency 'omniauth-oauth2', '~> 1.8.0'
29
- spec.add_dependency 'omniauth-rails_csrf_protection', '~> 1.0.1'
30
-
31
- spec.add_dependency 'activesupport'
32
29
 
33
30
  spec.add_development_dependency 'rack-test'
34
- spec.add_development_dependency 'rake', '~> 10.5'
35
- spec.add_development_dependency 'rspec', '~> 2.7'
31
+ spec.add_development_dependency 'rake', '~> 12.3.3'
32
+ spec.add_development_dependency 'rspec', '~> 3.10'
33
+ spec.add_development_dependency 'rubocop', '~> 1.0'
34
+ spec.add_development_dependency 'rubocop-performance'
35
+ spec.add_development_dependency 'rubocop-rspec'
36
36
  spec.add_development_dependency 'simplecov'
37
37
  spec.add_development_dependency 'webmock'
38
38
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe OmniAuth::MLH do
6
+ it 'has a version number' do
7
+ expect(OmniAuth::MLH::VERSION).not_to be_nil
8
+ expect(OmniAuth::MLH::VERSION).to eq('4.0.1')
9
+ end
10
+
11
+ it 'loads the MLH strategy' do
12
+ expect(OmniAuth::Strategies::MLH).to be_a(Class)
13
+ expect(OmniAuth::Strategies::MLH.superclass).to eq(OmniAuth::Strategies::OAuth2)
14
+ end
15
+ end
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe OmniAuth::Strategies::MLH do
6
+ let(:strategy) { described_class.new(app, 'client_id', 'client_secret') }
7
+
8
+ let(:app) { ->(_env) { [200, {}, ['Hello.']] } }
9
+ let(:access_token) { instance_double(OAuth2::AccessToken, options: {}) }
10
+
11
+ before do
12
+ allow(strategy).to receive(:access_token).and_return(access_token)
13
+ end
14
+
15
+ shared_context 'with oauth response' do |response_data|
16
+ let(:oauth_response) do
17
+ instance_double(OAuth2::Response,
18
+ body: response_data.to_json,
19
+ parsed: response_data)
20
+ end
21
+ before do
22
+ allow(access_token).to receive(:get)
23
+ .with('https://api.mlh.com/v4/users/me')
24
+ .and_return(oauth_response)
25
+ end
26
+ end
27
+
28
+ describe '#data' do
29
+ context 'with expandable fields' do
30
+ let(:response) do
31
+ instance_double(OAuth2::Response, body: {}.to_json, parsed: {})
32
+ end
33
+ let(:expand_url) { 'https://api.mlh.com/v4/users/me?expand[]=profile&expand[]=education' }
34
+
35
+ before do
36
+ allow(strategy).to receive(:options).and_return(expand_fields: ['profile', 'education'])
37
+ allow(access_token).to receive(:get).with(expand_url).and_return(response)
38
+ end
39
+
40
+ it 'constructs the correct URL with expand parameters' do
41
+ strategy.data
42
+
43
+ expect(access_token).to have_received(:get).with(expand_url)
44
+ end
45
+
46
+ it 'returns an empty hash for empty response' do
47
+ expect(strategy.data).to eq({})
48
+ end
49
+ end
50
+
51
+ context 'with v4 API nested profile data' do
52
+ include_context 'with oauth response', {
53
+ 'id' => 'test-id',
54
+ 'first_name' => 'Jane',
55
+ 'profile' => {
56
+ 'age' => 22,
57
+ 'gender' => 'Female'
58
+ }
59
+ }
60
+
61
+ it 'correctly parses nested profile data' do
62
+ result = strategy.data
63
+
64
+ expect(result).to be_a(Hash)
65
+ expect(result[:profile]).to eq({ age: 22, gender: 'Female' })
66
+ end
67
+ end
68
+
69
+ context 'with v4 API empty response' do
70
+ include_context 'with oauth response', {}
71
+
72
+ it 'returns an empty hash for empty data' do
73
+ expect(strategy.data).to eq({})
74
+ end
75
+ end
76
+
77
+ context 'with v4 API complex data structures' do
78
+ include_context 'with oauth response', {
79
+ 'id' => 'test-id',
80
+ 'education' => [{
81
+ 'school' => {
82
+ 'name' => 'Test University',
83
+ 'location' => 'Test City'
84
+ },
85
+ 'graduation_year' => 2024
86
+ }],
87
+ 'social_profiles' => [
88
+ { 'platform' => 'github', 'url' => 'https://github.com' },
89
+ 'https://twitter.com'
90
+ ],
91
+ 'professional_experience' => [{
92
+ 'company' => 'Tech Corp',
93
+ 'positions' => [
94
+ { 'title' => 'Engineer', 'years' => [2022, 2023] }
95
+ ]
96
+ }]
97
+ }
98
+
99
+ it 'correctly processes complex nested structures' do
100
+ result = strategy.data
101
+
102
+ expect(result).to be_a(Hash)
103
+ expect(result[:education].first[:school]).to eq({ name: 'Test University', location: 'Test City' })
104
+ expect(result[:social_profiles]).to eq([{ platform: 'github', url: 'https://github.com' }, 'https://twitter.com'])
105
+ expect(result[:professional_experience].first[:positions].first[:years]).to eq([2022, 2023])
106
+ end
107
+ end
108
+
109
+ context 'with v4 API nil and empty values' do
110
+ include_context 'with oauth response', {
111
+ 'id' => 'test-id',
112
+ 'first_name' => 'Jane',
113
+ 'last_name' => nil,
114
+ 'profile' => {
115
+ 'age' => 22,
116
+ 'gender' => nil,
117
+ 'location' => {
118
+ 'city' => nil,
119
+ 'country' => 'USA'
120
+ }
121
+ },
122
+ 'education' => nil,
123
+ 'social_profiles' => {
124
+ 'github' => {},
125
+ 'linkedin' => {}
126
+ }
127
+ }
128
+
129
+ it 'handles nil values correctly' do
130
+ result = strategy.data
131
+
132
+ expect(result[:last_name]).to be_nil
133
+ expect(result[:profile][:gender]).to be_nil
134
+ expect(result[:profile][:location]).to eq({ city: nil, country: 'USA' })
135
+ expect(result[:education]).to be_nil
136
+ end
137
+
138
+ it 'handles empty hash structures' do
139
+ result = strategy.data
140
+
141
+ expect(result[:social_profiles]).to eq({ github: {}, linkedin: {} })
142
+ end
143
+ end
144
+
145
+ context 'with API error' do
146
+ it 'returns empty hash on error' do
147
+ allow(access_token).to receive(:get).and_raise(StandardError)
148
+
149
+ expect(strategy.data).to eq({})
150
+ end
151
+ end
152
+ end
153
+
154
+ describe '#uid' do
155
+ context 'with valid data' do
156
+ it 'returns the id from the data hash' do
157
+ allow(strategy).to receive(:data).and_return({ id: 'test-123' })
158
+ expect(strategy.uid).to eq('test-123')
159
+ end
160
+ end
161
+
162
+ context 'with missing id' do
163
+ it 'returns nil when id is not present' do
164
+ allow(strategy).to receive(:data).and_return({})
165
+ expect(strategy.uid).to be_nil
166
+ end
167
+ end
168
+ end
169
+
170
+ describe '#info' do
171
+ let(:user_data) do
172
+ {
173
+ first_name: 'Jane',
174
+ last_name: 'Hacker',
175
+ email: 'jane@example.com',
176
+ roles: ['hacker']
177
+ }
178
+ end
179
+
180
+ before do
181
+ allow(strategy).to receive(:data).and_return(user_data)
182
+ end
183
+
184
+ it 'includes basic user information' do
185
+ expect(strategy.info).to include(
186
+ first_name: 'Jane',
187
+ last_name: 'Hacker',
188
+ email: 'jane@example.com'
189
+ )
190
+ end
191
+
192
+ it 'includes user roles' do
193
+ expect(strategy.info[:roles]).to eq(['hacker'])
194
+ end
195
+ end
196
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,23 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
4
-
5
- require 'simplecov'
6
- SimpleCov.start
7
-
8
4
  require 'bundler/setup'
9
- require 'rspec'
10
- require 'rack/test'
11
5
  require 'webmock/rspec'
6
+ require 'simplecov'
7
+ require 'active_support'
8
+ require 'active_support/core_ext/hash'
9
+
10
+ # Configure SimpleCov before requiring our library
11
+ SimpleCov.start do
12
+ add_filter '/spec/'
13
+ add_filter '/vendor/'
14
+ track_files 'lib/**/*.rb'
15
+ enable_coverage :branch
16
+ end
17
+
12
18
  require 'omniauth'
13
- require 'omniauth-mlh'
19
+ require 'omniauth-oauth2'
20
+ require 'omniauth_mlh'
21
+ require 'omniauth/strategies/mlh'
14
22
 
15
- Dir[File.expand_path('support/**/*', __dir__)].sort.each { |f| require f }
23
+ Dir[File.expand_path('support/**/*.rb', __dir__)].sort.each { |f| require f }
16
24
 
17
25
  RSpec.configure do |config|
18
- config.include WebMock::API
19
- config.include Rack::Test::Methods
20
- config.extend OmniAuth::Test::StrategyMacros, type: :strategy
21
-
22
- OmniAuth.config.test_mode = true
26
+ config.expect_with :rspec do |c|
27
+ c.syntax = :expect
28
+ end
23
29
  end
30
+
31
+ WebMock.disable_net_connect!(allow_localhost: true)
@@ -1,41 +1,84 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Credit: https://github.com/datariot/omniauth-paypal/blob/master/spec/support/shared_examples.rb
4
- # NOTE it would be useful if this lived in omniauth-oauth2 eventually
5
-
6
- shared_examples 'an oauth2 strategy' do
7
- describe '#client' do
8
- it 'should be initialized with symbolized client_options' do
9
- @options = { client_options: { 'authorize_url' => 'https://example.com' } }
10
- expect(subject.client.options[:authorize_url]).to eq('https://example.com')
3
+ RSpec.shared_examples 'basic data retrieval tests' do
4
+ context 'with successful API response' do
5
+ before do
6
+ allow(access_token).to receive(:get)
7
+ .with('https://api.mlh.com/v4/users/me')
8
+ .and_return(instance_double(OAuth2::Response, parsed: { 'data' => base_user_data }))
9
+ end
10
+
11
+ it 'returns symbolized user data' do
12
+ expect(strategy.data).to include(
13
+ id: 'c2ac35c6-aa8c-11ed-afa1-0242ac120002',
14
+ first_name: 'Jane'
15
+ )
11
16
  end
12
17
  end
18
+ end
13
19
 
14
- describe '#authorize_params' do
15
- it 'should include any authorize params passed in the :authorize_params option' do
16
- @options = { authorize_params: { foo: 'bar', baz: 'zip' } }
17
- expect(subject.authorize_params['foo']).to eq('bar')
18
- expect(subject.authorize_params['baz']).to eq('zip')
20
+ RSpec.shared_examples 'expandable fields tests' do
21
+ let(:expanded_user_data) do
22
+ base_user_data.merge(
23
+ 'profile' => {
24
+ 'age' => 22,
25
+ 'gender' => 'Female'
26
+ },
27
+ 'education' => [{
28
+ 'current' => true,
29
+ 'school_name' => 'Hacker University',
30
+ 'major' => 'Computer Science'
31
+ }]
32
+ )
33
+ end
34
+
35
+ context 'with expandable fields' do
36
+ before do
37
+ allow(access_token).to receive(:get)
38
+ .with('https://api.mlh.com/v4/users/me?expand[]=profile&expand[]=education')
39
+ .and_return(instance_double(OAuth2::Response, parsed: { 'data' => expanded_user_data }))
40
+ allow(strategy).to receive(:options).and_return(expand_fields: ['profile', 'education'])
19
41
  end
20
42
 
21
- it 'should include top-level options that are marked as :authorize_options' do
22
- @options = { authorize_options: %i[scope foo], scope: 'bar', foo: 'baz' }
23
- expect(subject.authorize_params['scope']).to eq('bar')
24
- expect(subject.authorize_params['foo']).to eq('baz')
43
+ it 'fetches expanded fields' do
44
+ expect(strategy.data).to include(
45
+ profile: include(age: 22),
46
+ education: include(hash_including(school_name: 'Hacker University'))
47
+ )
25
48
  end
26
49
  end
50
+ end
27
51
 
28
- describe '#token_params' do
29
- it 'should include any token params passed in the :token_params option' do
30
- @options = { token_params: { foo: 'bar', baz: 'zip' } }
31
- expect(subject.token_params['foo']).to eq('bar')
32
- expect(subject.token_params['baz']).to eq('zip')
52
+ RSpec.shared_examples 'error handling tests' do
53
+ context 'when API returns error' do
54
+ before do
55
+ allow(access_token).to receive(:get).and_raise(StandardError)
33
56
  end
34
57
 
35
- it 'should include top-level options that are marked as :token_options' do
36
- @options = { token_options: %i[scope foo], scope: 'bar', foo: 'baz' }
37
- expect(subject.token_params['scope']).to eq('bar')
38
- expect(subject.token_params['foo']).to eq('baz')
58
+ it 'returns empty hash on error' do
59
+ expect(strategy.data).to eq({})
39
60
  end
40
61
  end
41
62
  end
63
+
64
+ RSpec.shared_examples 'info hash tests' do
65
+ let(:user_info) do
66
+ {
67
+ id: 'c2ac35c6-aa8c-11ed-afa1-0242ac120002',
68
+ first_name: 'Jane',
69
+ last_name: 'Hacker',
70
+ email: 'jane.hacker@example.com'
71
+ }
72
+ end
73
+
74
+ before do
75
+ allow(strategy).to receive(:data).and_return(user_info)
76
+ end
77
+
78
+ it 'returns formatted info hash' do
79
+ expect(strategy.info).to include(
80
+ name: 'Jane Hacker',
81
+ email: 'jane.hacker@example.com'
82
+ )
83
+ end
84
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-mlh
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 4.0.1
5
5
  platform: ruby
6
6
  authors:
7
- - Swift
8
- autorequire:
7
+ - Major League Hacking (MLH)
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-30 00:00:00.000000000 Z
11
+ date: 2024-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oauth2
@@ -53,75 +53,89 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.8.0
55
55
  - !ruby/object:Gem::Dependency
56
- name: omniauth-rails_csrf_protection
56
+ name: rack-test
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 1.0.1
62
- type: :runtime
61
+ version: '0'
62
+ type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 1.0.1
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: activesupport
70
+ name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :runtime
75
+ version: 12.3.3
76
+ type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: 12.3.3
83
83
  - !ruby/object:Gem::Dependency
84
- name: rack-test
84
+ name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '3.10'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: '3.10'
97
97
  - !ruby/object:Gem::Dependency
98
- name: rake
98
+ name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '10.5'
103
+ version: '1.0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '10.5'
110
+ version: '1.0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: rspec
112
+ name: rubocop-performance
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '2.7'
117
+ version: '0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - "~>"
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
123
137
  - !ruby/object:Gem::Version
124
- version: '2.7'
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: simplecov
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -152,31 +166,35 @@ dependencies:
152
166
  version: '0'
153
167
  description: Official OmniAuth strategy for MyMLH.
154
168
  email:
155
- - swift@mlh.io
169
+ - hi@mlh.io
156
170
  executables: []
157
171
  extensions: []
158
172
  extra_rdoc_files: []
159
173
  files:
174
+ - ".github/workflows/gem-push.yml"
175
+ - ".github/workflows/test.yml"
160
176
  - ".gitignore"
161
177
  - ".rspec"
162
178
  - ".rubocop.yml"
163
179
  - ".travis.yml"
180
+ - CONTRIBUTING.md
164
181
  - Gemfile
165
182
  - LICENSE.txt
166
183
  - README.md
167
184
  - Rakefile
168
- - lib/omniauth-mlh.rb
169
185
  - lib/omniauth-mlh/version.rb
170
186
  - lib/omniauth/strategies/mlh.rb
187
+ - lib/omniauth_mlh.rb
171
188
  - omniauth-mlh.gemspec
172
- - spec/omniauth/mlh_spec.rb
189
+ - spec/omni_auth/mlh_spec.rb
190
+ - spec/omni_auth/strategies/mlh_spec.rb
173
191
  - spec/spec_helper.rb
174
192
  - spec/support/shared_examples.rb
175
193
  homepage: http://github.com/mlh/omniauth-mlh
176
194
  licenses:
177
195
  - MIT
178
196
  metadata: {}
179
- post_install_message:
197
+ post_install_message:
180
198
  rdoc_options: []
181
199
  require_paths:
182
200
  - lib
@@ -184,18 +202,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
184
202
  requirements:
185
203
  - - ">="
186
204
  - !ruby/object:Gem::Version
187
- version: 2.2.0
205
+ version: 2.7.0
188
206
  required_rubygems_version: !ruby/object:Gem::Requirement
189
207
  requirements:
190
208
  - - ">="
191
209
  - !ruby/object:Gem::Version
192
210
  version: '0'
193
211
  requirements: []
194
- rubygems_version: 3.2.33
195
- signing_key:
212
+ rubygems_version: 3.4.19
213
+ signing_key:
196
214
  specification_version: 4
197
215
  summary: Official OmniAuth strategy for MyMLH.
198
- test_files:
199
- - spec/omniauth/mlh_spec.rb
200
- - spec/spec_helper.rb
201
- - spec/support/shared_examples.rb
216
+ test_files: []
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe OmniAuth::MLH do
6
- subject do
7
- OmniAuth::Strategies::MLH.new(nil, @options || {})
8
- end
9
-
10
- it_should_behave_like 'an oauth2 strategy'
11
-
12
- describe '#client' do
13
- it 'has correct MyMLH site' do
14
- expect(subject.client.site).to eq('https://my.mlh.io')
15
- end
16
-
17
- it 'has correct authorize url' do
18
- expect(subject.client.options[:authorize_url]).to eq('oauth/authorize')
19
- end
20
-
21
- it 'has correct token url' do
22
- expect(subject.client.options[:token_url]).to eq('oauth/token')
23
- end
24
-
25
- it 'runs the setup block if passed one' do
26
- counter = ''
27
- @options = { setup: proc { |_env| counter = 'ok' } }
28
- subject.setup_phase
29
- expect(counter).to eq('ok')
30
- end
31
- end
32
-
33
- describe '#callback_path' do
34
- it 'has the correct callback path' do
35
- expect(subject.callback_path).to eq('/auth/mlh/callback')
36
- end
37
- end
38
- end