Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
7fdede57
Commit
7fdede57
authored
Apr 20, 2026
by
IanShaw027
Browse files
fix: preserve wechat bind resume state
parent
4d10ba42
Changes
2
Show whitespace changes
Inline
Side-by-side
frontend/src/views/auth/WechatCallbackView.vue
View file @
7fdede57
...
...
@@ -388,6 +388,15 @@ function resolveWeChatOAuthMode(): 'open' | 'mp' {
return
/MicroMessenger/i
.
test
(
navigator
.
userAgent
)
?
'
mp
'
:
'
open
'
}
function
normalizeWeChatOAuthMode
(
value
:
unknown
):
'
open
'
|
'
mp
'
|
null
{
return
value
===
'
open
'
||
value
===
'
mp
'
?
value
:
null
}
function
resolveRequestedWeChatOAuthMode
():
'
open
'
|
'
mp
'
{
const
queryMode
=
normalizeWeChatOAuthMode
(
route
.
query
.
mode
)
return
queryMode
||
resolveWeChatOAuthMode
()
}
function
resolveRedirectTarget
():
string
{
return
sanitizeRedirectPath
(
(
route
.
query
.
redirect
as
string
|
undefined
)
||
redirectTo
.
value
||
'
/dashboard
'
...
...
@@ -398,7 +407,7 @@ function resolveWeChatStartURL(intent: 'bind_current_user' | 'adopt_existing_use
const
apiBase
=
(
import
.
meta
.
env
.
VITE_API_BASE_URL
as
string
|
undefined
)
||
'
/api/v1
'
const
normalized
=
apiBase
.
replace
(
/
\/
$/
,
''
)
const
params
=
new
URLSearchParams
({
mode
:
resolveWeChatOAuthMode
(),
mode
:
resolve
Requested
WeChatOAuthMode
(),
redirect
:
resolveRedirectTarget
(),
intent
,
}
)
...
...
@@ -415,6 +424,7 @@ function buildExistingAccountResumePath(): string {
const
params
=
new
URLSearchParams
({
wechat_bind_existing
:
'
1
'
,
redirect
:
resolveRedirectTarget
(),
mode
:
resolveRequestedWeChatOAuthMode
(),
}
)
const
email
=
existingAccountEmail
.
value
.
trim
()
...
...
@@ -727,12 +737,24 @@ onMounted(async () => {
existingAccountEmail
.
value
=
route
.
query
.
email
}
if
(
route
.
query
.
wechat_bind_existing
===
'
1
'
&&
getAuthToken
())
{
if
(
route
.
query
.
wechat_bind_existing
===
'
1
'
)
{
if
(
getAuthToken
())
{
prepareOAuthBindAccessTokenCookie
()
window
.
location
.
href
=
resolveWeChatStartURL
(
'
bind_current_user
'
)
return
}
const
params
=
new
URLSearchParams
({
redirect
:
buildExistingAccountResumePath
(),
}
)
const
email
=
existingAccountEmail
.
value
.
trim
()
if
(
email
)
{
params
.
set
(
'
email
'
,
email
)
}
await
router
.
replace
(
`/login?${params.toString()
}
`
)
return
}
const
params
=
parseFragmentParams
()
const
error
=
params
.
get
(
'
error
'
)
const
errorDesc
=
params
.
get
(
'
error_description
'
)
||
params
.
get
(
'
error_message
'
)
||
''
...
...
frontend/src/views/auth/__tests__/WechatCallbackView.spec.ts
View file @
7fdede57
...
...
@@ -342,6 +342,7 @@ describe('WechatCallbackView', () => {
expect
(
replaceMock
.
mock
.
calls
[
0
]?.[
0
]).
toContain
(
'
/login?
'
)
expect
(
replaceMock
.
mock
.
calls
[
0
]?.[
0
]).
toContain
(
'
wechat_bind_existing%3D1
'
)
expect
(
replaceMock
.
mock
.
calls
[
0
]?.[
0
]).
toContain
(
'
email=user%40example.com
'
)
expect
(
replaceMock
.
mock
.
calls
[
0
]?.[
0
]).
toContain
(
'
mode%3Dopen
'
)
})
it
(
'
collects email for pending oauth account creation and submits adoption decisions
'
,
async
()
=>
{
...
...
@@ -592,7 +593,8 @@ describe('WechatCallbackView', () => {
it
(
'
restarts the current-user bind flow after returning from login
'
,
async
()
=>
{
routeState
.
query
=
{
wechat_bind_existing
:
'
1
'
,
redirect
:
'
/profile
'
redirect
:
'
/profile
'
,
mode
:
'
mp
'
,
}
getAuthTokenMock
.
mockReturnValue
(
'
existing-auth-token
'
)
...
...
@@ -612,7 +614,38 @@ describe('WechatCallbackView', () => {
expect
(
exchangePendingOAuthCompletionMock
).
not
.
toHaveBeenCalled
()
expect
(
prepareOAuthBindAccessTokenCookieMock
).
toHaveBeenCalledTimes
(
1
)
expect
(
locationState
.
current
.
href
).
toContain
(
'
/api/v1/auth/oauth/wechat/start?
'
)
expect
(
locationState
.
current
.
href
).
toContain
(
'
mode=mp
'
)
expect
(
locationState
.
current
.
href
).
toContain
(
'
intent=bind_current_user
'
)
expect
(
locationState
.
current
.
href
).
toContain
(
'
redirect=%2Fprofile
'
)
})
it
(
'
redirects back to login instead of falling through when bind-existing resume has no auth token
'
,
async
()
=>
{
routeState
.
query
=
{
wechat_bind_existing
:
'
1
'
,
redirect
:
'
/profile
'
,
mode
:
'
mp
'
,
email
:
'
resume@example.com
'
,
}
getAuthTokenMock
.
mockReturnValue
(
null
)
mount
(
WechatCallbackView
,
{
global
:
{
stubs
:
{
AuthLayout
:
{
template
:
'
<div><slot /></div>
'
},
Icon
:
true
,
RouterLink
:
{
template
:
'
<a><slot /></a>
'
},
transition
:
false
,
},
},
})
await
flushPromises
()
expect
(
exchangePendingOAuthCompletionMock
).
not
.
toHaveBeenCalled
()
expect
(
replaceMock
).
toHaveBeenCalledTimes
(
1
)
expect
(
replaceMock
.
mock
.
calls
[
0
]?.[
0
]).
toContain
(
'
/login?
'
)
expect
(
replaceMock
.
mock
.
calls
[
0
]?.[
0
]).
toContain
(
'
wechat_bind_existing%3D1
'
)
expect
(
replaceMock
.
mock
.
calls
[
0
]?.[
0
]).
toContain
(
'
mode%3Dmp
'
)
expect
(
replaceMock
.
mock
.
calls
[
0
]?.[
0
]).
toContain
(
'
email=resume%40example.com
'
)
})
})
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment