Подсистема прав доступа (анализ ролей, отладка RLS, английский код, обычные и управляемые формы)

Доброе время суток. Я, как обычно, с интересностями. И в этот раз мы поговорим о такой жуткой штуке, как RLS, генерация расширений на лету, и обратим внимание на одну интересную особенность «Полных прав» и английский сорцкод. Статья не является «продажной», ибо решение специфическое, кому надо, тот знает, что покупает. Однако в этой статье я расскажу про кучу тонкостей, с которыми мы столкнулись и как оптимизировали.

Немного про проблемы, которые мы хотели решить этой подсистемой

Представим себе ситуацию, что у нас есть некая конфигурация, типовая, или нет – не важно. И представим себе, что у нас реально возникает много проблем, связанных с ролями. Как минимум, давайте перечислим основные:

  1. Нельзя прочитать RLS, то есть внедренец, ставя ограничение на роль, вообще не имеет представления о том, что там эта роль реально ограничивает и по каким правилам. Например, есть некая роль:

Роль ДобавлениеИзменениеАвансовыхОтчетов

Глядя на нее в конфигураторе, можно прочитать текст ограничения и понять, как оно сработает.

  1. Роли при наличии БСП хоть и являются «универсальными», все равно не перекрывают все потребности. А особенно сложны для понимания роли, которые дают доступ к разным объектам. То есть надо четко уметь отделить некое право и посмотреть, какие роли его дают. В идеале – одна роль дает одно право.
  2. В конфигурациях бывают баги, а также бывают тонкости, про которые далеко не все знают. Например, одна роль на чтение может иметь RLS на некий справочник, а совсем левая роль на изменение (от другой подсистемы) может к этому справочнику давать безусловное чтение. Баг это или фича, не важно, но такое есть, и хорошо бы такие вещи отлавливать.
  3. Отдельное счастье – отладка RLS, что сейчас в принципе невозможно, так как язык RLS – это не тот же самый язык 1С (BSL), и просто написать не всегда получится.
  4. Любое изменение роли требует обращаться к конфигуратору. Любое добавление роли – надо идти в конфигуратор, тестировать под пользователем, открывать все параметры сеансов, смотреть что где – в общем, трэш.
  5. Когда выходит обновление конфигурации, надо перепроверять, не обновились ли шаблоны, и если они обновились, то тогда надо вот в те новые 10 ролей идти и перекидывать шаблоны, обновлять каждую роль.
  6. История изменения ролей. Кто, когда, зачем и на кой черт попросил что-то поправить. Так как роли добавляет программист, то он берет все входные данные и группирует их, а потом делает новые роли или модификацию предыдущих. И вот потом разобраться, зачем была та или иная модификация, или же какая модификация была на какую-то там дату – это нереально, разве что в задачниках, но и там надо каждый чих отслеживать и как-то группировать, чтобы найти.
  7. Ну и мой самый любимый прикол – это когда тебе попадается в руки УТ 10, УТП и им подобные, где уже никто ничего не понимает, что творится в ролях, никакого анализа адекватного нет, и пользователей просто создают «по аналогии», так как там изначально всего десяток ролей.
  8. И куча всякого другого…

Принятое решение

Итак, была поставлена задача по написанию принципиально нового подхода к разработке ролей:

  1. Это будет внешняя подсистема, отсутствие которой никак не скажется на конфигурации. То есть необходима модульность.
  2. Подсистема должна быть универсальной и не привязываться практически ни к каким модулям конфигурации или ее объектам.
  3. Основные функции системы – анализ ролей, отладка правил, создание новых ролей, хранение истории изменения ролей и т.д.

И такая подсистема была создана.

Вся суть работы с подсистемой описывается в перечислении нескольких шагов:

  1. Подключение расширения к конфигурации
  2. Загрузка ролей из XML
  3. Создание новых ролей
  4. Автогенерация нового расширения с новыми ролями
  5. Назначение новых ролей пользователю теми же механизмами, которыми назначаются новые роли, просто созданные в конфигураторе.

Как это все выглядит?

1. Подключается новое расширение, возьмем для примера УТ 11:

Подключается новое расширение, УТ11

  1. Параметры – пока оставим их, но суть в том, что можно создавать свои параметры сеанса.
  2. Пользователи – это просто сам справочник пользователей, из основной конфигурации.
  3. Профили доступа – этот справочник, по сути, аналогичен типовым из БСП: там просто есть таблица с ролями, и это позволяет комбинировать роли для конкретного пользователя, например.
  4. Роли доступа — это справочник самих ролей, вот прямо ролей, которые есть в конфигурации.
  5. Шаблоны – это шаблоны ролей. У 1С в конфигурации нет единого объекта шаблонов ролей, а на каждую роль – идет свое, однако в нашем случае это единый общий справочник.
  6. Отчет, который позволяет проанализировать роли.
  7. Загрузка данных ролей из XML.
  8. Конвертация шаблонов в код BSL.
  9. Генерация и подключения расширения с новыми ролями.
  10. Используется для обычных форм, это просто обработка с теми же 3 кнопками, что и выше.

2. Идем в опцию загрузки ролей и загружаем роли:

Загрузка ролей

Если выбрать первый или второй пункт, то нужно указать путь к базе и логин с паролем. Тогда система подключится в режиме конфигуратора, выгрузит XML конфигурации и загрузит их. Если выбрать третий вариант, то надо указать путь к XML выгрузке конфигурации или EDT формату.

При нажатии на кнопку Загрузить роли система начнет парсить XML и загружать роли в справочник системы.

Определение уникальности роли

Тут надо было решить несколько задач.

Первая – не загружать те роли, которые уже по факту были загружены и не изменились.

Для этого мы воспользовались технологией хешей: сначала происходит чтение текстового файла, потом считается его хеш вот такой вот функцией:

Function HashMD5(Data) Export
    Hash = New DataHashing(HashFunction.MD5);
    Hash.Append(Data);
    HashSum = Hash.HashSum;
    HashSumString = String(HashSum);
    HashSumString = StrReplace(HashSumString, " ", "");
    HashSumStringUUID = Left(HashSumString, 8)      + "-" +
                        Mid(HashSumString, 9, 4)    + "-" +
                        Mid(HashSumString, 15, 4)   + "-" +
                        Mid(HashSumString, 18, 4)   + "-" +
                        Right(HashSumString, 12);
    Return HashSumStringUUID;
EndFunction

