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

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

// Вызывается при обработке сообщения http://www.1c.ru/SaaS/RemoteAdministration/App/a.b.c.d}SetFullControl.
//
// Параметры:
//  ПользовательОбластиДанных - СправочникСсылка.Пользователи - пользователь 
//   принадлежность которого к группе Администраторы требуется изменить.
//  ДоступРазрешен - Булево - Истина включить пользователя в группу,
//   Ложь- исключить пользователя из группы.
//
Процедура УстановитьПринадлежностьПользователяКГруппеАдминистраторы(Знач ПользовательОбластиДанных, Знач ДоступРазрешен) Экспорт
	
	ГруппаАдминистраторы = УправлениеДоступом.ГруппаДоступаАдминистраторы();
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа");
	ЭлементБлокировки.УстановитьЗначение("Ссылка", ГруппаАдминистраторы);
	Блокировка.Заблокировать();
	
	ГруппаОбъект = ГруппаАдминистраторы.ПолучитьОбъект();
	
	СтрокаПользователь = ГруппаОбъект.Пользователи.Найти(ПользовательОбластиДанных, "Пользователь");
	
	Если ДоступРазрешен И СтрокаПользователь = Неопределено Тогда
		
		СтрокаПользователь = ГруппаОбъект.Пользователи.Добавить();
		СтрокаПользователь.Пользователь = ПользовательОбластиДанных;
		ГруппаОбъект.Записать();
		
	ИначеЕсли НЕ ДоступРазрешен И СтрокаПользователь <> Неопределено Тогда
		
		ГруппаОбъект.Пользователи.Удалить(СтрокаПользователь);
		ГруппаОбъект.Записать();
	Иначе
		УправлениеДоступом.ОбновитьРолиПользователей(ПользовательОбластиДанных);
	КонецЕсли;
	
КонецПроцедуры

#Область ОбработчикиСобытийПодсистемКонфигурации

// См. ОчередьЗаданийПереопределяемый.ПриПолученииСпискаШаблонов.
Процедура ПриПолученииСпискаШаблонов(ШаблоныЗаданий) Экспорт
	
	ШаблоныЗаданий.Добавить(Метаданные.РегламентныеЗадания.ЗаполнениеДанныхДляОграниченияДоступа.Имя);
	ШаблоныЗаданий.Добавить(Метаданные.РегламентныеЗадания.ОбновлениеДоступаНаУровнеЗаписей.Имя);
	
КонецПроцедуры

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

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

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

