mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 03:55:55 +00:00
feat: implement account email mismatch error handling and improve user feedback in authentication flows
This commit is contained in:
@@ -4,6 +4,7 @@ import asyncio
|
||||
import traceback
|
||||
|
||||
from .. import group
|
||||
from .....entity.errors import account as account_errors
|
||||
|
||||
|
||||
@group.group_class('user', '/api/v1/user')
|
||||
@@ -141,6 +142,8 @@ class UserRouterGroup(group.RouterGroup):
|
||||
'user': user_obj.user,
|
||||
}
|
||||
)
|
||||
except account_errors.AccountEmailMismatchError as e:
|
||||
return self.fail(3, str(e))
|
||||
except ValueError as e:
|
||||
traceback.print_exc()
|
||||
return self.fail(1, str(e))
|
||||
|
||||
@@ -10,6 +10,7 @@ import asyncio
|
||||
from ....core import app
|
||||
from ....entity.persistence import user
|
||||
from ....utils import constants
|
||||
from ....entity.errors import account as account_errors
|
||||
|
||||
|
||||
class UserService:
|
||||
@@ -174,9 +175,7 @@ class UserService:
|
||||
# Check if system is already initialized
|
||||
is_initialized = await self.is_initialized()
|
||||
if is_initialized:
|
||||
raise ValueError(
|
||||
'This LangBot instance already has an account. Please use the existing account to login.'
|
||||
)
|
||||
raise account_errors.AccountEmailMismatchError()
|
||||
|
||||
# Create new Space user (first time initialization)
|
||||
await self.ap.persistence_mgr.execute_async(
|
||||
|
||||
6
src/langbot/pkg/entity/errors/account.py
Normal file
6
src/langbot/pkg/entity/errors/account.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
class AccountEmailMismatchError(Exception):
|
||||
def __str__(self):
|
||||
return 'Account email mismatch'
|
||||
@@ -48,9 +48,15 @@ function SpaceOAuthCallbackContent() {
|
||||
setTimeout(() => {
|
||||
router.push('/home');
|
||||
}, 1000);
|
||||
} catch {
|
||||
} catch (err) {
|
||||
setStatus('error');
|
||||
setErrorMessage(t('common.spaceLoginFailed'));
|
||||
const errorObj = err as { msg?: string };
|
||||
const errMsg = (errorObj?.msg || '').toLowerCase();
|
||||
if (errMsg.includes('account email mismatch')) {
|
||||
setErrorMessage(t('account.spaceEmailMismatch'));
|
||||
} else {
|
||||
setErrorMessage(t('common.spaceLoginFailed'));
|
||||
}
|
||||
}
|
||||
},
|
||||
[router, t],
|
||||
@@ -74,9 +80,13 @@ function SpaceOAuthCallbackContent() {
|
||||
}, 1000);
|
||||
} catch (err) {
|
||||
setStatus('error');
|
||||
setErrorMessage(
|
||||
err instanceof Error ? err.message : t('account.bindSpaceFailed'),
|
||||
);
|
||||
const errorObj = err as { msg?: string };
|
||||
const errMsg = (errorObj?.msg || '').toLowerCase();
|
||||
if (errMsg.includes('account email mismatch')) {
|
||||
setErrorMessage(t('account.spaceEmailMismatch'));
|
||||
} else {
|
||||
setErrorMessage(t('account.bindSpaceFailed'));
|
||||
}
|
||||
} finally {
|
||||
setIsProcessing(false);
|
||||
}
|
||||
|
||||
@@ -753,7 +753,7 @@ export class BackendClient extends BaseHttpClient {
|
||||
});
|
||||
}
|
||||
|
||||
public bindSpaceAccount(
|
||||
public async bindSpaceAccount(
|
||||
code: string,
|
||||
state: string,
|
||||
): Promise<{
|
||||
@@ -761,7 +761,17 @@ export class BackendClient extends BaseHttpClient {
|
||||
user: string;
|
||||
account_type: 'local' | 'space';
|
||||
}> {
|
||||
return this.post('/api/v1/user/bind-space', { code, state });
|
||||
const response = await this.instance.post('/api/v1/user/bind-space', {
|
||||
code,
|
||||
state,
|
||||
});
|
||||
if (response.data.code !== 0) {
|
||||
throw {
|
||||
code: response.data.code,
|
||||
msg: response.data.msg || 'Unknown error',
|
||||
};
|
||||
}
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
// ============ Space OAuth API (Redirect Flow) ============
|
||||
@@ -778,10 +788,19 @@ export class BackendClient extends BaseHttpClient {
|
||||
return this.get('/api/v1/user/space/authorize-url', params);
|
||||
}
|
||||
|
||||
public exchangeSpaceOAuthCode(code: string): Promise<{
|
||||
public async exchangeSpaceOAuthCode(code: string): Promise<{
|
||||
token: string;
|
||||
user: string;
|
||||
}> {
|
||||
return this.post('/api/v1/user/space/callback', { code });
|
||||
const response = await this.instance.post('/api/v1/user/space/callback', {
|
||||
code,
|
||||
});
|
||||
if (response.data.code !== 0) {
|
||||
throw {
|
||||
code: response.data.code,
|
||||
msg: response.data.msg || 'Unknown error',
|
||||
};
|
||||
}
|
||||
return response.data.data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,9 +93,7 @@ export abstract class BaseHttpClient {
|
||||
// 统一错误处理
|
||||
if (error.response) {
|
||||
const { status, data } = error.response;
|
||||
// Backend uses 'msg' field, also check 'message' for compatibility
|
||||
const errMessage =
|
||||
(data as { msg?: string })?.msg || data?.message || error.message;
|
||||
const errMsg = (data as { msg?: string })?.msg || error.message;
|
||||
|
||||
switch (status) {
|
||||
case 401:
|
||||
@@ -107,23 +105,23 @@ export abstract class BaseHttpClient {
|
||||
}
|
||||
break;
|
||||
case 403:
|
||||
console.error('Permission denied:', errMessage);
|
||||
console.error('Permission denied:', errMsg);
|
||||
break;
|
||||
case 500:
|
||||
console.error('Server error:', errMessage);
|
||||
console.error('Server error:', errMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
return Promise.reject({
|
||||
code: data?.code || status,
|
||||
message: errMessage,
|
||||
msg: errMsg,
|
||||
data: data?.data || null,
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject({
|
||||
code: -1,
|
||||
message: error.message || 'Network Error',
|
||||
msg: error.message || 'Network Error',
|
||||
data: null,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -789,6 +789,8 @@ const enUS = {
|
||||
bindSpaceInvalidState:
|
||||
'Invalid bind request. Please try again from account settings.',
|
||||
setPasswordHint: 'Set a password to login with email and password',
|
||||
spaceEmailMismatch:
|
||||
'Space login email does not match the local account email',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -798,6 +798,8 @@ const jaJP = {
|
||||
'無効な連携リクエストです。アカウント設定から再度お試しください。',
|
||||
setPasswordHint:
|
||||
'パスワードを設定するとメールとパスワードでログインできます',
|
||||
spaceEmailMismatch:
|
||||
'Spaceログインのメールアドレスがローカルアカウントのメールアドレスと一致しません',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -753,6 +753,7 @@ const zhHans = {
|
||||
bindSpaceFailed: '绑定 Space 账户失败',
|
||||
bindSpaceInvalidState: '无效的绑定请求,请从账户设置重新发起',
|
||||
setPasswordHint: '设置密码后可使用邮箱密码登录',
|
||||
spaceEmailMismatch: 'Space登录账号邮箱与本实例账号邮箱不匹配',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -750,6 +750,7 @@ const zhHant = {
|
||||
bindSpaceFailed: '綁定 Space 帳戶失敗',
|
||||
bindSpaceInvalidState: '無效的綁定請求,請從帳戶設定重新發起',
|
||||
setPasswordHint: '設定密碼後可使用電子郵件密碼登入',
|
||||
spaceEmailMismatch: 'Space登入帳號電子郵件與本實例帳號電子郵件不匹配',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user