Skip to content

Commit 892feab

Browse files
committed
feat: 超爽 Open ID 註冊與登入
1 parent d6fe7c7 commit 892feab

File tree

8 files changed

+193
-157
lines changed

8 files changed

+193
-157
lines changed

app/contexts/user_auth_context.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ def has_authorization?
4646

4747
def parse_email
4848
email = params_to_user_attributes[:email]
49-
errors.add(:email, :not_found) unless email
49+
errors.add(:email, :not_found) if email.blank?
5050
email
5151
end
5252

5353
def already_auth?
54-
if @authorization
54+
if @authorization && @authorization.auth != @user
5555
errors.add(:authorization, :taken)
5656
throw :abort
5757
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
Feature: user 註冊
2+
Feature: Open ID 註冊
3+
Feature: 已登入狀態下使用 Open ID 註冊時,會進行帳號綁定
4+
Background:
5+
Given 已註冊 users:
6+
| name | email |
7+
| marsz | marsz@5fpro.com |
8+
Scenario: Email 為空
9+
When facebook 登入
10+
| email | |
11+
Then 使用者未登入
12+
Scenario: 已登入下,重複綁定相同的 Open ID 不會造成資料錯誤,且會更新已存的 Open ID 資料
13+
Given 使用者登入
14+
And facebook 登入
15+
| email | marsz@5fpro.com |
16+
| uid | 12345 |
17+
| name | marsz |
18+
When facebook 登入
19+
| email | marsz@5fpro.com |
20+
| uid | 12345 |
21+
| name | mars |
22+
Then User(marsz) 已綁定 facebook 1 筆
23+
And User(marsz) 的 facebook 資料為:
24+
| uid | 12345 |
25+
| name | mars |
26+
Scenario: 已登入下,同一個 Open ID 來源可重複綁定不同的帳號
27+
Given 使用者登入
28+
And facebook 登入
29+
| email | marsz@5fpro.com |
30+
| uid | 12345 |
31+
When facebook 登入
32+
| email | abcd@5fpro.com |
33+
| uid | 56789 |
34+
Then User(marsz) 已綁定 facebook 2 筆
35+
Scenario: 已登入下,若原為一般註冊,綁定後仍可以原帳號密碼登入
36+
Given 使用者登入
37+
And facebook 登入
38+
| email | marsz@5fpro.com |
39+
And 使用者登出
40+
When 使用者登入
41+
Then 使用者已登入
42+
Scenario: 已登入下,該 Open ID 已綁定在其他 user 身上時,無法進行綁定
43+
Given 已註冊 users:
44+
| name | email |
45+
| venus | venus@5fpro.com |
46+
And User(venus) 綁定 facebook
47+
| uid | 1234 |
48+
And 使用者登入
49+
When facebook 登入
50+
| uid | 1234 |
51+
Then User(marsz) 已綁定 facebook 0 筆
52+
Scenario: 已登入下,相同 Email 的不同 Open ID 已綁定(註冊)在其他 user 身上時,則無法進行綁定。
53+
Given 已註冊 users:
54+
| name | email |
55+
| venus | venus@5fpro.com |
56+
And User(venus) 綁定 facebook
57+
| uid | 1234 |
58+
| email | xxx@5fpro.com |
59+
And 使用者登入
60+
When google 登入
61+
| uid | 5678 |
62+
| email | xxx@5fpro.com |
63+
Then User(marsz) 已綁定 facebook 0 筆
64+
And 使用者已登入
65+
Scenario: 未登入下,有相同 Email 的其他 user 以不同 Open ID 註冊存在時,則會自動綁定,且登入
66+
Given facebook 登入
67+
| email | venus@5fpro.com |
68+
| uid | 1234 |
69+
And 使用者登出
70+
When facebook 登入
71+
| email | venus@5fpro.com |
72+
| uid | 5678 |
73+
Then User(venus@5fpro.com) 已綁定 facebook 2 筆
74+
And 使用者已登入
75+
Scenario: 未登入下,若有相同 email 的其他 user 以一般註冊、尚未驗證存在時,則會自動綁定該 user,設為已驗證,並且登入
76+
Given User(marsz) 設為未驗證
77+
When facebook 登入
78+
| email | marsz@5fpro.com |
79+
Then User(marsz) 已綁定 facebook 1 筆
80+
And User(marsz) 狀態為已驗證
81+
And 使用者已登入
82+
Scenario: 未登入下,若有相同 email user 已以其他 Open ID 註冊,則會自動綁定該 user,且登入
83+
Given google 登入
84+
| email | abc@5fpro.com |
85+
When facebook 登入
86+
| email | abc@5fpro.com |
87+
Then User(abc@5fpro.com) 已綁定 facebook 1 筆
88+
And User(abc@5fpro.com) 已綁定 google 1 筆
89+
And 使用者已登入
90+
Scenario: 未登入下,若有相同 email user 已以相同 Open ID 註冊,則會登入
91+
Given facebook 登入
92+
| email | abc@5fpro.com |
93+
And 使用者登出
94+
When facebook 登入
95+
| email | abc@5fpro.com |
96+
Then User(abc@5fpro.com) 已綁定 facebook 1 筆
97+
And 使用者已登入
98+
Scenario: 未登入下,若無相同 email user 註冊時,會建立新帳號,且登入
99+
When facebook 登入
100+
| email | abc@5fpro.com |
101+
Then User(abc@5fpro.com) 已綁定 facebook 1 筆
102+
And 使用者已登入
103+
Scenario: 未登入下,若有相同 email 綁定在其他 user 身上,但該 user email 與欲登入的 Open ID 不同時,會建立新帳號,且登入
104+
Given User(marsz@5fpro.com) 綁定 facebook
105+
| uid | 1234 |
106+
When facebook 登入
107+
| email | abc@5fpro.com |
108+
| uid | 5678 |
109+
Then User(marsz@5fpro.com) 已綁定 facebook 1 筆
110+
And User(abc@5fpro.com) 已綁定 facebook 1 筆
111+
And 使用者已登入

