Skip to content

Commit ef27a0b

Browse files
authored
Merge pull request increments#75 from tomoasleep/fix/oauth-redirection
Qiitaログイン時のリダイレクト先を修正
2 parents 1444ab0 + 50ac42d commit ef27a0b

9 files changed

Lines changed: 311 additions & 6 deletions

app/controllers/auth/omniauth_callbacks_controller.rb

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# frozen_string_literal: true
22

33
class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
4+
include AfterSignInPathLeadable
5+
46
def qiita
57
auth_hash = request.env['omniauth.auth']
68

@@ -15,21 +17,27 @@ def qiita
1517
else
1618
flash[:alert] = I18n.t('omniauth_callbacks.failure')
1719
end
18-
redirect_to settings_qiita_authorizations_path
20+
redirect_to after_sign_in_path_for(current_user)
1921
else
2022
if authorization = QiitaAuthorization.find_by(uid: auth_hash[:uid])
2123
sign_in(authorization.user)
22-
redirect_to web_path
24+
redirect_to after_sign_in_path_for(authorization.user)
2325
else
24-
store_omniauth_auth
26+
store_omniauth_data
2527
redirect_to new_user_oauth_registration_path
2628
end
2729
end
2830
end
2931

3032
private
3133

32-
def store_omniauth_auth
34+
def store_omniauth_data
3335
session[:devise_omniauth_auth] = request.env['omniauth.auth']
36+
session[:devise_omniauth_origin] = request.env['omniauth.origin']
37+
end
38+
39+
# @override
40+
def location_after_sign_in
41+
request.env['omniauth.origin'].presence || stored_location_for(:user)
3442
end
3543
end
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# frozen_string_literal: true
2+
3+
module AfterSignInPathLeadable
4+
extend ActiveSupport::Concern
5+
6+
protected
7+
8+
def after_sign_in_path_for(resource)
9+
after_sign_in_path = resolve_url(location_after_sign_in)
10+
11+
if home_paths(resource).include?((after_sign_in_path || '').split('?').first)
12+
root_path
13+
else
14+
after_sign_in_path || root_path
15+
end
16+
end
17+
18+
private
19+
20+
def home_paths(resource)
21+
paths = [about_path]
22+
if single_user_mode? && resource.is_a?(User)
23+
paths << short_account_path(username: resource.account)
24+
end
25+
paths
26+
end
27+
28+
def resolve_url(url)
29+
uri = URI.parse(url)
30+
if !uri.host || uri.host == request.host
31+
uri.query ? "#{uri.path}?#{uri.query}" : uri.path
32+
else
33+
nil
34+
end
35+
rescue URI::InvalidURIError => e
36+
nil
37+
end
38+
39+
def location_after_sign_in
40+
fail NotImplementedError
41+
end
42+
end

app/controllers/oauth_registrations_controller.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
class OauthRegistrationsController < DeviseController
2+
include AfterSignInPathLeadable
23
layout 'auth'
34

45
before_action :check_enabled_registrations
@@ -17,7 +18,7 @@ def create
1718

1819
if @oauth_registration.save
1920
sign_in(@oauth_registration.user)
20-
redirect_to web_path
21+
redirect_to after_sign_in_path_for(@oauth_registration.user)
2122
flash[:notice] = I18n.t('oauth_registration.success')
2223
else
2324
render :new, status: :unprocessable_entity
@@ -37,4 +38,9 @@ def check_enabled_registrations
3738
def require_omniauth_auth
3839
redirect_to root_path unless omniauth_auth
3940
end
41+
42+
# @override
43+
def location_after_sign_in
44+
session[:devise_omniauth_origin].presence || stored_location_for(:user)
45+
end
4046
end

app/models/form/oauth_registration.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ class UnsupportedProviderError < StandardError; end
1010

