Анализ прав доступа / Модуль менеджера

файл
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2024, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область ПрограммныйИнтерфейс

#Область ДляВызоваИзДругихПодсистем

// См. ВариантыОтчетовПереопределяемый.ПередДобавлениемКомандОтчетов.
Процедура ПередДобавлениемКомандОтчетов(КомандыОтчетов, Параметры, СтандартнаяОбработка) Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ВариантыОтчетов") Тогда
		Возврат;
	КонецЕсли;
	
	Если Не ПравоДоступа("Просмотр", Метаданные.Отчеты.АнализПравДоступа)
	 Или СтандартныеПодсистемыСервер.ЭтоБазоваяВерсияКонфигурации() Тогда
		Возврат;
	КонецЕсли;
	
	ЭтоПользователи = Ложь;
	ДобавитьКомандуПраваПользователей(КомандыОтчетов, Параметры, ЭтоПользователи);
	
	Если Не ЭтоПользователи И УправлениеДоступом.ПроизводительныйВариант() Тогда
		ДобавитьКомандуПраваНаЭлементДанных(КомандыОтчетов, Параметры);
	КонецЕсли;
	
	ДобавитьКомандуПраваВРазрезеЗначения(КомандыОтчетов, Параметры);
	
КонецПроцедуры

// Параметры:
//   Настройки - см. ВариантыОтчетовПереопределяемый.НастроитьВариантыОтчетов.Настройки.
//   НастройкиОтчета - см. ВариантыОтчетов.ОписаниеОтчета.
//
Процедура НастроитьВариантыОтчета(Настройки, НастройкиОтчета) Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ВариантыОтчетов") Тогда
		Возврат;
	КонецЕсли;
	
	МодульВариантыОтчетов = ОбщегоНазначения.ОбщийМодуль("ВариантыОтчетов");
	МодульВариантыОтчетов.УстановитьРежимВыводаВПанеляхОтчетов(Настройки, НастройкиОтчета, Ложь);
	НастройкиОтчета.ОпределитьНастройкиФормы = Истина;
	ПодсистемаАдминистрирования = Метаданные.Подсистемы.Найти("Администрирование");
	ПодсистемаКонтроля = ?(ПодсистемаАдминистрирования = Неопределено, Неопределено,
		ПодсистемаАдминистрирования.Подсистемы.Найти("КонтрольРаботыПользователей"));
	
	НастройкиВарианта = МодульВариантыОтчетов.ОписаниеВарианта(Настройки, НастройкиОтчета, "АнализПравДоступа");
	НастройкиВарианта.Описание = НСтр("ru = 'Показывает права пользователей на таблицы информационной базы (можно включить группировку по отчетам).'");
	Если ПодсистемаКонтроля <> Неопределено Тогда
		НастройкиВарианта.Размещение.Вставить(ПодсистемаКонтроля, "Важный");
	КонецЕсли;
	
	НастройкиВарианта = МодульВариантыОтчетов.ОписаниеВарианта(Настройки, НастройкиОтчета, "ПраваПользователейНаТаблицы");
	НастройкиВарианта.Описание = НСтр("ru = 'Показывает права пользователей на таблицы информационной базы.'");
	НастройкиВарианта.Включен = Ложь;
	
	НастройкиВарианта = МодульВариантыОтчетов.ОписаниеВарианта(Настройки, НастройкиОтчета, "ПраваПользователяНаТаблицы");
	НастройкиВарианта.Описание = НСтр("ru = 'Показывает права отдельного пользователя на разные таблицы информационной базы.'");
	НастройкиВарианта.Включен = Ложь;
	
	НастройкиВарианта = МодульВариантыОтчетов.ОписаниеВарианта(Настройки, НастройкиОтчета, "ПраваПользователейНаТаблицу");
	НастройкиВарианта.Описание = НСтр("ru = 'Показывает права разных пользователей на одну таблицу информационной базы.'");
	НастройкиВарианта.Включен = Ложь;
	
	НастройкиВарианта = МодульВариантыОтчетов.ОписаниеВарианта(Настройки, НастройкиОтчета, "ПраваПользователяНаТаблицу");
	НастройкиВарианта.Описание = НСтр("ru = 'Показывает права одного пользователя на одну таблицу информационной базы с настройками ограничений на уровне записей (RLS).'");
	НастройкиВарианта.Включен = Ложь;
	
	НастройкиВарианта = МодульВариантыОтчетов.ОписаниеВарианта(Настройки, НастройкиОтчета, "ПраваПользователяНаТаблицыОтчета");
	НастройкиВарианта.Описание = НСтр("ru = 'Показывает права отдельного пользователя на разные таблицы информационной базы, используемые в отдельном отчете.'");
	НастройкиВарианта.Включен = Ложь;
	
	НастройкиВарианта = МодульВариантыОтчетов.ОписаниеВарианта(Настройки, НастройкиОтчета, "ПраваПользователейНаТаблицыОтчета");
	НастройкиВарианта.Описание = НСтр("ru = 'Показывает права разных пользователей на разные таблицы информационной базы, используемые в отдельном отчете.'");
	НастройкиВарианта.Включен = Ложь;
	
	НастройкиВарианта = МодульВариантыОтчетов.ОписаниеВарианта(Настройки, НастройкиОтчета, "ПраваПользователяНаТаблицыОтчетов");
	НастройкиВарианта.Описание = НСтр("ru = 'Показывает права отдельного пользователя на разные таблицы информационной базы, сгруппированные по отчетам.'");
	НастройкиВарианта.Включен = Ложь;
	
	НастройкиВарианта = МодульВариантыОтчетов.ОписаниеВарианта(Настройки, НастройкиОтчета, "ПраваПользователейНаОбъект");
	НастройкиВарианта.Описание = НСтр("ru = 'Показывает рассчитанные права пользователей на объект информационной базы (документ, элемент справочника и др.).'");
	НастройкиВарианта.Включен = Ложь;
	
	НастройкиВарианта = МодульВариантыОтчетов.ОписаниеВарианта(Настройки, НастройкиОтчета, "ПраваПользователейВРазрезеРазрешенногоЗначения");
	НастройкиВарианта.Описание = НСтр("ru = 'Показывает пользователей, которым открыт доступ по выбранному значению (организация, склад и др.) к объектам информационной базы (документам, элементам справочника и др.'");
	НастройкиВарианта.Включен = Ложь;
	