Она возвращает строку, которую можно преобразовать UUID. Можно, конечно, передавать сам бинарник, тогда как бы и не надо было читать файл, однако нам все равно из файла нужно получить UUID роли, чтобы сопоставить с тем, что в базе.

И этот же UUID из ролей – является UUID элемента справочника ролей. Поэтому, если вы по какой-то причине потеряли эти UUID (а их можно иногда потерять, например, при слиянии конфигураций по наименованию, а не ID объектов), тогда можно получить дубли.

Особенности галочки «Устанавливать права для новых объектов»

Дошли мы до этапа загрузки данных, и тут, оказывается, что есть в правах доступа такие хитрые галочки:

Роль 1: Права

Хотелось бы в них разобраться детальнее.

Например, на ИТС про эти галочки говорится следующее:

Состояние флажка Устанавливать права для новых объектов определяет, будут ли установлены права для этой роли на новые добавляемые объекты конфигурации (снят по умолчанию для новой роли).

Состояние флажка Устанавливать права для реквизитов и табличных частей по умолчанию определяет, будут ли установлены права для этой роли на реквизиты (включая стандартные) и табличные части (включая стандартные) для новых объектов конфигурации (установлен по умолчанию).

При изменении состояния флажка Устанавливать права для реквизитов и табличных частей по умолчанию система предлагает изменить (установить или сбросить) права доступа для всех реквизитов (включая стандартные) и табличных частей (включая стандартные) всех объектов конфигурации.

И тут получается какая особенность: с одной стороны — галочка про новые права нужна и понятна, то есть поставили полным правам эту галочку и больше не мучаемся, но как это работает на самом деле?

Давайте проведем эксперимент, создадим конфигурацию с двумя справочниками и тремя ролями:

Три роли

Выгрузим их в XML и проведем анализ, что же на самом деле происходит. Мы создали три роли, сняли все права и установили все права только на справочники.

Вторая и третья роль полностью совпадают, что логично, а вот что произошло с первой и второй?

Совпадение ролей

(нажмите, чтобы увеличить картинку)

То есть в конфигурации, по факту, хранится информация о том, что во второй роли доступно, а в первой — запрещено.

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

Совпадение ролей

(нажмите, чтобы увеличить картинку)

Обратите внимание, что первая роль фиксирует у себя явный запрет к стандартным реквизитам Справочник2 и остальные доступы к объекту тоже (1 и 2 область), в третьей области ничего не изменилось, однако вторая роль тоже фиксирует явный запрет доступа к стандартным реквизитам Справочник2 (область 4).

Теперь давайте добавим справочник 3, а в ролях ничего менять не будем. После выгрузки мы увидим, что ничего не поменялось. Но при этом у второй роли есть доступ к стандартным реквизитам, хотя просто был создан объект Справочник3 и ничего не менялось более.

Какие выводы можно сделать:

  1. На самом деле галочка Устанавливать права для новых объектов ничего не устанавливает, если эта галочка стоит, то роль работает по принципу явного запрета, а без этой галочки — явного разрешения. То есть с галочкой — разрешено всё, что не запрещено, без галочки — запрещено все, что не разрешено.
  2. Видел пару раз случаи, когда эту галочку ставили по умолчанию, потом явно снимали все права и давали те, что надо, поговаривая при этом: «Зато программист не забудет дать права нужные». Или: «Какая разница, если я все контролирую?». Так вот, разница огромная. Если в роли с такой галочкой отменить все права у объектов и дать доступ к одному справочнику, то в случае УТ 11, например, само право доступа будет иметь около 100 000 строк и размер в 11 МБ. 100 000 строк, КАРЛ!
  3. Доступы к стандартным реквизитам не подчиняются общим правилам и всегда фиксируется отдельно. Похоже на то, что ранее система не имела возможности ставить такие права, и для обратной совместимости эти права ставятся отдельно и явно.

3. Теперь можно провести анализ ролей. Давайте откроем какую-нибудь роль и посмотрим — что там

Роли доступа

(нажмите, чтобы увеличить картинку)

Изначально открывается отчет, который позволяет просто сделать быстрый беглый анализ того, что дает, или запрещает эта роль. То есть тут четко видно — какие права доступа дают, какие RLS при этом действуют и т.д.

Остальные закладки дают дополнительную информацию по роли

Кроме этого, тут же видно, какие шаблоны есть в этой роли, и их можно прочитать:

Какие шаблоны в этой роли

(нажмите, чтобы увеличить картинку)

Видно, какое название имеет роль на разных языках, и тут же можно указать название, которое вы хотите дать созданной роли:

Роли доступа (Создание)

(нажмите, чтобы увеличить картинку)

Сводная информация по роли, так сказать, «внутренности хранения», где в целом видно, что на что действует, и можно сохранить куда-то для анализа:

Роли доступа (Создание)

(нажмите, чтобы увеличить картинку)

И, самое главное, — матрица ролей:

Матрица ролей

(нажмите, чтобы увеличить картинку)

Это то место, где можно проводить точечный анализ роли, или создать новую роль, или же — модифицировать ранее созданную.

По умолчанию выводятся только те объекты, к которым дан доступ, однако, если надо добавить объекты, можно выбрать опцию «Все объекты» и нажать кнопочку «Обновить права», тогда матрица перестроится.

И вот тут у нас есть много всего рассказать людям: про проблемы, с которыми мы столкнулись, как решали и какие решить не смогли.

Вводная по особенностям

В основном все проблемы крутятся в данном случае вокруг того, что для 1С тут выводится слишком много данных. Например, в случае УТ 11 если показать все объекты, то программа должна будет вывести 35 000 строк объектов, и все это – умноженное на 86 колонок, или, другими словами, около 3 000 000 ячеек.

Зачем нужен макет на первой вкладке, если он дублирует матрицу?

Ответ прост: потому что в табличный документ все выводится быстрее, чем в древо значений, однако за счет условного оформления работать с деревом значений значительно проще, чем с табличным документом. Именно поэтому модификация происходит в древе значений, а не в макете, а макет используется для экспресс-анализа.

Контекст и БезКонтекста

Тут позволю себе еще раз остановиться и всем напомнить о том, как важно дергать функции, если они нужны, в бесконтекстных вызовах. Изначально все тесты мы делали на простой конфигурации, где каждого объекта по одному типу. И вроде как все летало, но, как только пришла ERP, все рухнуло, а так как мы изначально забыли (читай — забили), то потом пришлось переписывать реально много кода.

Условное оформление на 80+ ячеек

