|
| 1 | +# UI Property Permissions |
| 2 | + |
| 3 | +The UI Property Permissions are used to restrict access to specific properties in the Backoffice UI. |
| 4 | + |
| 5 | +## Document Property Value User Permissions |
| 6 | + |
| 7 | +Out of the box, Umbraco provides a feature called Document Property Value User Permissions.This feature can restrict access to specific Document property values for certain user groups. By default, all the built-in User Groups have read and write permissions for all properties. However, you can limit a User Group's permissions specific properties through the UI. |
| 8 | + |
| 9 | +If a User Group does not have write access to a property, the property will be read-only for that User Group. If a User Group does not have read access to a property, the property will be hidden from that User Group. |
| 10 | + |
| 11 | +Be aware that the Document Property Value User Permissions are not enforced on the server-side. This means that a user can still access the property value through the API, even if the property is restricted in the UI. |
| 12 | + |
| 13 | +## Extending the Document Property Value User Permission with additional restrictions |
| 14 | + |
| 15 | +In addition to the User Permission logic, it is possible to add further restrictions to properties. This can be achieved through the `propertyReadOnlyState`-Manager available in property based Workspace Context. In the following example, we will make all invariant properties read-only. |
| 16 | + |
| 17 | +## Register a Workspace Context |
| 18 | + |
| 19 | +Register a [Workspace Context](./extending-overview/extension-types/workspaces/workspace-context.md) to append additional restrictions to properties. |
| 20 | + |
| 21 | +**Manifest** |
| 22 | + |
| 23 | +```ts |
| 24 | +import { UMB_WORKSPACE_CONDITION_ALIAS } from "@umbraco-cms/backoffice/workspace"; |
| 25 | +import { UMB_WORKSPACE_CONDITION_ALIAS } from "@umbraco-cms/backoffice/document"; |
| 26 | + |
| 27 | +const manifest: UmbExtensionManifest = { |
| 28 | + type: "workspaceContext", |
| 29 | + name: "My Document Property Permission Workspace Context", |
| 30 | + alias: "My.WorkspaceContext.DocumentPropertyPermission", |
| 31 | + api: () => import("./my-document-property-permission.workspace-context.js"), |
| 32 | + conditions: [ |
| 33 | + { |
| 34 | + alias: UMB_WORKSPACE_CONDITION_ALIAS, |
| 35 | + match: UMB_DOCUMENT_WORKSPACE_ALIAS, |
| 36 | + }, |
| 37 | + ], |
| 38 | +}; |
| 39 | +``` |
| 40 | + |
| 41 | +## Implement custom logic for Property Value Permissions |
| 42 | + |
| 43 | +Implement custom logic to identify all properties and add a read-only state for each one. To target a property, we use its unique identifier along with the variant ID that corresponds to that property. In the following example, we will focus specifically on the invariant properties. |
| 44 | + |
| 45 | +**Workspace Context** |
| 46 | + |
| 47 | +```ts |
| 48 | +import { UmbControllerBase } from "@umbraco-cms/backoffice/class-api"; |
| 49 | +import type { UmbControllerHost } from "@umbraco-cms/backoffice/controller-api"; |
| 50 | +import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from "@umbraco-cms/backoffice/document"; |
| 51 | +import { UmbVariantId } from "@umbraco-cms/backoffice/variant"; |
| 52 | + |
| 53 | +export class MyDocumentPropertyPermissionWorkspaceContext extends UmbControllerBase { |
| 54 | + constructor(host: UmbControllerHost) { |
| 55 | + super(host); |
| 56 | + |
| 57 | + // Consume the document workspace context |
| 58 | + this.consumeContext( |
| 59 | + UMB_DOCUMENT_WORKSPACE_CONTEXT, |
| 60 | + this.#observeStructure |
| 61 | + ); |
| 62 | + } |
| 63 | + |
| 64 | + #observeStructure(context: typeof UMB_DOCUMENT_WORKSPACE_CONTEXT.TYPE) { |
| 65 | + if (!context) return; |
| 66 | + |
| 67 | + // Observe all properties for the Content Type |
| 68 | + this.observe(context.structure.contentTypeProperties, (properties) => { |
| 69 | + if (properties.length === 0) return; |
| 70 | + |
| 71 | + // Create a new variant ID for the invariant properties |
| 72 | + const invariantId = new UmbVariantId(); |
| 73 | + |
| 74 | + // Create a read-only state for each property |
| 75 | + const states = properties.map((property) => { |
| 76 | + return { |
| 77 | + unique: |
| 78 | + "MY_INVARIANT_PROPERTY_RESTRICTION_" + property.unique, |
| 79 | + message: |
| 80 | + "The property is read only because of my restriction", |
| 81 | + propertyType: { |
| 82 | + unique: property.unique, |
| 83 | + variantId: invariantId, |
| 84 | + }, |
| 85 | + }; |
| 86 | + }); |
| 87 | + |
| 88 | + // Add the read-only states to the property read-only state manager |
| 89 | + context.structure.propertyReadOnlyState.addStates(states); |
| 90 | + }); |
| 91 | + } |
| 92 | +} |
| 93 | + |
| 94 | +export { MyDocumentPropertyPermissionWorkspaceContext as api }; |
| 95 | +``` |
| 96 | + |
| 97 | +## Custom logic For Property value permissions |
| 98 | + |
| 99 | +It is also possible to implement completely custom UI logic for managing property value permissions. To do this, you first need to remove the default read and write access to properties for the user group. As a result, all properties will be hidden from that user group. Afterward, you can create custom logic to determine whether a specific user group should have access to particular properties. |
| 100 | + |
| 101 | +We follow the same concept as the previous example, but instead of writing to the `propertyReadOnlyState`-Manager, we can use the `propertyViewState`-Manager and the `propertyWriteState`-Manager to control the view- and writability of properties. |
| 102 | + |
| 103 | +In the following example we will hide a specific property based on the propertyAlias. |
| 104 | + |
| 105 | +## Register a workspace context for the Document Workspace |
| 106 | + |
| 107 | +For the manifest we can use the same manifest as the previous example. |
| 108 | + |
| 109 | +## Implement custom logic for Property Value Permissions |
| 110 | + |
| 111 | +Implement custom logic to identify all properties and add a view and write state for each one. |
| 112 | + |
| 113 | +```ts |
| 114 | +import { UmbControllerBase } from "@umbraco-cms/backoffice/class-api"; |
| 115 | +import type { UmbControllerHost } from "@umbraco-cms/backoffice/controller-api"; |
| 116 | +import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from "@umbraco-cms/backoffice/document"; |
| 117 | +import { UmbVariantId } from "@umbraco-cms/backoffice/variant"; |
| 118 | + |
| 119 | +export class MyDocumentPropertyPermissionWorkspaceContext extends UmbControllerBase { |
| 120 | + constructor(host: UmbControllerHost) { |
| 121 | + super(host); |
| 122 | + |
| 123 | + // Consume the document workspace context |
| 124 | + this.consumeContext( |
| 125 | + UMB_DOCUMENT_WORKSPACE_CONTEXT, |
| 126 | + this.#observeStructure |
| 127 | + ); |
| 128 | + } |
| 129 | + |
| 130 | + #observeStructure(context: typeof UMB_DOCUMENT_WORKSPACE_CONTEXT.TYPE) { |
| 131 | + if (!context) return; |
| 132 | + |
| 133 | + // Observe all properties for the Content Type |
| 134 | + this.observe(context.structure.contentTypeProperties, (properties) => { |
| 135 | + if (properties.length === 0) return; |
| 136 | + |
| 137 | + // Filter out the property with the alias "myPropertyAlias" |
| 138 | + const allowedProperties = properties.filter( |
| 139 | + (property) => property.alias !== "myPropertyAlias" |
| 140 | + ); |
| 141 | + |
| 142 | + // Create a new variant ID for the invariant properties |
| 143 | + const invariantId = new UmbVariantId(); |
| 144 | + |
| 145 | + // Create a read-only state for each property |
| 146 | + const states = allowedProperties.map((property) => { |
| 147 | + return { |
| 148 | + unique: |
| 149 | + "MY_INVARIANT_PROPERTY_RESTRICTION_" + property.unique, |
| 150 | + message: "", |
| 151 | + propertyType: { |
| 152 | + unique: property.unique, |
| 153 | + variantId: invariantId, |
| 154 | + }, |
| 155 | + }; |
| 156 | + }); |
| 157 | + |
| 158 | + // Add the read-only states to the property read-only state manager |
| 159 | + context.structure.propertyViewState.addStates(states); |
| 160 | + context.structure.propertyWriteState.addStates(states); |
| 161 | + }); |
| 162 | + } |
| 163 | +} |
| 164 | +``` |
0 commit comments