КонецПроцедуры

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Скрывает всю доступность или восстанавливает исходную доступность
// указанных полей набора данных не нужных для соответствующего варианта отчета.
//
// Параметры:
//  ИмяНабораДанных - Строка - имя набора данных, как он указан в СКД.
//  ПутиКДанным - Строка - если "*" - все поля доступны.
//              - Массив из Строка - доступны только указанные поля.
//              - Соответствие из КлючИЗначение:
//                 * Ключ - Строка - имя недоступного поля.
//                 * Значение - Булево - например, Ложь.
//  ИсходнаяСхема - СхемаКомпоновкиДанных - схема, из которой получается доступность для доступных полей.
//  ТекущаяСхема  - СхемаКомпоновкиДанных - схема, в которой настраивается доступность полей.
//
Процедура СкрытьПоляДанныхКромеУказанных(ИмяНабораДанных, ПутиКДанным, ИсходнаяСхема, ТекущаяСхема) Экспорт
	
	Если ИмяНабораДанных = "*" Тогда
		ПоляДанных = ТекущаяСхема.ВычисляемыеПоля;
		ИсходныеПоляДанных = ИсходнаяСхема.ВычисляемыеПоля;
	Иначе
		ПоляДанных = ТекущаяСхема.НаборыДанных[ИмяНабораДанных].Поля;
		ИсходныеПоляДанных = ИсходнаяСхема.НаборыДанных[ИмяНабораДанных].Поля;
	КонецЕсли;
	
	Для Каждого ПолеДанных Из ПоляДанных Цикл
		Если ПутиКДанным = "*"
		 Или ТипЗнч(ПутиКДанным) = Тип("Массив")
		   И ПутиКДанным.Найти(ПолеДанных.ПутьКДанным) <> Неопределено
		 Или ТипЗнч(ПутиКДанным) = Тип("Соответствие")
		   И ПутиКДанным.Получить(ПолеДанных.ПутьКДанным) = Неопределено Тогда
			
			ИсходноеПолеДанных = ИсходныеПоляДанных.Найти(ПолеДанных.ПутьКДанным);
			Если ИсходноеПолеДанных = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			ЗаполнитьЗначенияСвойств(ПолеДанных.ОграничениеИспользования,
				ИсходноеПолеДанных.ОграничениеИспользования);
			Если ТипЗнч(ПолеДанных) <> Тип("ВычисляемоеПолеСхемыКомпоновкиДанных") Тогда
				ЗаполнитьЗначенияСвойств(ПолеДанных.ОграничениеИспользованияРеквизитов,
					ИсходноеПолеДанных.ОграничениеИспользованияРеквизитов);
			КонецЕсли;
			Продолжить;
		КонецЕсли;
		
		ПолеДанных.ОграничениеИспользования.Поле = Истина;
		ПолеДанных.ОграничениеИспользования.Условие = Истина;
		ПолеДанных.ОграничениеИспользования.Группировка = Истина;
		ПолеДанных.ОграничениеИспользования.Порядок = Истина;
		Если ТипЗнч(ПолеДанных) <> Тип("ВычисляемоеПолеСхемыКомпоновкиДанных") Тогда
			ЗаполнитьЗначенияСвойств(ПолеДанных.ОграничениеИспользованияРеквизитов,
				ПолеДанных.ОграничениеИспользования);
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура УстановитьИспользованиеГруппировки(ИмяГруппировки, Использование,
			НастройкиКД, ПользовательскиеНастройкиКД) Экспорт
	
	Элемент = НайтиЭлементГруппировкиПоИмени(НастройкиКД.Структура, ИмяГруппировки);
	Если Элемент <> Неопределено Тогда
		Настройка = ПользовательскиеНастройкиКД.Элементы.Найти(Элемент.ИдентификаторПользовательскойНастройки);
		Если Настройка = Неопределено Тогда
			Элемент.Использование = Использование;
		Иначе
			Настройка.Использование = Использование;
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Для функции ГруппировкаПоОтчетамВключена
Функция НайтиЭлементГруппировкиПоИмени(КоллекцияЭлементов, Имя)
	
	Результат = Неопределено;
	
	Для Каждого Элемент Из КоллекцияЭлементов Цикл
		Если ТипЗнч(Элемент) <> Тип("ГруппировкаКомпоновкиДанных")
		   И ТипЗнч(Элемент) <> Тип("ГруппировкаТаблицыКомпоновкиДанных")
		   И ТипЗнч(Элемент) <> Тип("ТаблицаКомпоновкиДанных") Тогда
			Продолжить;
		КонецЕсли;
		Если Элемент.Имя = Имя Тогда
			Результат = Элемент;
		ИначеЕсли ТипЗнч(Элемент) = Тип("ТаблицаКомпоновкиДанных") Тогда
			Результат = НайтиЭлементГруппировкиПоИмени(Элемент.Строки, Имя);
			Если Результат = Неопределено Тогда
				Результат = НайтиЭлементГруппировкиПоИмени(Элемент.Колонки, Имя);
			КонецЕсли;
		Иначе
			Результат = НайтиЭлементГруппировкиПоИмени(Элемент.Структура, Имя);
		КонецЕсли;
		Если Результат <> Неопределено Тогда
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Возвращаемое значение:
//  ОписаниеТипов
//
Функция ОписаниеТиповГруппИЗначенийВидовДоступа(ВсеТипы = Неопределено) Экспорт
	
	ИспользуемыеВидыДоступа = УправлениеДоступомСлужебный.ИспользуемыеВидыДоступа();
	
	Типы = Новый Массив;
	ТаблицаЗначений = УправлениеДоступомСлужебныйПовтИсп.ТипыГруппИЗначенийВидовДоступа();
	Для Каждого СтрокаТЗ Из ТаблицаЗначений Цикл
		Если ТипЗнч(СтрокаТЗ.ВидДоступа) = Тип("СправочникСсылка.Пользователи")
		 Или ТипЗнч(СтрокаТЗ.ВидДоступа) = Тип("СправочникСсылка.ВнешниеПользователи") Тогда
			Продолжить;
		КонецЕсли;
		Тип = ТипЗнч(СтрокаТЗ.ТипГруппИЗначений);
		Если ВсеТипы <> Неопределено Тогда
			ВсеТипы.Добавить(Тип);
		КонецЕсли;
		Если ИспользуемыеВидыДоступа.Получить(СтрокаТЗ.ВидДоступа) <> Неопределено Тогда
			Типы.Добавить(Тип);
		КонецЕсли;
	КонецЦикла;
	
	Типы.Добавить(Тип("СправочникСсылка.Пользователи"));
	Типы.Добавить(Тип("СправочникСсылка.ГруппыПользователей"));
	Если ВсеТипы <> Неопределено Тогда
		ВсеТипы.Добавить(Тип("СправочникСсылка.Пользователи"));
		ВсеТипы.Добавить(Тип("СправочникСсылка.ГруппыПользователей"));
	КонецЕсли;
	
	Если ВнешниеПользователи.ИспользоватьВнешнихПользователей() Тогда
		Типы.Добавить(Тип("СправочникСсылка.ВнешниеПользователи"));
		Типы.Добавить(Тип("СправочникСсылка.ГруппыВнешнихПользователей"));
		Если ВсеТипы <> Неопределено Тогда
			ВсеТипы.Добавить(Тип("СправочникСсылка.ВнешниеПользователи"));
			ВсеТипы.Добавить(Тип("СправочникСсылка.ГруппыВнешнихПользователей"));
		КонецЕсли;
	КонецЕсли;
	
	Возврат Новый ОписаниеТипов(Типы);
	
КонецФункции