1111
class << self
1212
def from_omniauth_auth(auth)
13+
auth = auth.deep_symbolize_keys
14+
1315
case auth[:provider]
1416
when 'qiita'
1517
new(
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
describe Auth::OmniauthCallbacksController, type: :controller do
6+
describe 'GET #qiita' do
7+
include_context 'mock qiita omniauth'
8+
9+
let(:omniauth_auth) { qiita_auth }
10+
before do
11+
request.env['devise.mapping'] = Devise.mappings[:user]
12+
request.env['omniauth.auth'] = omniauth_auth
13+
request.env['omniauth.origin'] = try(:omniauth_origin)
14+
end
15+
16+
subject { -> { get :qiita } }
17+
18+
context 'when signed in' do
19+
before { sign_in(user) }
20+
let(:user) { Fabricate(:user) }
21+
22+
context 'and current user is not linked to an qiita account' do
23+
it 'links the user to the qiita account' do
24+
is_expected.to change { user.reload.qiita_authorization }.from(nil).to(be_truthy)
25+
end
26+
end
27+
28+
context 'and omniauth.origin is empty' do
29+
it 'redirect_to root_path' do
30+
subject.call
31+
expect(response).to be_redirect
32+
expect(response).to redirect_to(root_path)
33+
end
34+
end
35+
36+
context 'and omniauth.origin is about_url' do
37+
let(:omniauth_origin) { about_url }
38+
39+
it 'redirect_to root_path' do
40+
subject.call
41+
expect(response).to be_redirect
42+
expect(response).to redirect_to(root_path)
43+
end
44+
end
45+
46+
context 'and omniauth.origin is settings_qiita_authorizations_url' do
47+
let(:omniauth_origin) { settings_qiita_authorizations_url }
48+
49+
it 'redirect_to settings_qiita_authorizations_path' do
50+
subject.call
51+
expect(response).to be_redirect
52+
expect(response).to redirect_to(settings_qiita_authorizations_path)
53+
end
54+
end
55+
end
56+
57+
context 'when not signed in' do
58+
context 'and there are a user linked to the qiita account' do
59+
let(:user) { Fabricate(:user) }
60+
let!(:qiita_authorization) { Fabricate(:qiita_authorization, uid: omniauth_auth[:uid], user: user) }
61+
62+
it 'logs the user in' do
63+
subject.call
64+
expect(controller.current_user).to eq user
65+
end
66+
67+
context 'and omniauth.origin is empty' do
68+
it 'redirect_to root_path' do
69+
subject.call
70+
expect(response).to be_redirect
71+
expect(response).to redirect_to(root_path)
72+
end
73+
end
74+
75+
context 'and omniauth.origin is about_url' do
76+
let(:omniauth_origin) { about_url }
77+
78+
it 'redirect_to root_path' do
79+
subject.call
80+
expect(response).to be_redirect
81+
expect(response).to redirect_to(root_path)
82+
end
83+
end
84+
85+
context 'and omniauth.origin is settings_qiita_authorizations_url' do
86+
let(:omniauth_origin) { settings_qiita_authorizations_url }
87+
88+
it 'redirect_to settings_qiita_authorizations_path' do
89+
subject.call
90+
expect(response).to be_redirect
91+
expect(response).to redirect_to(settings_qiita_authorizations_path)
92+
end
93+
end
94+
end
95+
96+
context 'and there are no user linked to the qiita account' do
97+
it 'redirects to new_user_oauth_registration_path' do
98+
subject.call
99+
expect(response).to redirect_to(new_user_oauth_registration_path)
100+
end
101+
102+
context 'when omniauth.origin is a url' do
103+
let(:omniauth_origin) { root_url }
104+
105+
it 'stores the omniauth origin to session' do
106+
subject.call
107+
expect(session[:devise_omniauth_origin]).to be(omniauth_origin)
108+
end
109+
end
110+
111+
it 'stores the omniauth data to session to build form' do
112+
subject.call
113+
expect(Form::OauthRegistration.from_omniauth_auth(session[:devise_omniauth_auth])).to have_attributes({
114+
provider: omniauth_auth[:provider],
115+
avatar: omniauth_auth[:info][:image],
116+
uid: omniauth_auth[:uid],
117+
username: omniauth_auth[:uid],
118+
token: omniauth_auth[:credentials][:token],
119+
})
120+
end
121+
end
122+
end
123+
end
124+
end
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
require 'rails_helper'
2+
require 'securerandom'
3+
4+
RSpec.describe OauthRegistrationsController, type: :controller do
5+
include_context 'mock qiita omniauth'
6+
7+
let(:omniauth_auth) { qiita_auth }
8+
before do
9+
request.env['devise.mapping'] = Devise.mappings[:user]
10+
stub_request(:get, qiita_auth[:info][:image]).to_return(request_fixture('avatar.txt'))
11+
end
12+
13+
shared_context 'store omniauth data' do
14+
before do
15+
session[:devise_omniauth_auth] = omniauth_auth
16+
session[:devise_omniauth_origin] = try(:omniauth_origin)
17+
end
18+
end
19+
20+
describe 'GET #new' do
21+
subject { -> { get :new } }
22+
23+
context 'when omniauth data are stored' do
24+
include_context 'store omniauth data'
25+
26+
it 'returns 200' do
27+
subject.call
28+
expect(response).to have_http_status(:success)
29+
end
30+
end
31+
32+
context 'when omniauth data are not stored' do
33+
it 'redirect_to root_path' do
34+
subject.call
35+
expect(response).to be_redirect
36+
expect(response).to redirect_to(root_path)
37+
end
38+
end
39+
end
40+
41+
describe 'POST #create' do
42+
subject { -> { post :create, { params: { form_oauth_registration: form_params } } } }
43+
44+
context 'when omniauth data are stored' do
45+
include_context 'store omniauth data'
46+
47+
context 'and email and username is given' do
48+
let(:form_params) { { email: email, username: username } }
49+
let(:username) { 'foo' }
50+
let(:email) { 'foo@example.com' }
51+
52+
it { is_expected.to change { User.find_by(account: Account.find_by(username: username), email: email) }.from(nil).to(be_truthy) }
53+
it { is_expected.to change { QiitaAuthorization.find_by(user: User.find_by(email: email), uid: omniauth_auth[:uid], token: omniauth_auth[:credentials][:token]) }.from(nil).to(be_truthy) }
54+
55+
context 'and omniauth.origin is empty' do
56+
it 'redirect_to root_path' do
57+
subject.call
58+
expect(response).to be_redirect
59+
expect(response).to redirect_to(root_path)
60+
end
61+
end
62+
63+
context 'and omniauth.origin is about_url' do
64+
let(:omniauth_origin) { about_url }
65+
66+
it 'redirect_to root_path' do
67+
subject.call
68+
expect(response).to be_redirect
69+
expect(response).to redirect_to(root_path)
70+
end
71+
end
72+
73+
context 'and omniauth.origin is settings_qiita_authorizations_url' do
74+
let(:omniauth_origin) { settings_qiita_authorizations_url }
75+
76+
it 'redirect_to settings_qiita_authorizations_path' do
77+
subject.call
78+
expect(response).to be_redirect
79+
expect(response).to redirect_to(settings_qiita_authorizations_path)
80+
end
81+
end
82+
end
83+
end
84+
85+
context 'when omniauth data are not stored' do
86+
let(:form_params) { { email: email, username: username } }
87+
let(:username) { 'foo' }
88+
let(:email) { 'foo@example.com' }
89+
90+
it 'redirect_to root_path' do
91+
subject.call
92+
expect(response).to be_redirect
93+
expect(response).to redirect_to(root_path)
94+
end
95+
end
96+
end
97+
end
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Fabricator(:qiita_authorization) do
22
user nil
33
uid "qiitan"
4-
provider "qiita"
4+
token "token"
55
end

spec/rails_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
Redis.current = Redis::Namespace.new("mastodon_test#{ENV['TEST_ENV_NUMBER']}", redis: Redis.current)
1717
Sidekiq::Testing.inline!
1818
Sidekiq::Logging.logger = nil
19+
OmniAuth.config.test_mode = true
1920

2021
Devise::Test::ControllerHelpers.module_eval do
2122
alias_method :original_sign_in, :sign_in
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# frozen_string_literal: true
2+
3+
shared_context 'mock qiita omniauth' do
4+
let(:qiita_auth) do
5+
{
6+
provider: 'qiita',
7+
uid: 'test_uid',
8+
info: {
9+
email: 'test@example.com',
10+
name: 'test_name',
11+
image: 'http://example.com/image.jpg'
12+
},
13+
credentials: {
14+
token: 'credentialstoken',
15+
refresh_token: 'credentialssecret',
16+
},
17+
extra: {
18+
raw_info: {}
19+
}
20+
}
21+
end
22+
23+
before { OmniAuth.config.mock_auth[:qiita] = OmniAuth::AuthHash.new(qiita_auth) }
24+
after { OmniAuth.config.mock_auth[:qiita] = nil }
25+
end

0 commit comments

Comments
 (0)