mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-11-01 00:27:30 +00:00
fix: improve Grok OAuth, image, and usage flows
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
vi.mock('@/stores/app', () => ({
|
||||
useAppStore: () => ({
|
||||
showError: vi.fn()
|
||||
})
|
||||
}))
|
||||
|
||||
vi.mock('vue-i18n', () => ({
|
||||
useI18n: () => ({
|
||||
t: (key: string) => {
|
||||
const messages: Record<string, string> = {
|
||||
'admin.accounts.oauth.grok.failedToExchangeCode': 'Grok 授权码兑换失败',
|
||||
'admin.accounts.oauth.grok.errors.GROK_OAUTH_INVALID_STATE':
|
||||
'Grok OAuth state 与当前会话不匹配。请粘贴同一次生成的授权链接返回的回调 URL。'
|
||||
}
|
||||
return messages[key] ?? key
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
vi.mock('@/api/admin', () => ({
|
||||
adminAPI: {
|
||||
grok: {
|
||||
generateAuthUrl: vi.fn(),
|
||||
exchangeCode: vi.fn(),
|
||||
refreshGrokToken: vi.fn()
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
import { useGrokOAuth } from '@/composables/useGrokOAuth'
|
||||
import { adminAPI } from '@/api/admin'
|
||||
|
||||
describe('useGrokOAuth.exchangeAuthCode', () => {
|
||||
it('shows a state mismatch recovery hint from structured backend errors', async () => {
|
||||
vi.mocked(adminAPI.grok.exchangeCode).mockRejectedValueOnce({
|
||||
status: 400,
|
||||
reason: 'GROK_OAUTH_INVALID_STATE',
|
||||
message: 'invalid oauth state'
|
||||
})
|
||||
const oauth = useGrokOAuth()
|
||||
|
||||
const tokenInfo = await oauth.exchangeAuthCode({
|
||||
code: 'code',
|
||||
sessionId: 'session-id',
|
||||
state: 'wrong-state'
|
||||
})
|
||||
|
||||
expect(tokenInfo).toBeNull()
|
||||
expect(oauth.error.value).toBe(
|
||||
'Grok OAuth state 与当前会话不匹配。请粘贴同一次生成的授权链接返回的回调 URL。'
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -3,6 +3,7 @@ import { useI18n } from 'vue-i18n'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { adminAPI } from '@/api/admin'
|
||||
import type { GrokTokenInfo } from '@/api/admin/grok'
|
||||
import { extractApiErrorMessage, extractI18nErrorMessage } from '@/utils/apiError'
|
||||
|
||||
export function useGrokOAuth() {
|
||||
const appStore = useAppStore()
|
||||
@@ -39,7 +40,7 @@ export function useGrokOAuth() {
|
||||
state.value = response.state
|
||||
return true
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.detail || t('admin.accounts.oauth.grok.failedToGenerateUrl')
|
||||
error.value = extractApiErrorMessage(err, t('admin.accounts.oauth.grok.failedToGenerateUrl'))
|
||||
appStore.showError(error.value)
|
||||
return false
|
||||
} finally {
|
||||
@@ -72,7 +73,12 @@ export function useGrokOAuth() {
|
||||
|
||||
return await adminAPI.grok.exchangeCode(payload as any)
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.detail || t('admin.accounts.oauth.grok.failedToExchangeCode')
|
||||
error.value = extractI18nErrorMessage(
|
||||
err,
|
||||
t,
|
||||
'admin.accounts.oauth.grok.errors',
|
||||
t('admin.accounts.oauth.grok.failedToExchangeCode')
|
||||
)
|
||||
appStore.showError(error.value)
|
||||
return null
|
||||
} finally {
|
||||
@@ -95,7 +101,12 @@ export function useGrokOAuth() {
|
||||
try {
|
||||
return await adminAPI.grok.refreshGrokToken(refreshToken.trim(), proxyId)
|
||||
} catch (err: any) {
|
||||
error.value = err.response?.data?.detail || t('admin.accounts.oauth.grok.failedToValidateRT')
|
||||
error.value = extractI18nErrorMessage(
|
||||
err,
|
||||
t,
|
||||
'admin.accounts.oauth.grok.errors',
|
||||
t('admin.accounts.oauth.grok.failedToValidateRT')
|
||||
)
|
||||
return null
|
||||
} finally {
|
||||
loading.value = false
|
||||
|
||||
Reference in New Issue
Block a user