// Параметры:
//  АдресДанныхРасшифровки - Строка - адрес временного хранилища данных расшифровки отчета.
//  Расшифровка - ИдентификаторРасшифровкиКомпоновкиДанных - элемент расшифровки.
//
// Возвращаемое значение:
//  Структура:
//   * ИмяПоляРасшифровки - Строка
//   * СписокПолей - Соответствие из КлючИЗначение:
//    ** Ключ - Строка
//    ** Значение - Произвольный
//   * ДоступенОтчетПраваРолей - Булево
//
Функция ПараметрыРасшифровки(АдресДанныхРасшифровки, Расшифровка) Экспорт
	
	ДанныеРасшифровки = ПолучитьИзВременногоХранилища(АдресДанныхРасшифровки); // ДанныеРасшифровкиКомпоновкиДанных
	ЭлементРасшифровки = ДанныеРасшифровки.Элементы[Расшифровка];

	СписокПолей = Новый Соответствие;
	ЗаполнитьСписокПолей(СписокПолей, ЭлементРасшифровки);
	
	ИмяПоляРасшифровки = "";
	Для Каждого ЗначениеПоля Из ЭлементРасшифровки.ПолучитьПоля() Цикл
		ИмяПоляРасшифровки = ЗначениеПоля.Поле;
		Прервать;
	КонецЦикла;
	
	Результат = Новый Структура;
	Результат.Вставить("ИмяПоляРасшифровки", ИмяПоляРасшифровки);
	Результат.Вставить("СписокПолей", СписокПолей);
	Результат.Вставить("ДоступенОтчетПраваРолей",
		ПравоДоступа("Просмотр", Метаданные.Отчеты.ПраваРолей));
	
	ПараметрФорматИмени = Новый ПараметрКомпоновкиДанных("ФорматИмени");
	ЭтоОтчетПраваРолей = ДанныеРасшифровки.Настройки.ПараметрыДанных.Элементы.Найти(ПараметрФорматИмени) <> Неопределено;
	
	ЗначениеРасшифровки = СписокПолей.Получить(ИмяПоляРасшифровки);
	ПолноеИмяОбъекта = СписокПолей.Получить("ПолноеИмяОбъекта");
	
	Если (ИмяПоляРасшифровки = "ОбъектМетаданныхЗаголовкаОтчета"
	      Или ИмяПоляРасшифровки = "ОбъектМетаданных"
	      Или ИмяПоляРасшифровки = "ОтчетЗаголовок"
	      Или ИмяПоляРасшифровки = "Отчет")
	   И ЗначениеЗаполнено(ЗначениеРасшифровки)
	 Или ЭтоОтчетПраваРолей
	   И ЗначениеЗаполнено(ПолноеИмяОбъекта)
	   И СписокПолей.Получить("ИмяРоли") = Неопределено Тогда
		
		Если ЭтоОтчетПраваРолей Тогда
			ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмяОбъекта);
		Иначе
			ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоИдентификатору(ЗначениеРасшифровки, Ложь);
		КонецЕсли;
		Если ТипЗнч(ОбъектМетаданных) = Тип("ОбъектМетаданных") Тогда
			Попытка
				НавигационнаяСсылка = ПолучитьНавигационнуюСсылку(ОбъектМетаданных);
			Исключение
				Если Метаданные.ОбщиеФормы.Содержит(ОбъектМетаданных) Тогда
					НавигационнаяСсылка = "e1cib/app/" + ОбъектМетаданных.ПолноеИмя();
				Иначе
					НавигационнаяСсылка = ""; // Навигационной ссылки может не быть.
				КонецЕсли;
			КонецПопытки;
			Если (СтрНайти(НавигационнаяСсылка, "/command/") > 0
			      Или СтрНачинаетсяС(НавигационнаяСсылка, "e1cib/list/")
			      Или СтрНачинаетсяС(НавигационнаяСсылка, "e1cib/app/"))
			   И ПравоДоступа("Просмотр", ОбъектМетаданных) Тогда
				СписокПолей.Вставить("ОбъектМетаданныхНавигационнаяСсылка", НавигационнаяСсылка);
			КонецЕсли;
			СписокПолей.Вставить("ОбъектМетаданныхПолноеИмя", ОбъектМетаданных.ПолноеИмя());
		КонецЕсли;
	КонецЕсли;
	
	Если ЭтоОтчетПраваРолей Тогда
		Возврат Результат;
	КонецЕсли;
	
	ГруппаДоступа = СписокПолей.Получить("ГруппаДоступа");
	Если Не ПравоДоступа("Просмотр", Метаданные.Справочники.ГруппыДоступа)
	 Или ЗначениеЗаполнено(ГруппаДоступа)
	   И ТипЗнч(ГруппаДоступа) = Тип("СправочникСсылка.ГруппыДоступа")
	   И Не УправлениеДоступом.ЧтениеРазрешено(ГруппаДоступа) Тогда
		
		СписокПолей.Удалить("ГруппаДоступа");
	КонецЕсли;
	
	ЗначениеДоступа = СписокПолей.Получить("ЗначениеДоступа");
	Если ТипЗнч(ЗначениеДоступа) = Тип("Строка") Тогда
		ПустыеСсылки = УправлениеДоступомСлужебный.ПустыеСсылкиЗначенийДоступа();
		НайденнаяСтрока = ПустыеСсылки.Найти(ЗначениеДоступа, "Представление");
		Если НайденнаяСтрока <> Неопределено Тогда
			СписокПолей.Вставить("ЗначениеДоступа", НайденнаяСтрока.ПустаяСсылка);
		КонецЕсли;
	КонецЕсли;
	
	МетаданныеЗначения = Метаданные.НайтиПоТипу(ТипЗнч(ЗначениеРасшифровки));
	Если МетаданныеЗначения = Неопределено
	 Или Не ПравоДоступа("Просмотр", МетаданныеЗначения)
	 Или ЗначениеЗаполнено(ЗначениеРасшифровки)
	   И Не УправлениеДоступом.ЧтениеРазрешено(ЗначениеРасшифровки) Тогда
		
		СписокПолей.Удалить(ИмяПоляРасшифровки);
		ЗначениеРасшифровки = Неопределено;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ЗначениеРасшифровки)
	   И ИмяПоляРасшифровки = "ВладелецИлиПользовательНастроек"
	   И Метаданные.ОпределяемыеТипы.ВладелецНастроекПрав.Тип.СодержитТип(ТипЗнч(ЗначениеРасшифровки))
	   И Не УправлениеДоступом.ЕстьПраво("УправлениеПравами", ЗначениеРасшифровки) Тогда
		
		СписокПолей.Удалить(ИмяПоляРасшифровки);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//   СписокПолей - Соответствие
//   ЭлементРасшифровки - ЭлементРасшифровкиКомпоновкиДанныхПоля
//                      - ЭлементРасшифровкиКомпоновкиДанныхГруппировка
//
Процедура ЗаполнитьСписокПолей(СписокПолей, ЭлементРасшифровки)
	
	Если ТипЗнч(ЭлементРасшифровки) = Тип("ЭлементРасшифровкиКомпоновкиДанныхПоля") Тогда
		Для Каждого ЗначениеПоля Из ЭлементРасшифровки.ПолучитьПоля() Цикл
			Если СписокПолей[ЗначениеПоля.Поле] = Неопределено Тогда
				СписокПолей.Вставить(ЗначениеПоля.Поле, ЗначениеПоля.Значение);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
		
	Для Каждого Родитель Из ЭлементРасшифровки.ПолучитьРодителей() Цикл
		ЗаполнитьСписокПолей(СписокПолей, Родитель);
	КонецЦикла;
	
КонецПроцедуры