spec/contexts/user_auth_context_spec.rb

-100
This file was deleted.

spec/requests/authorizations_controller_spec.rb

-55
This file was deleted.
File renamed without changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
placeholder :auth_provider do
2+
match /(facebook|github|google)/ do |provider|
3+
provider = provider.downcase
4+
provider = 'google_oauth2' if provider == 'google'
5+
provider
6+
end
7+
end

spec/steps/response_steps.rb

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
expect(response).to be_redirect
2929
end
3030

31+
step '頁面轉跳至 :path' do |path|
32+
expect(response).to redirect_to(path)
33+
end
34+
3135
step '頁面包含 :content' do |content|
3236
expect(response.body).to include(content)
3337
end

spec/steps/users/sign_steps.rb

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
step ':model_finder 設為未驗證' do |user|
2+
user.update(confirmed_at: nil)
3+
end
4+
5+
step ':model_finder 狀態為已驗證' do |user|
6+
expect(user.confirmed?).to eq(true)
7+
end
8+
9+
step ':model_finder 已綁定 :auth_provider :count 筆' do |user, auth_provider, count|
10+
expect(user.authorizations.where(provider: auth_provider).count).to eq(count.to_i)
11+
end
12+
13+
step '使用者登出' do
14+
delete '/users/sign_out'
15+
end
16+
17+
step '使用者已登入' do
18+
get '/users/sign_in'
19+
expect(response).to be_redirect
20+
end
21+
22+
step '使用者未登入' do
23+
get '/users/sign_in'
24+
expect(response).to be_success
25+
end
26+
27+
step ':model_finder 的 :auth_provider 資料為:' do |user, auth_provider, table|
28+
provider_data = table.rows_hash.symbolize_keys
29+
uid = provider_data.delete(:uid)
30+
authorization = user.authorizations.where(provider: auth_provider, uid: uid).first
31+
provider_data.each do |key, value|
32+
expect(authorization.auth_data.with_indifferent_access[:info][key]).to eq(value)
33+
end
34+
end
35+
36+
step '使用者登入' do
37+
@current_user = @user || @users.try(:first) || @current_user || create(:user)
38+
post '/users/sign_in', params: { user: { email: @current_user.email, password: @current_user.password } }
39+
expect(response).to redirect_to('/')
40+
end
41+
42+
step '使用者登入:' do |table|
43+
@current_user = create(:user, table.rows_hash.symbolize_keys)
44+
post '/users/sign_in', params: { user: { email: @current_user.email, password: @current_user.password } }
45+
expect(response).to redirect_to('/')
46+
end
47+
48+
step ':model_finder 綁定 :auth_provider' do |user, auth_provider, table|
49+
delete '/users/sign_out'
50+
post '/users/sign_in', params: { user: { email: user.email, password: user.password || '12341234' } }
51+
get "/authorizations/#{auth_provider}/callback", env: auth_mock(auth_provider, table)
52+
delete '/users/sign_out'
53+
end
54+
55+
step ':auth_provider 登入' do |auth_provider, table|
56+
get "/authorizations/#{auth_provider}/callback", env: auth_mock(auth_provider, table)
57+
end
58+
59+
def auth_mock(auth_provider, table)
60+
provider_data = table.rows_hash.symbolize_keys
61+
email = provider_data[:email]
62+
uid = provider_data[:uid]
63+
name = provider_data[:name]
64+
mock_data = omniauth_mock(auth_provider.to_sym)
65+
mock_data[:info][:email] = email.gsub(' ', '') if email.is_a?(String)
66+
mock_data[:uid] = uid.gsub(' ', '') if uid.is_a?(String)
67+
mock_data[:info][:name] = name if name.present?
68+
{ 'omniauth.auth' => mock_data }
69+
end

0 commit comments

Comments
 (0)