При таком объеме данных — все работает отлично. В системе находится 250 правил. Как реализовано все это в таблице, особенно те моменты, где права можно назначать только те, которые поддерживает текущий объект.

  1. Вначале на все ячейки ставится условие — доступность = Ложь.
  2. Выполняется условие, которое проверяет типы объектов и открывает доступность только тем правам, которым надо
  3. На все остальные роли накладывается фон цвета — запрет
  4. После этого накладывается условие на замену текста на кружок, и установка его цвета.

И если первый пункт, второй и третий — делался вручную, то четвертый, где просто говорится, что если Таблица.Чтение = 1, тогда поставь зеленый кружок, и заполни поле Чтение, Если Таблица.Чтение = 2, то поставь красный кружок и заполни Чтение, и т.д., около 70 прав * 3 = 210 случаев, то вот это уже делать было совсем не весело.

Как решена была эта проблема — конфигурация была выгружена в XML, в XML найдена форма, там скопирован пример заполнения одного поля, и потом просто написана за 5 минут обработка, которая бежит по все колонкам, и копирует этот пример столько раз, сколько надо. И после этого — результат вставили в XML, и загрузили конфигурацию.

Не забывайте про этот лайфхак. На самом деле — это расширение создано в EDT, и там даже выгружать ничего не надо, просто открыл VCS, заменил что надо, сохранил, EDT сразу переформатировало, и все – 5 минут времени.

Всякие иконки ????‍ …

Не забуду напоминать: если у вас Windows 10, то нажмите Win + . (русская Ю) и печатайте всякое — ????‍????. Не все символы поддерживает 1С и не все так выводит, как тут, но многие вещи решить позволяет. Но учтите, что на вебе и тонком — все может разница, так что проверяйте, и даже на разных браузерах — все может выглядеть по-разному.

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

Логика вывода макета построена на классических макетах. То есть есть некий общий макет, который содержит в себе области с именами, и, выводя отчет, надо получать эту область, и … выводить в документ.

Все очень просто. Однако в этой области находится 70 колонок и столько же параметров, а еще она разукрашена, и получилась такая интересная вещь, что получение этой области занимало порядка 15% времени, судя по замеру производительности.

И, казалось бы, надо как-то захешировать эти данные, и тут было потрачено немало времени, пока не стало очевидно, что адекватными путями эту проблему не решить.

Варианты:

  1. Скопировать область в переменную — не работает, так как нет такого понятия, как копирование табличного документа.
  2. Положить в хранилище, а потом постоянно дергать — тоже не вариант, так как табличный документ — это не простой тип, и 1С работает с адресом в памяти, т.е. меняя эту область где угодно, при этом меняться будет везде.
  3. По этой же причине — не спрятать ее в массиве, структуре или временном хранилище
  4. По этим же причинам — не передать ее в процедуры/функции в качестве параметра с описанием Знач
  5. Вариант сериализации и дальнейшей десериализации помогает, но по времени занимает столько же, сколько и просто получение области, что в принципе логично.
  6. И, как следовало бы ожидать, общий модуль с параметром переиспользования значений тоже нам ничем не поможет, так как, модифицируя полученную через него область, она меняется в памяти по адресу. Но действительно ли повторное использование нам ничем не поможет?

Давайте рассмотрим несколько вариантов:

1. Для получения каждой области — мы дергаем функцию общего модуля, которая возвращает следующее:

Return GetCommonTemplate("Roles_MatrixTemplate").GetArea("Row");

В этом случае отчет по всем ролям в УТ 11 строится за 150 секунд, из которых вот эта часть занимает 35% времени:

Отчет по всем ролям в УТ11

2. Вынесем получение макета в модуль, где идет возврат повторно используемых значений, ну или просто определим его в переменную, и тут видим, что прирост стал приличным, эта функция теперь выполняется за 17% времени:

Возврат повторно используемых значений

3. Но идем дальше: а что, если мы просто будем очищать область каждый раз перед ее использованием. В этом случае нам надо прописать нечто вроде такого кода:

Function RowTemplate() Export
	Template = Roles_SettingsReUse.MatrixTemplates_Rows();
	For Index = 0 To Template.Parameters.Count() - 1 Do
		Template.Parameters[Index] = Undefined;
	EndD;

	Return Template;
EndFunction

Такой код приходит сразу в голову, так в 1С нельзя получить список параметров с именами, по-нормальному получить… Но тут выясняется, что код стал работать медленнее, теперь тратится уже 20% времени.

Код стал работать медленнее

Можно было бы плюнуть и оставить второй вариант, ибо все-таки там 35 000 вызовов, а тут цикл на 2 000 000 + итераций, ясное дело будет медленнее, однако не давала покоя одна мысль, а именно — функция у параметров заполнить. Но она работает только с именами… Поэтому был придуман 4 вариант.

4. В общем модуле с переиспользованием размещаем вот такой код:

Function MatrixTemplates() Export
	Return GetCommonTemplate("Roles_MatrixTemplate");
EndFunction

Function MatrixTemplates_Rows() Export
	Str = New Structure;
	Str.Insert("Template", Roles_SettingsReUse.MatrixTemplates().GetArea("Row"));
	Params = New Structure;
	For Index = 1 To Str.Template.TableWidth Do
		Cell = Str.Template.Area(1, Index);
		Params.Insert(Cell.Parameter);
	EndDo;
		
	Str.Insert("Params", Params);
	
	Return New FixedStructure(Str);
EndFunction

В обычном общем модуле размещаем такой код:

Function RowTemplate() Export
	Str = Roles_SettingsReUse.MatrixTemplates_Rows();
	Template = Str.Template;
	Template.Parameters.Fill(Str.Params);
	Return Template;
EndFunction

И вуаля: производительность выросла в 15 раз, 15 раз! Относительно второго варианта, и в 30 раз — относительно первого

Производительность выросла в 15 раз

Не забываем про индексирование колонок в таблице значений, ускоряемся на порядок

Во время очередной оптимизации мы столкнулись с тем, что у нас идет поиск по 2 полям внутри таблицы значений, и этот поиск занимал 66% времени формирования отчета.

Когда же мы занялись оптимизацией, то думали, как можно ускорить поиск, думали о том, что найденные строки в итерации надо удалять, тогда поиск будет быстрее, но все равно — это реально много времени. А потом выяснили, что мы просто забыли проиндексировать поля поиска в таблице значений. Когда мы добавили индексы, то поиск ускорился с 80 секунд, до 0,2. То есть на полтора порядка. И в целом отчет стал строиться не 120 секунд, а 25 секунд. И всего-то надо было добавить индекс в таблицу значений.

