mirror of
https://github.com/langgenius/dify.git
synced 2026-03-19 22:52:01 +00:00
Compare commits
5 Commits
yanli/fix-
...
refactor/w
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
366f905b94 | ||
|
|
e7ac298ec6 | ||
|
|
f864604c94 | ||
|
|
7d19825659 | ||
|
|
11e1787100 |
@@ -7,6 +7,7 @@ from sqlalchemy import select
|
||||
from werkzeug.exceptions import Unauthorized
|
||||
|
||||
import services
|
||||
from configs import dify_config
|
||||
from controllers.common.errors import (
|
||||
FilenameNotExistsError,
|
||||
FileTooLargeError,
|
||||
@@ -29,6 +30,7 @@ from libs.helper import TimestampField
|
||||
from libs.login import current_account_with_tenant, login_required
|
||||
from models.account import Tenant, TenantStatus
|
||||
from services.account_service import TenantService
|
||||
from services.billing_service import BillingService
|
||||
from services.enterprise.enterprise_service import EnterpriseService
|
||||
from services.feature_service import FeatureService
|
||||
from services.file_service import FileService
|
||||
@@ -108,9 +110,27 @@ class TenantListApi(Resource):
|
||||
current_user, current_tenant_id = current_account_with_tenant()
|
||||
tenants = TenantService.get_join_tenants(current_user)
|
||||
tenant_dicts = []
|
||||
is_enterprise_only = dify_config.ENTERPRISE_ENABLED and not dify_config.BILLING_ENABLED
|
||||
is_saas = dify_config.EDITION == "CLOUD" and dify_config.BILLING_ENABLED
|
||||
tenant_plans: dict[str, dict] = {}
|
||||
use_legacy_feature_path = not is_enterprise_only and not is_saas
|
||||
|
||||
if is_saas:
|
||||
tenant_ids = [tenant.id for tenant in tenants]
|
||||
if tenant_ids:
|
||||
try:
|
||||
tenant_plans = BillingService.get_plan_bulk(tenant_ids)
|
||||
except Exception:
|
||||
logger.exception("failed to fetch workspace plans in bulk, falling back to legacy feature path")
|
||||
use_legacy_feature_path = True
|
||||
|
||||
for tenant in tenants:
|
||||
features = FeatureService.get_features(tenant.id)
|
||||
plan = CloudPlan.SANDBOX
|
||||
if is_saas and not use_legacy_feature_path:
|
||||
plan = tenant_plans.get(tenant.id, {}).get("plan", CloudPlan.SANDBOX)
|
||||
elif not is_enterprise_only:
|
||||
features = FeatureService.get_features(tenant.id)
|
||||
plan = features.billing.subscription.plan or CloudPlan.SANDBOX
|
||||
|
||||
# Create a dictionary with tenant attributes
|
||||
tenant_dict = {
|
||||
@@ -118,7 +138,7 @@ class TenantListApi(Resource):
|
||||
"name": tenant.name,
|
||||
"status": tenant.status,
|
||||
"created_at": tenant.created_at,
|
||||
"plan": features.billing.subscription.plan if features.billing.enabled else CloudPlan.SANDBOX,
|
||||
"plan": plan,
|
||||
"current": tenant.id == current_tenant_id if current_tenant_id else False,
|
||||
}
|
||||
|
||||
|
||||
@@ -48,41 +48,42 @@ class TestToolTransformService:
|
||||
name=fake.company(),
|
||||
description=fake.text(max_nb_chars=100),
|
||||
icon='{"background": "#FF6B6B", "content": "🔧"}',
|
||||
icon_dark='{"background": "#252525", "content": "🔧"}',
|
||||
tenant_id="test_tenant_id",
|
||||
user_id="test_user_id",
|
||||
credentials={"auth_type": "api_key_header", "api_key": "test_key"},
|
||||
provider_type="api",
|
||||
credentials_str='{"auth_type": "api_key_header", "api_key": "test_key"}',
|
||||
schema="{}",
|
||||
schema_type_str="openapi",
|
||||
tools_str="[]",
|
||||
)
|
||||
elif provider_type == "builtin":
|
||||
provider = BuiltinToolProvider(
|
||||
name=fake.company(),
|
||||
description=fake.text(max_nb_chars=100),
|
||||
icon="🔧",
|
||||
icon_dark="🔧",
|
||||
tenant_id="test_tenant_id",
|
||||
user_id="test_user_id",
|
||||
provider="test_provider",
|
||||
credential_type="api_key",
|
||||
credentials={"api_key": "test_key"},
|
||||
encrypted_credentials='{"api_key": "test_key"}',
|
||||
)
|
||||
elif provider_type == "workflow":
|
||||
provider = WorkflowToolProvider(
|
||||
name=fake.company(),
|
||||
description=fake.text(max_nb_chars=100),
|
||||
icon='{"background": "#FF6B6B", "content": "🔧"}',
|
||||
icon_dark='{"background": "#252525", "content": "🔧"}',
|
||||
tenant_id="test_tenant_id",
|
||||
user_id="test_user_id",
|
||||
workflow_id="test_workflow_id",
|
||||
app_id="test_workflow_id",
|
||||
label="Test Workflow",
|
||||
version="1.0.0",
|
||||
parameter_configuration="[]",
|
||||
)
|
||||
elif provider_type == "mcp":
|
||||
provider = MCPToolProvider(
|
||||
name=fake.company(),
|
||||
description=fake.text(max_nb_chars=100),
|
||||
provider_icon='{"background": "#FF6B6B", "content": "🔧"}',
|
||||
icon='{"background": "#FF6B6B", "content": "🔧"}',
|
||||
tenant_id="test_tenant_id",
|
||||
user_id="test_user_id",
|
||||
server_url="https://mcp.example.com",
|
||||
server_url_hash="test_server_url_hash",
|
||||
server_identifier="test_server",
|
||||
tools='[{"name": "test_tool", "description": "Test tool"}]',
|
||||
authed=True,
|
||||
|
||||
@@ -36,7 +36,98 @@ def unwrap(func):
|
||||
|
||||
|
||||
class TestTenantListApi:
|
||||
def test_get_success(self, app):
|
||||
def test_get_success_saas_path(self, app):
|
||||
api = TenantListApi()
|
||||
method = unwrap(api.get)
|
||||
|
||||
tenant1 = MagicMock(
|
||||
id="t1",
|
||||
name="Tenant 1",
|
||||
status="active",
|
||||
created_at=datetime.utcnow(),
|
||||
)
|
||||
tenant2 = MagicMock(
|
||||
id="t2",
|
||||
name="Tenant 2",
|
||||
status="active",
|
||||
created_at=datetime.utcnow(),
|
||||
)
|
||||
|
||||
with (
|
||||
app.test_request_context("/workspaces"),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.current_account_with_tenant", return_value=(MagicMock(), "t1")
|
||||
),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.TenantService.get_join_tenants",
|
||||
return_value=[tenant1, tenant2],
|
||||
),
|
||||
patch("controllers.console.workspace.workspace.dify_config.ENTERPRISE_ENABLED", False),
|
||||
patch("controllers.console.workspace.workspace.dify_config.BILLING_ENABLED", True),
|
||||
patch("controllers.console.workspace.workspace.dify_config.EDITION", "CLOUD"),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.BillingService.get_plan_bulk",
|
||||
return_value={
|
||||
"t1": {"plan": CloudPlan.TEAM, "expiration_date": 0},
|
||||
"t2": {"plan": CloudPlan.PROFESSIONAL, "expiration_date": 0},
|
||||
},
|
||||
) as get_plan_bulk_mock,
|
||||
patch("controllers.console.workspace.workspace.FeatureService.get_features") as get_features_mock,
|
||||
):
|
||||
result, status = method(api)
|
||||
|
||||
assert status == 200
|
||||
assert len(result["workspaces"]) == 2
|
||||
assert result["workspaces"][0]["current"] is True
|
||||
assert result["workspaces"][0]["plan"] == CloudPlan.TEAM
|
||||
assert result["workspaces"][1]["plan"] == CloudPlan.PROFESSIONAL
|
||||
get_plan_bulk_mock.assert_called_once_with(["t1", "t2"])
|
||||
get_features_mock.assert_not_called()
|
||||
|
||||
def test_get_saas_path_falls_back_to_sandbox_for_missing_tenant(self, app):
|
||||
api = TenantListApi()
|
||||
method = unwrap(api.get)
|
||||
|
||||
tenant1 = MagicMock(
|
||||
id="t1",
|
||||
name="Tenant 1",
|
||||
status="active",
|
||||
created_at=datetime.utcnow(),
|
||||
)
|
||||
tenant2 = MagicMock(
|
||||
id="t2",
|
||||
name="Tenant 2",
|
||||
status="active",
|
||||
created_at=datetime.utcnow(),
|
||||
)
|
||||
|
||||
with (
|
||||
app.test_request_context("/workspaces"),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.current_account_with_tenant", return_value=(MagicMock(), "t1")
|
||||
),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.TenantService.get_join_tenants",
|
||||
return_value=[tenant1, tenant2],
|
||||
),
|
||||
patch("controllers.console.workspace.workspace.dify_config.ENTERPRISE_ENABLED", False),
|
||||
patch("controllers.console.workspace.workspace.dify_config.BILLING_ENABLED", True),
|
||||
patch("controllers.console.workspace.workspace.dify_config.EDITION", "CLOUD"),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.BillingService.get_plan_bulk",
|
||||
return_value={"t1": {"plan": CloudPlan.TEAM, "expiration_date": 0}},
|
||||
) as get_plan_bulk_mock,
|
||||
patch("controllers.console.workspace.workspace.FeatureService.get_features") as get_features_mock,
|
||||
):
|
||||
result, status = method(api)
|
||||
|
||||
assert status == 200
|
||||
assert result["workspaces"][0]["plan"] == CloudPlan.TEAM
|
||||
assert result["workspaces"][1]["plan"] == CloudPlan.SANDBOX
|
||||
get_plan_bulk_mock.assert_called_once_with(["t1", "t2"])
|
||||
get_features_mock.assert_not_called()
|
||||
|
||||
def test_get_saas_path_falls_back_to_legacy_feature_path_on_bulk_error(self, app):
|
||||
api = TenantListApi()
|
||||
method = unwrap(api.get)
|
||||
|
||||
@@ -54,27 +145,41 @@ class TestTenantListApi:
|
||||
)
|
||||
|
||||
features = MagicMock()
|
||||
features.billing.enabled = True
|
||||
features.billing.subscription.plan = CloudPlan.SANDBOX
|
||||
features.billing.enabled = False
|
||||
features.billing.subscription.plan = CloudPlan.TEAM
|
||||
|
||||
with (
|
||||
app.test_request_context("/workspaces"),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.current_account_with_tenant", return_value=(MagicMock(), "t1")
|
||||
"controllers.console.workspace.workspace.current_account_with_tenant", return_value=(MagicMock(), "t2")
|
||||
),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.TenantService.get_join_tenants",
|
||||
return_value=[tenant1, tenant2],
|
||||
),
|
||||
patch("controllers.console.workspace.workspace.FeatureService.get_features", return_value=features),
|
||||
patch("controllers.console.workspace.workspace.dify_config.ENTERPRISE_ENABLED", False),
|
||||
patch("controllers.console.workspace.workspace.dify_config.BILLING_ENABLED", True),
|
||||
patch("controllers.console.workspace.workspace.dify_config.EDITION", "CLOUD"),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.BillingService.get_plan_bulk",
|
||||
side_effect=RuntimeError("billing down"),
|
||||
) as get_plan_bulk_mock,
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.FeatureService.get_features",
|
||||
return_value=features,
|
||||
) as get_features_mock,
|
||||
patch("controllers.console.workspace.workspace.logger.exception") as logger_exception_mock,
|
||||
):
|
||||
result, status = method(api)
|
||||
|
||||
assert status == 200
|
||||
assert len(result["workspaces"]) == 2
|
||||
assert result["workspaces"][0]["current"] is True
|
||||
assert result["workspaces"][0]["plan"] == CloudPlan.TEAM
|
||||
assert result["workspaces"][1]["plan"] == CloudPlan.TEAM
|
||||
get_plan_bulk_mock.assert_called_once_with(["t1", "t2"])
|
||||
assert get_features_mock.call_count == 2
|
||||
logger_exception_mock.assert_called_once()
|
||||
|
||||
def test_get_billing_disabled(self, app):
|
||||
def test_get_billing_disabled_community_path(self, app):
|
||||
api = TenantListApi()
|
||||
method = unwrap(api.get)
|
||||
|
||||
@@ -98,15 +203,83 @@ class TestTenantListApi:
|
||||
"controllers.console.workspace.workspace.TenantService.get_join_tenants",
|
||||
return_value=[tenant],
|
||||
),
|
||||
patch("controllers.console.workspace.workspace.dify_config.ENTERPRISE_ENABLED", False),
|
||||
patch("controllers.console.workspace.workspace.dify_config.BILLING_ENABLED", False),
|
||||
patch("controllers.console.workspace.workspace.dify_config.EDITION", "SELF_HOSTED"),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.FeatureService.get_features",
|
||||
return_value=features,
|
||||
),
|
||||
) as get_features_mock,
|
||||
):
|
||||
result, status = method(api)
|
||||
|
||||
assert status == 200
|
||||
assert result["workspaces"][0]["plan"] == CloudPlan.SANDBOX
|
||||
get_features_mock.assert_called_once_with("t1")
|
||||
|
||||
def test_get_enterprise_only_skips_feature_service(self, app):
|
||||
api = TenantListApi()
|
||||
method = unwrap(api.get)
|
||||
|
||||
tenant1 = MagicMock(
|
||||
id="t1",
|
||||
name="Tenant 1",
|
||||
status="active",
|
||||
created_at=datetime.utcnow(),
|
||||
)
|
||||
tenant2 = MagicMock(
|
||||
id="t2",
|
||||
name="Tenant 2",
|
||||
status="active",
|
||||
created_at=datetime.utcnow(),
|
||||
)
|
||||
|
||||
with (
|
||||
app.test_request_context("/workspaces"),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.current_account_with_tenant", return_value=(MagicMock(), "t2")
|
||||
),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.TenantService.get_join_tenants",
|
||||
return_value=[tenant1, tenant2],
|
||||
),
|
||||
patch("controllers.console.workspace.workspace.dify_config.ENTERPRISE_ENABLED", True),
|
||||
patch("controllers.console.workspace.workspace.dify_config.BILLING_ENABLED", False),
|
||||
patch("controllers.console.workspace.workspace.dify_config.EDITION", "SELF_HOSTED"),
|
||||
patch("controllers.console.workspace.workspace.FeatureService.get_features") as get_features_mock,
|
||||
):
|
||||
result, status = method(api)
|
||||
|
||||
assert status == 200
|
||||
assert result["workspaces"][0]["plan"] == CloudPlan.SANDBOX
|
||||
assert result["workspaces"][1]["plan"] == CloudPlan.SANDBOX
|
||||
assert result["workspaces"][0]["current"] is False
|
||||
assert result["workspaces"][1]["current"] is True
|
||||
get_features_mock.assert_not_called()
|
||||
|
||||
def test_get_enterprise_only_with_empty_tenants(self, app):
|
||||
api = TenantListApi()
|
||||
method = unwrap(api.get)
|
||||
|
||||
with (
|
||||
app.test_request_context("/workspaces"),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.current_account_with_tenant", return_value=(MagicMock(), None)
|
||||
),
|
||||
patch(
|
||||
"controllers.console.workspace.workspace.TenantService.get_join_tenants",
|
||||
return_value=[],
|
||||
),
|
||||
patch("controllers.console.workspace.workspace.dify_config.ENTERPRISE_ENABLED", True),
|
||||
patch("controllers.console.workspace.workspace.dify_config.BILLING_ENABLED", False),
|
||||
patch("controllers.console.workspace.workspace.dify_config.EDITION", "SELF_HOSTED"),
|
||||
patch("controllers.console.workspace.workspace.FeatureService.get_features") as get_features_mock,
|
||||
):
|
||||
result, status = method(api)
|
||||
|
||||
assert status == 200
|
||||
assert result["workspaces"] == []
|
||||
get_features_mock.assert_not_called()
|
||||
|
||||
|
||||
class TestWorkspaceListApi:
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "عنوان البريد الإلكتروني مطلوب",
|
||||
"error.emailInValid": "يرجى إدخال عنوان بريد إلكتروني صالح",
|
||||
"error.invalidEmailOrPassword": "بريد إلكتروني أو كلمة مرور غير صالحة.",
|
||||
"error.invalidRedirectUrlOrAppCode": "رابط إعادة التوجيه أو رمز التطبيق غير صالح",
|
||||
"error.invalidSSOProtocol": "بروتوكول SSO غير صالح",
|
||||
"error.nameEmpty": "الاسم مطلوب",
|
||||
"error.passwordEmpty": "كلمة المرور مطلوبة",
|
||||
"error.passwordInvalid": "يجب أن تحتوي كلمة المرور على أحرف وأرقام، ويجب أن يكون الطول أكبر من 8",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "E-Mail-Adresse wird benötigt",
|
||||
"error.emailInValid": "Bitte gib eine gültige E-Mail-Adresse ein",
|
||||
"error.invalidEmailOrPassword": "Ungültige E-Mail oder Passwort.",
|
||||
"error.invalidRedirectUrlOrAppCode": "Ungültige Weiterleitungs-URL oder App-Code",
|
||||
"error.invalidSSOProtocol": "Ungültiges SSO-Protokoll",
|
||||
"error.nameEmpty": "Name wird benötigt",
|
||||
"error.passwordEmpty": "Passwort wird benötigt",
|
||||
"error.passwordInvalid": "Das Passwort muss Buchstaben und Zahlen enthalten und länger als 8 Zeichen sein",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "Se requiere una dirección de correo electrónico",
|
||||
"error.emailInValid": "Por favor, ingresa una dirección de correo electrónico válida",
|
||||
"error.invalidEmailOrPassword": "Correo electrónico o contraseña inválidos.",
|
||||
"error.invalidRedirectUrlOrAppCode": "URL de redirección o código de aplicación inválido",
|
||||
"error.invalidSSOProtocol": "Protocolo SSO inválido",
|
||||
"error.nameEmpty": "Se requiere un nombre",
|
||||
"error.passwordEmpty": "Se requiere una contraseña",
|
||||
"error.passwordInvalid": "La contraseña debe contener letras y números, y tener una longitud mayor a 8",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "آدرس ایمیل لازم است",
|
||||
"error.emailInValid": "لطفاً یک آدرس ایمیل معتبر وارد کنید",
|
||||
"error.invalidEmailOrPassword": "ایمیل یا رمز عبور نامعتبر است.",
|
||||
"error.invalidRedirectUrlOrAppCode": "آدرس تغییر مسیر یا کد برنامه نامعتبر است",
|
||||
"error.invalidSSOProtocol": "پروتکل SSO نامعتبر است",
|
||||
"error.nameEmpty": "نام لازم است",
|
||||
"error.passwordEmpty": "رمز عبور لازم است",
|
||||
"error.passwordInvalid": "رمز عبور باید شامل حروف و اعداد باشد و طول آن بیشتر از ۸ کاراکتر باشد",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "Une adresse e-mail est requise",
|
||||
"error.emailInValid": "Veuillez entrer une adresse email valide",
|
||||
"error.invalidEmailOrPassword": "Adresse e-mail ou mot de passe invalide.",
|
||||
"error.invalidRedirectUrlOrAppCode": "URL de redirection ou code d'application invalide",
|
||||
"error.invalidSSOProtocol": "Protocole SSO invalide",
|
||||
"error.nameEmpty": "Le nom est requis",
|
||||
"error.passwordEmpty": "Un mot de passe est requis",
|
||||
"error.passwordInvalid": "Le mot de passe doit contenir des lettres et des chiffres, et la longueur doit être supérieure à 8.",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "ईमेल पता आवश्यक है",
|
||||
"error.emailInValid": "कृपया एक मान्य ईमेल पता दर्ज करें",
|
||||
"error.invalidEmailOrPassword": "अमान्य ईमेल या पासवर्ड।",
|
||||
"error.invalidRedirectUrlOrAppCode": "अमान्य रीडायरेक्ट URL या ऐप कोड",
|
||||
"error.invalidSSOProtocol": "अमान्य SSO प्रोटोकॉल",
|
||||
"error.nameEmpty": "नाम आवश्यक है",
|
||||
"error.passwordEmpty": "पासवर्ड आवश्यक है",
|
||||
"error.passwordInvalid": "पासवर्ड में अक्षर और अंक होने चाहिए, और लंबाई 8 से अधिक होनी चाहिए",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "Alamat email diperlukan",
|
||||
"error.emailInValid": "Silakan masukkan alamat email yang valid",
|
||||
"error.invalidEmailOrPassword": "Email atau kata sandi tidak valid.",
|
||||
"error.invalidRedirectUrlOrAppCode": "URL pengalihan atau kode aplikasi tidak valid",
|
||||
"error.invalidSSOProtocol": "Protokol SSO tidak valid",
|
||||
"error.nameEmpty": "Nama diperlukan",
|
||||
"error.passwordEmpty": "Kata sandi diperlukan",
|
||||
"error.passwordInvalid": "Kata sandi harus berisi huruf dan angka, dan panjangnya harus lebih besar dari 8",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "L'indirizzo email è obbligatorio",
|
||||
"error.emailInValid": "Per favore inserisci un indirizzo email valido",
|
||||
"error.invalidEmailOrPassword": "Email o password non validi.",
|
||||
"error.invalidRedirectUrlOrAppCode": "URL di reindirizzamento o codice app non valido",
|
||||
"error.invalidSSOProtocol": "Protocollo SSO non valido",
|
||||
"error.nameEmpty": "Il nome è obbligatorio",
|
||||
"error.passwordEmpty": "La password è obbligatoria",
|
||||
"error.passwordInvalid": "La password deve contenere lettere e numeri, e la lunghezza deve essere maggiore di 8",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "メールアドレスは必須です",
|
||||
"error.emailInValid": "有効なメールアドレスを入力してください",
|
||||
"error.invalidEmailOrPassword": "無効なメールアドレスまたはパスワードです。",
|
||||
"error.invalidRedirectUrlOrAppCode": "無効なリダイレクトURLまたはアプリコード",
|
||||
"error.invalidSSOProtocol": "無効なSSOプロトコル",
|
||||
"error.nameEmpty": "名前は必須です",
|
||||
"error.passwordEmpty": "パスワードは必須です",
|
||||
"error.passwordInvalid": "パスワードは文字と数字を含み、長さは 8 以上である必要があります",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "이메일 주소를 입력하세요.",
|
||||
"error.emailInValid": "유효한 이메일 주소를 입력하세요.",
|
||||
"error.invalidEmailOrPassword": "유효하지 않은 이메일이나 비밀번호입니다.",
|
||||
"error.invalidRedirectUrlOrAppCode": "유효하지 않은 리디렉션 URL 또는 앱 코드",
|
||||
"error.invalidSSOProtocol": "유효하지 않은 SSO 프로토콜",
|
||||
"error.nameEmpty": "사용자 이름을 입력하세요.",
|
||||
"error.passwordEmpty": "비밀번호를 입력하세요.",
|
||||
"error.passwordInvalid": "비밀번호는 문자와 숫자를 포함하고 8 자 이상이어야 합니다.",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "Email address is required",
|
||||
"error.emailInValid": "Please enter a valid email address",
|
||||
"error.invalidEmailOrPassword": "Invalid email or password.",
|
||||
"error.invalidRedirectUrlOrAppCode": "Ongeldige doorstuur-URL of app-code",
|
||||
"error.invalidSSOProtocol": "Ongeldig SSO-protocol",
|
||||
"error.nameEmpty": "Name is required",
|
||||
"error.passwordEmpty": "Password is required",
|
||||
"error.passwordInvalid": "Password must contain letters and numbers, and the length must be greater than 8",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "Adres e-mail jest wymagany",
|
||||
"error.emailInValid": "Proszę wpisać prawidłowy adres e-mail",
|
||||
"error.invalidEmailOrPassword": "Nieprawidłowy adres e-mail lub hasło.",
|
||||
"error.invalidRedirectUrlOrAppCode": "Nieprawidłowy adres URL przekierowania lub kod aplikacji",
|
||||
"error.invalidSSOProtocol": "Nieprawidłowy protokół SSO",
|
||||
"error.nameEmpty": "Nazwa jest wymagana",
|
||||
"error.passwordEmpty": "Hasło jest wymagane",
|
||||
"error.passwordInvalid": "Hasło musi zawierać litery i cyfry, a jego długość musi być większa niż 8",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "O endereço de e-mail é obrigatório",
|
||||
"error.emailInValid": "Digite um endereço de e-mail válido",
|
||||
"error.invalidEmailOrPassword": "E-mail ou senha inválidos.",
|
||||
"error.invalidRedirectUrlOrAppCode": "URL de redirecionamento ou código de aplicativo inválido",
|
||||
"error.invalidSSOProtocol": "Protocolo SSO inválido",
|
||||
"error.nameEmpty": "O nome é obrigatório",
|
||||
"error.passwordEmpty": "A senha é obrigatória",
|
||||
"error.passwordInvalid": "A senha deve conter letras e números e ter um comprimento maior que 8",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "Adresa de email este obligatorie",
|
||||
"error.emailInValid": "Te rugăm să introduci o adresă de email validă",
|
||||
"error.invalidEmailOrPassword": "Email sau parolă invalidă.",
|
||||
"error.invalidRedirectUrlOrAppCode": "URL de redirecționare sau cod de aplicație invalid",
|
||||
"error.invalidSSOProtocol": "Protocol SSO invalid",
|
||||
"error.nameEmpty": "Numele este obligatoriu",
|
||||
"error.passwordEmpty": "Parola este obligatorie",
|
||||
"error.passwordInvalid": "Parola trebuie să conțină litere și cifre, iar lungimea trebuie să fie mai mare de 8 caractere",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "Адрес электронной почты обязателен",
|
||||
"error.emailInValid": "Пожалуйста, введите действительный адрес электронной почты",
|
||||
"error.invalidEmailOrPassword": "Неверный адрес электронной почты или пароль.",
|
||||
"error.invalidRedirectUrlOrAppCode": "Неверный URL перенаправления или код приложения",
|
||||
"error.invalidSSOProtocol": "Неверный протокол SSO",
|
||||
"error.nameEmpty": "Имя обязательно",
|
||||
"error.passwordEmpty": "Пароль обязателен",
|
||||
"error.passwordInvalid": "Пароль должен содержать буквы и цифры, а длина должна быть больше 8",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "E-poštni naslov je obvezen",
|
||||
"error.emailInValid": "Prosimo, vnesite veljaven e-poštni naslov",
|
||||
"error.invalidEmailOrPassword": "Neveljaven e-poštni naslov ali geslo.",
|
||||
"error.invalidRedirectUrlOrAppCode": "Neveljaven URL preusmeritve ali koda aplikacije",
|
||||
"error.invalidSSOProtocol": "Neveljaven protokol SSO",
|
||||
"error.nameEmpty": "Ime je obvezno",
|
||||
"error.passwordEmpty": "Geslo je obvezno",
|
||||
"error.passwordInvalid": "Geslo mora vsebovati črke in številke, dolžina pa mora biti več kot 8 znakov",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "ต้องระบุที่อยู่อีเมล",
|
||||
"error.emailInValid": "โปรดป้อนที่อยู่อีเมลที่ถูกต้อง",
|
||||
"error.invalidEmailOrPassword": "อีเมลหรือรหัสผ่านไม่ถูกต้อง.",
|
||||
"error.invalidRedirectUrlOrAppCode": "URL เปลี่ยนเส้นทางหรือรหัสแอปไม่ถูกต้อง",
|
||||
"error.invalidSSOProtocol": "โปรโตคอล SSO ไม่ถูกต้อง",
|
||||
"error.nameEmpty": "ต้องระบุชื่อ",
|
||||
"error.passwordEmpty": "ต้องใช้รหัสผ่าน",
|
||||
"error.passwordInvalid": "รหัสผ่านต้องมีตัวอักษรและตัวเลข และความยาวต้องมากกว่า 8",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "E-posta adresi gereklidir",
|
||||
"error.emailInValid": "Geçerli bir e-posta adresi girin",
|
||||
"error.invalidEmailOrPassword": "Geçersiz e-posta veya şifre.",
|
||||
"error.invalidRedirectUrlOrAppCode": "Geçersiz yönlendirme URL'si veya uygulama kodu",
|
||||
"error.invalidSSOProtocol": "Geçersiz SSO protokolü",
|
||||
"error.nameEmpty": "İsim gereklidir",
|
||||
"error.passwordEmpty": "Şifre gereklidir",
|
||||
"error.passwordInvalid": "Şifre harf ve rakamlardan oluşmalı ve uzunluğu 8 karakterden fazla olmalıdır",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "Адреса електронної пошти обов'язкова",
|
||||
"error.emailInValid": "Введіть дійсну адресу електронної пошти",
|
||||
"error.invalidEmailOrPassword": "Невірний електронний лист або пароль.",
|
||||
"error.invalidRedirectUrlOrAppCode": "Недійсний URL перенаправлення або код додатку",
|
||||
"error.invalidSSOProtocol": "Недійсний протокол SSO",
|
||||
"error.nameEmpty": "Ім'я обов'язкове",
|
||||
"error.passwordEmpty": "Пароль є обов’язковим",
|
||||
"error.passwordInvalid": "Пароль повинен містити літери та цифри, а довжина повинна бути більшою за 8",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "Vui lòng nhập địa chỉ email",
|
||||
"error.emailInValid": "Vui lòng nhập một địa chỉ email hợp lệ",
|
||||
"error.invalidEmailOrPassword": "Email hoặc mật khẩu không hợp lệ.",
|
||||
"error.invalidRedirectUrlOrAppCode": "URL chuyển hướng hoặc mã ứng dụng không hợp lệ",
|
||||
"error.invalidSSOProtocol": "Giao thức SSO không hợp lệ",
|
||||
"error.nameEmpty": "Vui lòng nhập tên",
|
||||
"error.passwordEmpty": "Vui lòng nhập mật khẩu",
|
||||
"error.passwordInvalid": "Mật khẩu phải chứa cả chữ và số, và có độ dài ít nhất 8 ký tự",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "邮箱不能为空",
|
||||
"error.emailInValid": "请输入有效的邮箱地址",
|
||||
"error.invalidEmailOrPassword": "邮箱或密码错误",
|
||||
"error.invalidRedirectUrlOrAppCode": "无效的重定向 URL 或应用代码",
|
||||
"error.invalidSSOProtocol": "无效的 SSO 协议",
|
||||
"error.nameEmpty": "用户名不能为空",
|
||||
"error.passwordEmpty": "密码不能为空",
|
||||
"error.passwordInvalid": "密码必须包含字母和数字,且长度不小于 8 位",
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
"error.emailEmpty": "郵箱不能為空",
|
||||
"error.emailInValid": "請輸入有效的郵箱地址",
|
||||
"error.invalidEmailOrPassword": "無效的電子郵件或密碼。",
|
||||
"error.invalidRedirectUrlOrAppCode": "無效的重定向 URL 或應用程式代碼",
|
||||
"error.invalidSSOProtocol": "無效的 SSO 協定",
|
||||
"error.nameEmpty": "使用者名稱不能為空",
|
||||
"error.passwordEmpty": "密碼不能為空",
|
||||
"error.passwordInvalid": "密碼必須包含字母和數字,且長度不小於 8 位",
|
||||
|
||||
Reference in New Issue
Block a user