Skip to content

Commit

Permalink
Merge pull request #7436 from fjordllc/feature/oauth-discord-to-fetch-id
Browse files Browse the repository at this point in the history
Discord認証ができるようにする
  • Loading branch information
komagata authored Apr 3, 2024
2 parents 5b99729 + ad8503e commit f56b7f2
Show file tree
Hide file tree
Showing 14 changed files with 214 additions and 50 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ gem 'net-smtp', require: false # TODO: Remove it if you use rails 7.0.1
gem 'newspaper'
gem 'oauth2'
gem 'omniauth', '~> 2.1.1'
gem 'omniauth-discord'
gem 'omniauth-github', '~> 2.0.1'
gem 'omniauth-rails_csrf_protection'
gem 'parser', '3.2.2.4'
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,8 @@ GEM
hashie (>= 3.4.6)
rack (>= 2.2.3)
rack-protection
omniauth-discord (1.2.0)
omniauth-oauth2 (~> 1.6)
omniauth-github (2.0.1)
omniauth (~> 2.0)
omniauth-oauth2 (~> 1.8)
Expand Down Expand Up @@ -638,6 +640,7 @@ DEPENDENCIES
newspaper
oauth2
omniauth (~> 2.1.1)
omniauth-discord
omniauth-github (~> 2.0.1)
omniauth-rails_csrf_protection
parser (= 3.2.2.4)
Expand Down
48 changes: 24 additions & 24 deletions app/controllers/user_sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,32 +35,32 @@ def destroy
redirect_to root_url, notice: 'ログアウトしました。'
end

# rubocop:disable Metrics/MethodLength
def callback
auth = request.env['omniauth.auth']
github_id = auth[:uid]
if current_user.blank?
user = User.find_by(github_id:)
if user.blank?
flash[:alert] = 'ログインに失敗しました。先にアカウントを作成後、GitHub連携を行ってください。'
redirect_to root_url
elsif user.retired_on?
logout
redirect_to retire_path
else
session[:user_id] = user.id
redirect_back_or_to root_url, notice: 'サインインしました。'
authentication =
case params[:provider]
when 'discord'
Authentication::Discord.new(current_user, auth)
when 'github'
Authentication::Github.new(current_user, auth)
end
else
github_account = auth[:info][:nickname]
current_user.register_github_account(github_id, github_account) if current_user.github_id.blank?
flash[:notice] = 'GitHubと連携しました。'
redirect_to root_path
end
rescue StandardError => e
logger.warn "[GitHub Login] ログインに失敗しました。:#{e.message}"
flash[:alert] = 'GitHubログインに失敗しました。数回試しても続く場合、管理者に連絡してください。'
redirect_to root_path
result = authentication.authenticate
assign_flash_and_session(result)

return redirect_back_or_to result[:path] if result[:back]

redirect_to result[:path]
end

def failure
redirect_to root_path, alert: 'キャンセルしました'
end

private

def assign_flash_and_session(result)
flash[:notice] = result[:notice] if result[:notice]
flash[:alert] = result[:alert] if result[:alert]
session[:user_id] = result[:user_id] if result[:user_id]
end
# rubocop:enable Metrics/MethodLength
end
26 changes: 26 additions & 0 deletions app/models/authentication/discord.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

class Authentication::Discord
include Rails.application.routes.url_helpers

def initialize(login_user, auth)
@login_user = login_user
@auth = auth
end

def authenticate
if link
{ path: root_path, notice: 'Discordと連携しました' }
else
{ path: root_path, alert: 'Discordの連携に失敗しました' }
end
end

private

def link
discord_profile = DiscordProfile.find_or_initialize_by(user: @login_user)
discord_profile.account_name = @auth[:info][:name]
discord_profile.save
end
end
37 changes: 37 additions & 0 deletions app/models/authentication/github.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

class Authentication::Github
include Rails.application.routes.url_helpers

def initialize(user, auth)
@user = user
@auth = auth
end

