From 0762a429221b2d3933e495c812c5a64cc5717dd7 Mon Sep 17 00:00:00 2001 From: Denis Bykhov Date: Fri, 12 Dec 2025 08:15:56 +0500 Subject: [PATCH] Fix permissions for mixins/tags (#10294) * Fix permissions for mixins/tags Signed-off-by: Denis Bykhov * Fix Signed-off-by: Denis Bykhov --------- Signed-off-by: Denis Bykhov --- .../middleware/src/spacePermissions.ts | 26 +++++++++++--- .../src/components/CreateCardPopup.svelte | 9 +++++ plugins/contact-resources/src/utils.ts | 35 ++++++------------- plugins/view-assets/lang/cs.json | 1 + plugins/view-assets/lang/de.json | 1 + plugins/view-assets/lang/en.json | 1 + plugins/view-assets/lang/es.json | 1 + plugins/view-assets/lang/fr.json | 1 + plugins/view-assets/lang/it.json | 1 + plugins/view-assets/lang/ja.json | 1 + plugins/view-assets/lang/pt.json | 1 + plugins/view-assets/lang/ru.json | 1 + plugins/view-assets/lang/tr.json | 1 + plugins/view-assets/lang/zh.json | 1 + plugins/view/src/index.ts | 3 +- 15 files changed, 54 insertions(+), 30 deletions(-) diff --git a/foundations/server/packages/middleware/src/spacePermissions.ts b/foundations/server/packages/middleware/src/spacePermissions.ts index 8e51fe151d..a22fbfa8cb 100644 --- a/foundations/server/packages/middleware/src/spacePermissions.ts +++ b/foundations/server/packages/middleware/src/spacePermissions.ts @@ -174,10 +174,10 @@ export class SpacePermissionsMiddleware extends BaseMiddleware implements Middle const permissions = this.permissionsBySpace[space]?.[account.uuid] ?? [] let withoutMatch: Permission | undefined for (const permission of permissions) { - if (permission.txClass === undefined || permission.txClass !== tx._class) continue + if (!isTxClassMatched(tx, permission)) continue if ( permission.objectClass !== undefined && - !this.context.hierarchy.isDerived(tx.objectClass, permission.objectClass) + !this.context.hierarchy.isDerived(getTxObjectClass(tx), permission.objectClass) ) { continue } @@ -203,12 +203,13 @@ export class SpacePermissionsMiddleware extends BaseMiddleware implements Middle if (this.restrictedSpaces.has(space)) { const attachedDocAncestors = this.context.hierarchy.getAncestors(core.class.AttachedDoc) - const ancestors = this.context.hierarchy.getAncestors(tx.objectClass) + const ancestors = this.context.hierarchy.getAncestors(getTxObjectClass(tx)) const targetAncestors = ancestors.filter((a) => !attachedDocAncestors.includes(a)) + const txClass = getTxClass(tx) const permissions = this.context.modelDb.findAllSync(core.class.Permission, { objectClass: { $in: targetAncestors }, - txClass: tx._class + txClass }) const matched = permissions.filter((p) => { if (p.txMatch === undefined) return false @@ -460,3 +461,20 @@ export class SpacePermissionsMiddleware extends BaseMiddleware implements Middle } } } + +function getTxClass (tx: Tx): Ref> { + let _class = tx._class + if (tx._class === core.class.TxMixin && Object.keys((tx as TxMixin).attributes).length > 0) { + _class = core.class.TxUpdateDoc + } + return _class +} + +function isTxClassMatched (tx: Tx, permission: Permission): boolean { + const txClass = getTxClass(tx) + return permission.txClass === txClass +} + +function getTxObjectClass (tx: TxCUD): Ref> { + return tx._class === core.class.TxMixin ? (tx as TxMixin).mixin : tx.objectClass +} diff --git a/plugins/card-resources/src/components/CreateCardPopup.svelte b/plugins/card-resources/src/components/CreateCardPopup.svelte index 9f57d920bb..25442bc165 100644 --- a/plugins/card-resources/src/components/CreateCardPopup.svelte +++ b/plugins/card-resources/src/components/CreateCardPopup.svelte @@ -217,7 +217,16 @@ {/if} + +
+ {#if !allowed} +
diff --git a/plugins/contact-resources/src/utils.ts b/plugins/contact-resources/src/utils.ts index c5dde50bad..c71d0b934b 100644 --- a/plugins/contact-resources/src/utils.ts +++ b/plugins/contact-resources/src/utils.ts @@ -751,33 +751,18 @@ export const permissionsStore = derived( } ) -const spaceTypesQuery = createQuery(true) const permissionsQuery = createQuery(true) -type TargetClassesProjection = Record>, number> -spaceTypesQuery.query(core.class.SpaceType, {}, (types) => { - const targetClasses = types.reduce((acc, st) => { - acc[st.targetClass] = 1 - return acc - }, {}) - - permissionsQuery.query( - core.class.Space, - {}, - (res) => { - spacesStore.set(res) - }, - { - showArchived: true, - projection: { - _id: 1, - type: 1, - members: 1, - ...targetClasses - } as any - } - ) -}) +permissionsQuery.query( + core.class.Space, + {}, + (res) => { + spacesStore.set(res) + }, + { + showArchived: true + } +) export function getAccountClient (): AccountClient { const accountsUrl = getMetadata(login.metadata.AccountsUrl) diff --git a/plugins/view-assets/lang/cs.json b/plugins/view-assets/lang/cs.json index 1fb0ad5b9a..79d1f36414 100644 --- a/plugins/view-assets/lang/cs.json +++ b/plugins/view-assets/lang/cs.json @@ -15,6 +15,7 @@ "Role": "Role", "DeleteObject": "Smazat objekt", "DeleteObjectConfirm": "Chcete smazat {count, plural, =1 {tento objekt} other {těchto # objektů}}?", + "NoCreatePermissionTitle": "Nemáte dostatečná oprávnění pro vytvoření", "DeletePopupNoPermissionTitle": "Nemáte dostatečná oprávnění pro smazání.", "DeletePopupNoPermissionLabel": "Kontaktujte prosím osoby ze seznamu níže, aby to mohly provést.", "DeletePopupCreatorLabel": "Tvůrci (mohou mazat pouze objekty, které vytvořili):", diff --git a/plugins/view-assets/lang/de.json b/plugins/view-assets/lang/de.json index e7e0e31000..5696d664c5 100644 --- a/plugins/view-assets/lang/de.json +++ b/plugins/view-assets/lang/de.json @@ -15,6 +15,7 @@ "Role": "Rolle", "DeleteObject": "Objekt löschen", "DeleteObjectConfirm": "Möchten Sie {count, plural, =1 {dieses Objekt} other {diese # Objekte}} löschen?", + "NoCreatePermissionTitle": "Keine ausreichenden Berechtigungen zum Erstellen", "DeletePopupNoPermissionTitle": "Keine ausreichenden Berechtigungen zum Löschen.", "DeletePopupNoPermissionLabel": "Bitte kontaktieren Sie Personen aus der folgenden Liste.", "DeletePopupCreatorLabel": "Ersteller (können nur von ihnen erstellte Objekte löschen):", diff --git a/plugins/view-assets/lang/en.json b/plugins/view-assets/lang/en.json index 7f25838907..f0653a2588 100644 --- a/plugins/view-assets/lang/en.json +++ b/plugins/view-assets/lang/en.json @@ -15,6 +15,7 @@ "Role": "Role", "DeleteObject": "Delete object", "DeleteObjectConfirm": "Do you want to delete {count, plural, =1 {this object} other {these # objects}}?", + "NoCreatePermissionTitle": "Not enough permissions to create", "DeletePopupNoPermissionTitle": "Not enough permissions to delete.", "DeletePopupNoPermissionLabel": "Please contact people from the list below for them to do so.", "DeletePopupCreatorLabel": "Creators (can delete only ones that were created by them):", diff --git a/plugins/view-assets/lang/es.json b/plugins/view-assets/lang/es.json index 06340c4769..0b6ae204fe 100644 --- a/plugins/view-assets/lang/es.json +++ b/plugins/view-assets/lang/es.json @@ -15,6 +15,7 @@ "Role": "Rol", "DeleteObject": "Eliminar objeto", "DeleteObjectConfirm": "¿Desea eliminar {count, plural, =1 {este objeto} other {estos # objetos}}?", + "NoCreatePermissionTitle": "Permisos insuficientes para crear", "DeletePopupNoPermissionTitle": "Permisos insuficientes para eliminar.", "DeletePopupNoPermissionLabel": "Por favor, contacte con las personas de la siguiente lista para que puedan eliminarlo.", "DeletePopupCreatorLabel": "Creadores (pueden eliminar solo los que ellos crearon):", diff --git a/plugins/view-assets/lang/fr.json b/plugins/view-assets/lang/fr.json index 13efeac32b..682e6231e7 100644 --- a/plugins/view-assets/lang/fr.json +++ b/plugins/view-assets/lang/fr.json @@ -15,6 +15,7 @@ "Role": "Rôle", "DeleteObject": "Supprimer l'objet", "DeleteObjectConfirm": "Voulez-vous supprimer {count, plural, =1 {cet objet} other {ces # objets}} ?", + "NoCreatePermissionTitle": "Permissions insuffisantes pour créer", "DeletePopupNoPermissionTitle": "Permissions insuffisantes pour supprimer.", "DeletePopupNoPermissionLabel": "Veuillez contacter les personnes de la liste ci-dessous pour qu'elles le fassent.", "DeletePopupCreatorLabel": "Créateurs (peuvent supprimer uniquement ceux qu'ils ont créés) :", diff --git a/plugins/view-assets/lang/it.json b/plugins/view-assets/lang/it.json index 274d5447fd..6d9833dc13 100644 --- a/plugins/view-assets/lang/it.json +++ b/plugins/view-assets/lang/it.json @@ -15,6 +15,7 @@ "Role": "Ruolo", "DeleteObject": "Elimina oggetto", "DeleteObjectConfirm": "Vuoi eliminare {count, plural, =1 {questo oggetto} other {questi # oggetti}}?", + "NoCreatePermissionTitle": "Permessi insufficienti per creare", "DeletePopupNoPermissionTitle": "Permessi insufficienti per eliminare.", "DeletePopupNoPermissionLabel": "Contatta le persone della lista qui sotto affinché possano farlo.", "DeletePopupCreatorLabel": "Creatori (possono eliminare solo quelli creati da loro):", diff --git a/plugins/view-assets/lang/ja.json b/plugins/view-assets/lang/ja.json index 66ab70464c..fb26ba07d9 100644 --- a/plugins/view-assets/lang/ja.json +++ b/plugins/view-assets/lang/ja.json @@ -15,6 +15,7 @@ "Role": "役割", "DeleteObject": "オブジェクトを削除", "DeleteObjectConfirm": "{count, plural, =1 {このオブジェクト} other {これらの # 個のオブジェクト}}を削除しますか?", + "NoCreatePermissionTitle": "作成する権限がありません", "DeletePopupNoPermissionTitle": "削除する権限がありません。", "DeletePopupNoPermissionLabel": "削除するには、以下のリストの担当者にご連絡ください。", "DeletePopupCreatorLabel": "作成者 (自分で作成したもののみ削除できます):", diff --git a/plugins/view-assets/lang/pt.json b/plugins/view-assets/lang/pt.json index 322f4fbce2..d4164e4f59 100644 --- a/plugins/view-assets/lang/pt.json +++ b/plugins/view-assets/lang/pt.json @@ -15,6 +15,7 @@ "Role": "Função", "DeleteObject": "Apagar objecto", "DeleteObjectConfirm": "Deseja apagar {count, plural, =1 {este objecto} other {estes # objectos}}?", + "NoCreatePermissionTitle": "Sem permissões suficientes para criar", "DeletePopupNoPermissionTitle": "Sem permissões suficientes para apagar.", "DeletePopupNoPermissionLabel": "Por favor, contacte as pessoas da lista abaixo para que o possam fazer.", "DeletePopupCreatorLabel": "Criadores (só podem apagar os que criaram):", diff --git a/plugins/view-assets/lang/ru.json b/plugins/view-assets/lang/ru.json index 1fa220687c..25e2b46c20 100644 --- a/plugins/view-assets/lang/ru.json +++ b/plugins/view-assets/lang/ru.json @@ -15,6 +15,7 @@ "Role": "Роль", "DeleteObject": "Удалить объект", "DeleteObjectConfirm": "Вы действительно хотите удалить {count, plural, =1 {этот объект} one {этот # объект} few {эти # объекта} other {эти # объектов}}?", + "NoCreatePermissionTitle": "Недостаточно прав для создания", "DeletePopupNoPermissionTitle": "Недостаточно прав для удаления.", "DeletePopupNoPermissionLabel": "Пожалуйста, обратитесь к людям из списка ниже, чтобы они это сделали.", "DeletePopupCreatorLabel": "Создатели объектов (могут удалить лишь те, что были созданы ими):", diff --git a/plugins/view-assets/lang/tr.json b/plugins/view-assets/lang/tr.json index aa5d7f40c6..eafad8979f 100644 --- a/plugins/view-assets/lang/tr.json +++ b/plugins/view-assets/lang/tr.json @@ -15,6 +15,7 @@ "Role": "Rol", "DeleteObject": "Nesneyi sil", "DeleteObjectConfirm": "{count, plural, =1 {bu nesneyi} other {bu # nesneyi}} silmek istiyor musunuz?", + "NoCreatePermissionTitle": "Oluşturmak için yeterli izin yok", "DeletePopupNoPermissionTitle": "Silmek için yeterli izin yok.", "DeletePopupNoPermissionLabel": "Lütfen aşağıdaki listedeki kişilerle iletişime geçin.", "DeletePopupCreatorLabel": "Oluşturanlar (sadece kendilerinin oluşturduklarını silebilir):", diff --git a/plugins/view-assets/lang/zh.json b/plugins/view-assets/lang/zh.json index 718a943ce3..8685e44ee3 100644 --- a/plugins/view-assets/lang/zh.json +++ b/plugins/view-assets/lang/zh.json @@ -15,6 +15,7 @@ "Role": "角色", "DeleteObject": "删除对象", "DeleteObjectConfirm": "您想要删除 {count, plural, =1 {这个对象} other {这些 # 个对象}} 吗?", + "NoCreatePermissionTitle": "没有足够的权限创建", "DeletePopupNoPermissionTitle": "没有足够的权限删除。", "DeletePopupNoPermissionLabel": "请联系以下列表中的人员以便他们执行此操作。", "DeletePopupCreatorLabel": "创建者(只能删除他们创建的):", diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts index 44c6807e91..721ad5c471 100644 --- a/plugins/view/src/index.ts +++ b/plugins/view/src/index.ts @@ -255,7 +255,8 @@ const view = plugin(viewId, { CopyDocumentMarkdown: '' as IntlString, RoleLabel: '' as IntlString, ForbidAttributeChanges: '' as IntlString, - AllowAttributeChanges: '' as IntlString + AllowAttributeChanges: '' as IntlString, + NoCreatePermissionTitle: '' as IntlString }, icon: { Table: '' as Asset,