Не забывайте про это. А я в реальности вижу это очень часто. Когда, например, идет загрузка из Excel в базу товара, то парсят Excel, делают его таблицей значений, а потом делают поиски в нем по штрих-кодам, или ценам, особенно если в Excel 2 страницы, которые надо связать. А индексы не ставят, и когда товара становится много, поиск по таблице жрет половину времени загрузки.

Но, общаясь с коллегами, я их спросил, как они ставят индекс, и был немного удивлен — сейчас поясню.

Есть у нас некая ТЗ, и в ней есть колонки: ObjectPath, ObjectName, Disable … и еще куча других, но поиск выполняется по этим трем. Когда я спросил коллег, как они ставят индекс при условии, что надо выполнить поиск вот такими функциями:

RightTable.FindRows(New Structure("ObjectName, Disable", MetaItem.Name, False))

и:

RightTable.FindRows(New Structure("ObjectPath, Disable", MetaItem.Name, False))

В ответ я получил два варианта. Первый вариант:

RightTable.Indexes.Add("ObjectPath");
RightTable.Indexes.Add("Disable");
RightTable.Indexes.Add("ObjectName");

И второй вариант:

RightTable.Indexes.Add("ObjectPath, Disable, ObjectName");

И когда началось выяснение, почему так, то оказалось, что большинство из них не знало, что в 1С на таблицу значений идут составные индексы, то есть все эти добавления индексов бесполезные, даже более — они вредят.

Правильный ответ был такой:

RightTable.Indexes.Add("ObjectPath, Disable");
RightTable.Indexes.Add("ObjectName, Disable");

Мало того — тут важен порядок колонок, он должен быть строго такой, в котором идет поиск. И желательно, чтобы первый параметр отсекал максимум, то есть я неправильно задал условие, так как первый параметр является булево, то он должен был идти впереди, а потом только строковый параметр, но я не уточнял это в условии, так что не обращаем на это внимание.

4. Справочник профилей

На самом деле это справочник, в котором просто собираются разные роли, по типу такого же справочника в типовых, на БСП. Однако этот справочник более ничего не делает. Он позволяет только делать анализ.

Если конфигурация написана на БСП, то в этом случае можно скопировать профили из текущей конфигурации сюда, для этого есть специальная кнопка:

Профили доступа

И давайте откроем любой профиль:

Профиль доступа

(нажмите, чтобы увеличить картинку)

Тут видно, что есть галочки разных вариантов, простая галочка говорит, что доступ к этому праву этого объекта дает ТОЛЬКО ОДНА роль. Что по-хорошему и должно быть.

В случае галочки в черном квадрате — это значит, что несколько ролей дают доступ, причем, как видите, ниже пишется сам RLS, который ограничивает чтение. Однако обратите внимание на то, что роль перечеркнута — это значит, что одна из ролей, которая дает доступ к этому объекту по этому праву, не имеет RLS, то есть в этом профиле не будет действовать ограничение по этому регистру на чтение.

Также справа подсвечиваются зеленым цветом те роли, которые, собственно, и дают это самое право.

Еще несколько особенностей этого отчета

Профиль доступа

(нажмите, чтобы увеличить картинку)

Вот так отчет выглядит в целом, желтый цвет означает, что в группе есть объекты, которым дано право, и те объекты, которым оно не дано.

Профиль доступа

(нажмите, чтобы увеличить картинку)

Галочки в таблице ролей говорят о том, что данная роль будет скрыта из отчета, то есть всегда можно «не отходя от кассы» скрыть не нужные роли и посмотреть — а что же будет в итоге.

Профиль доступа

(нажмите, чтобы увеличить картинку)

Для того чтобы пользователь не ошибся, отчет у него по тем ролям, что справа, или он забыл обновить его, при любом изменении правой таблицы — отчет переводится в черно-белый режим. Не помню, где это подсмотрели, но идея зачетная :)

Профиль доступа

(нажмите, чтобы увеличить картинку)

Так как ролей в профиле может быть реально много, то вверху есть галочка — «Показывать все роли», если ее снять, то справа остаются только те роли, которые дают конкретное право на конкретный объект.

5. Отчет по правам доступа

Однако очень часто возникает задача узнать, какие роли дают право доступа к конкретному объекту и с какими ограничениями.

Например, прилетела задача — нам надо сделать пользователю роль, где он сможет читать возвраты клиентов с отбором по подразделению. Возникает вопрос: а есть ли вообще такая роль?

Значит, идем и формируем отчет:

Анализ доступов к объектам

(нажмите, чтобы увеличить картинку)

Указывает часть пути к объекту, который нас интересует, это может быть любая часть из примера строки:

InformationRegister.ОчередьСообщенийИСМП.StandardAttribute.Active

То есть идет поиск по вхождению, и если стоит отдельное право на разрешение или запрет чтения реквизита, то и по реквизитам тоже поиск может делать.

Далее можем указать подтип объекта, это имеет смысл делать, если нас интересуют права на реквизиты, табличные части и т.д.

После этого можем указать тип объекта — документ, справочник и т.д.

И в завершение можем указать само право. Что мы и сделаем, так как вывелось сильно много информации.

Тогда отчет будет выглядеть вот так:

Анализ доступов к объектам

(нажмите, чтобы увеличить картинку)

Тут сразу видно, какие роли дают доступ к документу, в каких профилях они находятся и какие RLS их ограничивают.

То есть сразу понятно что к чему.

И мы сразу видим, что роль, которая нас интересует — это роли ДобавлениеИзменениеВозвратовТоваровОтКлиентов или ЧтениеВозвратовТоваровОтКлиентов.

Вывод картинок в отчете

Начиная с некой версии 1С, вроде 8.3.14, появилась возможность нормально выводить картинки в отчет, а тут эта задача стояла очень остро, так как без картинок ничего не понятно, а картинки выводит по старому (ну там через парсинг макета и т.д.) — задача была обречена на провал, так как их тут тонна.

В итоге получилось сделать весьма элегантно:

В самом отчете прописаны были вот такие вычисляемые поля:

Вычисляемые поля в отчете

(нажмите, чтобы увеличить картинку)

Тут надо обратить внимание на оформление и на тип значение. Модуль, как видно из названия — повторного использования, и там находится вот такой код:

Function RightPictureByRef(RefData) Export
	If ValueIsFilled(RefData) Then
		Name = MetaNameByRef(RefData);
		Return New ValueStorage(PictureLib["Roles_right_" + Name].GetBinaryData());
	Else
		Return New ValueStorage(New Picture);
	EndIf;