// Возвращает таблицу, содержащую вид ограничений доступа
// по каждому праву объектов метаданных.
//  Если записи по праву нет, значит ограничений по праву нет.
//
// Параметры:
//  ДляВнешнихПользователей - Булево, Неопределено - когда Истина вернуть ограничения
//    для внешних пользователей, Ложь - для пользователей, Неопределено для тех и других.
//    Учитывается только для универсального ограничения.
//
//  ДобавитьЭтоАвторизованныйПользователь - Булево - добавить
//    вид доступа Пользователи или ВнешниеПользователи с признаком
//    ЭтоАвторизованныйПользователь, если для таблицы есть проверка
//    только с помощью функции ЭтоАвторизованныйПользователь.
//
//  ВсеТаблицыСОграничением - Массив из СправочникСсылка.ИдентификаторыОбъектовМетаданных
//                          - Массив из СправочникСсылка.ИдентификаторыОбъектовРасширений - возвращаемое значение.
//                              Если указан массив, тогда в него добавляются таблицы,
//                              для которых предусмотрен RLS с помощью подсистемы УправлениеДоступом.
//                          - Неопределено - не требуется.
//
// Возвращаемое значение:
//  ТаблицаЗначений:
//   * ДляВнешнихПользователей - Булево - если Ложь, тогда ограничение для пользователей,
//                                 если Истина, тогда для внешних пользователей.
//                                 Колонка присутствует только для универсального ограничения.
//   * Таблица       - СправочникСсылка.ИдентификаторыОбъектовМетаданных
//                   - СправочникСсылка.ИдентификаторыОбъектовРасширений - идентификатор таблицы.
//   * ВидДоступа    - ОпределяемыйТип.ЗначениеДоступа - пустая ссылка основного типа
//      значений вида доступа или одно из следующих значений
//        1. Перечисление.ДополнительныеЗначенияДоступа.Неопределено <Ограничение без видов доступа>.
//          В стандартном варианте это соответствует наличию одного из следующих ключевых слов
//            в одном из параметров ВидДоступа стандартного шаблона ограничения доступа
//            "Объект", "НастройкиПрав", "ПравоЧтения", "ПравоИзменения",
//            "ПравоЧтенияПоИдентификатору", "ПравоИзмененияПоИдентификатору".
//          В производительном варианте это соответствует наличию одной из следующих функций
//            в ограничение доступа объекта
//            ЧтениеОбъектаРазрешено, ИзменениеОбъектаРазрешено, ЧтениеСпискаРазрешено,
//            ИзменениеСпискаРазрешено, ЭтоАвторизованныйПользователь, ПравоДоступа, РольДоступна.
//        2. Перечисление.ДополнительныеЗначенияДоступа.ДоступРазрешен <Ограничение отключено>.
//        3. Перечисление.ДополнительныеЗначенияДоступа.ДоступЗапрещен <Доступ запрещен> (ограничение "ГДЕ ЛОЖЬ").
//   * Представление - Строка - представление вида доступа.
//   * Право         - Строка - "Чтение", "Изменение".
//   * ЭтоАвторизованныйПользователь - Булево - может быть Истина,
//      если включен параметр ДобавитьЭтоАвторизованныйПользователь.
//
Функция ВидыОграниченийПрав(ДляВнешнихПользователей = Неопределено, ДобавитьЭтоАвторизованныйПользователь = Ложь,
			ВсеТаблицыСОграничением = Неопределено) Экспорт
	
	УниверсальноеОграничение =
		УправлениеДоступомСлужебный.ОграничиватьДоступНаУровнеЗаписейУниверсально(Истина, Истина);
	
	Если Не УниверсальноеОграничение Тогда
		Кэш = УправлениеДоступомСлужебныйПовтИсп.ВидыОграниченийПравОбъектовМетаданных();
		
		Если ТекущаяДатаСеанса() < Кэш.ДатаОбновления + 60*30 Тогда
			Возврат Кэш.Таблица;
		КонецЕсли;
	КонецЕсли;
	
	ТипыЗначенийВидовДоступа =
		УправлениеДоступомСлужебныйПовтИсп.ТипыЗначенийВидовДоступаИВладельцевНастроекПрав().Получить(); // ТаблицаЗначений
	
	Запрос = Новый Запрос;
	ПостоянныеВидыОграничений = УправлениеДоступомСлужебныйПовтИсп.ПостоянныеВидыОграниченийПравОбъектовМетаданных();
	Запрос.УстановитьПараметр("ПостоянныеВидыОграничений", ПостоянныеВидыОграничений);
	
	Если УниверсальноеОграничение Тогда
		Запрос.Текст =
		"ВЫБРАТЬ
		|	ПостоянныеВидыОграничений.ДляВнешнихПользователей КАК ДляВнешнихПользователей,
		|	ПостоянныеВидыОграничений.ПолноеИмя КАК ПолноеИмя,
		|	ПостоянныеВидыОграничений.Таблица КАК Таблица,
		|	ПостоянныеВидыОграничений.Право КАК Право,
		|	ПостоянныеВидыОграничений.ВидДоступа КАК ВидДоступа,
		|	ПостоянныеВидыОграничений.ЭтоАвторизованныйПользователь КАК ЭтоАвторизованныйПользователь
		|ПОМЕСТИТЬ ПостоянныеВидыОграничений
		|ИЗ
		|	&ПостоянныеВидыОграничений КАК ПостоянныеВидыОграничений
		|ГДЕ
		|	&ОтборДляВнешнихПользователей
		|	И &ОтборЭтоАвторизованныйПользователь
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	ВидыДоступаСПредставлением.ВидДоступа КАК ВидДоступа,
		|	ВидыДоступаСПредставлением.Представление КАК Представление
		|ПОМЕСТИТЬ ВидыДоступаСПредставлением
		|ИЗ
		|	&ВидыДоступаСПредставлением КАК ВидыДоступаСПредставлением
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	ТаблицыСОтключеннымОграничением.ДляВнешнихПользователей КАК ДляВнешнихПользователей,
		|	ТаблицыСОтключеннымОграничением.ПолноеИмя КАК ПолноеИмя,
		|	ТаблицыСОтключеннымОграничением.Таблица КАК Таблица,
		|	ТаблицыСОтключеннымОграничением.Право КАК Право,
		|	ТаблицыСОтключеннымОграничением.ВидДоступа КАК ВидДоступа,
		|	ТаблицыСОтключеннымОграничением.Представление КАК Представление
		|ПОМЕСТИТЬ ТаблицыСОтключеннымОграничением
		|ИЗ
		|	&ТаблицыСОтключеннымОграничением КАК ТаблицыСОтключеннымОграничением
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ВидыОграниченийПрав.ДляВнешнихПользователей КАК ДляВнешнихПользователей,
		|	ВидыОграниченийПрав.Таблица КАК Таблица,
		|	ВидыОграниченийПрав.Право КАК Право,
		|	ВидыОграниченийПрав.ВидДоступа КАК ВидДоступа,
		|	ВидыОграниченийПрав.Представление КАК Представление,
		|	ВидыОграниченийПрав.ЭтоАвторизованныйПользователь КАК ЭтоАвторизованныйПользователь
		|ИЗ
		|	(ВЫБРАТЬ
		|		ПостоянныеВидыОграничений.ДляВнешнихПользователей КАК ДляВнешнихПользователей,
		|		ПостоянныеВидыОграничений.Таблица КАК Таблица,
		|		ВЫБОР
		|			КОГДА НЕ ТаблицыСОтключеннымОграничением.ПолноеИмя ЕСТЬ NULL
		|				ТОГДА ТаблицыСОтключеннымОграничением.Право
		|			ИНАЧЕ ПостоянныеВидыОграничений.Право
		|		КОНЕЦ КАК Право,
		|		ВЫБОР
		|			КОГДА НЕ ТаблицыСОтключеннымОграничением.ПолноеИмя ЕСТЬ NULL
		|				ТОГДА ТаблицыСОтключеннымОграничением.ВидДоступа
		|			ИНАЧЕ ПостоянныеВидыОграничений.ВидДоступа
		|		КОНЕЦ КАК ВидДоступа,
		|		ВЫБОР
		|			КОГДА НЕ ТаблицыСОтключеннымОграничением.ПолноеИмя ЕСТЬ NULL
		|				ТОГДА ТаблицыСОтключеннымОграничением.Представление
		|			ИНАЧЕ ЕСТЬNULL(ВидыДоступаСПредставлением.Представление, &ПредставлениеНеизвестногоВидаДоступа)
		|		КОНЕЦ КАК Представление,
		|		ВЫБОР
		|			КОГДА НЕ ТаблицыСОтключеннымОграничением.ПолноеИмя ЕСТЬ NULL
		|				ТОГДА ЛОЖЬ
		|			ИНАЧЕ ПостоянныеВидыОграничений.ЭтоАвторизованныйПользователь
		|		КОНЕЦ КАК ЭтоАвторизованныйПользователь
		|	ИЗ
		|		ПостоянныеВидыОграничений КАК ПостоянныеВидыОграничений
		|			ЛЕВОЕ СОЕДИНЕНИЕ ТаблицыСОтключеннымОграничением КАК ТаблицыСОтключеннымОграничением
		|			ПО (ТаблицыСОтключеннымОграничением.ДляВнешнихПользователей = ПостоянныеВидыОграничений.ДляВнешнихПользователей)
		|				И (ТаблицыСОтключеннымОграничением.ПолноеИмя = ПостоянныеВидыОграничений.ПолноеИмя)
		|				И (ТаблицыСОтключеннымОграничением.Право = ПостоянныеВидыОграничений.Право)
		|				И (ПостоянныеВидыОграничений.ЭтоАвторизованныйПользователь = ЛОЖЬ)
		|			ЛЕВОЕ СОЕДИНЕНИЕ ВидыДоступаСПредставлением КАК ВидыДоступаСПредставлением
		|			ПО (ВидыДоступаСПредставлением.ВидДоступа = ПостоянныеВидыОграничений.ВидДоступа)
		|	ГДЕ
		|		ПостоянныеВидыОграничений.ВидДоступа <> НЕОПРЕДЕЛЕНО
		|	
		|	ОБЪЕДИНИТЬ ВСЕ
		|	
		|	ВЫБРАТЬ
		|		ТаблицыСОтключеннымОграничением.ДляВнешнихПользователей,
		|		ТаблицыСОтключеннымОграничением.Таблица,
		|		ТаблицыСОтключеннымОграничением.Право,
		|		ТаблицыСОтключеннымОграничением.ВидДоступа,
		|		ТаблицыСОтключеннымОграничением.Представление,
		|		ЛОЖЬ
		|	ИЗ
		|		ТаблицыСОтключеннымОграничением КАК ТаблицыСОтключеннымОграничением
		|			ЛЕВОЕ СОЕДИНЕНИЕ ПостоянныеВидыОграничений КАК ПостоянныеВидыОграничений
		|			ПО (ПостоянныеВидыОграничений.ДляВнешнихПользователей = ТаблицыСОтключеннымОграничением.ДляВнешнихПользователей)
		|				И (ПостоянныеВидыОграничений.ПолноеИмя = ТаблицыСОтключеннымОграничением.ПолноеИмя)
		|	ГДЕ
		|		ПостоянныеВидыОграничений.ПолноеИмя ЕСТЬ NULL
		|		И ТаблицыСОтключеннымОграничением.Таблица <> НЕОПРЕДЕЛЕНО) КАК ВидыОграниченийПрав";
		
		Если ТипЗнч(ДляВнешнихПользователей) = Тип("Булево") Тогда
			Запрос.УстановитьПараметр("ДляВнешнихПользователей", ДляВнешнихПользователей);
			Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ОтборДляВнешнихПользователей",
				"ПостоянныеВидыОграничений.ДляВнешнихПользователей = &ДляВнешнихПользователей");
		Иначе
			Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ОтборДляВнешнихПользователей", "ИСТИНА");
		КонецЕсли;
		Запрос.УстановитьПараметр("ВидыДоступаСПредставлением",
			ВидыДоступаСПредставлением(ТипыЗначенийВидовДоступа, Ложь));
		Запрос.УстановитьПараметр("ПредставлениеНеизвестногоВидаДоступа",
			ПредставлениеНеизвестногоВидаДоступа());
		ТаблицыСОтключеннымОграничением = ТаблицыСОтключеннымОграничением(ДляВнешнихПользователей,
			ПостоянныеВидыОграничений);
		Запрос.УстановитьПараметр("ТаблицыСОтключеннымОграничением", ТаблицыСОтключеннымОграничением);
	Иначе
		Запрос.УстановитьПараметр("ТипыЗначенийВидовДоступа", ТипыЗначенийВидовДоступа);
		Запрос.УстановитьПараметр("ИспользуемыеВидыДоступа",
			ВидыДоступаСПредставлением(ТипыЗначенийВидовДоступа, Истина));
		// АПК:96-выкл - №434 Использование ОБЪЕДИНИТЬ допустимо, так как
		// строки не должны повторятся и результат кэшируется.
		Запрос.Текст =
		"ВЫБРАТЬ
		|	ПостоянныеВидыОграничений.Таблица КАК Таблица,
		|	ПостоянныеВидыОграничений.Право КАК Право,
		|	ПостоянныеВидыОграничений.ВидДоступа КАК ВидДоступа,
		|	ПостоянныеВидыОграничений.ТаблицаОбъекта КАК ТаблицаОбъекта,
		|	ПостоянныеВидыОграничений.ЭтоАвторизованныйПользователь КАК ЭтоАвторизованныйПользователь
		|ПОМЕСТИТЬ ПостоянныеВидыОграничений
		|ИЗ
		|	&ПостоянныеВидыОграничений КАК ПостоянныеВидыОграничений
		|ГДЕ
		|	&ОтборЭтоАвторизованныйПользователь
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	ТипыЗначенийВидовДоступа.ВидДоступа КАК ВидДоступа,
		|	ТипыЗначенийВидовДоступа.ТипЗначений КАК ТипЗначений
		|ПОМЕСТИТЬ ТипыЗначенийВидовДоступа
		|ИЗ
		|	&ТипыЗначенийВидовДоступа КАК ТипыЗначенийВидовДоступа
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	ИспользуемыеВидыДоступа.ВидДоступа КАК ВидДоступа,
		|	ИспользуемыеВидыДоступа.Представление КАК Представление
		|ПОМЕСТИТЬ ИспользуемыеВидыДоступа
		|ИЗ
		|	&ИспользуемыеВидыДоступа КАК ИспользуемыеВидыДоступа
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ПостоянныеВидыОграничений.Таблица КАК Таблица,
		|	""Чтение"" КАК Право,
		|	ТИПЗНАЧЕНИЯ(СтрокиНаборов.ЗначениеДоступа) КАК ТипЗначений
		|ПОМЕСТИТЬ ПеременныеВидыОграничений
		|ИЗ
		|	РегистрСведений.НаборыЗначенийДоступа КАК НомераНаборов
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПостоянныеВидыОграничений КАК ПостоянныеВидыОграничений
		|		ПО (ПостоянныеВидыОграничений.Право = ""Чтение"")
		|			И (ПостоянныеВидыОграничений.ВидДоступа = НЕОПРЕДЕЛЕНО)
		|			И (ТИПЗНАЧЕНИЯ(НомераНаборов.Объект) = ТИПЗНАЧЕНИЯ(ПостоянныеВидыОграничений.ТаблицаОбъекта))
		|			И (НомераНаборов.Чтение)
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаборыЗначенийДоступа КАК СтрокиНаборов
		|		ПО (СтрокиНаборов.Объект = НомераНаборов.Объект)
		|			И (СтрокиНаборов.НомерНабора = НомераНаборов.НомерНабора)
		|
		|ОБЪЕДИНИТЬ ВСЕ
		|
		|ВЫБРАТЬ РАЗЛИЧНЫЕ
		|	ПостоянныеВидыОграничений.Таблица,
		|	""Изменение"",
		|	ТИПЗНАЧЕНИЯ(СтрокиНаборов.ЗначениеДоступа)
		|ИЗ
		|	РегистрСведений.НаборыЗначенийДоступа КАК НомераНаборов
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПостоянныеВидыОграничений КАК ПостоянныеВидыОграничений
		|		ПО (ПостоянныеВидыОграничений.Право = ""Изменение"")
		|			И (ПостоянныеВидыОграничений.ВидДоступа = НЕОПРЕДЕЛЕНО)
		|			И (ТИПЗНАЧЕНИЯ(НомераНаборов.Объект) = ТИПЗНАЧЕНИЯ(ПостоянныеВидыОграничений.ТаблицаОбъекта))
		|			И (НомераНаборов.Изменение)
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.НаборыЗначенийДоступа КАК СтрокиНаборов
		|		ПО (СтрокиНаборов.Объект = НомераНаборов.Объект)
		|			И (СтрокиНаборов.НомерНабора = НомераНаборов.НомерНабора)
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	ПостоянныеВидыОграничений.Таблица КАК Таблица,
		|	ПостоянныеВидыОграничений.Право КАК Право,
		|	ПостоянныеВидыОграничений.ВидДоступа КАК ВидДоступа,
		|	ПостоянныеВидыОграничений.ЭтоАвторизованныйПользователь КАК ЭтоАвторизованныйПользователь
		|ПОМЕСТИТЬ ВсеВидыОграниченийПрав
		|ИЗ
		|	ПостоянныеВидыОграничений КАК ПостоянныеВидыОграничений
		|		ЛЕВОЕ СОЕДИНЕНИЕ ТипыЗначенийВидовДоступа КАК ТипыЗначенийВидовДоступа
		|		ПО ПостоянныеВидыОграничений.ВидДоступа = ТипыЗначенийВидовДоступа.ВидДоступа
		|ГДЕ
		|	ПостоянныеВидыОграничений.ВидДоступа <> НЕОПРЕДЕЛЕНО
		|	И (НЕ ТипыЗначенийВидовДоступа.ВидДоступа ЕСТЬ NULL
		|			ИЛИ ТИПЗНАЧЕНИЯ(ПостоянныеВидыОграничений.ВидДоступа) = ТИП(Перечисление.ДополнительныеЗначенияДоступа))
		|
		|ОБЪЕДИНИТЬ
		|
		|ВЫБРАТЬ
		|	ПеременныеВидыОграничений.Таблица,
		|	ПеременныеВидыОграничений.Право,
		|	ТипыЗначенийВидовДоступа.ВидДоступа,
		|	ЛОЖЬ
		|ИЗ
		|	ПеременныеВидыОграничений КАК ПеременныеВидыОграничений
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТипыЗначенийВидовДоступа КАК ТипыЗначенийВидовДоступа
		|		ПО (ПеременныеВидыОграничений.ТипЗначений = ТИПЗНАЧЕНИЯ(ТипыЗначенийВидовДоступа.ТипЗначений))
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	ВсеВидыОграниченийПрав.Таблица КАК Таблица,
		|	ВсеВидыОграниченийПрав.Право КАК Право,
		|	ВсеВидыОграниченийПрав.ВидДоступа КАК ВидДоступа,
		|	ВсеВидыОграниченийПрав.ЭтоАвторизованныйПользователь КАК ЭтоАвторизованныйПользователь,
		|	ЕСТЬNULL(ИспользуемыеВидыДоступа.Представление, """") КАК Представление
		|ИЗ
		|	ВсеВидыОграниченийПрав КАК ВсеВидыОграниченийПрав
		|		ЛЕВОЕ СОЕДИНЕНИЕ ИспользуемыеВидыДоступа КАК ИспользуемыеВидыДоступа
		|		ПО ВсеВидыОграниченийПрав.ВидДоступа = ИспользуемыеВидыДоступа.ВидДоступа
		|ГДЕ
		|	(НЕ ИспользуемыеВидыДоступа.ВидДоступа ЕСТЬ NULL
		|			ИЛИ ВсеВидыОграниченийПрав.ЭтоАвторизованныйПользователь)";
		// АПК:96-вкл.
	КонецЕсли;
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ОтборЭтоАвторизованныйПользователь",
		?(ДобавитьЭтоАвторизованныйПользователь, "ИСТИНА",
			"ПостоянныеВидыОграничений.ЭтоАвторизованныйПользователь = ЛОЖЬ"));
	
	Выгрузка = Запрос.Выполнить().Выгрузить();
	
	Если Не УниверсальноеОграничение Тогда
		Кэш.Таблица = Выгрузка;
		Кэш.ДатаОбновления = ТекущаяДатаСеанса();
	КонецЕсли;
	
	Если ВсеТаблицыСОграничением <> Неопределено Тогда
		ТаблицыСОграничением = ПостоянныеВидыОграничений.Скопировать(, "Таблица");
		Если УниверсальноеОграничение Тогда
			Для Каждого СтрокаТЗ Из ТаблицыСОтключеннымОграничением Цикл
				ТаблицыСОграничением.Добавить().Таблица = СтрокаТЗ.Таблица;
			КонецЦикла;
		КонецЕсли;
		ТаблицыСОграничением.Свернуть("Таблица");
		ВсеТаблицыСОграничением = ТаблицыСОграничением.ВыгрузитьКолонку("Таблица");
	КонецЕсли;
	
	Возврат Выгрузка;
	
КонецФункции

// Для функции ВидыОграниченийПрав.
Функция ВидыДоступаСПредставлением(ТипыЗначенийВидовДоступа, ТолькоИспользуемые)
	
	ВидыДоступа = ТипыЗначенийВидовДоступа.Скопировать(, "ВидДоступа");
	
	ВидыДоступа.Свернуть("ВидДоступа");
	ВидыДоступа.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(150)));
	ИспользуемыеВидыДоступа = УправлениеДоступомСлужебный.ИспользуемыеВидыДоступа();
	
	Индекс = ВидыДоступа.Количество()-1;
	Пока Индекс >= 0 Цикл
		Строка = ВидыДоступа[Индекс];
		СвойстваВидаДоступа = УправлениеДоступомСлужебный.СвойстваВидаДоступа(Строка.ВидДоступа);
		
		Если СвойстваВидаДоступа = Неопределено Тогда
			МетаданныеВладельцаНастроекПрав = Метаданные.НайтиПоТипу(ТипЗнч(Строка.ВидДоступа));
			Если МетаданныеВладельцаНастроекПрав = Неопределено Тогда
				Строка.Представление = ПредставлениеНеизвестногоВидаДоступа();
			Иначе
				Строка.Представление = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Настройки прав на %1'"),
					МетаданныеВладельцаНастроекПрав.Представление());
			КонецЕсли;
			
		ИначеЕсли Не ТолькоИспользуемые
		      Или ИспользуемыеВидыДоступа.Получить(СвойстваВидаДоступа.Ссылка) <> Неопределено Тогда
			
			Строка.Представление = УправлениеДоступомСлужебный.ПредставлениеВидаДоступа(СвойстваВидаДоступа);
		Иначе
			ВидыДоступа.Удалить(Строка);
		КонецЕсли;
		
		Индекс = Индекс - 1;
	КонецЦикла;
	
	НоваяСтрока = ВидыДоступа.Добавить();
	НоваяСтрока.ВидДоступа = Перечисления.ДополнительныеЗначенияДоступа.Неопределено;
	НоваяСтрока.Представление = ПредставлениеОграниченияБезВидовДоступа();
	
	Возврат ВидыДоступа;
	
КонецФункции

// Для функций ВидыОграниченийПрав, ВидыДоступаСПредставлением.
Функция ПредставлениеНеизвестногоВидаДоступа()
	
	Возврат НСтр("ru = 'Неизвестный вид доступа'");
	
КонецФункции

// Для функции ВидыОграниченийПрав.
Функция ТаблицыСОтключеннымОграничением(ДляВнешнихПользователей, ПостоянныеВидыОграничений)
	
	ТипыИдентификаторов = Новый Массив;
	ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	ТипыИдентификаторов.Добавить(Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений"));
	
	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("ДляВнешнихПользователей", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("ПолноеИмя",
		Метаданные.Справочники.ИдентификаторыОбъектовМетаданных.Реквизиты.ПолноеИмя.Тип);
	Результат.Колонки.Добавить("Таблица",    Новый ОписаниеТипов(ТипыИдентификаторов));
	Результат.Колонки.Добавить("Право",      Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20)));
	Результат.Колонки.Добавить("ВидДоступа", УправлениеДоступомСлужебныйПовтИсп.ОписаниеТиповЗначенийДоступаИВладельцевНастроекПрав());
	Результат.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(150)));
	
	ДействующиеПараметры = УправлениеДоступомСлужебный.ДействующиеПараметрыОграниченияДоступа(
		Неопределено, Неопределено, Ложь);
	
	Если ДляВнешнихПользователей <> Истина Тогда
		ДобавитьТаблицыСОтключеннымОграничением(Результат, ДействующиеПараметры, ПостоянныеВидыОграничений, Ложь);
	КонецЕсли;
	Если ДляВнешнихПользователей <> Ложь Тогда
		ДобавитьТаблицыСОтключеннымОграничением(Результат, ДействующиеПараметры, ПостоянныеВидыОграничений, Истина);
	КонецЕсли;
	ПолныеИмена = Результат.ВыгрузитьКолонку("ПолноеИмя");
	ИдентификаторыИмен = ОбщегоНазначения.ИдентификаторыОбъектовМетаданных(ПолныеИмена, Ложь);
	Для Каждого Строка Из Результат Цикл
		Строка.Таблица = ИдентификаторыИмен.Получить(Строка.ПолноеИмя);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Для функции ТаблицыСОтключеннымОграничением.
Процедура ДобавитьТаблицыСОтключеннымОграничением(ТаблицыСОтключеннымОграничением,
			ДействующиеПараметры, ПостоянныеВидыОграничений, ДляВнешнихПользователей)
	
	Если ДляВнешнихПользователей Тогда
		ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляВнешнихПользователей;
	Иначе
		ДополнительныйКонтекст = ДействующиеПараметры.ДополнительныйКонтекст.ДляПользователей;
	КонецЕсли;
	
	СпискиСОтключеннымОграничением       = ДополнительныйКонтекст.СпискиСОтключеннымОграничением;
	СпискиСОтключеннымОграничениемЧтения = ДополнительныйКонтекст.СпискиСОтключеннымОграничениемЧтения;
	СвойстваОграниченияСписков           = ДополнительныйКонтекст.СвойстваОграниченияСписков;
	
	Для Каждого КлючИЗначение Из СвойстваОграниченияСписков Цикл
		ПолноеИмя = КлючИЗначение.Ключ;
		Свойства = КлючИЗначение.Значение;
		ВидДоступа = Неопределено;
		Права = "Чтение,Изменение";
		
		Если Свойства.ДоступЗапрещен Тогда
			ВидДоступа    = Перечисления.ДополнительныеЗначенияДоступа.ДоступЗапрещен;
			Представление = "<" + НСтр("ru = 'Доступ запрещен'") + ">";
			
		ИначеЕсли СпискиСОтключеннымОграничением.Получить(ПолноеИмя) <> Неопределено Тогда
			ВидДоступа    = Перечисления.ДополнительныеЗначенияДоступа.ДоступРазрешен;
			Представление = "<" + НСтр("ru = 'Ограничение отключено'") + ">";
		Иначе
			Если СпискиСОтключеннымОграничениемЧтения.Получить(ПолноеИмя) <> Неопределено Тогда
				НоваяСтрока = ТаблицыСОтключеннымОграничением.Добавить();
				НоваяСтрока.ДляВнешнихПользователей = ДляВнешнихПользователей;
				НоваяСтрока.ПолноеИмя = ПолноеИмя;
				НоваяСтрока.Право = "Чтение";
				НоваяСтрока.ВидДоступа = Перечисления.ДополнительныеЗначенияДоступа.ДоступРазрешен;
				НоваяСтрока.Представление = "<" + НСтр("ru = 'Ограничение чтения отключено'") + ">";
				Права = "Изменение";
			КонецЕсли;
			Если Не ЗначениеЗаполнено(Свойства.ИспользуемыеТипыЗначенийДоступа.Получить()) Тогда
				Отбор = Новый Структура("ПолноеИмя, ДляВнешнихПользователей", ПолноеИмя, ДляВнешнихПользователей);
				Если Права = "Изменение" Тогда
					Отбор.Вставить("Право", "Изменение");
				КонецЕсли;
				Если ПостоянныеВидыОграничений.НайтиСтроки(Отбор).Количество() > 0 Тогда
					ВидДоступа    = Перечисления.ДополнительныеЗначенияДоступа.Неопределено;
					Представление = ПредставлениеОграниченияБезВидовДоступа();
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		
		Если ВидДоступа = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Для Каждого Право Из СтрРазделить(Права, ",") Цикл
			НоваяСтрока = ТаблицыСОтключеннымОграничением.Добавить();
			НоваяСтрока.ДляВнешнихПользователей = ДляВнешнихПользователей;
			НоваяСтрока.ПолноеИмя = ПолноеИмя;
			НоваяСтрока.Право = Право;
			НоваяСтрока.ВидДоступа = ВидДоступа;
			НоваяСтрока.Представление = Представление;
		КонецЦикла;
	КонецЦикла;
	
КонецПроцедуры

Функция ПредставлениеОграниченияБезВидовДоступа() Экспорт
	Возврат "<" + НСтр("ru = 'Ограничение без видов доступа'") + ">";
КонецФункции


Процедура ДобавитьКомандуПраваПользователей(КомандыОтчетов, Параметры, ЭтоПользователи)
	
	ПредставлениеВарианта = НСтр("ru = 'Права пользователей'");
	ТолькоВоВсехДействиях = Ложь;
	ВажностьВарианта = "";
	
	Если Параметры.ИмяФормы = "Справочник.Пользователи.Форма.ФормаСписка"
	 Или Параметры.ИмяФормы = "Справочник.ВнешниеПользователи.Форма.ФормаСписка" Тогда
		
		ЭтоПользователи = Истина;
		Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда
			Возврат;
		КонецЕсли;
		КлючВарианта = "ПраваПользователейНаТаблицы";
		
	ИначеЕсли Параметры.ИмяФормы = "Справочник.Пользователи.Форма.ФормаЭлемента"
	      Или Параметры.ИмяФормы = "Справочник.ВнешниеПользователи.Форма.ФормаЭлемента" Тогда
		
		ЭтоПользователи = Истина;
		Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда
			Возврат;
		КонецЕсли;
		КлючВарианта = "ПраваПользователяНаТаблицы";
		ПредставлениеВарианта = НСтр("ru = 'Права пользователя'");
	Иначе
		Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда
			КлючВарианта = "ПраваПользователяНаТаблицу";
			ПредставлениеВарианта = НСтр("ru = 'Права пользователя'");
		Иначе
			КлючВарианта = "ПраваПользователейНаТаблицу";
		КонецЕсли;
		ТолькоВоВсехДействиях = Истина;
		ВажностьВарианта = "СмТакже";
	КонецЕсли;
	
	Команда = КомандыОтчетов.Добавить();
	Команда.КлючВарианта = КлючВарианта;
	Команда.Представление = ПредставлениеВарианта;
	Команда.ТолькоВоВсехДействиях = ТолькоВоВсехДействиях;
	Команда.МножественныйВыбор = Истина;
	Команда.Важность = ВажностьВарианта;
	Команда.Менеджер = "Отчет.АнализПравДоступа";
	
КонецПроцедуры

Процедура ДобавитьКомандуПраваНаЭлементДанных(КомандыОтчетов, Параметры)
	
	ДобавитьКоманду = Истина;
	ПредставлениеВарианта = ПредставлениеВариантаПраваПользователейНаОбъект(Параметры, ДобавитьКоманду);
	
	Если Не ДобавитьКоманду Тогда
		Возврат;
	КонецЕсли;
	
	Команда = КомандыОтчетов.Добавить();
	Команда.КлючВарианта = "ПраваПользователейНаОбъект";
	Команда.Представление = ПредставлениеВарианта;
	Команда.ТолькоВоВсехДействиях = Истина;
	Команда.МножественныйВыбор = Ложь;
	Команда.Важность = "СмТакже";
	Команда.Менеджер = "Отчет.АнализПравДоступа";
	Команда.ТипПараметра = УправлениеДоступомСлужебныйПовтИсп.ТипыЭлементовДанных();
	
КонецПроцедуры

Процедура ДобавитьКомандуПраваВРазрезеЗначения(КомандыОтчетов, Параметры)
	
	Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда
		Возврат;
	КонецЕсли;
	
	ВсеТипы = Новый Массив;
	ТипИспользуемыхЗначений = ОписаниеТиповГруппИЗначенийВидовДоступа(ВсеТипы);
	
	ДобавитьКоманду = Ложь;
	Для Каждого Тип Из Параметры.ТипыИсточников Цикл
		Если ТипИспользуемыхЗначений.СодержитТип(Тип) Тогда
			ДобавитьКоманду = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Если Не ДобавитьКоманду Тогда
		Возврат;
	КонецЕсли;
	
	Команда = КомандыОтчетов.Добавить();
	Команда.КлючВарианта = "ПраваПользователейВРазрезеРазрешенногоЗначения";
	Команда.Представление = НСтр("ru = 'Права в разрезе значения'");
	Команда.ТолькоВоВсехДействиях = Истина;
	Команда.МножественныйВыбор = Ложь;
	Команда.Важность = "СмТакже";
	Команда.Менеджер = "Отчет.АнализПравДоступа";
	Команда.ТипПараметра = Новый ОписаниеТипов(ВсеТипы);
	
КонецПроцедуры

Функция ПредставлениеВариантаПраваПользователейНаОбъект(Параметры, ДобавитьКоманду)
	
	ВидОбъектаМетаданных = ВРег(СтрРазделить(Параметры.ИмяФормы, ".")[0]);
	Результат = Null;
	
	Если ВРег(ВидОбъектаМетаданных) = ВРег("ПланОбмена") Тогда
		Результат = НСтр("ru = 'Права на план обмена'");
		
	ИначеЕсли ВРег(ВидОбъектаМетаданных) = ВРег("Справочник") Тогда
		Результат = НСтр("ru = 'Права на элемент справочника'");
		
	ИначеЕсли ВРег(ВидОбъектаМетаданных) = ВРег("Документ")
	      Или ВРег(ВидОбъектаМетаданных) = ВРег("ЖурналДокументов") Тогда
		
		Результат = НСтр("ru = 'Права на документ'");
		
	ИначеЕсли ВРег(ВидОбъектаМетаданных) = ВРег("ПланВидовХарактеристик") Тогда
		Результат = НСтр("ru = 'Права на план видов характеристик'");
		
	ИначеЕсли ВРег(ВидОбъектаМетаданных) = ВРег("ПланСчетов") Тогда
		Результат = НСтр("ru = 'Права на план счетов'");
		
	ИначеЕсли ВРег(ВидОбъектаМетаданных) = ВРег("ПланВидовРасчета") Тогда
		Результат = НСтр("ru = 'Права на план видов расчета'");
		
	ИначеЕсли ВРег(ВидОбъектаМетаданных) = ВРег("РегистрСведений")
	      Или ВРег(ВидОбъектаМетаданных) = ВРег("РегистрНакопления")
	      Или ВРег(ВидОбъектаМетаданных) = ВРег("РегистрБухгалтерии")
	      Или ВРег(ВидОбъектаМетаданных) = ВРег("РегистрРасчета") Тогда
		
		Результат = НСтр("ru = 'Права на строку регистра'");
		ДобавитьКоманду = Ложь;
		
	ИначеЕсли ВРег(ВидОбъектаМетаданных) = ВРег("БизнесПроцесс") Тогда
		Результат = НСтр("ru = 'Права на бизнес-процесс'");
		
	ИначеЕсли ВРег(ВидОбъектаМетаданных) = ВРег("Задача") Тогда
		Результат = НСтр("ru = 'Права на задачу'");
	КонецЕсли;
	
	Если Результат = Null Тогда
		ДобавитьКоманду = Ложь;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

#КонецОбласти

#КонецЕсли

Связанные материалы