def authenticate
if @user.blank?
user = User.find_by(github_id: @auth[:uid])
if user.blank?
{ path: root_path, alert: 'ログインに失敗しました。先にアカウントを作成後、GitHub連携を行ってください。' }
elsif user.retired_on?
{ path: retirement_path }
else
{ path: root_path, notice: 'サインインしました。', user_id: user.id, back: true }
end
else
link if @user.github_id.blank?
{ path: root_path, notice: 'GitHubと連携しました。' }
end
rescue StandardError => e
Rails.logger.warn "[GitHub Login] ログインに失敗しました。:#{e.message}"
{ path: root_path, alert: 'GitHubログインに失敗しました。数回試しても続く場合、管理者に連絡してください。' }
end

private

def link
@user.github_account = @auth[:info][:nickname]
@user.github_id = @auth[:uid]
@user.save!
end
end
6 changes: 0 additions & 6 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -619,12 +619,6 @@ def participating?(event)
send(method_name).include?(event)
end

def register_github_account(id, account_name)
self.github_account = account_name
self.github_id = id
save!
end

def depressed?
reported_reports = reports.order(reported_on: :desc).limit(DEPRESSED_SIZE)
reported_reports.size == DEPRESSED_SIZE && reported_reports.all?(&:sad?)
Expand Down
9 changes: 3 additions & 6 deletions app/views/users/form/_company.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,15 @@
= f.collection_select :company_id, desc_ordered_companies_with_empty, :id, :name, {}, { id: 'js-choices-single-select' }
.a-form-help
- if user.admin?
p フィヨルドを選択
p 株式会社ロッカを選択
- elsif user.mentor?
p
| もし良かったら所属企業を登録してください。
| 所属企業がない場合は管理者にご連絡をお願いします。
| 差し支えがなければ所属企業(どこかの企業に所属している場合は)を登録してください。
- elsif user.adviser?
p
| 所属企業を登録してください。研修でお使いいただいている場合は、
| 所属企業を登録することで研修生の日報、提出物の通知が飛ぶようになります。
- elsif user.graduated_on?
p
| もし良かったら所属企業を登録してください
| 差し支えがなければ所属企業を登録してください
| 所属企業の登録は必須ではありません。
| 所属企業がない場合は管理者にご連絡をお願いします。
end
26 changes: 14 additions & 12 deletions app/views/users/form/_sns.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@
.form-item
label.a-form-label
| Discord アカウント
.form-item__mention-input
= discord_profile_fields.text_field :account_name, class: 'a-text-input', placeholder: 'komagata1111'
.a-form-help
p
| Discord で使用しているアカウント名を入力してください。
p
| Discord のアカウントの調べ方は
label.a-form-help-link.is-danger(for='modal-discord-account')
span.a-form-help-link__label
| こちら
span.a-help
i.fa-solid.fa-question
- if f.object.discord_profile.account_name?
.form-item__mention-input
= discord_profile_fields.text_field :account_name, class: 'a-text-input', disabled: true
.a-form-help
p Discord アカウントは登録されています。
- else
= link_to '/auth/discord', class: 'a-button is-sm is-primary', method: :post do
p Discord アカウントを登録する
.a-form-help
p
| 今後、Discord とフィヨルドブートキャンプアプリとの
| 連携に Discord アカウントの登録が必要になります。
| フィヨルドブートキャンプの Discord サーバに入室をしたら、
| 必ず登録をしてください。

.form-item#times-url
= discord_profile_fields.label :times_url, class: 'a-form-label'
Expand Down
3 changes: 3 additions & 0 deletions config/initializers/omniauth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@

Rails.application.config.middleware.use OmniAuth::Builder do
provider :github, ENV["GITHUB_KEY"], ENV["GITHUB_SECRET"], scope: 'user:email'
provider :discord, ENV['DISCORD_CLIENT_ID'], ENV['DISCORD_CLIENT_SECRET']