Процедура УстановитьПраваПользователя(Пользователь, ГруппыДоступа, ГруппыПользователей) Экспорт	
	Запрос = Новый Запрос("ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ИсключитьИзГрупп.Ссылка КАК Группа,
	|	ИсключитьИзГрупп.Ссылка.Профиль КАК Профиль,
	|	ИсключитьИзГрупп.Ссылка.Родитель КАК Родитель
	|ИЗ
	|	Справочник.ГруппыДоступа.Пользователи КАК ИсключитьИзГрупп
	|ГДЕ
	|	ИсключитьИзГрупп.Пользователь = &Пользователь
	|	И ИсключитьИзГрупп.Ссылка НЕ В (&ГруппыДоступа)
	|	И ИсключитьИзГрупп.Ссылка.Профиль НЕ В (&ГруппыДоступа)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ИсключитьИзГрупп.Ссылка КАК Группа
	|ИЗ
	|	Справочник.ГруппыПользователей.Состав КАК ИсключитьИзГрупп
	|ГДЕ
	|	ИсключитьИзГрупп.Пользователь = &Пользователь
	|	И ИсключитьИзГрупп.Ссылка НЕ В (&ГруппыПользователей)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ГруппыДоступа.Ссылка КАК Группа
	|ИЗ
	|	Справочник.ГруппыДоступа КАК ГруппыДоступа
	|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК СоставГрупп
	|		ПО СоставГрупп.Ссылка = ГруппыДоступа.Ссылка
	|		И СоставГрупп.Пользователь = &Пользователь
	|ГДЕ
	|	ГруппыДоступа.Ссылка В (&ГруппыДоступа)
	|	И СоставГрупп.Пользователь ЕСТЬ NULL
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ГруппыПользователей.Ссылка КАК Группа
	|ИЗ
	|	Справочник.ГруппыПользователей КАК ГруппыПользователей
	|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ГруппыПользователей.Состав КАК СоставГрупп
	|		ПО (ГруппыПользователей.Ссылка = СоставГрупп.Ссылка)
	|		И (СоставГрупп.Пользователь = &Пользователь)
	|ГДЕ
	|	ГруппыПользователей.Ссылка В (&ГруппыПользователей)
	|	И СоставГрупп.Пользователь ЕСТЬ NULL
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ПрофилиГруппДоступа.Ссылка КАК Профиль
	|ИЗ
	|	Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа
	|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа КАК ГруппыДоступа
	|		ПО ГруппыДоступа.Профиль = ПрофилиГруппДоступа.Ссылка
	|		И ГруппыДоступа.Родитель = &РодительПерсональныхГрупп
	|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа.Пользователи КАК СоставГрупп
	|		ПО СоставГрупп.Ссылка = ГруппыДоступа.Ссылка
	|		И СоставГрупп.Пользователь = &Пользователь
	|ГДЕ
	|	ПрофилиГруппДоступа.Ссылка В (&ГруппыДоступа)
	|	И СоставГрупп.Пользователь ЕСТЬ NULL");
	
	РодительПерсональныхГрупп = Справочники.ГруппыДоступа.РодительПерсональныхГруппДоступа(Истина);
	
	Запрос.УстановитьПараметр("Пользователь", Пользователь);
	Запрос.УстановитьПараметр("ГруппыДоступа", ГруппыДоступа);
	Запрос.УстановитьПараметр("ГруппыПользователей", ГруппыПользователей);
	Запрос.УстановитьПараметр("РодительПерсональныхГрупп", РодительПерсональныхГрупп);
	
	Результат = Запрос.ВыполнитьПакет();
	
	ГруппыДоступаИсключить = Результат[0].Выгрузить();
	ГруппыПользователейИсключить = Результат[1].Выгрузить();
	ГруппыДоступаВключить = Результат[2].Выгрузить();
	ГруппыПользователейВключить = Результат[3].Выгрузить();
	ПрофилиВключить = Результат[4].Выгрузить();
	
	Блокировка = ПодготовитьБлокировкуПоГруппамПользователя(
		ГруппыДоступаВключить, 
		ГруппыДоступаИсключить, 
		ГруппыПользователейВключить, 
		ГруппыПользователейИсключить);
	
	ДобавитьБлокировкуПоПрофилямПользователя(
		Блокировка,
		ПрофилиВключить, 
		ГруппыДоступаИсключить, 
		РодительПерсональныхГрупп);
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		
		ОбработатьВключениеИсключениеИзГрупп(Пользователь, ГруппыДоступаИсключить, ГруппыДоступаВключить, Ложь);
		
		ОбработатьВключениеИсключениеИзГрупп(
			Пользователь, ГруппыПользователейИсключить, ГруппыПользователейВключить, Истина);
			
		ОбработатьВключениеИсключениеИзПрофилей(
			Пользователь, ГруппыДоступаИсключить, ПрофилиВключить, РодительПерсональныхГрупп);
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
КонецПроцедуры

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

Процедура ОтправитьСообщениеИзмененияГруппыПользователей(ОбъектГруппы, Удаление = Ложь, ВсеИдентификаторыПользователейСервиса = Неопределено) Экспорт
	УстановитьПривилегированныйРежим(Истина);
	
	Если Не ПоддерживаетсяНастройкаПравПользователейБТС() Тогда
		Возврат;
	КонецЕсли;
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	МодульОбменСообщениями = ОбщегоНазначения.ОбщийМодуль("ОбменСообщениями");
	
	ГруппаПользователей = Новый Структура;
	ГруппаПользователей.Вставить("Zone", МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса());
	ГруппаПользователей.Вставить("Id", XMLСтрока(ОбъектГруппы.Ссылка));
	ГруппаПользователей.Вставить("Name", ОбъектГруппы.Наименование);
	ГруппаПользователей.Вставить("Comment", ОбъектГруппы.Комментарий);
	ГруппаПользователей.Вставить("DeletionMark", ОбъектГруппы.ПометкаУдаления);
	ГруппаПользователей.Вставить("Deleted", Удаление);
	ГруппаПользователей.Вставить("Parent", XMLСтрока(ОбъектГруппы.Родитель));
	ГруппаПользователей.Вставить("GroupAllUsers", ОбъектГруппы.Ссылка = Пользователи.ГруппаВсеПользователи());
	ГруппаПользователей.Вставить("Users", 
		ИдентификаторыПользователейСервиса(
			ОбъектГруппы.Состав.ВыгрузитьКолонку("Пользователь"),
			ВсеИдентификаторыПользователейСервиса));
	
	МодульОбменСообщениями.ОтправитьСообщение(
		"AccessRights/UserGroups",
		ОбщегоНазначения.ЗначениеВJSON(ГруппаПользователей),
		МодульРаботаВМоделиСервиса.КонечнаяТочкаМенеджераСервиса());
КонецПроцедуры


// Отправить сообщение изменения группы доступа.
// 
// Параметры:
//  ОбъектГруппы - СправочникСсылка.ГруппыДоступа, СправочникСсылка.ПрофилиГруппДоступа
//  Удаление - Булево
//  ВсеИдентификаторыПользователейСервиса - Неопределено, Соответствие
//
Процедура ОтправитьСообщениеИзмененияГруппыДоступа(ОбъектГруппы, Удаление = Ложь, ВсеИдентификаторыПользователейСервиса = Неопределено) Экспорт
	УстановитьПривилегированныйРежим(Истина);
	
	Если Не ПоддерживаетсяНастройкаПравПользователейБТС() Тогда
		Возврат;
	КонецЕсли;
	
	МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
	МодульОбменСообщениями = ОбщегоНазначения.ОбщийМодуль("ОбменСообщениями");
	
	ГруппаДоступа = Новый Структура;
	ГруппаДоступа.Вставить("Zone", МодульРаботаВМоделиСервиса.ЗначениеРазделителяСеанса());
	ГруппаДоступа.Вставить("Id", XMLСтрока(ОбъектГруппы.Ссылка));
	ГруппаДоступа.Вставить("Name", ОбъектГруппы.Наименование);
	ГруппаДоступа.Вставить("Parent", XMLСтрока(ОбъектГруппы.Родитель));
	ГруппаДоступа.Вставить("IsFolder", ОбъектГруппы.ЭтоГруппа);
	ГруппаДоступа.Вставить("DeletionMark", ОбъектГруппы.ПометкаУдаления);
	ГруппаДоступа.Вставить("Deleted", Удаление);
	
	УпрощенныйРежим = УправлениеДоступомСлужебный.УпрощенныйИнтерфейсНастройкиПравДоступа();
	
	Если Не ОбъектГруппы.ЭтоГруппа Тогда
	
		СписокПользователей = Новый Массив;
		СписокГруппПользователей = Новый Массив;
		Профиль = Справочники.ПрофилиГруппДоступа.ПустаяСсылка();
		РодительПерсональныхГрупп = Справочники.ГруппыДоступа.РодительПерсональныхГруппДоступа(Истина);
		
		Если УпрощенныйРежим 
			Или (РодительПерсональныхГрупп <> Неопределено И РодительПерсональныхГрупп = ОбъектГруппы.Родитель) Тогда
			Если ТипЗнч(ОбъектГруппы) = Тип("СправочникОбъект.ПрофилиГруппДоступа") Тогда
				Профиль = ОбъектГруппы.Ссылка;
			Иначе
				Профиль = ОбъектГруппы.Профиль;
			КонецЕсли;
			
			ГруппаДоступа.Id = XMLСтрока(Профиль);
			ГруппаДоступа.Parent = XMLСтрока(Справочники.ГруппыДоступа.ПустаяСсылка());
			СписокПользователей = УчастникиПоПрофилю(Профиль);			
						
		Иначе
			Профиль = ОбъектГруппы.Профиль;
			
			СсылкиПользователей = Новый Массив;
			Для Каждого Пользователь Из ОбъектГруппы.Пользователи.ВыгрузитьКолонку("Пользователь") Цикл
				
				Если ТипЗнч(Пользователь) = Тип("СправочникСсылка.Пользователи") Тогда
					СсылкиПользователей.Добавить(Пользователь);
				ИначеЕсли ТипЗнч(Пользователь) = Тип("СправочникСсылка.ГруппыПользователей") Тогда 
					СписокГруппПользователей.Добавить(XMLСтрока(Пользователь));
				КонецЕсли;
				
			КонецЦикла;
			
			СписокПользователей = 
				ИдентификаторыПользователейСервиса(СсылкиПользователей, ВсеИдентификаторыПользователейСервиса);
			
			Если СсылкиПользователей.Количество() > 0
			   И СписокПользователей.Количество() = 0
			   И Профиль = УправлениеДоступом.ПрофильАдминистратор() Тогда
				// Происходит при записи группы доступа перед записью первого администратора, группа будет отправлена позже
				Возврат;
			КонецЕсли;
		КонецЕсли;
		
		ГруппаДоступа.Вставить("Comment", ОбъектГруппы.Комментарий);		
		ГруппаДоступа.Вставить("SimplifiedMode", УпрощенныйРежим);
		ГруппаДоступа.Вставить("IsAdmin", Профиль = УправлениеДоступом.ПрофильАдминистратор());
		ГруппаДоступа.Вставить("LoginToAppAllowed", ПрофильДаетПраваНаВходВПриложение(Профиль));
		ГруппаДоступа.Вставить("Users", СписокПользователей);
		ГруппаДоступа.Вставить("UserGroups", СписокГруппПользователей);
		ГруппаДоступа.Вставить("ProfileId", XMLСтрока(Профиль));
		
		Если СписокПользователей.Количество() > 0 И ГруппаДоступа.Users.Количество() = 0 И ГруппаДоступа.IsAdmin Тогда
			// Происходит при записи группы доступа перед записью первого администратора, группа будет отправлена позже
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	МодульОбменСообщениями.ОтправитьСообщение(
		"AccessRights/AccessGroups",
		ОбщегоНазначения.ЗначениеВJSON(ГруппаДоступа),
		МодульРаботаВМоделиСервиса.КонечнаяТочкаМенеджераСервиса());
КонецПроцедуры

Процедура ОтправитьГруппыДоступаВМенеджерСервиса() Экспорт
	Если Не ПоддерживаетсяНастройкаПравПользователейБТС() Тогда
		Возврат;
	КонецЕсли;
	
	// АПК:96-выкл Объединить в данном случае требуется, чтобы выбрать уникальные записи
	Запрос = Новый Запрос("ВЫБРАТЬ
	|	ГруппыПользователей.Ссылка КАК Группа
	|ИЗ
	|	Справочник.ГруппыПользователей КАК ГруппыПользователей
	|
	|УПОРЯДОЧИТЬ ПО
	|	Группа ИЕРАРХИЯ
	|;
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ГруппыДоступаПользователи.Пользователь КАК Пользователь,
	|	ВЫРАЗИТЬ(ГруппыДоступаПользователи.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяСервиса КАК
	|		ИдентификаторПользователяСервиса
	|ИЗ
	|	Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступаПользователи
	|ГДЕ
	|	НЕ ВЫРАЗИТЬ(ГруппыДоступаПользователи.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяСервиса ЕСТЬ NULL
	|
	|ОБЪЕДИНИТЬ
	|
	|ВЫБРАТЬ
	|	ГруппыПользователейСостав.Пользователь,
	|	ВЫРАЗИТЬ(ГруппыПользователейСостав.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяСервиса
	|ИЗ
	|	Справочник.ГруппыПользователей.Состав КАК ГруппыПользователейСостав
	|ГДЕ
	|	НЕ ВЫРАЗИТЬ(ГруппыПользователейСостав.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяСервиса ЕСТЬ NULL");
	// АПК:96-вкл
	
	Запрос.Текст = Запрос.Текст + ОбщегоНазначения.РазделительПакетаЗапросов() + ТекстЗапросаВыборкиГруппДоступа();
	
	Результат = Запрос.ВыполнитьПакет();
	
	ВсеИдентификаторыПользователейСервиса = Новый Соответствие;
	
	ВыборкаИдентификаторы = Результат[1].Выбрать();
	Пока ВыборкаИдентификаторы.Следующий() Цикл
		ВсеИдентификаторыПользователейСервиса[ВыборкаИдентификаторы.Пользователь] = 
			ВыборкаИдентификаторы.ИдентификаторПользователяСервиса; 		
	КонецЦикла;
	
	УпрощенныйРежим = УправлениеДоступомСлужебный.УпрощенныйИнтерфейсНастройкиПравДоступа();
	
	ВыборкаГруппыПользователей = Результат[0].Выбрать();
	Пока ВыборкаГруппыПользователей.Следующий() Цикл
		ГруппаОбъект = ВыборкаГруппыПользователей.Группа.ПолучитьОбъект();
		//@skip-check query-in-loop
		ОтправитьСообщениеИзмененияГруппыПользователей(ГруппаОбъект, , ВсеИдентификаторыПользователейСервиса);
	КонецЦикла;
	
	ВыборкаГруппыДоступа = Результат[2].Выбрать();
	Пока ВыборкаГруппыДоступа.Следующий() Цикл
		ГруппаОбъект = ВыборкаГруппыДоступа.Группа.ПолучитьОбъект();	
		//@skip-check query-in-loop
		ОтправитьСообщениеИзмененияГруппыДоступа(ГруппаОбъект, , ВсеИдентификаторыПользователейСервиса);
	КонецЦикла;
КонецПроцедуры

Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
	Если Не ПоддерживаетсяНастройкаПравПользователейБТС() Тогда
		Возврат;
	КонецЕсли;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.11.1";
	Обработчик.Процедура = "УправлениеДоступомСлужебныйВМоделиСервиса.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.Комментарий = НСтр("ru = 'Отправляет группы доступа и группы пользователей в Менеджер сервиса.'");
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("7fce724c-8d26-49ab-805d-dd5c21ca0af5");
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "УправлениеДоступомСлужебныйВМоделиСервиса.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ЧитаемыеОбъекты = "Справочник.ГруппыДоступа,Справочник.ГруппыПользователей";
КонецПроцедуры

Процедура ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию(Параметры) Экспорт
	
	// Регистрация данных не требуется.
	Возврат;
	
КонецПроцедуры

Процедура ОбработатьДанныеДляПереходаНаНовуюВерсию(Параметры) Экспорт	
	ОтправитьГруппыДоступаВМенеджерСервисаПриПереходеНаНовуюВерсию();	
	Параметры.ОбработкаЗавершена = Истина;
КонецПроцедуры

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

	ХранилищеСистемныхНастроек.Сохранить(КлючОбъекта, КлючНастроек, Истина);
КонецПроцедуры

Процедура ПриОпределенииПоддерживаемыхВерсийПрограммныхИнтерфейсов(СтруктураПоддерживаемыхВерсий) Экспорт
	
	МассивВерсий = Новый Массив;
	МассивВерсий.Добавить("1.0.0.1");
	
	СтруктураПоддерживаемыхВерсий.Вставить(
		"SettingUpUserRightsInServiceModel",
		МассивВерсий);
	
КонецПроцедуры

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

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

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

Процедура ОбработатьВключениеИсключениеИзПрофилей(Пользователь, 
												  ГруппыДоступаИсключить,												   
												  ПрофилиВключить,
												  РодительПерсональныхГрупп)

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

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

	ЭлементБлокировки = Блокировка.Добавить("Справочник.ПрофилиГруппДоступа");
	ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Ссылка", "Профиль");
	ЭлементБлокировки.ИсточникДанных = ПрофилиДляБлокировки;
КонецПроцедуры

Функция УчастникиПоПрофилю(Профиль)
	// Блокировка по профилю накладывается ранее, при записи группы доступа
	
	Результат = Новый Массив();
	
	Запрос = Новый Запрос("ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ВЫРАЗИТЬ(ГруппыДоступа.Пользователь КАК Справочник.Пользователи).ИдентификаторПользователяСервиса КАК
	|		ИдентификаторПользователяСервиса
	|ИЗ
	|	Справочник.ГруппыДоступа.Пользователи КАК ГруппыДоступа
	|ГДЕ
	|	ГруппыДоступа.Ссылка.Профиль = &Профиль
	|	И НЕ ГруппыДоступа.Ссылка.ПометкаУдаления
	|	И ВЫРАЗИТЬ(ГруппыДоступа.Пользователь КАК Справочник.Пользователи) <> Значение(Справочник.Пользователи.ПустаяСсылка)
	|	И ТИПЗНАЧЕНИЯ(ГруппыДоступа.Пользователь) = ТИП(Справочник.Пользователи)
	|	И ВЫРАЗИТЬ(ГруппыДоступа.Пользователь КАК
	|		Справочник.Пользователи).ИдентификаторПользователяСервиса <> &ПустойИдентификатор");
	Запрос.УстановитьПараметр("Профиль", Профиль);
	Запрос.УстановитьПараметр("ПустойИдентификатор", 
		Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000"));
		
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Результат.Добавить(Строка(Выборка.ИдентификаторПользователяСервиса));
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

Функция ПодготовитьБлокировкуПоГруппамПользователя(ГруппыДоступаВключить, 
												   ГруппыДоступаИсключить, 
												   ГруппыПользователейВключить, 
												   ГруппыПользователейИсключить)
	
	ПоГруппамДоступа = ГруппыДоступаВключить.Скопировать();
	Для Каждого СтрокаГруппаДоступа Из ГруппыДоступаИсключить Цикл
		ПоГруппамДоступа.Добавить().Группа = СтрокаГруппаДоступа.Группа;
	КонецЦикла;
	
	ПоГруппамПользователей = ГруппыПользователейВключить.Скопировать();
	Для Каждого СтрокаГруппаПользователей Из ГруппыПользователейИсключить Цикл
		ПоГруппамПользователей.Добавить().Группа = СтрокаГруппаПользователей.Группа;
	КонецЦикла;

	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыДоступа");
	ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Ссылка", "Группа");
	ЭлементБлокировки.ИсточникДанных = ПоГруппамДоступа;
		
	ЭлементБлокировки = Блокировка.Добавить("Справочник.ГруппыПользователей");
	ЭлементБлокировки.ИспользоватьИзИсточникаДанных("Ссылка", "Группа");
	ЭлементБлокировки.ИсточникДанных = ПоГруппамПользователей;
	
	Возврат Блокировка;
КонецФункции

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

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

Функция ИдентификаторыПользователейСервиса(ПользователиГруппы, ВсеИдентификаторыПользователейСервиса = Неопределено)
	Результат = Новый Массив;
	ПустойИдентификатор = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000");
	
	Если ВсеИдентификаторыПользователейСервиса = Неопределено Тогда
		
		Запрос = Новый Запрос("ВЫБРАТЬ
		|	Пользователи.ИдентификаторПользователяСервиса КАК ИдентификаторПользователяСервиса
		|ИЗ
		|	Справочник.Пользователи КАК Пользователи
		|ГДЕ 
		|	Ссылка В (&ПользователиГруппы)
		|	И Пользователи.ИдентификаторПользователяСервиса <> &ПустойИдентификатор");
		Запрос.УстановитьПараметр("ПользователиГруппы", ПользователиГруппы);
		Запрос.УстановитьПараметр("ПустойИдентификатор", ПустойИдентификатор);
		
		ТаблицаПользователей = Запрос.Выполнить().Выгрузить();
		Для Каждого ТекСтрока Из ТаблицаПользователей Цикл
			Результат.Добавить(Строка(ТекСтрока.ИдентификаторПользователяСервиса));
		КонецЦикла;
		
	Иначе
		
		Для Каждого ПользовательГруппы Из ПользователиГруппы Цикл
			ИдентификаторПользователя = ВсеИдентификаторыПользователейСервиса.Получить(ПользовательГруппы);
			Если ИдентификаторПользователя = Неопределено Или ИдентификаторПользователя = ПустойИдентификатор Тогда
				Продолжить;
			КонецЕсли;
			
			Результат.Добавить(Строка(ИдентификаторПользователя));
		КонецЦикла;
		
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

Функция ПрофильДаетПраваНаВходВПриложение(Профиль)

	БазовыеРоли = Новый Массив;
	БазовыеРоли.Добавить(ОбщегоНазначения.ИдентификаторОбъектаМетаданных(
		Метаданные.Роли.БазовыеПраваБСП.ПолноеИмя()));
	БазовыеРоли.Добавить(ОбщегоНазначения.ИдентификаторОбъектаМетаданных(
		Метаданные.Роли.БазовыеПраваВнешнихПользователейБСП.ПолноеИмя()));
	
	РолиДающиеПравоЗапуска = Новый Массив;
	РолиДающиеПравоЗапуска.Добавить(ОбщегоНазначения.ИдентификаторОбъектаМетаданных(
		Метаданные.Роли.ЗапускТонкогоКлиента.ПолноеИмя()));
	РолиДающиеПравоЗапуска.Добавить(ОбщегоНазначения.ИдентификаторОбъектаМетаданных(
		Метаданные.Роли.ЗапускВебКлиента.ПолноеИмя()));
	РолиДающиеПравоЗапуска.Добавить(ОбщегоНазначения.ИдентификаторОбъектаМетаданных(
		Метаданные.Роли.ЗапускМобильногоКлиента.ПолноеИмя()));
	РолиДающиеПравоЗапуска.Добавить(ОбщегоНазначения.ИдентификаторОбъектаМетаданных(
		Метаданные.Роли.ЗапускТолстогоКлиента.ПолноеИмя()));
		
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("РолиДающиеПравоЗапуска", РолиДающиеПравоЗапуска);
	Запрос.УстановитьПараметр("БазовыеРоли", БазовыеРоли);
	Запрос.УстановитьПараметр("Профиль", Профиль);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Подзапрос.Профиль КАК Профиль
	|ИЗ
	|	(ВЫБРАТЬ РАЗЛИЧНЫЕ
	|		РолиПрофилей.Ссылка КАК Профиль
	|	ИЗ
	|		Справочник.ПрофилиГруппДоступа.Роли КАК РолиПрофилей
	|	ГДЕ
	|		РолиПрофилей.Ссылка = &Профиль
	|		И РолиПрофилей.Роль В (&РолиДающиеПравоЗапуска)
	|
	|	ОБЪЕДИНИТЬ ВСЕ
	|
	|	ВЫБРАТЬ РАЗЛИЧНЫЕ
	|		РолиПрофилей.Ссылка КАК Профиль
	|	ИЗ
	|		Справочник.ПрофилиГруппДоступа.Роли КАК РолиПрофилей
	|	ГДЕ
	|		РолиПрофилей.Ссылка = &Профиль
	|		И РолиПрофилей.Роль В (&БазовыеРоли)) КАК Подзапрос
	|СГРУППИРОВАТЬ ПО
	|	Подзапрос.Профиль
	|ИМЕЮЩИЕ
	|	Количество(Подзапрос.Профиль) > 1";
	
	Возврат Не Запрос.Выполнить().Пустой();
	
КонецФункции

Функция СуществуютНеобходимыеПодсистемыБТС()
	
	Возврат ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность")
		И ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ОбменСообщениями");
			
КонецФункции

Функция ПрограммныйИнтерфейсПоддерживается(
	ПоддерживаемыеВерсии, ИмяИнтерфейса, ВерсияИнтерфейса = Неопределено)
	
	ВерсииИнтерфейса = Неопределено;
	
	Если Не ПоддерживаемыеВерсии.Свойство(ИмяИнтерфейса, ВерсииИнтерфейса)
		Или Не ЗначениеЗаполнено(ВерсииИнтерфейса) Тогда
		
		Возврат Ложь;
		
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ВерсияИнтерфейса)
		И ВерсииИнтерфейса.Найти(ВерсияИнтерфейса) = Неопределено Тогда
		
		Возврат Ложь;
		
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

Функция ИмяИнтерфейсаУправлениеПравамиДоступ()
	
	Возврат "ManageAccessRights";
	
КонецФункции

Функция ИмяИнтерфейсаУдаленноеАдминистрированиеПриложений()
	
	Возврат "RemoteAdministrationApp";
	
КонецФункции

Функция ТекстЗапросаВыборкиГруппДоступа()
	Если УправлениеДоступомСлужебный.УпрощенныйИнтерфейсНастройкиПравДоступа() Тогда
		Возврат "ВЫБРАТЬ
			|	ПрофилиГруппДоступа.Ссылка КАК Группа
			|ИЗ
			|	Справочник.ПрофилиГруппДоступа КАК ПрофилиГруппДоступа
			|ГДЕ
			|	НЕ ПрофилиГруппДоступа.ЭтоГруппа";
	Иначе
		Возврат "ВЫБРАТЬ
			|	ГруппыДоступа.Ссылка КАК Группа
			|ИЗ
			|	Справочник.ГруппыДоступа КАК ГруппыДоступа
			|
			|УПОРЯДОЧИТЬ ПО
			|	Группа ИЕРАРХИЯ"
	КонецЕсли;
КонецФункции

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