EndFunction

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

В самом отчете это выглядит вот так:

Отчет

(нажмите, чтобы увеличить картинку)

И это все позволяет еще вывести вот такую красивую легенду:

Отчет

(нажмите, чтобы увеличить картинку)

Так что — на забывайте про эти механизмы.

6. Анализ и дебаг RLS

Все было бы скучно, если бы мы ограничились только просмотром. А что, если нам поставили задачу и сказали — сделайте ограничение, чтобы некий пользователь мог видеть только заказы вне статуса Закрыт. То есть все не закрытые заказы. Это на самом деле становится нередкой задачей в связи с мобильным клиентом, когда надо максимум всего скрыть в угоду производительности.

И тут у нас два пути: первый, если мы говорим про БСП, то все сделать стандартами ограничения БСП, где прописать параметр ограничения, сделать запуск обновления и кучу всяких других действий, а можем пойти просто скопировать роль, и просто дописать в ней условие.

По такому же принципу, как и ранее, мы находим нужную нам роль, это будет роль — ДобавлениеИзменениеЗаказовКлиентов.

Копирую роль в справочнике ролей и пишу другое название, например — ДобавлениеИзменениеЗаказовКлиентовСЧтениемПоСтатусу, и не забываю переименовать на вкладке наименований, а то иначе у меня будет две роли с один и тем же синонимом.

Идем в матрицу ролей, находим нужное место и видим RLS:

Роли доступа (создание)

(нажмите, чтобы увеличить картинку)

Нам надо дописать условие, и если мы четко знаем как это сделать, то можем это написать прямо тут. Однако я не помню, где и как это прописывать. Допустим, я хочу задать вот такой вот код:

#Если &ОграничениеДоступаНаУровнеЗаписейУниверсально #Тогда
#ДляОбъекта("")
#Иначе
#ПоЗначениям( "Документ.ЗаказКлиента","Чтение","",
"Организации","Организация",
"Склады","Склад",
"ГруппыПартнеров","Партнер",
"Подразделения","Подразделение", 
"НЕ Статус = ПредопределенноеЗначение("Перечисление.СтатусыЗаказовКлиентов.Закрыт")","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","" )
#КонецЕсли

Итого — дописали вот такую строку:

НЕ Статус = ПредопределенноеЗначение("Перечисление.СтатусыЗаказовКлиентов.Закрыт")

Однако как проверить, правильно ли я написал?

Для этого открываем этот RLS по кнопочке «Открыть», прям в этом поле и видим вот такую картинку:

Конвертировать шаблон

(нажмите, чтобы увеличить картинку)

Тут все просто:

1. Имя текущей таблицы — по умолчанию, это имя текущего объекта

2. Имя доступа — берется из матрицы, обычно это Чтение, Изменение, Удаление, Добавление.

3. Поговорим позже. Отвечает за ситуацию, когда вы используете в RLS параметры сеанса, но они должны быть не теми, которые сейчас.

4. Сам текст RLS

5. Шаблоны, которые привязаны к текущей роли

6. После  нажатия кнопки «Конвертировать в запрос» вы получаете результирующий код запроса. И обратите внимание — 1С внизу мне вывело текст ошибки, это значит, что можно уже не перезаходить в базу под кем-то, ибо работать все равно не будет.

7 — 10 — используются для формирования запроса. Обычно в 7 пишут что типа:

Т ГДЕ

А в 8:

Выбрать Т.Ссылка Из Документ.ЗаказКлиента Как Т ГДЕ

То есть мы формируем валидный запрос.

11. Выводится результат запроса.

Исправляем ошибку:

#Если &ОграничениеДоступаНаУровнеЗаписейУниверсально #Тогда
#ДляОбъекта("")
#Иначе
#ПоЗначениям( "Документ.ЗаказКлиента","Чтение","",
"Организации","Организация",
"Склады","Склад",
"ГруппыПартнеров","Партнер",
"Подразделения","Подразделение", 
"","НЕ Статус = ПредопределенноеЗначение(Перечисление.СтатусыЗаказовКлиентов.Закрыт)", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","" )
#КонецЕсли

То есть перенесем во второй параметр условие и уберем кавычки, так как в запросе они не нужны.

Теперь программа вернет «нормальный» текст запроса:

Текст запроса

(нажмите, чтобы увеличить картинку)

Пробую выполнить и получаю ошибку, естественно. То есть система не позволит допустить даже такие ошибки. Исправляю ошибку, меняю «ПредопределенноеЗначение«, на просто «Значение«, нажимаю «Конструктор запросов» и выравниваю запрос, и сразу могу его выполнить.

Однако, если его выполнить, то БСП вернет пустой список, так как у пользователя Администратор нет никаких настроек в БСП.

Для исправления этой ситуации переходим на вкладку Параметры сеанса, и устанавливаем параметр АвторизованныйПользователь в значение тестируемого пользователя, в моем случае это — Гладилина Вера Михайловна, менеджер. Далее необходимо поставить галочку «Использовать параметры сессий из таблицы» и теперь можно выполнить запрос:

Отладка

(нажмите, чтобы увеличить картинку)

Дебаг и конвертация RLS в BSL

Однако ситуации бывают много сложнее, иногда не понятно, почему то или иное условие не выполнилось. И чтобы разобраться с этим, можно перейти на вкладку отладки:

Вкладка отладки

(нажмите, чтобы увеличить картинку)

Тут идет развертывание всего цикла выполнения запроса. То есть:

  1. Условие, которое проверяется
  2. Текст условия проверки
  3. Результат — условие выполнилось или нет
  4. Код, который будет взят, если условие выполнилось
  5. Статус выполнения. Он показывает, что именно этот код будет взят, например, у нас может быть 5-е условие ЕслиИначе. Результат может показать, что все 5 были выполнены, но в итоговый результат попадет только то, где стоит флаг статус.
  6. Если будет ошибка, то она попадет сюда.
  7. Расшифровка поля 2.
  8. Расшифровка поля 4.

Однако возникает ситуация, когда и с этим кодом разобраться не реально, так как 6000 строк анализировать таким путем — задача не тривиальная.

Своего отладчика у RLS нет, но что если мы просто конвертнем код RLS в код BSL, к которому мы привыкли, и таким образом просто обычным отладчиком все проверим?

Тогда идем на вкладку BSL код и видим пару кнопок:

Вкладка BSL

