mirror of
https://github.com/langgenius/dify.git
synced 2026-05-09 21:28:25 +08:00
Merge branch 'main' into fix/issue-35910
This commit is contained in:
commit
18e2ecd6c5
@ -876,10 +876,10 @@ class ToolBuiltinProviderSetDefaultApi(Resource):
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
def post(self, provider):
|
||||
current_user, current_tenant_id = current_account_with_tenant()
|
||||
_, current_tenant_id = current_account_with_tenant()
|
||||
payload = BuiltinProviderDefaultCredentialPayload.model_validate(console_ns.payload or {})
|
||||
return BuiltinToolManageService.set_default_provider(
|
||||
tenant_id=current_tenant_id, user_id=current_user.id, provider=provider, id=payload.id
|
||||
tenant_id=current_tenant_id, provider=provider, id=payload.id
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -408,7 +408,7 @@ class BuiltinToolManageService:
|
||||
return {"result": "success"}
|
||||
|
||||
@staticmethod
|
||||
def set_default_provider(tenant_id: str, user_id: str, provider: str, id: str):
|
||||
def set_default_provider(tenant_id: str, provider: str, id: str):
|
||||
"""
|
||||
set default provider
|
||||
"""
|
||||
@ -422,12 +422,11 @@ class BuiltinToolManageService:
|
||||
if target_provider is None:
|
||||
raise ValueError("provider not found")
|
||||
|
||||
# clear default provider
|
||||
# clear default provider (tenant-scoped: only one default per provider per workspace)
|
||||
session.execute(
|
||||
update(BuiltinToolProvider)
|
||||
.where(
|
||||
BuiltinToolProvider.tenant_id == tenant_id,
|
||||
BuiltinToolProvider.user_id == user_id,
|
||||
BuiltinToolProvider.provider == provider,
|
||||
BuiltinToolProvider.is_default.is_(True),
|
||||
)
|
||||
|
||||
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
import base64
|
||||
import json
|
||||
from types import SimpleNamespace
|
||||
from typing import Any, cast
|
||||
from typing import Any
|
||||
from unittest.mock import MagicMock, patch
|
||||
from uuid import uuid4
|
||||
|
||||
@ -71,6 +71,7 @@ def _pending_yaml_content(version: str = "99.0.0") -> bytes:
|
||||
|
||||
|
||||
def _app_stub(**overrides: Any) -> App:
|
||||
"""Create a stub App object for testing without hitting the database."""
|
||||
defaults = {
|
||||
"id": str(uuid4()),
|
||||
"tenant_id": _DEFAULT_TENANT_ID,
|
||||
@ -83,7 +84,10 @@ def _app_stub(**overrides: Any) -> App:
|
||||
"use_icon_as_answer_icon": False,
|
||||
"app_model_config": None,
|
||||
}
|
||||
return cast(App, SimpleNamespace(**(defaults | overrides)))
|
||||
app = MagicMock(spec=App)
|
||||
for key, value in (defaults | overrides).items():
|
||||
object.__setattr__(app, key, value)
|
||||
return app
|
||||
|
||||
|
||||
class TestAppDslService:
|
||||
|
||||
@ -180,7 +180,7 @@ class TestSetDefaultProvider:
|
||||
session.scalar.return_value = None
|
||||
|
||||
with pytest.raises(ValueError, match="provider not found"):
|
||||
BuiltinToolManageService.set_default_provider("t", "u", "p", "id")
|
||||
BuiltinToolManageService.set_default_provider("t", "p", "id")
|
||||
|
||||
@patch(f"{MODULE}.sessionmaker")
|
||||
@patch(f"{MODULE}.db")
|
||||
@ -189,11 +189,29 @@ class TestSetDefaultProvider:
|
||||
target = MagicMock()
|
||||
session.scalar.return_value = target
|
||||
|
||||
result = BuiltinToolManageService.set_default_provider("t", "u", "p", "id")
|
||||
result = BuiltinToolManageService.set_default_provider("t", "p", "id")
|
||||
|
||||
assert result == {"result": "success"}
|
||||
assert target.is_default is True
|
||||
|
||||
@patch(f"{MODULE}.sessionmaker")
|
||||
@patch(f"{MODULE}.db")
|
||||
def test_clear_default_is_tenant_scoped_not_user_scoped(self, mock_db, mock_sm_cls):
|
||||
# Regression: clearing prior defaults must NOT filter by user_id, otherwise
|
||||
# two workspace members can each leave their own credential as default at
|
||||
# the same time (the default flag is tenant-scoped, not per-user).
|
||||
session = _mock_sessionmaker(mock_sm_cls)
|
||||
session.scalar.return_value = MagicMock()
|
||||
|
||||
BuiltinToolManageService.set_default_provider("tenant-1", "google", "cred-id")
|
||||
|
||||
session.execute.assert_called_once()
|
||||
update_stmt = session.execute.call_args.args[0]
|
||||
compiled = str(update_stmt.compile(compile_kwargs={"literal_binds": True}))
|
||||
assert "user_id" not in compiled
|
||||
assert "tenant_id" in compiled
|
||||
assert "provider" in compiled
|
||||
|
||||
|
||||
class TestUpdateBuiltinToolProvider:
|
||||
@patch(f"{MODULE}.sessionmaker")
|
||||
|
||||
@ -261,14 +261,14 @@
|
||||
"notSetAPIKey.trailFinished": "Deneme süresi sona erdi",
|
||||
"notSetVar": "Değişkenler, kullanıcıların form doldururken prompt kelimelerini veya açılış ifadelerini getirmesine izin verir. Prompt kelimelerine \"{{input}}\" yazmayı deneyebilirsiniz.",
|
||||
"openingStatement.add": "Ekle",
|
||||
"openingStatement.editorTitle": "Acilis Mesaji",
|
||||
"openingStatement.editorTitle": "Açılış Mesajı",
|
||||
"openingStatement.noDataPlaceHolder": "Kullanıcı ile konuşmayı başlatmak, AI'ın konuşma uygulamalarında onlarla daha yakın bir bağlantı kurmasına yardımcı olabilir.",
|
||||
"openingStatement.notIncludeKey": "Başlangıç promptu değişkeni içermiyor: {{key}}. Lütfen bunu başlangıç promptuna ekleyin.",
|
||||
"openingStatement.openingQuestion": "Açılış Soruları",
|
||||
"openingStatement.openingQuestionDescription": "Acilis mesajindan sonra gosterilen istege bagli yonlendirmeler; kullanicilarin konusmayi surdurmesine yardimci olur.",
|
||||
"openingStatement.openingQuestionPlaceholder": "Bir acilis sorusu girin.",
|
||||
"openingStatement.placeholderLine1": "Buradan baslayin. Yapay zekanin gondermesi gereken ilk mesaji yazin.",
|
||||
"openingStatement.placeholderLine2": "Değişkenler kullanabilirsiniz, {{variable}} yazmayı deneyin.",
|
||||
"openingStatement.openingQuestionDescription": "Açılış mesajından sonra gösterilen isteğe bağlı yönlendirmeler; kullanıcıların konuşmayı sürdürmesine yardımcı olur.",
|
||||
"openingStatement.openingQuestionPlaceholder": "Bir açılış sorusu girin.",
|
||||
"openingStatement.placeholderLine1": "Buradan başlayın. Yapay zekânın göndermesi gereken ilk mesajı yazın.",
|
||||
"openingStatement.placeholderLine2": "Değişkenleri kullanabilirsiniz; {{variable}} yazmayı deneyin.",
|
||||
"openingStatement.title": "Konuşma Başlatıcı",
|
||||
"openingStatement.tooShort": "Konuşma için açılış ifadeleri oluşturmak için en az 20 kelimelik başlangıç promptu gereklidir.",
|
||||
"openingStatement.varTip": "Değişkenler kullanabilirsiniz, örneğin {{variable}} yazmayı deneyin",
|
||||
|
||||
@ -136,11 +136,11 @@
|
||||
"marketplace.template.fetchFailed": "Şablon alınamadı",
|
||||
"marketplace.template.importConfirm": "İçe Aktar",
|
||||
"marketplace.template.importFailed": "Şablon içe aktarılamadı",
|
||||
"marketplace.template.modalTitle": "Marketplace'den İçe Aktar",
|
||||
"marketplace.template.modalTitle": "Pazar Yeri'nden İçe Aktar",
|
||||
"marketplace.template.overview": "Genel Bakış",
|
||||
"marketplace.template.publishedBy": "Yayıncı",
|
||||
"marketplace.template.usageCount": "Kullanım",
|
||||
"marketplace.template.viewOnMarketplace": "Marketplace'de Görüntüle",
|
||||
"marketplace.template.viewOnMarketplace": "Pazar Yeri'nde Görüntüle",
|
||||
"maxActiveRequests": "Maksimum eş zamanlı istekler",
|
||||
"maxActiveRequestsPlaceholder": "Sınırsız için 0 girin",
|
||||
"maxActiveRequestsTip": "Her uygulama için maksimum eşzamanlı aktif istek sayısı (sınırsız için 0)",
|
||||
|
||||
@ -1,24 +1,24 @@
|
||||
{
|
||||
"applied.activeSubscription.description": "Aktif bir aboneliğiniz var. Aboneliğinizin süresi dolduktan sonra eğitim indirimini kullanabilirsiniz. Aboneliğinizi <stripeLink>Stripe</stripeLink>'da onaylayın.",
|
||||
"applied.description": "Tebrikler! Eğitim indirimi için başarıyla başvurdunuz.",
|
||||
"applied.noPaymentPermission.description": "Bu workspace'te ödeme izniniz yok. Eğitim indirimini kullanmak için lütfen faturalamayı yönetebileceğiniz bir workspace'e geçin.",
|
||||
"applied.noPaymentPermission.description": "Bu çalışma alanında ödeme izniniz yok. Eğitim indirimini kullanmak için lütfen faturalamayı yönetebileceğiniz bir çalışma alanına geçin.",
|
||||
"applied.noPaymentPermission.returnHome": "Dify'e geri dön",
|
||||
"applied.step1.description": "Eğitim indirimi için başarıyla başvurdunuz.",
|
||||
"applied.step1.title": "Adım 1",
|
||||
"applied.step2.description": "Eğitim indirimiyle kullanmak istediğiniz workspace'i seçin.",
|
||||
"applied.step2.description": "Eğitim indirimiyle kullanmak istediğiniz çalışma alanını seçin.",
|
||||
"applied.step2.title": "Adım 2",
|
||||
"applied.tabs.activeSubscription": "Abonelikte",
|
||||
"applied.tabs.eligible": "Satın alabilir",
|
||||
"applied.tabs.noPaymentPermission": "Ödeme izni yok",
|
||||
"applied.title": "Eğitim indirimi uygulandı",
|
||||
"applied.workspace.plan": "Ücretli plan",
|
||||
"applied.workspace.title": "Mevcut Workspace",
|
||||
"applied.workspace.title": "Mevcut Çalışma Alanı",
|
||||
"currentSigned": "ŞU ANDA GİRİŞ YAPILDIĞI KİŞİ",
|
||||
"educationPricingConfirm.billingPeriod.monthly": "aylık",
|
||||
"educationPricingConfirm.billingPeriod.yearly": "yıllık",
|
||||
"educationPricingConfirm.cancel": "İptal",
|
||||
"educationPricingConfirm.continue": "İndirim olmadan devam et",
|
||||
"educationPricingConfirm.description": "{{planName}} {{billingPeriod}} planınız eğitim indirimini desteklemiyor. Yalnızca Professional yıllık plan uygun.",
|
||||
"educationPricingConfirm.description": "{{planName}} {{billingPeriod}} planınız eğitim indirimini desteklemiyor. Yalnızca yıllık Professional planı uygundur.",
|
||||
"educationPricingConfirm.title": "Eğitim indirimi mevcut değil",
|
||||
"emailLabel": "Şu anki e-posta adresin",
|
||||
"form.schoolName.placeholder": "Okulunuzun resmi, kısaltılmamış adını girin",
|
||||
|
||||
@ -16,8 +16,8 @@
|
||||
"chat.privacyPolicyMiddle": "gizlilik politikası",
|
||||
"chat.privacyPolicyRight": "uygulama geliştiricisi tarafından sağlanmıştır.",
|
||||
"chat.privatePromptConfigTitle": "Konuşma ayarları",
|
||||
"chat.prompt": "Prompt",
|
||||
"chat.publicPromptConfigTitle": "Başlangıç Promptu",
|
||||
"chat.prompt": "İstem",
|
||||
"chat.publicPromptConfigTitle": "Başlangıç İstemi",
|
||||
"chat.resetChat": "Konuşmayı sıfırla",
|
||||
"chat.startChat": "Sohbete Başla",
|
||||
"chat.temporarySystemIssue": "Üzgünüz, geçici sistem sorunu.",
|
||||
|
||||
@ -111,33 +111,33 @@
|
||||
"chatVariable.updatedAt": "Güncellenme zamanı: ",
|
||||
"collaboration.historyAction.generic": "Bir işbirlikçi geri alma/yeniden yapma gerçekleştirdi",
|
||||
"comments.actions.addComment": "Yorum ekle",
|
||||
"comments.actions.deleteReply": "Delete reply",
|
||||
"comments.actions.deleteReply": "Yanıtı sil",
|
||||
"comments.actions.editComment": "Yorumu düzenle",
|
||||
"comments.actions.editReply": "Edit reply",
|
||||
"comments.aria.closeComment": "Close comment",
|
||||
"comments.actions.editReply": "Yanıtı düzenle",
|
||||
"comments.aria.closeComment": "Yorumu kapat",
|
||||
"comments.aria.commentActions": "Yorum işlemleri",
|
||||
"comments.aria.deleteComment": "Delete thread",
|
||||
"comments.aria.deleteComment": "Konuyu sil",
|
||||
"comments.aria.filterComments": "Yorumları filtrele",
|
||||
"comments.aria.nextComment": "Next comment",
|
||||
"comments.aria.previousComment": "Previous comment",
|
||||
"comments.aria.replyActions": "Reply actions",
|
||||
"comments.aria.resolveComment": "Resolve",
|
||||
"comments.confirm.deleteReplyDesc": "This reply will be removed permanently.",
|
||||
"comments.confirm.deleteReplyTitle": "Delete this reply?",
|
||||
"comments.confirm.deleteThreadDesc": "This action will permanently delete the thread and all its replies. This cannot be undone.",
|
||||
"comments.confirm.deleteThreadTitle": "Delete this thread?",
|
||||
"comments.fallback.user": "User",
|
||||
"comments.aria.nextComment": "Sonraki yorum",
|
||||
"comments.aria.previousComment": "Önceki yorum",
|
||||
"comments.aria.replyActions": "Yanıt işlemleri",
|
||||
"comments.aria.resolveComment": "Çöz",
|
||||
"comments.confirm.deleteReplyDesc": "Bu yanıt kalıcı olarak kaldırılacak.",
|
||||
"comments.confirm.deleteReplyTitle": "Bu yanıt silinsin mi?",
|
||||
"comments.confirm.deleteThreadDesc": "Bu işlem konuyu ve tüm yanıtlarını kalıcı olarak siler. Bu işlem geri alınamaz.",
|
||||
"comments.confirm.deleteThreadTitle": "Bu konu silinsin mi?",
|
||||
"comments.fallback.user": "Kullanıcı",
|
||||
"comments.filter.all": "Tümü",
|
||||
"comments.filter.onlyYourThreads": "Yalnızca senin başlıkların",
|
||||
"comments.filter.onlyYourThreads": "Yalnızca kendi konuların",
|
||||
"comments.filter.showResolved": "Çözülenleri göster",
|
||||
"comments.loading": "Loading…",
|
||||
"comments.noComments": "No comments yet",
|
||||
"comments.panelTitle": "Comment",
|
||||
"comments.placeholder.add": "Add a comment",
|
||||
"comments.loading": "Yükleniyor…",
|
||||
"comments.noComments": "Henüz yorum yok",
|
||||
"comments.panelTitle": "Yorum",
|
||||
"comments.placeholder.add": "Yorum ekle",
|
||||
"comments.placeholder.editComment": "Yorumu düzenle",
|
||||
"comments.placeholder.editReply": "Edit reply",
|
||||
"comments.placeholder.reply": "Reply",
|
||||
"comments.reply": "Reply",
|
||||
"comments.placeholder.editReply": "Yanıtı düzenle",
|
||||
"comments.placeholder.reply": "Yanıtla",
|
||||
"comments.reply": "Yanıtla",
|
||||
"common.ImageUploadLegacyTip": "Artık başlangıç formunda dosya türü değişkenleri oluşturabilirsiniz. Gelecekte resim yükleme özelliğini artık desteklemeyeceğiz.",
|
||||
"common.accessAPIReference": "API Referansına Eriş",
|
||||
"common.addBlock": "Düğüm Ekle",
|
||||
@ -229,8 +229,8 @@
|
||||
"common.previewPlaceholder": "Sohbet Robotunu hata ayıklamak için aşağıdaki kutuya içerik girin",
|
||||
"common.processData": "Veriyi İşle",
|
||||
"common.publish": "Yayınla",
|
||||
"common.publishToMarketplace": "Marketplace'de Yayınla",
|
||||
"common.publishToMarketplaceFailed": "Marketplace'de Yayınlama Başarısız",
|
||||
"common.publishToMarketplace": "Pazar Yeri'nde Yayınla",
|
||||
"common.publishToMarketplaceFailed": "Pazar Yeri'nde yayınlanamadı",
|
||||
"common.publishUpdate": "Güncellemeyi Yayınla",
|
||||
"common.published": "Yayınlandı",
|
||||
"common.publishedAt": "Yayınlandı",
|
||||
@ -812,7 +812,7 @@
|
||||
"nodes.llm.outputVars.output": "İçerik Üret",
|
||||
"nodes.llm.outputVars.reasoning_content": "Akıl yürütme içeriği",
|
||||
"nodes.llm.outputVars.usage": "Model Kullanım Bilgileri",
|
||||
"nodes.llm.prompt": "prompt",
|
||||
"nodes.llm.prompt": "istem",
|
||||
"nodes.llm.reasoningFormat.separated": "Ayrı düşünce etiketleri",
|
||||
"nodes.llm.reasoningFormat.tagged": "Etiketleri düşünmeye devam et",
|
||||
"nodes.llm.reasoningFormat.title": "Akıl yürütme etiket ayrımını etkinleştir",
|
||||
@ -891,7 +891,7 @@
|
||||
"nodes.parameterExtractor.outputVars.usage": "Model Kullanım Bilgileri",
|
||||
"nodes.parameterExtractor.reasoningMode": "Akıl Yürütme Modu",
|
||||
"nodes.parameterExtractor.reasoningModeFunctionToolCalling": "Fonksiyon/Araç Çağrısı",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "Prompt",
|
||||
"nodes.parameterExtractor.reasoningModePrompt": "İstem",
|
||||
"nodes.parameterExtractor.reasoningModeTip": "Modelin fonksiyon çağırma veya istemler için talimatlara yanıt verme yeteneğine bağlı olarak uygun akıl yürütme modunu seçebilirsiniz.",
|
||||
"nodes.questionClassifiers.addClass": "Sınıf Ekle",
|
||||
"nodes.questionClassifiers.advancedSetting": "Gelişmiş Ayarlar",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user