[ELMA3] Создание серверного модуля для приложения
Перед созданием модуля ознакомьтесь со страницей Создание модуля для приложения.
Основы взаимодействия модуля и основной конфигурации
Для начала необходимо объяснить, что же такое модуль и как он должен взаимодействовать с основной конфигурацией (платформой и ядром) приложения. Модуль – это отделяемая часть бизнес логики приложения, использующая возможности ядра и платформы для интеграции с другими модулями и с платформой системы. Другими словами, модуль – значительный блок логики и данных в контексте всего приложения. Взаимодействие модуля и других частей конфигурации происходит на 3-х уровнях:
- Модель данных – на этом уровне можно создавать собственные модели, расширять и наследовать уже существующие в других частях;
- Точки расширения – через этот механизм происходит основная часть интеграции в приложение, тут вы просто реализуете определенные интерфейсы и получаете требуемый функционал;
- События – простая событийная модель позволяет осуществлять еще более глубокую интеграцию.
Сам по себе модуль, обычно, представляет набор библиотек и веб-приложение для отображения данных. Модули могут быть самыми разными, от простых кусочков интеграции (например, интеграция модуля задач и модуля документов), до сложных самостоятельных модулей (например, модуль Управления проектами).
Создание модуля
Для создания модуля можно использовать Visual Studio 2010/2013/2015/2017 и плагин для разработки ELMA. Структура модуля одинакова для той и другой версии VS. Примеры сделаны в 2013 версии.
Чтобы создать модуль, нужно открыть VS – Создать проект (New Project) – Модуль для системы ELMA3.
Результатом создания будет решение с двумя проектами:
где EleWise.ELMA.CRMExtension – серверная часть модуля, а EleWise.ELMA.CRMExtension.Web – веб-часть модуля.
Файл AssemblyInfo.md теперь создается сразу. Он находится в серверной части модуля. Здесь вы можете задать необходимые Вам отображаемой имя, описание и т.д.
Создание и подготовка модели данных
Перед созданием полей по умолчанию необходимо в проект добавить сборку EleWise.ELMA.Security.
После всех приготовлений мы получаем проект, в котором можно добавлять новые модели и расширять существующие. В нашем примере, мы создадим модуль Работа с клиентами, в котором будет отображаться список компаний, будет возможность создавать\изменять компании. Также будет возможность прикреплять к компании документ и файл с комментарием. У компании будут поля:
- Наименование;
- Дата создания;
- Дата изменения;
- Автор создания;
- Автор изменения;
- ИНН;
- КПП.
Для демонстрации этих полей будет достаточно. Сначала добавим новую сущность в папку Models, назовем ее Company и добавим в нее свойства по умолчанию: Наименование, Автор создания, Автор изменения, Дата создания, Дата изменения. Для создания сущности нажимаем правой кнопкой мыши по папке Models – Add – New Item – ELMA Entity Interface.
Свойства Наименование, Автор и Дата создания необходимо отметить как обязательные для заполнения. Добавим свойства ИНН и КПП строкового типа. Для объекта Company нужно установить флажок Генерировать фильтр.
Подготовка бизнес логики
Вся бизнес логика приложения должна быть вынесена в специальные классы-менеджеры. Создадим свой класс-менеджер для работы с Компаниями:
1 | public class CompanyManager : EntityManager<ICompany, long > |
Обратите внимание, ICompany – это интерфейс. При создании сущности в Дизайнере на самом деле генерируется интерфейс, на основе свойств, добавленных в сущность. Второй параметр – это тип идентификатора сущности, он по умолчанию long, но это можно изменить при необходимости. Базовый класс EntityManager уже содержит необходимые методы для создания, сохранения, загрузки и удаления сущности. Особое внимание необходимо уделить тому, как создаются новые экземпляры сущности. Поскольку мы работаем с интерфейсами, то создавать напрямую объекты мы не можем, но есть два способа сделать это быстро и правильно:
- Вызвать метод Create() в менеджере.
- Использовать методы Create() класса EleWise.ELMA.Model.Services.InterfaceActivator.
На самом деле в первом случае делается перевызов второго варианта. В этом классе нужно определять любую логику работы с сущностями. В любом месте приложения будет доступен глобальный экземпляр вашего менеджера через статическое свойство Instance. Чтобы переопределить и возвращать сразу нужный тип менеджера, добавьте в ваш класс:
1 2 3 4 5 6 7 | public new static CompanyManager Instance { get { return Locator.GetServiceNotNull<CompanyManager>(); } } |
В нашем модуле нам потребуется разграничивать права пользователей. У нас будет всего 2 уровня доступа:
- Доступ к модулю (глобально возможность видеть модуль).
- Возможность редактировать компанию (это право есть только у автора компании).
Первый – это глобальный уровень, он назначается ролям через интерфейс администрирования. Второй – это уровень доступа на сущность, он зависит от значения поля Автор сущности. Для создания этих уровней необходимо использовать точку расширения EleWise.ELMA.Security.Services.IPermissionProvider, в ней необходимо реализовать 2 функции и 3 свойства:
- GetPermissions() – функция, возвращает набор готовых экземпляров класса EleWise.ELMA.Security.Permission;
- GetPermissionStereotypes() – функция, возвращает набор предустановленных прав для этого модуля, они будут созданы при подключении модуля;
- LocalizedItemsNames – свойство, возвращает локализированные имена привилегий;
- LocalizedItemsDescriptions – свойство, возвращает локализированные описания привилегий;
- LocalizedItemsCategories – свойство, возвращает локализированные имена категорий.
Более подробно смотрите страницы Настраиваемые привилегии на объекты и Привилегии. В нашем случае реализация довольно простая:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | [Component] public class CRMExtensionPermissionProvider : IPermissionProvider { public const string Module = "EleWise.ELMA.CRMExtensions" ; public const string CRMAccessPermissionId = "1958FB0F-755E-4C03-B94A-694B6E80333B" ; public static readonly Permission CRMAccessPermission = new Permission(CRMAccessPermissionId, SR.T( "Доступ к модулю" ), "" , SR.T( "Работа с клиентами" ), moduleUid: Module); public const string ViewCompanyPermissionId = "243C5DBA-ED64-4417-919A-2F20893F5017" ; public static readonly Permission ViewCompanyPermission = new Permission(ViewCompanyPermissionId, SR.T( "Просмотр компании" ), "" , SR.T( "Работа с клиентами" ), moduleUid: Module, //Тут задается ключ для группировки по модулям permissionType: PermissionType.Instance, //Тип привилегии, в данном случае - на сущность @ base : CommonPermissions.View, //Базовая привилегия entityType: InterfaceActivator.TypeOf<ICompany>()); //Тип сущности для данной привилегии public IEnumerable<Permission> GetPermissions() { return new [] { CRMAccessPermission, ViewCompanyPermission }; } public IEnumerable<PermissionStereotype> GetPermissionStereotypes() { return new [] { new PermissionStereotype( new [] { CRMAccessPermission, ViewCompanyPermission }, SecurityConstants.AllUsersGroupDescriptor), }; } public List< string > LocalizedItemsNames { get { return new List< string > { SR.T( "Доступ к модулю" ), SR.T( "Просмотр компании" ) }; } } public List< string > LocalizedItemsDescriptions { get { return new List< string > { SR.T( "Пользователи, обладающие этой привилегией, могут редактировать структуру дерева общих фильтров. Для предоставление полного доступа ко всем фильтрам необходимо дабавить глобальную привилегию \"Доступ ко всем фильтрам\"" ) }; } } public List< string > LocalizedItemsCategories { get { return new List< string > { SR.T( "Работа с клиентами" ) }; } } } |
На данном этапе работа закончена, текущий менеджер сущности удовлетворяет всем нашим условиям, уровни доступа сконфигурированы.
Можно переходить к созданию веб-модуля.