(нажмите, чтобы увеличить картинку)

  1. Конвертирует RLS в BSL код, который можно выполнить прямо тут.
  2. Выполнение кода BSL
  3. Конвертирует во внешний код, который можно вставить во внешнюю обработку.
  4. Собственно сам BSL
  5. Результат выполнения BSL.

Ну и, конечно, при анализе больших RLS нередко возникает необходимость использования шаблонов, и шаблонов может использоваться 2, 3, 5 и более. В таком случае вам поможет вкладка RLS просмотр, которая вернет результирующий RLS, со всеми шаблонами и т.д.

Вкладка BSL

(нажмите, чтобы увеличить картинку)

7. Создание новых ролей в конфигурации

Окей, роль мы создали, надо теперь ее проверить в действии, но у нас же в конфигурации роли такой нету.

Для начала нам надо немного обновить эту роль, а именно — всем объектам, входящим в нее, дать право на просмотр/редактирование стандартных реквизитов, по умолчанию — расширение их не ставит.

То же самое касается отдельных реквизитов, если вы хотите в какой-то роли запретить явно работать с неким реквизитом, то в других ролях, которые тоже расширяют этот объект, надо дать явное разрешение.

Для того, чтобы она там появилась, жмем кнопку «Обновить расширение» в меню сервиса нашей подсистемы.

Что происходит в этот момент

В этот момент генерируется расширение.

Генерация происходит в несколько этапов:

  1. Из макета Roles_TemplateDB выгружается во временную папку пустая база с расширением в ZIP архиве.
  2. Архив распаковывается, и выполняется команда, которая выгружает данные расширения в XML
  3. XML парсится, и туда добавляются новые роли, добавляются расширяемые объекты, параметры сеанса, если нужны, и куча всего другого.
  4. XML собирается обратно в cfe
  5. cfe подключается в базу.

Почему именно через тестовую базу? Все просто, это позволяет не заморачиваться на разные форматы конфигурации, которые зависят от версии платформы.

В этот момент в систему добавляется новое расширение, которое содержит в себе указанную ранее роль.

Далее дело за малым: идем в профили, убираем старую роль и даем новую, и все – можем теперь зайти под этим пользователем и убедиться, что все сработало на ура :)

8. Свои параметры сеансов

А что, если надо дать этот запрет ТОЛЬКО в том случае, когда мы заходим мод мобильным клиентом, а если под стационарным, то все должно быть видно.

В этом случае нам надо создать свой параметр сеанса и поставить отбор по нему.

Тогда создаем новый параметр:

Создаем новый параметр

Ставим галочку «Использовать код» и прописываем код установки этого параметра:

SessionParameters.AccRoles_isMobileClient = ОбщегоНазначения.ЭтоМобильныйКлиент();

Тут есть один нюанс — имя параметра имеет префикс «AccRoles_» и надо не забывать его прописывать.

Функция «ОбщегоНазначения.ЭтоМобильныйКлиент()» возвращает, мобильный клиент это или нет. По-другому тут получить не выйдет, так как сервер один и тот же у стационарной и у мобильного клиента, а установка параметров — это серверный вызов. Поэтому просто дергаем функцию из стандартной библиотеки.

Потом идем в роль и дописываем условие:

#Если &ОграничениеДоступаНаУровнеЗаписейУниверсально #Тогда
#ДляОбъекта("")
#Иначе
#ПоЗначениям( "Документ.ЗаказКлиента","Чтение","",
"Организации","Организация",
"Склады","Склад",
"ГруппыПартнеров","Партнер",
"Подразделения","Подразделение", 
"","НЕ Статус = Значение(Перечисление.СтатусыЗаказовКлиентов.Закрыт) 
     OR Not &AccRoles_isMobileClient", 
"","", "","", "","", "","", "","", "","", "","", "","", "","", "","", "","" )
#КонецЕсли

После этого — обновляем расширение и заходим под тем пользователем, и все. Теперь под тонким клиентом видны все заказы, а под мобильным — только незакрытые.

Однако можно было бы и параметры с фиксированными данными создавать, ну типа отбор по конкретной организации или списку, и задать его свой для роли:

Отбор

Таким образом — эта система позволяет настроить почти любую сложность роли, и создавать свои параметры сеансов.

9. Обычные формы и расширение…

Мы уже говорили о том, что это расширение прекрасно работает и с обычными формами? Условие только одно — совместимость на 8.3.14.

Если говорить про управляемые формы, то там уже достаточно гибкая подсистема прав доступа, а вот с обычными формами — все грустнее.

Давайте возьмем типовую УТ 10 и накатим на нее все тоже самое.

Для начала — поднимем совместимость

ВНИМАНИЕ — не делайте этого, если вы четко не понимаете последствий, и ТОЧНО не делайте это сразу на оригинальной базе, только на копии. Также надо учесть, что обновление на больших базах может занять прилично времени!

Возьмем типовую «голую» УТ 10. И первое, что надо сделать — включить режим редактирования конфигурации:

Режим редактирования конфигурации

Настроить правила поддержки

Далее — на основной ветке конфигурации щелкнуть по второй колонке два раза и выбрать второй пункт:

Настроить правила поддержки

Так как поднятие платформы включает доп. настройку в подсистемах, что на обычных формах никак не сказывается, то разрешим изменение всех подсистем:

Настроить правила поддержки

После этого — в древе конфигурации зайдем в свойства и поменяем режим совместимости, где нас и предупредят про подсистемы:

Сообщение-предупреждение

Далее жмем обновление и ждем, в ходе обновления могут появляться всякие предупреждения, о том, что имя картинки не уникально и т.д., смело жмем ДА:

Сообщение-предупреждение

Если вы попробуете сразу запустить конфигурацию, то можно увидеть вот такие ошибки, например:

