forked from baron/baron-sso
네이버 계정 정합성 맞춤
This commit is contained in:
@@ -34,13 +34,53 @@ class AuthProxyService {
|
||||
}
|
||||
|
||||
static Exception _error(String key, String fallback, {String? detail}) {
|
||||
return Exception(
|
||||
tr(
|
||||
key,
|
||||
fallback: fallback,
|
||||
params: detail != null ? {'error': detail} : null,
|
||||
),
|
||||
);
|
||||
final params = detail != null ? {'error': detail} : null;
|
||||
var message = tr(key, fallback: fallback, params: params);
|
||||
if (message == key && fallback.isNotEmpty) {
|
||||
message = _interpolateFallback(fallback, params);
|
||||
}
|
||||
return Exception(message);
|
||||
}
|
||||
|
||||
static String _interpolateFallback(
|
||||
String fallback,
|
||||
Map<String, String>? params,
|
||||
) {
|
||||
var message = fallback;
|
||||
params?.forEach((key, value) {
|
||||
message = message.replaceAll('{{$key}}', value);
|
||||
});
|
||||
return message;
|
||||
}
|
||||
|
||||
static String _responseErrorDetail(http.Response response) {
|
||||
final body = response.body.trim();
|
||||
if (body.isEmpty) {
|
||||
return 'HTTP ${response.statusCode}';
|
||||
}
|
||||
try {
|
||||
final decoded = jsonDecode(body);
|
||||
if (decoded is Map<String, dynamic>) {
|
||||
final value = decoded['error'] ?? decoded['message'];
|
||||
if (value is String && value.trim().isNotEmpty) {
|
||||
return _formatUserPolicyError(value);
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// Fall back to the raw response body.
|
||||
}
|
||||
return _formatUserPolicyError(body);
|
||||
}
|
||||
|
||||
static String _formatUserPolicyError(String message) {
|
||||
final normalized = message.toLowerCase();
|
||||
if (normalized.contains(
|
||||
'internal email domain cannot be assigned to personal tenant',
|
||||
) ||
|
||||
normalized.contains('내부 도메인 사용자는 개인 소속으로 생성하거나 변경할 수 없습니다')) {
|
||||
return '내부 도메인 사용자는 개인 소속으로 생성하거나 변경할 수 없습니다. 대표소속을 회사 또는 조직 소속으로 지정해 주세요.';
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
static http.Client _createClient({bool withCredentials = false}) {
|
||||
@@ -735,8 +775,8 @@ class AuthProxyService {
|
||||
if (response.statusCode != 200) {
|
||||
throw _error(
|
||||
'err.userfront.auth_proxy.user_create',
|
||||
'Failed to create the user: {{error}}',
|
||||
detail: response.body,
|
||||
'사용자 생성 실패: {{error}}',
|
||||
detail: _responseErrorDetail(response),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -844,8 +884,8 @@ class AuthProxyService {
|
||||
if (response.statusCode != 200) {
|
||||
throw _error(
|
||||
'err.userfront.auth_proxy.user_update',
|
||||
'Failed to update the user: {{error}}',
|
||||
detail: response.body,
|
||||
'사용자 수정 실패: {{error}}',
|
||||
detail: _responseErrorDetail(response),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,18 +242,6 @@ const Map<String, String> koStrings = {
|
||||
"msg.admin.tenants.sub.empty": "하위 테넌트가 없습니다.",
|
||||
"msg.admin.tenants.sub.subtitle": "현재 테넌트 하위에 생성된 조직입니다.",
|
||||
"msg.admin.tenants.subtitle": "현재 등록된 테넌트를 확인하고 상태를 관리합니다.",
|
||||
"msg.admin.user_projection.action_error": "사용자 동기화 작업에 실패했습니다.",
|
||||
"msg.admin.user_projection.action_success":
|
||||
"{{count}}명 기준으로 사용자 동기화를 갱신했습니다.",
|
||||
"msg.admin.user_projection.forbidden.description":
|
||||
"이 화면은 super_admin 권한으로만 접근할 수 있습니다.",
|
||||
"msg.admin.user_projection.forbidden_description":
|
||||
"이 화면은 super_admin 권한으로만 접근할 수 있습니다.",
|
||||
"msg.admin.user_projection.load_error": "사용자 동기화 상태를 불러오지 못했습니다.",
|
||||
"msg.admin.user_projection.reset_confirm":
|
||||
"사용자 동기화를 Kratos 기준으로 다시 구축하시겠습니까?",
|
||||
"msg.admin.user_projection.subtitle":
|
||||
"Kratos 사용자 read model을 확인하고 동기화 상태를 갱신합니다.",
|
||||
"msg.admin.users.bulk.delete_confirm": "선택한 {{count}}명의 사용자를 정말로 삭제하시겠습니까?",
|
||||
"msg.admin.users.bulk.delete_success": "{{count}}명의 사용자가 삭제되었습니다.",
|
||||
"msg.admin.users.bulk.description": "CSV 파일을 통해 사용자를 일괄 등록하거나 관리합니다.",
|
||||
@@ -1229,21 +1217,6 @@ const Map<String, String> koStrings = {
|
||||
"ui.admin.tenants.worksmobile.sync_user": "구성원 Sync",
|
||||
"ui.admin.tenants.worksmobile.title": "Worksmobile 연동",
|
||||
"ui.admin.title": "Admin Control",
|
||||
"ui.admin.user_projection.actions.reconcile": "재동기화",
|
||||
"ui.admin.user_projection.actions.reset": "초기화 후 재구축",
|
||||
"ui.admin.user_projection.card.description":
|
||||
"Backend DB 통계가 참조하는 사용자 read model 상태입니다.",
|
||||
"ui.admin.user_projection.card.title": "Kratos 사용자 동기화",
|
||||
"ui.admin.user_projection.forbidden.title": "접근 권한이 없습니다",
|
||||
"ui.admin.user_projection.loading": "불러오는 중",
|
||||
"ui.admin.user_projection.status.failed": "실패",
|
||||
"ui.admin.user_projection.status.not_ready": "준비되지 않음",
|
||||
"ui.admin.user_projection.status.ready": "준비됨",
|
||||
"ui.admin.user_projection.summary.last_synced": "마지막 동기화",
|
||||
"ui.admin.user_projection.summary.projected_users": "동기화 사용자",
|
||||
"ui.admin.user_projection.summary.status": "상태",
|
||||
"ui.admin.user_projection.summary.updated_at": "상태 갱신",
|
||||
"ui.admin.user_projection.title": "사용자 동기화 관리",
|
||||
"ui.admin.users.bulk.acknowledge_warning": "경고를 확인했으며 계속 진행합니다.",
|
||||
"ui.admin.users.bulk.create_missing_tenant": "신규 생성",
|
||||
"ui.admin.users.bulk.do_move": "이동 실행",
|
||||
@@ -2583,18 +2556,6 @@ const Map<String, String> enStrings = {
|
||||
"Review and manage child tenants linked under this tenant.",
|
||||
"msg.admin.tenants.subtitle":
|
||||
"Review registered tenants and manage their current status.",
|
||||
"msg.admin.user_projection.action_error": "Projection operation failed.",
|
||||
"msg.admin.user_projection.action_success":
|
||||
"Refreshed the projection for {{count}} users.",
|
||||
"msg.admin.user_projection.forbidden.description":
|
||||
"This screen is only available to super_admin users.",
|
||||
"msg.admin.user_projection.forbidden_description":
|
||||
"This screen is only available to super_admin users.",
|
||||
"msg.admin.user_projection.load_error": "Failed to load projection status.",
|
||||
"msg.admin.user_projection.reset_confirm":
|
||||
"Rebuild user projection from the Kratos source of truth?",
|
||||
"msg.admin.user_projection.subtitle":
|
||||
"Review and sync the Kratos user read model.",
|
||||
"msg.admin.users.bulk.delete_confirm":
|
||||
"Are you sure you want to delete the selected {{count}} users?",
|
||||
"msg.admin.users.bulk.delete_success": "{{count}} users have been deleted.",
|
||||
@@ -3718,23 +3679,6 @@ const Map<String, String> enStrings = {
|
||||
"ui.admin.tenants.worksmobile.sync_user": "User Sync",
|
||||
"ui.admin.tenants.worksmobile.title": "Worksmobile Integration",
|
||||
"ui.admin.title": "Admin Control",
|
||||
"ui.admin.user_projection.actions.reconcile": "Re-sync",
|
||||
"ui.admin.user_projection.actions.reset": "Reset and rebuild",
|
||||
"ui.admin.user_projection.card.description":
|
||||
"Current user read model state referenced by backend DB statistics.",
|
||||
"ui.admin.user_projection.card.title": "Kratos users projection",
|
||||
"ui.admin.user_projection.forbidden.title": "Access denied",
|
||||
"ui.admin.user_projection.loading": "Loading user projection data...",
|
||||
"ui.admin.user_projection.status.failed": "failed",
|
||||
"ui.admin.user_projection.status.not_ready": "not ready",
|
||||
"ui.admin.user_projection.status.ready": "ready",
|
||||
"ui.admin.user_projection.subtitle":
|
||||
"Review and sync the Kratos user read model.",
|
||||
"ui.admin.user_projection.summary.last_synced": "Last synced",
|
||||
"ui.admin.user_projection.summary.projected_users": "Projected users",
|
||||
"ui.admin.user_projection.summary.status": "Status",
|
||||
"ui.admin.user_projection.summary.updated_at": "Updated at",
|
||||
"ui.admin.user_projection.title": "User Projection Management",
|
||||
"ui.admin.users.bulk.acknowledge_warning":
|
||||
"I acknowledge the warning and will proceed.",
|
||||
"ui.admin.users.bulk.create_missing_tenant": "Create new",
|
||||
|
||||
@@ -203,6 +203,49 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
test('createUser는 내부 도메인 personal 정책 오류를 한국어 안내로 표시한다', () async {
|
||||
client.enqueueJson({
|
||||
'error':
|
||||
'internal email domain cannot be assigned to personal tenant: user@hanmaceng.co.kr',
|
||||
}, statusCode: 400);
|
||||
|
||||
await expectLater(
|
||||
AuthProxyService.createUser(
|
||||
loginId: 'user@hanmaceng.co.kr',
|
||||
adminPassword: 'admin-pass',
|
||||
email: 'user@hanmaceng.co.kr',
|
||||
),
|
||||
throwsA(
|
||||
isA<Exception>().having(
|
||||
(error) => error.toString(),
|
||||
'message',
|
||||
contains('대표소속을 회사 또는 조직 소속으로 지정해 주세요'),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('updateUserDetails는 내부 도메인 personal 정책 오류를 한국어 안내로 표시한다', () async {
|
||||
client.enqueueJson({
|
||||
'error': '내부 도메인 사용자는 개인 소속으로 생성하거나 변경할 수 없습니다: user@brsw.kr',
|
||||
}, statusCode: 400);
|
||||
|
||||
await expectLater(
|
||||
AuthProxyService.updateUserDetails(
|
||||
adminPassword: 'admin-pass',
|
||||
loginId: 'user@brsw.kr',
|
||||
email: 'user@brsw.kr',
|
||||
),
|
||||
throwsA(
|
||||
isA<Exception>().having(
|
||||
(error) => error.toString(),
|
||||
'message',
|
||||
contains('대표소속을 회사 또는 조직 소속으로 지정해 주세요'),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('sendLog는 민감 정보를 제거한 client log를 전송한다', () async {
|
||||
client.enqueueJson({'ok': true});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user