WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 113a8cb

Browse files
jonmarkgodevin-ai-integration[bot]
authored andcommitted
[DEV-2013] V4 updates (#16)
* Update to MLH API v4 - Update endpoints to use v4 API - Add support for expandable fields - Update scopes to use new granular system - Configure auth params to use request body - Document offline_access scope for refresh tokens * Update to MLH API v4 - Update endpoints to use v4 API - Add support for expandable fields - Update scopes to use new granular system - Configure auth params to use request body - Document offline_access scope for refresh tokens - Add deep symbolization for nested arrays - Include all fields from user object schema * test: Add comprehensive test coverage for v4 API - Added ActiveSupport for deep symbolization - Updated test structure for v4 API compatibility - Improved SimpleCov configuration - Increased line coverage to 80.49% - Added branch coverage tracking Link to Devin run: https://preview.devin.ai/devin/3be39d31a19840d9ae7b7bebabe8c9c6 * test: Increase test coverage from 80.49% to 87.8% - Add tests for complex nested arrays and hashes - Add tests for hash pruning with nil values - Add tests for completely empty hashes - Add tests for version constant and module loading - Add explicit tests for uid method - Fix spec_helper.rb to properly load all files * Replace subject with strategy in tests to fix RSpec/NamedSubject violations * Apply RuboCop auto-corrections for code style improvements * Fix RuboCop offenses and improve test infrastructure - Refactored MLH strategy for better code organization - Fixed hash indentation in shared examples - Replaced unverified doubles with instance_double - Moved spec files to correct directory structure - All tests passing with 88.64% line coverage * We don't need to support Ruby 2.7 * Update gem version to 2.0 * Correct json parsing * fix: properly handle data wrapper in API response and update test infrastructure * Revert "fix: properly handle data wrapper in API response and update test infrastructure" This reverts commit 6cafa4e. * fix: update test doubles to match strategy implementation * style: fix argument alignment in spec file * rubocop formatting * add line breaks as per Rashika's request * Change the style as per Rashika's request in #16 (comment) * Update the README for v4 * add example for accessing user data * README formatting fix --------- Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 5983238 commit 113a8cb

File tree

9 files changed

+399
-103
lines changed

9 files changed

+399
-103
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
runs-on: ubuntu-latest
1414
strategy:
1515
matrix:
16-
ruby: ['2.7', '3.2']
16+
ruby: ['3.2']
1717
steps:
1818
- uses: actions/checkout@v2
1919
- name: Set up Ruby ${{ matrix.ruby }}

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ source 'https://rubygems.org'
44

55
# Specify your gem's dependencies in omniauth-mlh.gemspec
66
gemspec
7+
gem 'activesupport'

README.md

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,16 @@
44
[![Test](https://github.com/MLH/omniauth-mlh/actions/workflows/test.yml/badge.svg)](https://github.com/MLH/omniauth-mlh/actions/workflows/test.yml)
55

66
This is the official [OmniAuth](https://github.com/omniauth/omniauth) strategy for
7-
authenticating with [MyMLH](https://my.mlh.io). To use it, you'll need to
8-
[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.
99

10-
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).
1111

1212
Once you have done so, you can follow the instructions below:
1313

1414
## Requirements
1515

16-
This Gem requires your Ruby version to be at least `2.2.0`, which is set
17-
downstream by [Omniauth](https://github.com/omniauth/omniauth/blob/master/omniauth.gemspec#L22).
16+
This Gem requires your Ruby version to be at least `3.2.0`.
1817

1918
## Installation
2019

@@ -34,9 +33,13 @@ Or install it yourself as:
3433

3534
## Usage (Rack)
3635

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+
3738
```ruby
3839
use OmniAuth::Builder do
39-
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']
4043
end
4144
```
4245

@@ -46,10 +49,27 @@ end
4649
# config/devise.rb
4750

4851
Devise.setup do |config|
49-
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']
5055
end
5156
```
5257

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+
5373
## Contributing
5474

5575
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).
@@ -61,6 +81,6 @@ We used part of [datariot/omniauth-paypal](http://github.com/datariot/omniauth-p
6181
## Questions?
6282

6383
Have a question about the API or this library? Start by checking out the
64-
[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
6585
find an answer, tweet at [@MLHacks](http://twitter.com/mlhacks) or drop an
6686

lib/omniauth-mlh/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
module OmniAuth
44
module MLH
5-
VERSION = '1.0.1'
5+
VERSION = '4.0.0'
66
end
77
end

lib/omniauth/strategies/mlh.rb

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,42 +5,99 @@
55

66
module OmniAuth
77
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.
829
class MLH < OmniAuth::Strategies::OAuth2 # :nodoc:
930
option :name, :mlh
1031

1132
option :client_options, {
1233
site: 'https://my.mlh.io',
1334
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
1537
}
1638

39+
# Support expandable fields through options
40+
option :expand_fields, []
41+
1742
uid { data[:id] }
1843

1944
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+
}
3764
end
3865

3966
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
44101
end
45102
end
46103
end

spec/omni_auth/mlh_spec.rb

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,14 @@
22

33
require 'spec_helper'
44

5-
describe OmniAuth::MLH do
6-
subject(:omniauth_mlh) do
7-
# The instance variable @options is being used to pass options to the subject of the shared examples
8-
OmniAuth::Strategies::MLH.new(nil, @options || {}) # rubocop:disable RSpec/InstanceVariable
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('2.0.0')
99
end
1010

11-
it_behaves_like 'an oauth2 strategy'
12-
13-
describe '#client' do
14-
it 'has correct MyMLH site' do
15-
expect(omniauth_mlh.client.site).to eq('https://my.mlh.io')
16-
end
17-
18-
it 'has correct authorize url' do
19-
expect(omniauth_mlh.client.options[:authorize_url]).to eq('oauth/authorize')
20-
end
21-
22-
it 'has correct token url' do
23-
expect(omniauth_mlh.client.options[:token_url]).to eq('oauth/token')
24-
end
25-
26-
it 'runs the setup block if passed one' do
27-
counter = ''
28-
@options = { setup: proc { |_env| counter = 'ok' } }
29-
omniauth_mlh.setup_phase
30-
expect(counter).to eq('ok')
31-
end
32-
end
33-
34-
describe '#callback_path' do
35-
it 'has the correct callback path' do
36-
expect(omniauth_mlh.callback_path).to eq('/auth/mlh/callback')
37-
end
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)
3814
end
3915
end

0 commit comments

Comments
 (0)