{ОбщийМодуль.ИнтеграцияЕГАИСУТКлиентСерверГлобальный.Модуль(8,9)}: Процедура или функция с указанным именем уже определена (СтрНайти)
Функция <<?>>СтрНайти(Строка,
{ОбщийМодуль.ИнтеграцияЕГАИСУТКлиентСерверГлобальный.Модуль(38,9)}: Процедура или функция с указанным именем уже определена (СтрНачинаетсяС)
Функция <<?>>СтрНачинаетсяС(Строка, ПодстрокаПоиска) Экспорт

Это связано с тем, что в платформах более древних не было каких-то функций и в конфигурацию они добавлены для совместимости, поэтому надо найти модули СтроковыеФункцииКлиентСервер и ИнтеграцияЕГАИСУТКлиентСерверГлобальный, найти в них функции и удалить:

В модуле ИнтеграцияЕГАИСУТКлиентСерверГлобальный:

Функции в модуле ИнтеграцияЕГАИСУТКлиентСерверГлобальный

В модуле СтроковыеФункцииКлиентСервер:

Функции в модуле СтроковыеФункцииКлиентСервер

При обновлении этого модуля программа может ругаться, но мы не обращаем на это внимание, в разумных пределах, разумеется, ибо если удалили что-то лишнее — будет грустно, но вы же делаете это на бекапе — верно?

Теперь подключаем расширение, если не нужен английский язык, то удаляем его, если не нужен русский — то удаляем его. В случае ERP — там уже есть английский, поэтому надо просто переименовать с English, на Английский:

Теперь подключаем расширение

И не забываем пользователям дать права, по умолчанию — две роли: для Админа и для всех остальных пользователей. И у пользователя, у которого обновляем расширение, снимаем защиту от опасных действий либо отключаем профилями безопасности:

Права пользователя

Если все сделано хорошо, то тогда в Операции — Обработка, вы сможете найти обработку с названием «Роль команд для общих форм»:

Открываем ее, нажимаем «Загрузить роли из XML». Закрываем конфигуратор, если он был открыт. Выбираем тип подключения к базе и заполняем данные или указываем просто путь к папке, куда заранее были выгружены файлы XML конфигурации.

Жмем «Загрузить роли» и видим, что система подгрузила 18 ролей:

Загрузить роли

И теперь можем открыть любую роль:

Можем открыть любую роль

(нажмите, чтобы увеличить картинку)

Ну а дальше уже — можно создавать роли, копировать и модифицировать, ставить ограничения и кучу всего другого.

FAQ

Небольшой FAQ для разработчиков и тех, кому интересно.

Почему используется выгрузка DumpConfigToFiles вместо DumpConfigFiles с параметром Right?

Да, используя первый параметр — мы выгружаем всю конфигурацию, что происходит очень долго и много места может занимать, но если пользоваться вторым параметром, то тогда мы не сможем получить GUID роли, а значит — если в роли что то поменяется, то мы тогда не сможем их никак соотнести, кроме как по наименованию. Но мы предполагаем, что имя может подменяться, например, старую роль переименовали и добавили префикс, а новую назвали так, как называлась старая и т.д.

Как происходит генерация расширения с учётом кучи свойств?

Роли в расширениях работают по принципу зависимости от объектов, то есть если можно расширить форму и просто забить на реквизиты, то все будет работать, мы сможем к ним общаться из расширения и т.д. Однако в случае ролей — если дается право на таблицу, на реквизит, то тогда этот реквизит обязан быть в конфигурации.

Таким образом — нужен был механизм, который может полностью сгенерировать расширение, и для того, чтобы он работал — достаточно передать пару реквизитов, таких, как путь объекта, тип объекта и еще несколько.

У разных объектов — есть разные свойства, например, XML справочника выглядит вот так:

<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.8">
	<Catalog uuid="9c2b82fa-1adc-427f-a0d8-6eaeb2bef2b0">
		<InternalInfo>
			<xr:GeneratedType name="CatalogObject.Банки" category="Object">
				<xr:TypeId>0ad45a19-1ec2-440a-8751-9f9a658125cb</xr:TypeId>
				<xr:ValueId>21cc3b2b-46a7-4efe-8458-115eb901e246</xr:ValueId>
			</xr:GeneratedType>
			<xr:GeneratedType name="CatalogRef.Банки" category="Ref">
				<xr:TypeId>c8b51a5c-fe62-4e33-b9c9-7218f4c45a62</xr:TypeId>
				<xr:ValueId>a15ef270-ad3c-4f0f-afb0-91764ba2e0b0</xr:ValueId>
			</xr:GeneratedType>
			<xr:GeneratedType name="CatalogSelection.Банки" category="Selection">
				<xr:TypeId>2d97819f-3b3f-4aac-867b-266f85c0f85e</xr:TypeId>
				<xr:ValueId>62024f40-7fa1-43ef-81c2-f6338804f868</xr:ValueId>
			</xr:GeneratedType>
			<xr:GeneratedType name="CatalogList.Банки" category="List">
				<xr:TypeId>df1dcbc8-6545-46d9-b292-39bae1dbe780</xr:TypeId>
				<xr:ValueId>8f46be6d-0f35-4cbc-b312-cf827c3021d3</xr:ValueId>
			</xr:GeneratedType>
			<xr:GeneratedType name="CatalogManager.Банки" category="Manager">
				<xr:TypeId>50f2b315-fd0c-438c-85c1-a597c6ddeb63</xr:TypeId>
				<xr:ValueId>55db6044-a457-48c0-8daf-32450793ee00</xr:ValueId>
			</xr:GeneratedType>
		</InternalInfo>
		<Properties>
			<Name>Банки</Name>
			<Comment/>
			<ObjectBelonging>Adopted</ObjectBelonging>
		</Properties>
		<ChildObjects/>
	</Catalog>
</MetaDataObject>

То есть для него обязательно нужны теги InternalInfo, Properties, ChildObjects. Причем у каждого типа объекта они могут быть разными.

Все GUID генерируются каждый раз динамически, и платформа это нормально принимает, так как эти GUID важны, только если вы привязываетесь к объекту не только по имени, но и его ID (а мы это не используем), или если вы делаете собственные объекты в расширении, которые модифицируют структуру конфигурации, например — не расширяете справочник, а добавляете новый.

Для того, чтобы определить — какие теги у каких объектов, существует три функции:

Roles_Settings.hasOnlyProperties(RefData)
Roles_Settings.hasNoChildObjects(RefData)
Roles_Settings.hasNoInternalInfo(RefData)

В них и описано все.

Кроме этого — есть функция Roles_Settings.MetaDataObject, в которой описаны все варианты этих тегов для всех объектов, например:

	AccumulationRegister = New Structure;
	AccumulationRegister.Insert("AccumulationRegisterRecord"   , "Record"	);
	AccumulationRegister.Insert("AccumulationRegisterManager"  , "Manager"	);
	AccumulationRegister.Insert("AccumulationRegisterSelection", "Selection");
	AccumulationRegister.Insert("AccumulationRegisterList"	   , "List"     );
	AccumulationRegister.Insert("AccumulationRegisterRecordSet", "RecordSet");
	AccumulationRegister.Insert("AccumulationRegisterRecordKey", "RecordKey");
	MetaDataObject.Insert("AccumulationRegister", AccumulationRegister);

Проблемы с русским и английским скриптом

До того, как мы решили подключить это расширение к русским конфигурациям — мы бед не знали.

Однако, как только решились — начала всплывать куча головняка. В основном все это связано с тем, что на русском коде — метаданные возвращают имя типа объекта на русском, а в английском — на английском, и переводчика никакого нет, заставить вернуть на английском не реально.

И вот мы столкнулись с проблемой: как получить имена на английском? Например, что Справочник — это Catalog. Писать соответствия — можно, но это очень не хочется.

Итого, родился вот такой франкенштейн:

Function GetRefForAllLang(Name, XMLTypeRef = Undefined) Export
	If Metadata.ScriptVariant = Metadata.ObjectProperties.ScriptVariant.English Then
		Return Enums.Roles_MetadataTypes[Name];
	Else
		If XMLTypeRef = Undefined Then
			Return Undefined;
		Else
			XMLParts = StrSplit(XMLTypeRef, "<.:", False);
			TypeIndexFromEnd = 2;
			TypeName = XMLParts[XMLParts.UBound() - TypeIndexFromEnd];
			RefText = "Ref";
			TypeName = Left(TypeName, StrLen(TypeName) - StrLen(RefText));
			Return Enums.Roles_MetadataTypes[TypeName];
		EndIf;		
	EndIf;
EndFunction

в Name приходит конструкция типа Метаданные.Документы.ЗаказКлиента, и в ответ я должен получить Enums.Roles_MetadataTypes.Document, вот второй вариант, когда конфигурация на русском получает на вход еще и сериализованное в XML представление этого типа, откуда собственно все и парсится.

Однако есть другое счастье — это стандартные реквизиты, сама 1С их возвращает на русском, а если вы хотите создать расширение, то там они обязаны быть на английском, и тут мы уже вообще ничего не смогли придумать, кроме вот такого словаря:

Function TranslationList(Val TranslateString = "") Export
	Str = New Structure;
	Str.Insert("ИмяПредопределенныхДанных", "PredefinedDataName");
	Str.Insert("Код", "Code");
	Str.Insert("Наименование", "Description");
	Str.Insert("ПометкаУдаления", "DeletionMark");
	Str.Insert("Предопределенный", "Predefined");
	Str.Insert("Ссылка", "Ref");
	Str.Insert("ВидДвижения", "RecordType");
	Str.Insert("Активность", "Active");
	Str.Insert("НомерСтроки", "LineNumber");
	Str.Insert("Регистратор", "Recorder");
........
EndFunction

И таких чудес на самом деле нереально много, т.е. попытаться применить новые технологии в тех местах, где есть кириллица — то еще счастье, но и сама 1С не способствует этому. И в данном случае — на английском коде работать значительно приятнее.

Загрузка ролей из другой версии выгрузки 1С

Увы, но 1С сделана так, что если вы выгрузили конфигурацию в XML с платформы 8.3.15, и при том даже конфигурация была в режиме 8.3.14 — то вы все равно ее не загрузите в 8.3.14. Потому что в каждом файлике 1С ставит версию в главном теге:

version="2.8"

И казалось бы — ну и что? Теперь идем дальше. Мы хотим распарсить роль, чтобы ее загрузить.

Парсить ее при помощи просто пробега по XML — задача нереальная, ну ок, тогда используем XDTO фабрику, и тут нас ждет очень веселое событие.

Роли, как и прочие объекты имеют пространство имен xmlns=»http://v8.1c.ru/8.3/MDClasses», и все бы ничего, но! Но с ними ничего нельзя сделать, даже нельзя пакет создать с таким именем. То есть оно, как суслик, вроде есть, а не видно.

Так вот, если попытаться прочитать при помощи фабрики XDTO XML с таким пространством имени — 1С его распознает и попробует привести к родному типу, однако, если у вас конфигурация текущая крутится на 8.3.14, то есть версия xml 2.8, и вы хотите прочитать файлы, которые выгрузили в 8.3.15, где версия 2.9, то 1С вам скажет — неа! Атрибут версия должен быть равен 2.8. И не выше!

В этом, конечно, есть логика, поэтому оспаривать ее не будем, но нам ее надо обойти. Поэтому был придуман такой костыль:

	Try
		RightInfo = Roles_ServiceServer.DeserializeXMLUseXDTOFactory(Text);
	Except
		// Try to make lower version
		VersionIndex = StrFind(Text, "version=" + Char(34), , StrFind(Text, "Rights"));
		VersioneEndIndex = StrFind(Text, Char(34), , VersionIndex + 9) + 1;
		Version = Mid(Text, VersionIndex, VersioneEndIndex - VersionIndex);
		Text = StrReplace(Text, Version, "version=""2.8""");	
		RightInfo = Roles_ServiceServer.DeserializeXMLUseXDTOFactory(Text);
	EndTry;

Причины купить

Кому этот продукт может быть нужен?

  1. Разработчикам для анализа прав доступа, особенно в те моменты, когда принимают новых клиентов на обслуживание
  2. Внедренцам, так как теперь можно модифицировать права без программиста и не написав практически ни одной строчки кода. Если вы умеете пользоваться консолью запросов — то сможете создавать права доступа
  3. Владельцам бизнеса, с точки зрения того, что теперь права можно модифицировать, не выгоняя пользователей из базы. Иметь четкую историю того, какие права и когда менялись, и даже — кем и что именно менялось
  4. Безопасникам — так как они смогут анализировать реальные права доступа
  5. Конечным пользователям, если так можно выразиться, так как теперь не будут больше слушать фразы, что это долго, дорого, для этого надо звать программиста и т.д.

Помимо прочего — в этой подсистеме есть генерация расширений, чтение XML конфигураций, код написан на английском, и реализованы разные интересные моменты, которые можно подсмотреть для своих задач.

Достоинства

  1. Не зависит от конфигурации
  2. Работает с конфигурациями на базе БСП и без них
  3. Работает с английскими и русскими конфигурациями
  4. Работает с обычными и управляемыми формами
  5. Подключается и отключается при необходимости, то есть можно спокойно генерировать все в тестовой базе, а в рабочую переносить просто расширение с ролями
  6. Не влияет на обновления, а если пришли существенные изменения в механизме ролей — позволяет их отладить и перегенерировать роли.

Если есть вопросы по качеству кода, то мы можем предоставить информацию по результатам сценарного тестирования, покрытия кода, оценкам качества кода в sonar cube (плагинами bsl и АПК).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

 Ознакомлен с условиями Публичной оферты и Пользовательского соглашения
 Согласен на обработку персональных данных (Политика обработки ПДн)