Перейти к содержанию

Как скрыть узлы дерева рабочего места для определённых ролей

Как скрыть узлы дерева рабочего места для определённых ролей

Для того, чтобы скрыть те или иные узлы рабочих мест (папки, представления, сабсеты и пр.), в зависимости от любого условия (например, входит ли пользователь в роль, или является ли он администратором) следует написать и зарегистрировать правило инициализации рабочих мест WorkplaceInitializationRule. Такие правила будут работать и для толстого клиента, и для веб-клиента.

Note

Правила инициализации рабочих мест доступны, начиная со сборки 2.4.

Правило наследуется от базового класса WorkplaceInitializationRule. Переопределите метод IsSatisfiedBy, который должен возвращать false для всех узлов node, которые требуется скрыть, и true для всех остальных узлов. В конструкторе класса можно указать любые зависимости, полученные из Unity, например, ICardRepository или ICardCache. Текущая сессия ISession и доступ к базе IDbScope обеспечиваются через объект context. Для каждого рабочего места, доступного пользователю, будет создан отдельный экземпляр правила, поэтому в полях класса можно хранить данные, актуальные для текущего рабочего места.

Ниже приведён пример такого правила и его регистратора. Правило скрывает узел с представлением “Мои документы” и скрывает всю папку “Регистратор”, если текущий сотрудник не входит в роль “Регистраторы”. Правило написано таким образом, чтобы один раз вычислить вхождение пользователя во все интересующие нас роли allRolesToCheck, и затем быстро для каждого узла каждого рабочего места определить его доступность.

using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Tessa.Platform.Data; using Tessa.Platform.Initialization; using Tessa.Platform.Storage; using Tessa.Views.Workplaces; using Unity.Lifetime;

namespace Tessa.Extensions.Server.Initialization { /// <summary> /// Правило фильтрации узлов рабочего места. /// Экземпляр класса будет создан на каждое рабочее место, доступное пользователю. /// /// Например, если пользователю доступны рабочие места "Пользователь" и "Администратор", /// то конструктор будет вызван дважды для каждого рабочего места. /// </summary> public sealed class AbWorkplaceInitializationRule : WorkplaceInitializationRule { public AbWorkplaceInitializationRule() { // любые зависимости можно получить через конструктор, как и в любом другом расширении }

/// <summary> /// Узел с представлением "Мои документы". /// </summary> private static readonly Guid myDocumentsNodeID = new Guid("c6dc0ca5-d903-41e2-b5f9-0bb91f9bc354");

/// <summary> /// Узел с папкой "Регистратор". /// </summary> private static readonly Guid registratorNodeID = new Guid("241099c7-ac45-4d0a-b566-5dd45c4cbb62");

/// <summary> /// Идентификатор роли "Регистраторы". /// </summary> private static readonly Guid registratorsRoleID = new Guid("0071b103-0ffa-49da-8776-53b9c654d815");

/// <summary> /// Список всех ролей, вхождение в которые потребуется проверить. /// </summary> private static readonly Guid[] allRolesToCheck = { registratorsRoleID };

/// <summary> /// Роли, про которые правило знает, что пользователь в них входит, /// или <c>null</c>, если роли ещё не расчитаны для текущего рабочего места. /// </summary> private HashSet<Guid> availableRoles;

private async ValueTask<bool> IsRoleAvailableAsync( Guid roleID, IWorkplaceInitializationContext context, CancellationToken cancellationToken = default) { if (this.availableRoles != null) { // для текущего рабочего места уже вычислен список ролей return this.availableRoles.Contains(roleID); }

this.availableRoles = context.Info.TryGet<HashSet<Guid>>("AbAvailableRoles"); if (this.availableRoles != null) { // список ролей был вычислен для другого рабочего места; // поскольку экземпляр класса тоже другой, то мы сохраняем список ролей в текущем экземпляре return this.availableRoles.Contains(roleID); }

// выполняется первая проверка, входит ли пользователь в роль; // расчитываем все интересующие нас роли одним запросом, и сохраняем результат // в поле this.availableRoles для текущего рабочего места // и в свойстве context.Info для других рабочих мест

await using (context.DbScope.Create()) { DbManager db = context.DbScope.Db;

List<Guid> availableRoles = await db .SetCommand( "select ID from RoleUsers with(nolock) where UserID = @UserID" // and ID in ('...', '...') + " and ID " + SqlHelper.GetQuotedEqualsExpression(allRolesToCheck), db.Parameter("UserID", context.Session.User.ID)) .LogCommand() .ExecuteListAsync<Guid>(cancellationToken);

this.availableRoles = new HashSet<Guid>(availableRoles); }

context.Info["AbAvailableRoles"] = this.availableRoles; return this.availableRoles.Contains(roleID); }

public override async ValueTask<bool> IsSatisfiedByAsync( IWorkplaceComponentMetadata node, IWorkplaceInitializationContext context, CancellationToken cancellationToken = default) { if (node.CompositionId == myDocumentsNodeID || node.CompositionId == registratorNodeID) { // узлы "Мои документы" и "Регистратор" будут доступны только пользователям, входящим в роль "Регистраторы" return await this.IsRoleAvailableAsync(registratorsRoleID, context, cancellationToken); }

return true; } }

[Registrator] public sealed class Registrator : RegistratorBase { public override void RegisterUnity() { this.UnityContainer .RegisterWorkplaceInitializationRule<AbWorkplaceInitializationRule>(new PerResolveLifetimeManager()) ; } } }

Back to top