OmniAuth.config.on_failure = proc { |_env| [302, {'Location' => '/auth/failure', 'Content-Type'=> 'text/html'}, []] }
end
3 changes: 2 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@
get "pages/tags/:tag", to: "pages#index", as: :pages_tag, tag: /.+/, format: "html"
get "questions/tags/:tag", to: "questions#index", as: :questions_tag, tag: /.+/, format: "html"
get "login" => "user_sessions#new", as: :login
get "auth/github/callback" => "user_sessions#callback"
get "auth/:provider/callback" => "user_sessions#callback"
get 'auth/failure', to: "user_sessions#failure"
post "user_sessions" => "user_sessions#create"
get "logout" => "user_sessions#destroy", as: :logout
get "thanks", to: "static_pages#thanks"
Expand Down
24 changes: 24 additions & 0 deletions test/models/authentication/discord_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

require 'test_helper'

class Authentication::DiscordTest < ActiveSupport::TestCase
include Rails.application.routes.url_helpers

test 'authentication succeeds when arguments are valid' do
user = users(:komagata)
discord_authentication = Authentication::Discord.new(user, { info: { name: 'komagata_discord' } })
result = discord_authentication.authenticate

assert_equal result[:notice], 'Discordと連携しました'
assert_equal result[:path], root_path
end

test 'authentication fails when arguments are invalid' do
discord_authentication = Authentication::Discord.new(nil, { info: { name: 'komagata_discord' } })
result = discord_authentication.authenticate

assert_equal result[:alert], 'Discordの連携に失敗しました'
assert_equal result[:path], root_path
end
end
49 changes: 49 additions & 0 deletions test/models/authentication/github_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

require 'test_helper'

class Authentication::GithubTest < ActiveSupport::TestCase
include Rails.application.routes.url_helpers

test 'authentication fails when github id does not match' do
github_authentication = Authentication::Github.new(nil, { info: { nickname: 'kimura_github' }, uid: 'uid_test_data' })
result = github_authentication.authenticate

assert_equal result[:path], root_path
assert_equal result[:alert], 'ログインに失敗しました。先にアカウントを作成後、GitHub連携を行ってください。'
end

test 'retirement path when github id matches a retired user' do
user = users(:yameo)
user.github_id = 'uid_test_data'
user.save!

github_authentication = Authentication::Github.new(nil, { info: { nickname: 'yameo_github' }, uid: 'uid_test_data' })

assert_equal github_authentication.authenticate[:path], retirement_path
end

test 'authentication succeeds when github id matches a regular user' do
user = users(:kimura)
user.github_id = 'uid_test_data'
user.save!

github_authentication = Authentication::Github.new(nil, { info: { name: 'komagata_discord' }, uid: 'uid_test_data' })
result = github_authentication.authenticate

assert_equal result[:path], root_path
assert_equal result[:notice], 'サインインしました。'
assert_equal result[:user_id], user.id
assert_equal result[:back], true
end

test 'github is linked when user is logged in and not linked with Github' do
user = users(:kimura)
github_authentication = Authentication::Github.new(user, { info: { nickname: 'kimura_github' }, uid: 'uid_test_data' })
result = github_authentication.authenticate

assert_equal result[:path], root_path
assert_equal user.reload.github_account, 'kimura_github'
assert_equal user.reload.github_id, 'uid_test_data'
end
end
27 changes: 27 additions & 0 deletions test/system/authentication/discord_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

require 'application_system_test_case'

class Authentication::DiscordSystemTest < ApplicationSystemTestCase
setup do
OmniAuth.config.test_mode = true
OmniAuth.config.add_mock(:discord, { info: { name: 'discord_name' } })
end

test 'cannot register discord account already setting user' do
visit_with_auth '/current_user/edit', 'kimura'

assert_text 'Discord アカウントは登録されています。'
assert_no_text 'Discord アカウントを登録する'
end

test 'can register discord account not setting user' do
visit_with_auth '/current_user/edit', 'hatsuno'

click_link 'Discord アカウントを登録する'
assert_text 'Discordと連携しました'

visit '/current_user/edit'
assert_text 'Discord アカウントは登録されています。'
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require 'application_system_test_case'

class SignInWithGithubTest < ApplicationSystemTestCase
class Authentication::GithubSystemTest < ApplicationSystemTestCase
fixtures :users

setup do
Expand Down

0 comments on commit f56b7f2

Please sign in to comment.