Каталог решений - Апрельские нешутки, записанные в пятницу не 13-го (продолжение)

Апрельские нешутки, записанные в пятницу не 13-го (продолжение)

Апрельские нешутки, записанные в пятницу не 13-го (продолжение)

В наличии

Еще одна байка про незадачливого кодера:
Загадочный РЛС или почему не могут работать "ПолныеПрава"

Категория:

Описание

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

Но… По субъективным ощущениям (это которые без замеров) все стало чуть-чуть медленнее работать.

Кодер знал, что за кажущейся простотой ограничения доступа вроде

ОрганизацияВШапке("Организация")

скрывается подобный монстр-запрос:

##Если &ИспользоватьОграниченияПравДоступаНаУровнеЗаписей ##Тогда
ТекущаяТаблица ИЗ #ТекущаяТаблица КАК ТекущаяТаблица
    ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ РАЗЛИЧНЫЕ
        СоставГруппы.Ссылка КАК ГруппаПользователей
    ИЗ
        Справочник.ГруппыПользователей.ПользователиГруппы КАК СоставГруппы
    ГДЕ
        СоставГруппы.Пользователь = &ТекущийПользователь) КАК ГруппыПользователей
    ПО (&ИспользоватьОграниченияПравДоступаНаУровнеЗаписей)
ГДЕ (&ИспользоватьОграниченияПравДоступаНаУровнеЗаписей = ЛОЖЬ
            ИЛИ (НЕ 1 В
                    (ВЫБРАТЬ ПЕРВЫЕ 1
                        1 КАК ПолеОтбора
                    ИЗ
                        РегистрСведений.НазначениеВидовОбъектовДоступа КАК НазначениеВидовОбъектовДоступа
                    ГДЕ
                        НазначениеВидовОбъектовДоступа.ГруппаПользователей = ГруппыПользователей.ГруппаПользователей
                        И ВЫБОР
                            КОГДА НазначениеВидовОбъектовДоступа.ВидОбъектаДоступа = ЗНАЧЕНИЕ(Перечисление.ВидыОбъектовДоступа.Организации)
                            	И ТекущаяТаблица.#Параметр(1) ССЫЛКА Справочник.Организации
                            	И НЕ ТекущаяТаблица.#Параметр(1) = ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка)
                                ТОГДА ВЫБОР
                                        КОГДА 1 В
                                                (ВЫБРАТЬ ПЕРВЫЕ 1
                                                    1
                                                ИЗ
                                                    (ВЫБРАТЬ
                                                        1 КАК ПолеОтбора
                                                    ) КАК Оптмизация ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НастройкиПравДоступаПользователей КАК НастройкиПравДоступаПользователей
                                                        ПО
                                                            НастройкиПравДоступаПользователей.ОбъектДоступа = ТекущаяТаблица.#Параметр(1)
                                                                И НастройкиПравДоступаПользователей.ВидОбъектаДоступа = ЗНАЧЕНИЕ(Перечисление.ВидыОбъектовДоступа.Организации)
                                                                И (НастройкиПравДоступаПользователей.Пользователь = НазначениеВидовОбъектовДоступа.ГруппаПользователей
                                                                    ИЛИ НастройкиПравДоступаПользователей.Пользователь = ЗНАЧЕНИЕ(Справочник.ГруппыПользователей.ВсеПользователи)))
                                            ТОГДА ИСТИНА
                                        ИНАЧЕ ЛОЖЬ
                                        КОНЕЦ
                                        ИНАЧЕ ИСТИНА
                                    КОНЕЦ = ЛОЖЬ))
                        И НЕ ГруппыПользователей.ГруппаПользователей ЕСТЬ NULL)
##КонецЕсли

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

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

