mirror of
https://github.com/langgenius/dify.git
synced 2026-07-22 03:08:33 +08:00
refactor(web): migrate rbac access console contracts (#38256)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
f1f6ab0ac6
commit
ee1d33eaa6
@ -20213,7 +20213,7 @@ Whitelist scopes accepted by RBAC app and dataset access config APIs.
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| data | [ [ResourceUserAccessPolicies](#resourceuseraccesspolicies) ] | | No |
|
||||
| scope | string | | Yes |
|
||||
| scope | [RBACResourceWhitelistScope](#rbacresourcewhitelistscope) | | Yes |
|
||||
|
||||
#### ResourceWhitelist
|
||||
|
||||
|
||||
@ -249,7 +249,7 @@ class ResourceUserAccessPolicies(_RBACModel):
|
||||
|
||||
|
||||
class ResourceUserAccessPoliciesResponse(_RBACModel):
|
||||
scope: str
|
||||
scope: RBACResourceWhitelistScope
|
||||
data: list[ResourceUserAccessPolicies] = Field(default_factory=list)
|
||||
|
||||
|
||||
|
||||
@ -299,7 +299,7 @@ class TestResourceAccess:
|
||||
|
||||
def test_app_user_access_policies(self, mock_send: MagicMock):
|
||||
mock_send.return_value = {
|
||||
"scope": "app",
|
||||
"scope": "specific",
|
||||
"data": [
|
||||
{
|
||||
"account": {"account_id": "acct-1", "account_name": "Alice"},
|
||||
|
||||
@ -551,7 +551,7 @@ export type AppAccessMatrix = {
|
||||
|
||||
export type ResourceUserAccessPoliciesResponse = {
|
||||
data?: Array<ResourceUserAccessPolicies>
|
||||
scope: string
|
||||
scope: RbacResourceWhitelistScope
|
||||
}
|
||||
|
||||
export type ReplaceUserAccessPolicies = {
|
||||
|
||||
@ -1841,7 +1841,7 @@ export const zResourceUserAccessPolicies = z.object({
|
||||
*/
|
||||
export const zResourceUserAccessPoliciesResponse = z.object({
|
||||
data: z.array(zResourceUserAccessPolicies).optional(),
|
||||
scope: z.string(),
|
||||
scope: zRbacResourceWhitelistScope,
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
@ -134,10 +134,13 @@ describe('AccessRulesEditor', () => {
|
||||
expect(screen.getByRole('button', { name: 'permission.accessRule.resourceOpenScopeDescription' })).toBeInTheDocument()
|
||||
|
||||
const allMembersButton = screen.getByRole('button', { name: /permission\.accessRule\.allPermittedMembers/ })
|
||||
const onlyMeButton = screen.getByRole('button', { name: /permission\.accessRule\.onlyMe/ })
|
||||
const specificMembersButton = screen.getByRole('button', { name: /permission\.accessRule\.specificMembersOnly/ })
|
||||
expect(allMembersButton).toBeDisabled()
|
||||
expect(onlyMeButton).toBeDisabled()
|
||||
expect(specificMembersButton).toBeDisabled()
|
||||
expect(allMembersButton).toHaveAttribute('aria-pressed', 'false')
|
||||
expect(onlyMeButton).toHaveAttribute('aria-pressed', 'false')
|
||||
expect(specificMembersButton).toHaveAttribute('aria-pressed', 'false')
|
||||
})
|
||||
|
||||
@ -181,6 +184,30 @@ describe('AccessRulesEditor', () => {
|
||||
expect(onRemoveAccessPolicyMemberBinding).toHaveBeenCalledWith('account-1', 'app-policy-id')
|
||||
})
|
||||
|
||||
it('should render and update the only-me resource access scope', () => {
|
||||
const onOpenScopeChange = vi.fn()
|
||||
|
||||
render(
|
||||
<AccessRulesEditor
|
||||
rules={[]}
|
||||
userAccessSettings={[]}
|
||||
isLoadingRules={false}
|
||||
isLoadingUserAccessSettings={false}
|
||||
openScope="only_me"
|
||||
isUpdatingOpenScope={false}
|
||||
updatingAccountId={null}
|
||||
onOpenScopeChange={onOpenScopeChange}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByRole('button', { name: /permission\.accessRule\.onlyMe/ })).toHaveAttribute('aria-pressed', 'true')
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /permission\.accessRule\.specificMembersOnly/ }))
|
||||
fireEvent.click(screen.getByRole('button', { name: 'common.operation.change' }))
|
||||
|
||||
expect(onOpenScopeChange).toHaveBeenCalledWith('specific')
|
||||
})
|
||||
|
||||
it('should render the fixed default option when an account has no exception policy', () => {
|
||||
render(
|
||||
<AccessRulesEditor
|
||||
|
||||
@ -49,7 +49,7 @@ function ResourceOpenScopeSection({
|
||||
</h2>
|
||||
<TitleInfotip content={resourceOpenScopeDescription} />
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
|
||||
<div className="grid grid-cols-1 gap-2 sm:grid-cols-3">
|
||||
<OpenScopeOption
|
||||
value="all"
|
||||
selected={value === 'all'}
|
||||
@ -58,6 +58,14 @@ function ResourceOpenScopeSection({
|
||||
description={t('accessRule.allPermittedMembersDescription', { ns: 'permission' })}
|
||||
onChange={onChange ? handleRequestChange : undefined}
|
||||
/>
|
||||
<OpenScopeOption
|
||||
value="only_me"
|
||||
selected={value === 'only_me'}
|
||||
disabled={disabled || !onChange}
|
||||
title={t('accessRule.onlyMe', { ns: 'permission' })}
|
||||
description={t('accessRule.onlyMeDescription', { ns: 'permission' })}
|
||||
onChange={onChange ? handleRequestChange : undefined}
|
||||
/>
|
||||
<OpenScopeOption
|
||||
value="specific"
|
||||
selected={value === 'specific'}
|
||||
|
||||
@ -1,182 +0,0 @@
|
||||
import type { AccessControlTemplateLanguage } from '@/i18n-config/language'
|
||||
import type {
|
||||
GetAccessPolicyDetailResponse,
|
||||
GetAppAccessPolicyByAppIdResponse,
|
||||
GetAppUserAccessSettingsResponse,
|
||||
GetDatasetAccessPolicyByDatasetIdResponse,
|
||||
GetDatasetUserAccessSettingsResponse,
|
||||
ResourceOpenScope,
|
||||
} from '@/models/access-control'
|
||||
import { type } from '@orpc/contract'
|
||||
import { base } from '../base'
|
||||
|
||||
const appAccessRulesContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/rbac/apps/{appId}/access-policy',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
appId: string
|
||||
}
|
||||
query: {
|
||||
language: AccessControlTemplateLanguage
|
||||
}
|
||||
}>())
|
||||
.output(type<GetAppAccessPolicyByAppIdResponse>())
|
||||
|
||||
const appUserAccessSettingsContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/rbac/apps/{appId}/user-access-policies',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
appId: string
|
||||
}
|
||||
query: {
|
||||
language: AccessControlTemplateLanguage
|
||||
}
|
||||
}>())
|
||||
.output(type<GetAppUserAccessSettingsResponse>())
|
||||
|
||||
const updateAppUserAccessSettingsContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/rbac/apps/{appId}/users/{accountId}/access-policies',
|
||||
method: 'PUT',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
appId: string
|
||||
accountId: string
|
||||
}
|
||||
body: {
|
||||
access_policy_ids: string[]
|
||||
}
|
||||
}>())
|
||||
.output(type<GetAccessPolicyDetailResponse>())
|
||||
|
||||
const removeAppAccessPolicyMemberBindingsContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/rbac/apps/{appId}/access-policies/{policyId}/member-bindings',
|
||||
method: 'DELETE',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
appId: string
|
||||
policyId: string
|
||||
}
|
||||
body: {
|
||||
account_ids: string[]
|
||||
}
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
const updateAppOpenScopeContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/rbac/apps/{appId}/whitelist',
|
||||
method: 'PUT',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
appId: string
|
||||
}
|
||||
body: {
|
||||
scope: ResourceOpenScope
|
||||
}
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
const datasetAccessRulesContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/rbac/datasets/{datasetId}/access-policy',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
datasetId: string
|
||||
}
|
||||
query: {
|
||||
language: AccessControlTemplateLanguage
|
||||
}
|
||||
}>())
|
||||
.output(type<GetDatasetAccessPolicyByDatasetIdResponse>())
|
||||
|
||||
const datasetUserAccessSettingsContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/rbac/datasets/{datasetId}/user-access-policies',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
datasetId: string
|
||||
}
|
||||
query: {
|
||||
language: AccessControlTemplateLanguage
|
||||
}
|
||||
}>())
|
||||
.output(type<GetDatasetUserAccessSettingsResponse>())
|
||||
|
||||
const updateDatasetUserAccessSettingsContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/rbac/datasets/{datasetId}/users/{accountId}/access-policies',
|
||||
method: 'PUT',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
datasetId: string
|
||||
accountId: string
|
||||
}
|
||||
body: {
|
||||
access_policy_ids: string[]
|
||||
}
|
||||
}>())
|
||||
.output(type<GetAccessPolicyDetailResponse>())
|
||||
|
||||
const removeDatasetAccessPolicyMemberBindingsContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/rbac/datasets/{datasetId}/access-policies/{policyId}/member-bindings',
|
||||
method: 'DELETE',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
datasetId: string
|
||||
policyId: string
|
||||
}
|
||||
body: {
|
||||
account_ids: string[]
|
||||
}
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
const updateDatasetOpenScopeContract = base
|
||||
.route({
|
||||
path: '/workspaces/current/rbac/datasets/{datasetId}/whitelist',
|
||||
method: 'PUT',
|
||||
})
|
||||
.input(type<{
|
||||
params: {
|
||||
datasetId: string
|
||||
}
|
||||
body: {
|
||||
scope: ResourceOpenScope
|
||||
}
|
||||
}>())
|
||||
.output(type<unknown>())
|
||||
|
||||
export const rbacAccessConfigContract = {
|
||||
apps: {
|
||||
accessRules: appAccessRulesContract,
|
||||
userAccessSettings: appUserAccessSettingsContract,
|
||||
updateUserAccessSettings: updateAppUserAccessSettingsContract,
|
||||
removeMemberBindings: removeAppAccessPolicyMemberBindingsContract,
|
||||
updateOpenScope: updateAppOpenScopeContract,
|
||||
},
|
||||
datasets: {
|
||||
accessRules: datasetAccessRulesContract,
|
||||
userAccessSettings: datasetUserAccessSettingsContract,
|
||||
updateUserAccessSettings: updateDatasetUserAccessSettingsContract,
|
||||
removeMemberBindings: removeDatasetAccessPolicyMemberBindingsContract,
|
||||
updateOpenScope: updateDatasetOpenScopeContract,
|
||||
},
|
||||
}
|
||||
@ -45,7 +45,6 @@ import { workflowGenerate } from '@dify/contracts/api/console/workflow-generate/
|
||||
import { workflow } from '@dify/contracts/api/console/workflow/orpc.gen'
|
||||
import { workspaces } from '@dify/contracts/api/console/workspaces/orpc.gen'
|
||||
import { contract as enterpriseContract } from '@dify/contracts/enterprise/orpc.gen'
|
||||
import { rbacAccessConfigContract } from './console/access-control'
|
||||
import { exploreRouterContract } from './console/explore'
|
||||
import { modelProvidersRouterContract } from './console/model-providers'
|
||||
import { pluginsRouterContract } from './console/plugins'
|
||||
@ -108,7 +107,6 @@ export const consoleRouterContract = {
|
||||
explore: exploreRouterContract,
|
||||
modelProviders: modelProvidersRouterContract,
|
||||
plugins: pluginsRouterContract,
|
||||
rbacAccessConfig: rbacAccessConfigContract,
|
||||
snippets: snippetsRouterContract,
|
||||
triggers: triggersRouterContract,
|
||||
trialApps: trialAppsRouterContract,
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "لا يوجد وصف",
|
||||
"accessRule.noRules": "لا توجد قواعد وصول",
|
||||
"accessRule.noUserAccessSettings": "لا توجد إعدادات أذونات فردية",
|
||||
"accessRule.onlyMe": "أنا فقط",
|
||||
"accessRule.onlyMeDescription": "يمكنك وحدك الوصول إلى هذا المورد.",
|
||||
"accessRule.permission": "الإذن",
|
||||
"accessRule.resourceOpenScope": "نطاق فتح المورد",
|
||||
"accessRule.resourceOpenScopeDescription": "اختر من يُفتح له هذا المورد. لا تزال أذونات الأدوار تحدد ما يمكن لكل عضو فعله.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Keine Beschreibung",
|
||||
"accessRule.noRules": "Keine Zugriffsregeln",
|
||||
"accessRule.noUserAccessSettings": "Keine individuellen Berechtigungseinstellungen",
|
||||
"accessRule.onlyMe": "Nur ich",
|
||||
"accessRule.onlyMeDescription": "Nur Sie können auf diese Ressource zugreifen.",
|
||||
"accessRule.permission": "Berechtigung",
|
||||
"accessRule.resourceOpenScope": "Freigabebereich der Ressource",
|
||||
"accessRule.resourceOpenScopeDescription": "Wählen Sie, für wen diese Ressource geöffnet ist. Rollenberechtigungen bestimmen weiterhin, was jedes Mitglied tun kann.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "No description",
|
||||
"accessRule.noRules": "No access rules",
|
||||
"accessRule.noUserAccessSettings": "No individual permission settings",
|
||||
"accessRule.onlyMe": "Only me",
|
||||
"accessRule.onlyMeDescription": "Only you can access this resource.",
|
||||
"accessRule.permission": "Permission",
|
||||
"accessRule.resourceOpenScope": "Resource open scope",
|
||||
"accessRule.resourceOpenScopeDescription": "Choose who this resource is open to. Role permissions still decide what each member can do.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Sin descripción",
|
||||
"accessRule.noRules": "Sin reglas de acceso",
|
||||
"accessRule.noUserAccessSettings": "Sin ajustes de permisos individuales",
|
||||
"accessRule.onlyMe": "Solo yo",
|
||||
"accessRule.onlyMeDescription": "Solo tú puedes acceder a este recurso.",
|
||||
"accessRule.permission": "Permiso",
|
||||
"accessRule.resourceOpenScope": "Ámbito de apertura del recurso",
|
||||
"accessRule.resourceOpenScopeDescription": "Elige a quién está abierto este recurso. Los permisos de rol siguen decidiendo lo que puede hacer cada miembro.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "بدون توضیحات",
|
||||
"accessRule.noRules": "بدون قانون دسترسی",
|
||||
"accessRule.noUserAccessSettings": "بدون تنظیمات مجوز فردی",
|
||||
"accessRule.onlyMe": "فقط من",
|
||||
"accessRule.onlyMeDescription": "فقط شما میتوانید به این منبع دسترسی داشته باشید.",
|
||||
"accessRule.permission": "مجوز",
|
||||
"accessRule.resourceOpenScope": "دامنه دسترسی منبع",
|
||||
"accessRule.resourceOpenScopeDescription": "انتخاب کنید این منبع برای چه کسانی باز است. مجوزهای نقش همچنان تعیین میکنند هر عضو چه کاری میتواند انجام دهد.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Aucune description",
|
||||
"accessRule.noRules": "Aucune règle d'accès",
|
||||
"accessRule.noUserAccessSettings": "Aucun paramètre d'autorisation individuel",
|
||||
"accessRule.onlyMe": "Moi uniquement",
|
||||
"accessRule.onlyMeDescription": "Vous seul pouvez accéder à cette ressource.",
|
||||
"accessRule.permission": "Autorisation",
|
||||
"accessRule.resourceOpenScope": "Portée d'ouverture de la ressource",
|
||||
"accessRule.resourceOpenScopeDescription": "Choisissez à qui cette ressource est ouverte. Les autorisations de rôle déterminent toujours ce que chaque membre peut faire.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "कोई विवरण नहीं",
|
||||
"accessRule.noRules": "कोई एक्सेस नियम नहीं",
|
||||
"accessRule.noUserAccessSettings": "कोई व्यक्तिगत अनुमति सेटिंग्स नहीं",
|
||||
"accessRule.onlyMe": "केवल मैं",
|
||||
"accessRule.onlyMeDescription": "केवल आप इस संसाधन तक पहुँच सकते हैं।",
|
||||
"accessRule.permission": "अनुमति",
|
||||
"accessRule.resourceOpenScope": "संसाधन का खुला दायरा",
|
||||
"accessRule.resourceOpenScopeDescription": "चुनें कि यह संसाधन किसके लिए खुला है। भूमिका अनुमतियां अभी भी तय करती हैं कि प्रत्येक सदस्य क्या कर सकता है।",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Tidak ada deskripsi",
|
||||
"accessRule.noRules": "Tidak ada aturan akses",
|
||||
"accessRule.noUserAccessSettings": "Tidak ada pengaturan izin individu",
|
||||
"accessRule.onlyMe": "Hanya saya",
|
||||
"accessRule.onlyMeDescription": "Hanya Anda yang dapat mengakses resource ini.",
|
||||
"accessRule.permission": "Izin",
|
||||
"accessRule.resourceOpenScope": "Cakupan akses sumber daya",
|
||||
"accessRule.resourceOpenScopeDescription": "Pilih siapa yang dapat mengakses sumber daya ini. Izin peran tetap menentukan apa yang dapat dilakukan setiap anggota.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Nessuna descrizione",
|
||||
"accessRule.noRules": "Nessuna regola di accesso",
|
||||
"accessRule.noUserAccessSettings": "Nessuna impostazione dei permessi individuali",
|
||||
"accessRule.onlyMe": "Solo io",
|
||||
"accessRule.onlyMeDescription": "Solo tu puoi accedere a questa risorsa.",
|
||||
"accessRule.permission": "Permesso",
|
||||
"accessRule.resourceOpenScope": "Ambito di apertura della risorsa",
|
||||
"accessRule.resourceOpenScopeDescription": "Scegli a chi è aperta questa risorsa. I permessi di ruolo determinano comunque cosa può fare ciascun membro.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "説明なし",
|
||||
"accessRule.noRules": "アクセスルールがありません",
|
||||
"accessRule.noUserAccessSettings": "個別権限設定がありません",
|
||||
"accessRule.onlyMe": "自分のみ",
|
||||
"accessRule.onlyMeDescription": "このリソースにアクセスできるのは自分だけです。",
|
||||
"accessRule.permission": "権限",
|
||||
"accessRule.resourceOpenScope": "リソース公開範囲",
|
||||
"accessRule.resourceOpenScopeDescription": "このリソースを公開する対象を選択します。各メンバーが実行できる操作はロール権限で決まります。",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "설명 없음",
|
||||
"accessRule.noRules": "접근 규칙 없음",
|
||||
"accessRule.noUserAccessSettings": "개별 권한 설정 없음",
|
||||
"accessRule.onlyMe": "나만",
|
||||
"accessRule.onlyMeDescription": "이 리소스에는 본인만 접근할 수 있습니다.",
|
||||
"accessRule.permission": "권한",
|
||||
"accessRule.resourceOpenScope": "리소스 공개 범위",
|
||||
"accessRule.resourceOpenScopeDescription": "이 리소스를 누구에게 공개할지 선택합니다. 각 멤버가 할 수 있는 작업은 여전히 역할 권한이 결정합니다.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Geen beschrijving",
|
||||
"accessRule.noRules": "Geen toegangsregels",
|
||||
"accessRule.noUserAccessSettings": "Geen individuele rechteninstellingen",
|
||||
"accessRule.onlyMe": "Alleen ik",
|
||||
"accessRule.onlyMeDescription": "Alleen jij kunt toegang krijgen tot deze resource.",
|
||||
"accessRule.permission": "Recht",
|
||||
"accessRule.resourceOpenScope": "Toegangsbereik van resource",
|
||||
"accessRule.resourceOpenScopeDescription": "Kies voor wie deze resource toegankelijk is. Rolrechten bepalen nog steeds wat elk lid kan doen.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Brak opisu",
|
||||
"accessRule.noRules": "Brak reguł dostępu",
|
||||
"accessRule.noUserAccessSettings": "Brak indywidualnych ustawień uprawnień",
|
||||
"accessRule.onlyMe": "Tylko ja",
|
||||
"accessRule.onlyMeDescription": "Tylko Ty możesz uzyskać dostęp do tego zasobu.",
|
||||
"accessRule.permission": "Uprawnienie",
|
||||
"accessRule.resourceOpenScope": "Zakres otwarcia zasobu",
|
||||
"accessRule.resourceOpenScopeDescription": "Wybierz, dla kogo ten zasób jest otwarty. Uprawnienia ról nadal decydują o tym, co każdy członek może robić.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Sem descrição",
|
||||
"accessRule.noRules": "Sem regras de acesso",
|
||||
"accessRule.noUserAccessSettings": "Sem configurações de permissão individuais",
|
||||
"accessRule.onlyMe": "Somente eu",
|
||||
"accessRule.onlyMeDescription": "Somente você pode acessar este recurso.",
|
||||
"accessRule.permission": "Permissão",
|
||||
"accessRule.resourceOpenScope": "Escopo de abertura do recurso",
|
||||
"accessRule.resourceOpenScopeDescription": "Escolha para quem este recurso está aberto. As permissões de função ainda determinam o que cada membro pode fazer.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Fără descriere",
|
||||
"accessRule.noRules": "Fără reguli de acces",
|
||||
"accessRule.noUserAccessSettings": "Fără setări individuale de permisiuni",
|
||||
"accessRule.onlyMe": "Doar eu",
|
||||
"accessRule.onlyMeDescription": "Numai tu poți accesa această resursă.",
|
||||
"accessRule.permission": "Permisiune",
|
||||
"accessRule.resourceOpenScope": "Domeniul de deschidere al resursei",
|
||||
"accessRule.resourceOpenScopeDescription": "Alege cui îi este deschisă această resursă. Permisiunile de rol decid în continuare ce poate face fiecare membru.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Без описания",
|
||||
"accessRule.noRules": "Нет правил доступа",
|
||||
"accessRule.noUserAccessSettings": "Нет индивидуальных настроек прав",
|
||||
"accessRule.onlyMe": "Только я",
|
||||
"accessRule.onlyMeDescription": "Только вы можете получить доступ к этому ресурсу.",
|
||||
"accessRule.permission": "Право",
|
||||
"accessRule.resourceOpenScope": "Область открытости ресурса",
|
||||
"accessRule.resourceOpenScopeDescription": "Выберите, кому открыт этот ресурс. Права роли по-прежнему определяют, что может делать каждый участник.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Brez opisa",
|
||||
"accessRule.noRules": "Brez pravil za dostop",
|
||||
"accessRule.noUserAccessSettings": "Brez individualnih nastavitev dovoljenj",
|
||||
"accessRule.onlyMe": "Samo jaz",
|
||||
"accessRule.onlyMeDescription": "Do tega vira lahko dostopate samo vi.",
|
||||
"accessRule.permission": "Dovoljenje",
|
||||
"accessRule.resourceOpenScope": "Obseg odprtosti vira",
|
||||
"accessRule.resourceOpenScopeDescription": "Izberite, komu je ta vir na voljo. Dovoljenja vlog še vedno določajo, kaj lahko vsak član počne.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "ไม่มีคําอธิบาย",
|
||||
"accessRule.noRules": "ไม่มีกฎการเข้าถึง",
|
||||
"accessRule.noUserAccessSettings": "ไม่มีการตั้งค่าสิทธิ์เฉพาะบุคคล",
|
||||
"accessRule.onlyMe": "ฉันเท่านั้น",
|
||||
"accessRule.onlyMeDescription": "เฉพาะคุณเท่านั้นที่เข้าถึงทรัพยากรนี้ได้",
|
||||
"accessRule.permission": "สิทธิ์",
|
||||
"accessRule.resourceOpenScope": "ขอบเขตการเปิดของทรัพยากร",
|
||||
"accessRule.resourceOpenScopeDescription": "เลือกว่าทรัพยากรนี้เปิดให้ใครเข้าถึง สิทธิ์ตามบทบาทยังคงเป็นตัวกําหนดว่าสมาชิกแต่ละคนทําอะไรได้บ้าง",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Açıklama yok",
|
||||
"accessRule.noRules": "Erişim kuralı yok",
|
||||
"accessRule.noUserAccessSettings": "Bireysel izin ayarı yok",
|
||||
"accessRule.onlyMe": "Yalnızca ben",
|
||||
"accessRule.onlyMeDescription": "Bu kaynağa yalnızca siz erişebilirsiniz.",
|
||||
"accessRule.permission": "İzin",
|
||||
"accessRule.resourceOpenScope": "Kaynak açık kapsamı",
|
||||
"accessRule.resourceOpenScopeDescription": "Bu kaynağın kime açık olduğunu seçin. Her üyenin ne yapabileceğine yine de rol izinleri karar verir.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Немає опису",
|
||||
"accessRule.noRules": "Немає правил доступу",
|
||||
"accessRule.noUserAccessSettings": "Немає індивідуальних налаштувань дозволів",
|
||||
"accessRule.onlyMe": "Лише я",
|
||||
"accessRule.onlyMeDescription": "Лише ви можете отримати доступ до цього ресурсу.",
|
||||
"accessRule.permission": "Дозвіл",
|
||||
"accessRule.resourceOpenScope": "Сфера відкритості ресурсу",
|
||||
"accessRule.resourceOpenScopeDescription": "Виберіть, кому відкрито цей ресурс. Дозволи ролей усе одно визначають, що може робити кожен учасник.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "Không có mô tả",
|
||||
"accessRule.noRules": "Không có quy tắc truy cập",
|
||||
"accessRule.noUserAccessSettings": "Không có cài đặt quyền riêng lẻ",
|
||||
"accessRule.onlyMe": "Chỉ mình tôi",
|
||||
"accessRule.onlyMeDescription": "Chỉ bạn có thể truy cập tài nguyên này.",
|
||||
"accessRule.permission": "Quyền",
|
||||
"accessRule.resourceOpenScope": "Phạm vi mở của tài nguyên",
|
||||
"accessRule.resourceOpenScopeDescription": "Chọn tài nguyên này được mở cho ai. Quyền vai trò vẫn quyết định mỗi thành viên có thể làm gì.",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "无描述",
|
||||
"accessRule.noRules": "暂无访问规则",
|
||||
"accessRule.noUserAccessSettings": "暂无个人权限设置",
|
||||
"accessRule.onlyMe": "仅自己",
|
||||
"accessRule.onlyMeDescription": "仅你自己可以访问此资源。",
|
||||
"accessRule.permission": "权限",
|
||||
"accessRule.resourceOpenScope": "访问范围",
|
||||
"accessRule.resourceOpenScopeDescription": "选择此资源对哪些成员开放。角色权限仍决定每位成员可执行的操作。",
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
"accessRule.noDescription": "無描述",
|
||||
"accessRule.noRules": "暫無訪問規則",
|
||||
"accessRule.noUserAccessSettings": "暫無個人權限設定",
|
||||
"accessRule.onlyMe": "僅自己",
|
||||
"accessRule.onlyMeDescription": "僅你自己可以存取此資源。",
|
||||
"accessRule.permission": "權限",
|
||||
"accessRule.resourceOpenScope": "訪問範圍",
|
||||
"accessRule.resourceOpenScopeDescription": "選擇此資源對哪些成員開放。角色權限仍決定每位成員可執行的操作。",
|
||||
|
||||
@ -263,8 +263,4 @@ export type RemoveAppAccessPolicyMemberBindingsRequest = RemoveResourceAccessPol
|
||||
|
||||
export type RemoveDatasetAccessPolicyMemberBindingsRequest = RemoveResourceAccessPolicyMemberBindingsRequest
|
||||
|
||||
export type GetAccessPolicyDetailResponse = {
|
||||
access_policies: Pick<AccessPolicy, 'id' | 'name' | 'resource_type' | 'policy_key' | 'permission_keys'>[]
|
||||
}
|
||||
|
||||
export type ResourceOpenScope = 'all' | 'specific'
|
||||
export type ResourceOpenScope = 'all' | 'only_me' | 'specific'
|
||||
|
||||
23
web/service/access-control/__tests__/normalizers.spec.ts
Normal file
23
web/service/access-control/__tests__/normalizers.spec.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import type { ResourceUserAccessPoliciesResponse } from '@dify/contracts/api/console/workspaces/types.gen'
|
||||
import { normalizeAppUserAccessPolicies } from '../normalizers'
|
||||
|
||||
const createResourceUserAccessPoliciesResponse = (
|
||||
overrides: Partial<ResourceUserAccessPoliciesResponse> = {},
|
||||
): ResourceUserAccessPoliciesResponse => ({
|
||||
data: [],
|
||||
scope: 'specific',
|
||||
...overrides,
|
||||
})
|
||||
|
||||
describe('access-control normalizers', () => {
|
||||
// Resource access scope values come from the RBAC whitelist enum and must not be collapsed.
|
||||
describe('Resource user access policies', () => {
|
||||
it('should preserve only-me open scope when normalizing app user access policies', () => {
|
||||
const response = createResourceUserAccessPoliciesResponse({
|
||||
scope: 'only_me',
|
||||
})
|
||||
|
||||
expect(normalizeAppUserAccessPolicies(response).scope).toBe('only_me')
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -28,25 +28,55 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/service/client', () => ({
|
||||
consoleClient: {
|
||||
rbacAccessConfig: {
|
||||
apps: {
|
||||
updateOpenScope: mocks.updateOpenScope,
|
||||
updateUserAccessSettings: mocks.updateUserAccessSettings,
|
||||
removeMemberBindings: mocks.removeMemberBindings,
|
||||
workspaces: {
|
||||
current: {
|
||||
rbac: {
|
||||
apps: {
|
||||
byAppId: {
|
||||
accessPolicies: {
|
||||
byPolicyId: {
|
||||
memberBindings: {
|
||||
delete: mocks.removeMemberBindings,
|
||||
},
|
||||
},
|
||||
},
|
||||
users: {
|
||||
byTargetAccountId: {
|
||||
accessPolicies: {
|
||||
put: mocks.updateUserAccessSettings,
|
||||
},
|
||||
},
|
||||
},
|
||||
whitelist: {
|
||||
put: mocks.updateOpenScope,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
consoleQuery: {
|
||||
rbacAccessConfig: {
|
||||
apps: {
|
||||
accessRules: {
|
||||
key: mocks.accessRulesKey,
|
||||
queryOptions: mocks.accessRulesQueryOptions,
|
||||
},
|
||||
userAccessSettings: {
|
||||
key: mocks.userAccessSettingsKey,
|
||||
queryKey: mocks.userAccessSettingsQueryKey,
|
||||
queryOptions: mocks.userAccessSettingsQueryOptions,
|
||||
workspaces: {
|
||||
current: {
|
||||
rbac: {
|
||||
apps: {
|
||||
byAppId: {
|
||||
accessPolicy: {
|
||||
get: {
|
||||
key: mocks.accessRulesKey,
|
||||
queryOptions: mocks.accessRulesQueryOptions,
|
||||
},
|
||||
},
|
||||
userAccessPolicies: {
|
||||
get: {
|
||||
key: mocks.userAccessSettingsKey,
|
||||
queryKey: mocks.userAccessSettingsQueryKey,
|
||||
queryOptions: mocks.userAccessSettingsQueryOptions,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -79,7 +109,7 @@ describe('use-app-access-config', () => {
|
||||
expect(mocks.accessRulesQueryOptions).toHaveBeenCalledWith({
|
||||
input: {
|
||||
params: {
|
||||
appId: 'app-1',
|
||||
app_id: 'app-1',
|
||||
},
|
||||
query: {
|
||||
language: 'zh',
|
||||
@ -97,7 +127,7 @@ describe('use-app-access-config', () => {
|
||||
expect(mocks.userAccessSettingsQueryOptions).toHaveBeenCalledWith({
|
||||
input: {
|
||||
params: {
|
||||
appId: 'app-1',
|
||||
app_id: 'app-1',
|
||||
},
|
||||
query: {
|
||||
language: 'en',
|
||||
@ -115,8 +145,8 @@ describe('use-app-access-config', () => {
|
||||
|
||||
expect(mocks.updateUserAccessSettings).toHaveBeenCalledWith({
|
||||
params: {
|
||||
appId: 'app-1',
|
||||
accountId: 'account-1',
|
||||
app_id: 'app-1',
|
||||
target_account_id: 'account-1',
|
||||
},
|
||||
body: {
|
||||
access_policy_ids: ['policy-1', 'policy-2'],
|
||||
@ -135,8 +165,8 @@ describe('use-app-access-config', () => {
|
||||
|
||||
expect(mocks.removeMemberBindings).toHaveBeenCalledWith({
|
||||
params: {
|
||||
appId: 'app-1',
|
||||
policyId: 'policy-1',
|
||||
app_id: 'app-1',
|
||||
policy_id: 'policy-1',
|
||||
},
|
||||
body: {
|
||||
account_ids: ['account-1'],
|
||||
@ -155,7 +185,7 @@ describe('use-app-access-config', () => {
|
||||
|
||||
expect(mocks.updateOpenScope).toHaveBeenCalledWith({
|
||||
params: {
|
||||
appId: 'app-1',
|
||||
app_id: 'app-1',
|
||||
},
|
||||
body: {
|
||||
scope: 'all',
|
||||
|
||||
@ -28,25 +28,55 @@ const mocks = vi.hoisted(() => ({
|
||||
|
||||
vi.mock('@/service/client', () => ({
|
||||
consoleClient: {
|
||||
rbacAccessConfig: {
|
||||
datasets: {
|
||||
updateOpenScope: mocks.updateOpenScope,
|
||||
updateUserAccessSettings: mocks.updateUserAccessSettings,
|
||||
removeMemberBindings: mocks.removeMemberBindings,
|
||||
workspaces: {
|
||||
current: {
|
||||
rbac: {
|
||||
datasets: {
|
||||
byDatasetId: {
|
||||
accessPolicies: {
|
||||
byPolicyId: {
|
||||
memberBindings: {
|
||||
delete: mocks.removeMemberBindings,
|
||||
},
|
||||
},
|
||||
},
|
||||
users: {
|
||||
byTargetAccountId: {
|
||||
accessPolicies: {
|
||||
put: mocks.updateUserAccessSettings,
|
||||
},
|
||||
},
|
||||
},
|
||||
whitelist: {
|
||||
put: mocks.updateOpenScope,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
consoleQuery: {
|
||||
rbacAccessConfig: {
|
||||
datasets: {
|
||||
accessRules: {
|
||||
key: mocks.accessRulesKey,
|
||||
queryOptions: mocks.accessRulesQueryOptions,
|
||||
},
|
||||
userAccessSettings: {
|
||||
key: mocks.userAccessSettingsKey,
|
||||
queryKey: mocks.userAccessSettingsQueryKey,
|
||||
queryOptions: mocks.userAccessSettingsQueryOptions,
|
||||
workspaces: {
|
||||
current: {
|
||||
rbac: {
|
||||
datasets: {
|
||||
byDatasetId: {
|
||||
accessPolicy: {
|
||||
get: {
|
||||
key: mocks.accessRulesKey,
|
||||
queryOptions: mocks.accessRulesQueryOptions,
|
||||
},
|
||||
},
|
||||
userAccessPolicies: {
|
||||
get: {
|
||||
key: mocks.userAccessSettingsKey,
|
||||
queryKey: mocks.userAccessSettingsQueryKey,
|
||||
queryOptions: mocks.userAccessSettingsQueryOptions,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -79,7 +109,7 @@ describe('use-dataset-access-config', () => {
|
||||
expect(mocks.accessRulesQueryOptions).toHaveBeenCalledWith({
|
||||
input: {
|
||||
params: {
|
||||
datasetId: 'dataset-1',
|
||||
dataset_id: 'dataset-1',
|
||||
},
|
||||
query: {
|
||||
language: 'ja',
|
||||
@ -97,7 +127,7 @@ describe('use-dataset-access-config', () => {
|
||||
expect(mocks.userAccessSettingsQueryOptions).toHaveBeenCalledWith({
|
||||
input: {
|
||||
params: {
|
||||
datasetId: 'dataset-1',
|
||||
dataset_id: 'dataset-1',
|
||||
},
|
||||
query: {
|
||||
language: 'zh',
|
||||
@ -115,8 +145,8 @@ describe('use-dataset-access-config', () => {
|
||||
|
||||
expect(mocks.updateUserAccessSettings).toHaveBeenCalledWith({
|
||||
params: {
|
||||
datasetId: 'dataset-1',
|
||||
accountId: 'account-1',
|
||||
dataset_id: 'dataset-1',
|
||||
target_account_id: 'account-1',
|
||||
},
|
||||
body: {
|
||||
access_policy_ids: ['policy-1', 'policy-2'],
|
||||
@ -135,8 +165,8 @@ describe('use-dataset-access-config', () => {
|
||||
|
||||
expect(mocks.removeMemberBindings).toHaveBeenCalledWith({
|
||||
params: {
|
||||
datasetId: 'dataset-1',
|
||||
policyId: 'policy-1',
|
||||
dataset_id: 'dataset-1',
|
||||
policy_id: 'policy-1',
|
||||
},
|
||||
body: {
|
||||
account_ids: ['account-1'],
|
||||
@ -155,7 +185,7 @@ describe('use-dataset-access-config', () => {
|
||||
|
||||
expect(mocks.updateOpenScope).toHaveBeenCalledWith({
|
||||
params: {
|
||||
datasetId: 'dataset-1',
|
||||
dataset_id: 'dataset-1',
|
||||
},
|
||||
body: {
|
||||
scope: 'specific',
|
||||
|
||||
175
web/service/access-control/normalizers.ts
Normal file
175
web/service/access-control/normalizers.ts
Normal file
@ -0,0 +1,175 @@
|
||||
import type {
|
||||
AccessPolicy,
|
||||
AccessPolicyResourceType,
|
||||
AccessPolicyWithBindings,
|
||||
GetAppAccessPolicyByAppIdResponse,
|
||||
GetAppUserAccessSettingsResponse,
|
||||
GetDatasetAccessPolicyByDatasetIdResponse,
|
||||
GetDatasetUserAccessSettingsResponse,
|
||||
ResourceOpenScope,
|
||||
ResourceUserAccessSetting,
|
||||
Role,
|
||||
} from '@/models/access-control'
|
||||
|
||||
type GeneratedAccessMatrixItem = import('@dify/contracts/api/console/workspaces/types.gen').AccessMatrixItem
|
||||
type GeneratedAccessPolicy = import('@dify/contracts/api/console/workspaces/types.gen').AccessPolicy
|
||||
type GeneratedAccessPolicyAccount = import('@dify/contracts/api/console/workspaces/types.gen').AccessPolicyAccount
|
||||
type GeneratedAccessPolicyRole = import('@dify/contracts/api/console/workspaces/types.gen').AccessPolicyRole
|
||||
type GeneratedAppAccessMatrix = import('@dify/contracts/api/console/workspaces/types.gen').AppAccessMatrix
|
||||
type GeneratedDatasetAccessMatrix = import('@dify/contracts/api/console/workspaces/types.gen').DatasetAccessMatrix
|
||||
type GeneratedRbacRole = import('@dify/contracts/api/console/workspaces/types.gen').RbacRole
|
||||
type GeneratedRbacRoleAccount = import('@dify/contracts/api/console/workspaces/types.gen').RbacRoleAccount
|
||||
type GeneratedResourceOpenScope = import('@dify/contracts/api/console/workspaces/types.gen').RbacResourceWhitelistScope
|
||||
type GeneratedResourceUserAccessPoliciesResponse = import('@dify/contracts/api/console/workspaces/types.gen').ResourceUserAccessPoliciesResponse
|
||||
type GeneratedResourceUserAccessPolicies = NonNullable<GeneratedResourceUserAccessPoliciesResponse['data']>[number]
|
||||
|
||||
const normalizeRoleCategory = (category?: string): Role['category'] => {
|
||||
if (category === 'global_system_default')
|
||||
return 'global_system_default'
|
||||
|
||||
return 'global_custom'
|
||||
}
|
||||
|
||||
const normalizeRoleType = (type?: string): Role['type'] => {
|
||||
if (type === 'app' || type === 'dataset')
|
||||
return type
|
||||
|
||||
return 'workspace'
|
||||
}
|
||||
|
||||
const normalizeRoleTag = (roleTag?: string): Role['role_tag'] => {
|
||||
if (roleTag === 'owner')
|
||||
return 'owner'
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
const normalizeResourceType = (resourceType: string, fallback: AccessPolicyResourceType): AccessPolicyResourceType => {
|
||||
if (resourceType === 'app' || resourceType === 'dataset')
|
||||
return resourceType
|
||||
|
||||
return fallback
|
||||
}
|
||||
|
||||
const normalizeAccessPolicy = (
|
||||
policy: GeneratedAccessPolicy,
|
||||
fallbackResourceType: AccessPolicyResourceType,
|
||||
): AccessPolicy => ({
|
||||
id: policy.id,
|
||||
tenant_id: policy.tenant_id ?? '',
|
||||
resource_type: normalizeResourceType(policy.resource_type, fallbackResourceType),
|
||||
policy_key: policy.policy_key ?? '',
|
||||
name: policy.name,
|
||||
description: policy.description ?? '',
|
||||
permission_keys: policy.permission_keys ?? [],
|
||||
is_builtin: policy.is_builtin ?? false,
|
||||
category: normalizeRoleCategory(policy.category),
|
||||
created_at: String(policy.created_at ?? 0),
|
||||
updated_at: String(policy.updated_at ?? 0),
|
||||
})
|
||||
|
||||
const normalizeAccessPolicyRole = (role: GeneratedAccessPolicyRole) => ({
|
||||
role_id: role.role_id,
|
||||
role_name: role.role_name,
|
||||
binding_id: role.binding_id,
|
||||
is_locked: role.is_locked ?? false,
|
||||
role_tag: normalizeRoleTag(role.role_tag),
|
||||
})
|
||||
|
||||
const normalizeAccessPolicyAccount = (account: GeneratedAccessPolicyAccount) => ({
|
||||
account_id: account.account_id,
|
||||
account_name: account.account_name,
|
||||
binding_id: account.binding_id,
|
||||
is_locked: account.is_locked ?? false,
|
||||
avatar: account.avatar ?? '',
|
||||
})
|
||||
|
||||
const normalizeAccessMatrixItem = (
|
||||
item: GeneratedAccessMatrixItem,
|
||||
fallbackResourceType: AccessPolicyResourceType,
|
||||
): AccessPolicyWithBindings | null => {
|
||||
if (!item.policy)
|
||||
return null
|
||||
|
||||
return {
|
||||
policy: normalizeAccessPolicy(item.policy, fallbackResourceType),
|
||||
roles: (item.roles ?? []).map(normalizeAccessPolicyRole),
|
||||
accounts: (item.accounts ?? []).map(normalizeAccessPolicyAccount),
|
||||
}
|
||||
}
|
||||
|
||||
const isAccessPolicyWithBindings = (item: AccessPolicyWithBindings | null): item is AccessPolicyWithBindings => {
|
||||
return item !== null
|
||||
}
|
||||
|
||||
const normalizeResourceOpenScope = (scope: GeneratedResourceOpenScope): ResourceOpenScope => {
|
||||
switch (scope) {
|
||||
case 'all':
|
||||
return 'all'
|
||||
case 'only_me':
|
||||
return 'only_me'
|
||||
case 'specific':
|
||||
return 'specific'
|
||||
}
|
||||
}
|
||||
|
||||
const normalizeAccount = (account: GeneratedRbacRoleAccount): ResourceUserAccessSetting['account'] => ({
|
||||
account_id: account.account_id,
|
||||
account_name: account.account_name ?? '',
|
||||
email: account.email ?? '',
|
||||
avatar: account.avatar ?? '',
|
||||
})
|
||||
|
||||
const normalizeRole = (role: GeneratedRbacRole): ResourceUserAccessSetting['roles'][number] => ({
|
||||
id: role.id,
|
||||
type: normalizeRoleType(role.type),
|
||||
category: normalizeRoleCategory(role.category),
|
||||
name: role.name,
|
||||
is_builtin: role.is_builtin ?? false,
|
||||
permission_keys: role.permission_keys ?? [],
|
||||
})
|
||||
|
||||
const normalizeResourceUserAccessSetting = (
|
||||
setting: GeneratedResourceUserAccessPolicies,
|
||||
fallbackResourceType: AccessPolicyResourceType,
|
||||
): ResourceUserAccessSetting => ({
|
||||
account: normalizeAccount(setting.account),
|
||||
roles: (setting.roles ?? []).map(normalizeRole),
|
||||
access_policies: (setting.access_policies ?? []).map(policy => normalizeAccessPolicy(policy, fallbackResourceType)),
|
||||
})
|
||||
|
||||
const normalizeResourceUserAccessPolicies = (
|
||||
response: GeneratedResourceUserAccessPoliciesResponse,
|
||||
fallbackResourceType: AccessPolicyResourceType,
|
||||
): GetAppUserAccessSettingsResponse | GetDatasetUserAccessSettingsResponse => ({
|
||||
data: (response.data ?? []).map(setting => normalizeResourceUserAccessSetting(setting, fallbackResourceType)),
|
||||
scope: normalizeResourceOpenScope(response.scope),
|
||||
})
|
||||
|
||||
export const normalizeAppAccessMatrix = (response: GeneratedAppAccessMatrix): GetAppAccessPolicyByAppIdResponse => ({
|
||||
app_id: response.app_id ?? '',
|
||||
items: (response.items ?? [])
|
||||
.map(item => normalizeAccessMatrixItem(item, 'app'))
|
||||
.filter(isAccessPolicyWithBindings),
|
||||
})
|
||||
|
||||
export const normalizeDatasetAccessMatrix = (
|
||||
response: GeneratedDatasetAccessMatrix,
|
||||
): GetDatasetAccessPolicyByDatasetIdResponse => ({
|
||||
dataset_id: response.dataset_id ?? '',
|
||||
items: (response.items ?? [])
|
||||
.map(item => normalizeAccessMatrixItem(item, 'dataset'))
|
||||
.filter(isAccessPolicyWithBindings),
|
||||
})
|
||||
|
||||
export const normalizeAppUserAccessPolicies = (
|
||||
response: GeneratedResourceUserAccessPoliciesResponse,
|
||||
): GetAppUserAccessSettingsResponse => {
|
||||
return normalizeResourceUserAccessPolicies(response, 'app')
|
||||
}
|
||||
|
||||
export const normalizeDatasetUserAccessPolicies = (
|
||||
response: GeneratedResourceUserAccessPoliciesResponse,
|
||||
): GetDatasetUserAccessSettingsResponse => {
|
||||
return normalizeResourceUserAccessPolicies(response, 'dataset')
|
||||
}
|
||||
@ -6,33 +6,42 @@ import type {
|
||||
} from '@/models/access-control'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { consoleClient, consoleQuery } from '@/service/client'
|
||||
import { normalizeAppAccessMatrix, normalizeAppUserAccessPolicies } from './normalizers'
|
||||
|
||||
const NAME_SPACE = 'app-access-config'
|
||||
const appRbacContract = consoleQuery.workspaces.current.rbac.apps.byAppId
|
||||
const appRbacClient = consoleClient.workspaces.current.rbac.apps.byAppId
|
||||
|
||||
export const useAppAccessRules = (appId: string, language: AccessControlTemplateLanguage) => {
|
||||
return useQuery(consoleQuery.rbacAccessConfig.apps.accessRules.queryOptions({
|
||||
input: {
|
||||
params: {
|
||||
appId,
|
||||
return useQuery({
|
||||
...appRbacContract.accessPolicy.get.queryOptions({
|
||||
input: {
|
||||
params: {
|
||||
app_id: appId,
|
||||
},
|
||||
query: {
|
||||
language,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
language,
|
||||
},
|
||||
},
|
||||
}))
|
||||
}),
|
||||
select: normalizeAppAccessMatrix,
|
||||
})
|
||||
}
|
||||
|
||||
export const useAppUserAccessSettings = (appId: string, language: AccessControlTemplateLanguage) => {
|
||||
return useQuery(consoleQuery.rbacAccessConfig.apps.userAccessSettings.queryOptions({
|
||||
input: {
|
||||
params: {
|
||||
appId,
|
||||
return useQuery({
|
||||
...appRbacContract.userAccessPolicies.get.queryOptions({
|
||||
input: {
|
||||
params: {
|
||||
app_id: appId,
|
||||
},
|
||||
query: {
|
||||
language,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
language,
|
||||
},
|
||||
},
|
||||
}))
|
||||
}),
|
||||
select: normalizeAppUserAccessPolicies,
|
||||
})
|
||||
}
|
||||
|
||||
export const useUpdateAppUserAccessSettings = (appId: string) => {
|
||||
@ -40,10 +49,10 @@ export const useUpdateAppUserAccessSettings = (appId: string) => {
|
||||
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'update-app-user-access-settings', appId],
|
||||
mutationFn: (payload: UpdateAppUserAccessSettingsRequest) => consoleClient.rbacAccessConfig.apps.updateUserAccessSettings({
|
||||
mutationFn: (payload: UpdateAppUserAccessSettingsRequest) => appRbacClient.users.byTargetAccountId.accessPolicies.put({
|
||||
params: {
|
||||
appId,
|
||||
accountId: payload.accountId,
|
||||
app_id: appId,
|
||||
target_account_id: payload.accountId,
|
||||
},
|
||||
body: {
|
||||
access_policy_ids: payload.accessPolicyIds,
|
||||
@ -52,10 +61,10 @@ export const useUpdateAppUserAccessSettings = (appId: string) => {
|
||||
onSuccess: async () => {
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.rbacAccessConfig.apps.userAccessSettings.key(),
|
||||
queryKey: appRbacContract.userAccessPolicies.get.key({ type: 'query' }),
|
||||
}),
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.rbacAccessConfig.apps.accessRules.key(),
|
||||
queryKey: appRbacContract.accessPolicy.get.key({ type: 'query' }),
|
||||
}),
|
||||
])
|
||||
},
|
||||
@ -67,10 +76,10 @@ export const useRemoveAppAccessPolicyMemberBindings = (appId: string) => {
|
||||
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'remove-app-access-policy-member-bindings', appId],
|
||||
mutationFn: (payload: RemoveAppAccessPolicyMemberBindingsRequest) => consoleClient.rbacAccessConfig.apps.removeMemberBindings({
|
||||
mutationFn: (payload: RemoveAppAccessPolicyMemberBindingsRequest) => appRbacClient.accessPolicies.byPolicyId.memberBindings.delete({
|
||||
params: {
|
||||
appId,
|
||||
policyId: payload.accessPolicyId,
|
||||
app_id: appId,
|
||||
policy_id: payload.accessPolicyId,
|
||||
},
|
||||
body: {
|
||||
account_ids: payload.accountIds,
|
||||
@ -79,10 +88,10 @@ export const useRemoveAppAccessPolicyMemberBindings = (appId: string) => {
|
||||
onSuccess: async () => {
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.rbacAccessConfig.apps.userAccessSettings.key(),
|
||||
queryKey: appRbacContract.userAccessPolicies.get.key({ type: 'query' }),
|
||||
}),
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.rbacAccessConfig.apps.accessRules.key(),
|
||||
queryKey: appRbacContract.accessPolicy.get.key({ type: 'query' }),
|
||||
}),
|
||||
])
|
||||
},
|
||||
@ -94,9 +103,9 @@ export const useUpdateAppOpenScope = (appId: string) => {
|
||||
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'update-app-open-scope', appId],
|
||||
mutationFn: (openScope: ResourceOpenScope) => consoleClient.rbacAccessConfig.apps.updateOpenScope({
|
||||
mutationFn: (openScope: ResourceOpenScope) => appRbacClient.whitelist.put({
|
||||
params: {
|
||||
appId,
|
||||
app_id: appId,
|
||||
},
|
||||
body: {
|
||||
scope: openScope,
|
||||
@ -105,7 +114,7 @@ export const useUpdateAppOpenScope = (appId: string) => {
|
||||
onSuccess: async () => {
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.rbacAccessConfig.apps.userAccessSettings.key(),
|
||||
queryKey: appRbacContract.userAccessPolicies.get.key({ type: 'query' }),
|
||||
}),
|
||||
])
|
||||
},
|
||||
|
||||
@ -6,8 +6,11 @@ import type {
|
||||
} from '@/models/access-control'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { consoleClient, consoleQuery } from '@/service/client'
|
||||
import { normalizeDatasetAccessMatrix, normalizeDatasetUserAccessPolicies } from './normalizers'
|
||||
|
||||
const NAME_SPACE = 'dataset-access-config'
|
||||
const datasetRbacContract = consoleQuery.workspaces.current.rbac.datasets.byDatasetId
|
||||
const datasetRbacClient = consoleClient.workspaces.current.rbac.datasets.byDatasetId
|
||||
|
||||
type DatasetAccessConfigQueryOptions = {
|
||||
enabled?: boolean
|
||||
@ -15,10 +18,10 @@ type DatasetAccessConfigQueryOptions = {
|
||||
|
||||
export const useDatasetAccessRules = (datasetId: string, language: AccessControlTemplateLanguage, options?: DatasetAccessConfigQueryOptions) => {
|
||||
return useQuery({
|
||||
...consoleQuery.rbacAccessConfig.datasets.accessRules.queryOptions({
|
||||
...datasetRbacContract.accessPolicy.get.queryOptions({
|
||||
input: {
|
||||
params: {
|
||||
datasetId,
|
||||
dataset_id: datasetId,
|
||||
},
|
||||
query: {
|
||||
language,
|
||||
@ -26,15 +29,16 @@ export const useDatasetAccessRules = (datasetId: string, language: AccessControl
|
||||
},
|
||||
}),
|
||||
enabled: options?.enabled ?? true,
|
||||
select: normalizeDatasetAccessMatrix,
|
||||
})
|
||||
}
|
||||
|
||||
export const useDatasetUserAccessSettings = (datasetId: string, language: AccessControlTemplateLanguage, options?: DatasetAccessConfigQueryOptions) => {
|
||||
return useQuery({
|
||||
...consoleQuery.rbacAccessConfig.datasets.userAccessSettings.queryOptions({
|
||||
...datasetRbacContract.userAccessPolicies.get.queryOptions({
|
||||
input: {
|
||||
params: {
|
||||
datasetId,
|
||||
dataset_id: datasetId,
|
||||
},
|
||||
query: {
|
||||
language,
|
||||
@ -42,6 +46,7 @@ export const useDatasetUserAccessSettings = (datasetId: string, language: Access
|
||||
},
|
||||
}),
|
||||
enabled: options?.enabled ?? true,
|
||||
select: normalizeDatasetUserAccessPolicies,
|
||||
})
|
||||
}
|
||||
|
||||
@ -50,10 +55,10 @@ export const useUpdateDatasetUserAccessSettings = (datasetId: string) => {
|
||||
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'update-dataset-user-access-settings', datasetId],
|
||||
mutationFn: (payload: UpdateDatasetUserAccessSettingsRequest) => consoleClient.rbacAccessConfig.datasets.updateUserAccessSettings({
|
||||
mutationFn: (payload: UpdateDatasetUserAccessSettingsRequest) => datasetRbacClient.users.byTargetAccountId.accessPolicies.put({
|
||||
params: {
|
||||
datasetId,
|
||||
accountId: payload.accountId,
|
||||
dataset_id: datasetId,
|
||||
target_account_id: payload.accountId,
|
||||
},
|
||||
body: {
|
||||
access_policy_ids: payload.accessPolicyIds,
|
||||
@ -62,10 +67,10 @@ export const useUpdateDatasetUserAccessSettings = (datasetId: string) => {
|
||||
onSuccess: async () => {
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.rbacAccessConfig.datasets.userAccessSettings.key(),
|
||||
queryKey: datasetRbacContract.userAccessPolicies.get.key({ type: 'query' }),
|
||||
}),
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.rbacAccessConfig.datasets.accessRules.key(),
|
||||
queryKey: datasetRbacContract.accessPolicy.get.key({ type: 'query' }),
|
||||
}),
|
||||
])
|
||||
},
|
||||
@ -77,10 +82,10 @@ export const useRemoveDatasetAccessPolicyMemberBindings = (datasetId: string) =>
|
||||
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'remove-dataset-access-policy-member-bindings', datasetId],
|
||||
mutationFn: (payload: RemoveDatasetAccessPolicyMemberBindingsRequest) => consoleClient.rbacAccessConfig.datasets.removeMemberBindings({
|
||||
mutationFn: (payload: RemoveDatasetAccessPolicyMemberBindingsRequest) => datasetRbacClient.accessPolicies.byPolicyId.memberBindings.delete({
|
||||
params: {
|
||||
datasetId,
|
||||
policyId: payload.accessPolicyId,
|
||||
dataset_id: datasetId,
|
||||
policy_id: payload.accessPolicyId,
|
||||
},
|
||||
body: {
|
||||
account_ids: payload.accountIds,
|
||||
@ -89,10 +94,10 @@ export const useRemoveDatasetAccessPolicyMemberBindings = (datasetId: string) =>
|
||||
onSuccess: async () => {
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.rbacAccessConfig.datasets.userAccessSettings.key(),
|
||||
queryKey: datasetRbacContract.userAccessPolicies.get.key({ type: 'query' }),
|
||||
}),
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.rbacAccessConfig.datasets.accessRules.key(),
|
||||
queryKey: datasetRbacContract.accessPolicy.get.key({ type: 'query' }),
|
||||
}),
|
||||
])
|
||||
},
|
||||
@ -104,9 +109,9 @@ export const useUpdateDatasetOpenScope = (datasetId: string) => {
|
||||
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'update-dataset-open-scope', datasetId],
|
||||
mutationFn: (openScope: ResourceOpenScope) => consoleClient.rbacAccessConfig.datasets.updateOpenScope({
|
||||
mutationFn: (openScope: ResourceOpenScope) => datasetRbacClient.whitelist.put({
|
||||
params: {
|
||||
datasetId,
|
||||
dataset_id: datasetId,
|
||||
},
|
||||
body: {
|
||||
scope: openScope,
|
||||
@ -115,7 +120,7 @@ export const useUpdateDatasetOpenScope = (datasetId: string) => {
|
||||
onSuccess: async () => {
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: consoleQuery.rbacAccessConfig.datasets.userAccessSettings.key(),
|
||||
queryKey: datasetRbacContract.userAccessPolicies.get.key({ type: 'query' }),
|
||||
}),
|
||||
])
|
||||
},
|
||||
|
||||
@ -17,8 +17,6 @@ const customConsoleContractLoaders: Record<string, () => Promise<AnyContractRout
|
||||
modelProviders: () =>
|
||||
import('@/contract/console/model-providers').then(({ modelProvidersRouterContract }) => wrapConsoleContract('modelProviders', modelProvidersRouterContract)),
|
||||
plugins: () => import('@/contract/console/plugins').then(({ pluginsRouterContract }) => wrapConsoleContract('plugins', pluginsRouterContract)),
|
||||
rbacAccessConfig: () =>
|
||||
import('@/contract/console/access-control').then(({ rbacAccessConfigContract }) => wrapConsoleContract('rbacAccessConfig', rbacAccessConfigContract)),
|
||||
snippets: () => import('@/contract/console/snippets').then(({ snippetsRouterContract }) => wrapConsoleContract('snippets', snippetsRouterContract)),
|
||||
triggers: () => import('@/contract/console/trigger').then(({ triggersRouterContract }) => wrapConsoleContract('triggers', triggersRouterContract)),
|
||||
trialApps: () => import('@/contract/console/try-app').then(({ trialAppsRouterContract }) => wrapConsoleContract('trialApps', trialAppsRouterContract)),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user