Если НЕ РольДоступна("ПолныеПрава") Тогда
	Если Константы.ИспользоватьОграниченияПравДоступаНаУровнеЗаписей.Получить() Тогда
		Запрос = Новый Запрос("ВЫБРАТЬ
		                      |	ГруппыПользователейПользователиГруппы.Ссылка
		                      |ПОМЕСТИТЬ ВТ_ГП
		                      |ИЗ
		                      |	Справочник.ГруппыПользователей.ПользователиГруппы КАК ГруппыПользователейПользователиГруппы
		                      |ГДЕ
		                      |	ГруппыПользователейПользователиГруппы.Пользователь = &Пользователь
		                      |;
		                      |
		                      |////////////////////////////////////////////////////////////////////////////////
		                      |ВЫБРАТЬ РАЗРЕШЕННЫЕ
		                      |	&Пользователь КАК Пользователь,
		                      |	НастройкиПравДоступаПользователей.ОбъектДоступа КАК Организация,
		                      |	НастройкиПравДоступаПользователей.Запись,
		                      |	НастройкиПравДоступаПользователей.Отчеты
		                      |ПОМЕСТИТЬ ВТ_Доступ
		                      |ИЗ
		                      |	РегистрСведений.НастройкиПравДоступаПользователей КАК НастройкиПравДоступаПользователей
		                      |ГДЕ
		                      |	НастройкиПравДоступаПользователей.Пользователь В
		                      |			(ВЫБРАТЬ
		                      |				ВТ_ГП.Ссылка
		                      |			ИЗ
		                      |				ВТ_ГП КАК ВТ_ГП)
		                      |		КОНЕЦ
		                      |
		                      |СГРУППИРОВАТЬ ПО
		                      |	НастройкиПравДоступаПользователей.ОбъектДоступа,
		                      |	НастройкиПравДоступаПользователей.Запись
		                      |;
		                      |
		                      |////////////////////////////////////////////////////////////////////////////////
		                      |ВЫБРАТЬ
		                      |	ВТ_Доступ.Пользователь,
		                      |	ВТ_Доступ.Организация
		                      |ИЗ
		                      |	ВТ_Доступ КАК ВТ_Доступ
		                      |;
		                      |
		                      |////////////////////////////////////////////////////////////////////////////////
		                      |ВЫБРАТЬ
		                      |	ВТ_Доступ.Пользователь,
		                      |	ВТ_Доступ.Организация
		                      |ИЗ
		                      |	ВТ_Доступ КАК ВТ_Доступ
		                      |ГДЕ
		                      |	ВТ_Доступ.Запись");
		ТекущийПользователь = ПараметрыСеанса.ТекущийПользователь;
		Запрос.УстановитьПараметр("Пользователь", ТекущийПользователь);
		МассивРезультатов = Запрос.ВыполнитьПакет();
		РезультатЗапросаЧтение = МассивРезультатов[2].Выгрузить();
		РезультатЗапросаЗапись = МассивРезультатов[3].Выгрузить();
		
		МассивОрганизацийДоступныхДляЧтения = РезультатЗапросаЧтение.ВыгрузитьКолонку("Организация");
		ПараметрыСеанса.СписокОрганизацийДоступныхДляЧтения = Новый ФиксированныйМассив(МассивОрганизацийДоступныхДляЧтения);
		МассивОрганизацийДоступныхДляЗаписи = РезультатЗапросаЗапись.ВыгрузитьКолонку("Организация");
		ПараметрыСеанса.СписокОрганизацийДоступныхДляЗаписи = Новый ФиксированныйМассив(МассивОрганизацийДоступныхДляЗаписи);		
	КонецЕсли;	
КонецЕсли; 

И монстр-запрос для чтения превратился во вполне компактный:

##Если &ИспользоватьОграниченияПравДоступаНаУровнеЗаписей ##Тогда
ТекущаяТаблица ИЗ #ТекущаяТаблица КАК ТекущаяТаблица
    ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
	1 КАК Поле1) КАК РазрешениеДоступа
    ПО (&ИспользоватьОграниченияПравДоступаНаУровнеЗаписей)
ГДЕ 
(ТекущаяТаблица.#Параметр(1) В (&СписокОрганизацийДоступныхДляЧтения) 
ИЛИ ТекущаяТаблица.#Параметр(1) = ЗНАЧЕНИЕ(Справочник.Организации.)) ##КонецЕсли

Для записи аналогично, только подставить другой параметр сеанса.

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

Наступило утро. Обычные пользователи без полных прав вошли в программу и стали работать как обычно.

Пользователи же с полными правами стали натыкаться в разных местах на непонятное сообщение: «Попытка получить неинициализированное значение параметра сеанса».

Анализ ситуации показал, что приведенный код выполнял инициализацию параметров сеанса только для неполноправных пользователей.

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

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

А зря. У пользователей с полными правами, (наверное для большей полноты прав) были добавлены еще по нескольку ролей, эти роли и пытались получить список доступных организаций через неинициализированный параметр сеанса.

Попытка снять «лишние» роли привела к отключению у полноправных пользователей некоторых возможностей. Это, в свою очередь, произошло от того, что часть из этих «лишних» ролей использовалась только в коде для включения определенного функционала (речь идет об УТ 10.3, функциональные опции еще только снятся), но поскольку роли были скопированы с типовых ролей, то и потянули за собой и шаблоны ограничений доступа, и ограничения доступа к метаданным.

Финал оптимистичный, в стиле анекдота про отца-программиста и сына: «Знаешь что, сынок! Не трогай-ка ты работающую систему!» — наборы ролей пользователей были восстановлены в прежнем состоянии, над условием «Если не РольДоступна(«ПолныеПрава»)…» появилась пара строк инициализации параметров сеанса пустыми фиксированными массивами и все продолжили спокойно работать до следущего внедрения…

has been added to your cart:
Оформление заказа