Загрузка данных


// Возвращает сообщения обращения с картинками в виде строк Base64 и файлами каждого сообщения.
//
// Параметры:
//  ЗапросПарам - HTTPСервисЗапрос - запрос с параметром id.
//
// Возвращаемое значение:
//  HTTPСервисОтвет - результат в существующем формате метода GetComment.
//
Функция GetComment(ЗапросПарам) Экспорт

	Попытка

		Ответ = Новый HTTPСервисОтвет(200);

		ID = ЗапросПарам.ПараметрыЗапроса.Получить("id");

		Если ID = Неопределено Тогда
			Ошибка404(Ответ, "Параметр ID не заполнен");
			ЗаписатьЛоги(404, "Параметр ID не заполнен", "getComment");
			Возврат Ответ;
		КонецЕсли;

		Запрос = Новый Запрос;
		Запрос.Текст =
		"ВЫБРАТЬ
		|	ИТ_ОбщениеПоДокументам.Обращение.Номер КАК incidentId,
		|	ИТ_ОбщениеПоДокументам.Комментарий КАК text,
		|	ИТ_ОбщениеПоДокументам.Дата КАК date,
		|	ИТ_ОбщениеПоДокументам.ВходящееПисьмо.СтруктураКартинок КАК attachments,
		|	ПРЕДСТАВЛЕНИЕССЫЛКИ(ИТ_ОбщениеПоДокументам.Установил) КАК author,
		|	ИТ_ОбщениеПоДокументам.ФорматированныйКомментарий КАК ФорматированныйКомментарий,
		|	ВЫРАЗИТЬ(ИТ_ОбщениеПоДокументам.UUID КАК СТРОКА(36)) КАК UUIDКомментария,
		|	ЕСТЬNULL(
		|		ИТ_ОбщениеПоДокументам.ВходящееПисьмо,
		|		ЗНАЧЕНИЕ(Документ.ЭлектронноеПисьмоВходящее.ПустаяСсылка)) КАК ВходящееПисьмоСообщения
		|ИЗ
		|	РегистрСведений.ИТ_ОбщениеПоДокументам КАК ИТ_ОбщениеПоДокументам
		|ГДЕ
		|	ИТ_ОбщениеПоДокументам.Обращение.Номер = &Номер
		|
		|ОБЪЕДИНИТЬ ВСЕ
		|
		|ВЫБРАТЬ
		|	ДокументЭлектронноеПисьмо.ИспользуемыйДокументНомер,
		|	ДокументЭлектронноеПисьмо.ВходящееПисьмо.Текст,
		|	ДокументЭлектронноеПисьмо.ВходящееПисьмо.Дата,
		|	ДокументЭлектронноеПисьмо.ВходящееПисьмо.СтруктураКартинок,
		|	ПРЕДСТАВЛЕНИЕССЫЛКИ(ДокументЭлектронноеПисьмо.ВходящееПисьмо.ОтправительКонтакт),
		|	NULL,
		|	ВЫРАЗИТЬ("""" КАК СТРОКА(36)),
		|	ДокументЭлектронноеПисьмо.ВходящееПисьмо
		|ИЗ
		|	(ВЫБРАТЬ ПЕРВЫЕ 1
		|		ДействияВходящихПисемПоОбращениям.ВходящееПисьмо КАК ВходящееПисьмо,
		|		ДействияВходящихПисемПоОбращениям.ИспользуемыйДокумент.Номер КАК ИспользуемыйДокументНомер
		|	ИЗ
		|		РегистрСведений.ДействияВходящихПисемПоОбращениям КАК ДействияВходящихПисемПоОбращениям
		|	ГДЕ
		|		ДействияВходящихПисемПоОбращениям.Регистрация
		|		И ДействияВходящихПисемПоОбращениям.ИспользуемыйДокумент.Номер = &Номер) КАК ДокументЭлектронноеПисьмо
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ИТ_СтруктурыДанныхПисемВходящейПочты КАК ИТ_СтруктурыДанныхПисемВходящейПочты
		|		ПО (ИТ_СтруктурыДанныхПисемВходящейПочты.ВходящееПисьмо = ДокументЭлектронноеПисьмо.ВходящееПисьмо)";

		Запрос.УстановитьПараметр("Номер", ID);

		РезультатЗапроса = Запрос.Выполнить();
		Выборка = РезультатЗапроса.Выбрать();
		Если Выборка.Количество() <> 0 Тогда
			СтруктураОбщения = Новый Структура;

			СтруктураОбщения.Вставить("incidentId", ID);
			СтруктураОбщения.Вставить("messages", Новый Массив);
			ДанныеФайловСообщений = Новый Массив;
			UUIDСообщений = Новый Массив;
			ВходящиеПисьмаСообщений = Новый Массив;
			Пока Выборка.Следующий() Цикл
				Обращение = ПолучитьОбщенияОбращения();
				ЗаполнитьЗначенияСвойств(Обращение, Выборка, , "attachments");
				ДобавитьКартинкиФорматированногоКомментария(Выборка.ФорматированныйКомментарий, Обращение.attachments);

				// Почтовое хранилище остается резервным источником для сообщений без встроенных картинок.
				Если Обращение.attachments.Количество() = 0 Тогда
					ВложениеВыборки = Выборка.attachments;
					Если ТипЗнч(ВложениеВыборки) = Тип("ХранилищеЗначения") Тогда
						Вложения = ВложениеВыборки.Получить();
					ИначеЕсли ТипЗнч(ВложениеВыборки) = Тип("Массив") Тогда
						Вложения = ВложениеВыборки;
					Иначе
						Вложения = Неопределено;
					КонецЕсли;

					Если Вложения <> Неопределено Тогда
						Для Каждого ВложениеКартинка Из Вложения Цикл
							КартинкаСтрока = ПодготовитьТекстПисьмаИСтруктуруКартинок(ВложениеКартинка.Значение);
							Если КартинкаСтрока <> "" Тогда
								Обращение.attachments.Добавить(КартинкаСтрока);
							КонецЕсли;
						КонецЦикла;
					КонецЕсли;
				КонецЕсли;

				СтруктураОбщения.messages.Добавить(Обращение);
				ДанныеФайловСообщений.Добавить(Новый Структура(
					"UUIDКомментария,ВходящееПисьмо",
					Выборка.UUIDКомментария,
					Выборка.ВходящееПисьмоСообщения));
				Если Не ПустаяСтрока(Выборка.UUIDКомментария)
					И UUIDСообщений.Найти(Выборка.UUIDКомментария) = Неопределено Тогда
					UUIDСообщений.Добавить(Выборка.UUIDКомментария);
				КонецЕсли;
				Если ЗначениеЗаполнено(Выборка.ВходящееПисьмоСообщения)
					И ВходящиеПисьмаСообщений.Найти(Выборка.ВходящееПисьмоСообщения) = Неопределено Тогда
					ВходящиеПисьмаСообщений.Добавить(Выборка.ВходящееПисьмоСообщения);
				КонецЕсли;
			КонецЦикла;

			ФайлыПоUUIDСообщений = ПолучитьФайлыПоUUIDСообщенийОбращения(UUIDСообщений);
			ФайлыПоПисьмамСообщений = ПолучитьФайлыПоПисьмамСообщенийОбращения(
				ВходящиеПисьмаСообщений);
			Для ИндексСообщения = 0 По СтруктураОбщения.messages.ВГраница() Цикл
				ДанныеФайлов = ДанныеФайловСообщений[ИндексСообщения];
				ФайлыСообщения = Новый Массив;
				UUIDДобавленныхФайлов = Новый Соответствие;
				ДобавитьФайлыСообщенияОбращения(
					ФайлыСообщения,
					UUIDДобавленныхФайлов,
					ФайлыПоUUIDСообщений.Получить(ДанныеФайлов.UUIDКомментария));
				ДобавитьФайлыСообщенияОбращения(
					ФайлыСообщения,
					UUIDДобавленныхФайлов,
					ФайлыПоПисьмамСообщений.Получить(ДанныеФайлов.ВходящееПисьмо));
				СтруктураОбщения.messages[ИндексСообщения].Вставить("Files", ФайлыСообщения);
			КонецЦикла;

			Запись = Новый ЗаписьJSON;
			Запись.УстановитьСтроку();
			ЗаписатьJSON(Запись, СтруктураОбщения);
			СтрокаОтвета = Запись.Закрыть();
			Ответ.УстановитьТелоИзСтроки(СтрокаОтвета);
			ЗаписатьЛоги(200, "Успешный запрос", "getComment");

		Иначе

			Ошибка404(Ответ, СтрШаблон("Обращение с номером %1 не найдено или не найдены сообщения в обращении", ID));
			ЗаписатьЛоги(404, СтрШаблон("Обращение с номером %1", ID), "getComment");

		КонецЕсли;

	Исключение

		Ответ = Новый HTTPСервисОтвет(200);
		Ответ.УстановитьТелоИзСтроки(ПолучитьJSONОшибка(ОписаниеОшибки()));
		ЗаписатьЛоги(200, ОписаниеОшибки(), "getComment");

	КонецПопытки;

	Возврат Ответ;

КонецФункции

// Возвращает файлы, явно связанные с сообщениями по UUID комментария.
Функция ПолучитьФайлыПоUUIDСообщенийОбращения(UUIDСообщений)

	ФайлыПоUUIDСообщений = Новый Соответствие;
	Если UUIDСообщений.Количество() = 0 Тогда
		Возврат ФайлыПоUUIDСообщений;
	КонецЕсли;

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	СвязиФайлов.ИДОбщения КАК UUIDСообщения,
	|	ПрикрепленныеФайлы.UUID КАК UUID,
	|	ПрикрепленныеФайлы.Название КАК Название
	|ИЗ
	|	РегистрСведений.ФайлыОбщенияПрикрепленныеВИтилиум КАК СвязиФайлов
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ПрикрепленныеФайлы КАК ПрикрепленныеФайлы
	|		ПО СвязиФайлов.ИДФайлаСтрокой = ПрикрепленныеФайлы.UUID
	|ГДЕ
	|	СвязиФайлов.ИДОбщения В (&UUIDСообщений)";
	Запрос.УстановитьПараметр("UUIDСообщений", UUIDСообщений);

	РезультатЗапроса = Запрос.Выполнить();
	ВыборкаФайлов = РезультатЗапроса.Выбрать();
	Пока ВыборкаФайлов.Следующий() Цикл
		ОписанияФайлов = ФайлыПоUUIDСообщений.Получить(ВыборкаФайлов.UUIDСообщения);
		Если ОписанияФайлов = Неопределено Тогда
			ОписанияФайлов = Новый Массив;
			ФайлыПоUUIDСообщений.Вставить(ВыборкаФайлов.UUIDСообщения, ОписанияФайлов);
		КонецЕсли;

		ОписанияФайлов.Добавить(Новый Структура(
			"UUID,Name",
			ВыборкаФайлов.UUID,
			ВыборкаФайлов.Название));
	КонецЦикла;

	Возврат ФайлыПоUUIDСообщений;

КонецФункции

// Возвращает файлы, явно связанные с входящими письмами сообщений.
Функция ПолучитьФайлыПоПисьмамСообщенийОбращения(ВходящиеПисьма)

	ФайлыПоПисьмамСообщений = Новый Соответствие;
	Если ВходящиеПисьма.Количество() = 0 Тогда
		Возврат ФайлыПоПисьмамСообщений;
	КонецЕсли;

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ПрикрепленныеФайлы.ЭлектронноеПисьмо КАК ВходящееПисьмо,
	|	ПрикрепленныеФайлы.UUID КАК UUID,
	|	ПрикрепленныеФайлы.Название КАК Название
	|ИЗ
	|	РегистрСведений.ПрикрепленныеФайлы КАК ПрикрепленныеФайлы
	|ГДЕ
	|	ПрикрепленныеФайлы.ЭлектронноеПисьмо В (&ВходящиеПисьма)";
	Запрос.УстановитьПараметр("ВходящиеПисьма", ВходящиеПисьма);

	РезультатЗапроса = Запрос.Выполнить();
	ВыборкаФайлов = РезультатЗапроса.Выбрать();
	Пока ВыборкаФайлов.Следующий() Цикл
		ОписанияФайлов = ФайлыПоПисьмамСообщений.Получить(ВыборкаФайлов.ВходящееПисьмо);
		Если ОписанияФайлов = Неопределено Тогда
			ОписанияФайлов = Новый Массив;
			ФайлыПоПисьмамСообщений.Вставить(ВыборкаФайлов.ВходящееПисьмо, ОписанияФайлов);
		КонецЕсли;

		ОписанияФайлов.Добавить(Новый Структура(
			"UUID,Name",
			ВыборкаФайлов.UUID,
			ВыборкаФайлов.Название));
	КонецЦикла;

	Возврат ФайлыПоПисьмамСообщений;

КонецФункции

// Добавляет описания файлов в результат без повторов одного UUID.
Процедура ДобавитьФайлыСообщенияОбращения(ФайлыСообщения, UUIDДобавленныхФайлов, ОписанияФайлов)

	Если ОписанияФайлов = Неопределено Тогда
		Возврат;
	КонецЕсли;

	Для Каждого ОписаниеФайла Из ОписанияФайлов Цикл
		Если UUIDДобавленныхФайлов.Получить(ОписаниеФайла.UUID) = Неопределено Тогда
			ФайлыСообщения.Добавить(ОписаниеФайла);
			UUIDДобавленныхФайлов.Вставить(ОписаниеФайла.UUID, Истина);
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

// Добавляет встроенные рисунки комментария; обращения к внешним URL не выполняются.
//
// Параметры:
//  ХранилищеКомментария - ХранилищеЗначения, Null - сохраненный форматированный комментарий.
//  Вложения - Массив из Строка - выходные изображения в Base64.
//
Процедура ДобавитьКартинкиФорматированногоКомментария(ХранилищеКомментария, Вложения)

	Если ТипЗнч(ХранилищеКомментария) <> Тип("ХранилищеЗначения") Тогда
		Возврат;
	КонецЕсли;

	ФорматированныйКомментарий = ХранилищеКомментария.Получить();
	Если ТипЗнч(ФорматированныйКомментарий) <> Тип("ФорматированныйДокумент") Тогда
		Возврат;
	КонецЕсли;

	Для Каждого ЭлементКомментария Из ФорматированныйКомментарий.ПолучитьЭлементы() Цикл
		Если ТипЗнч(ЭлементКомментария) <> Тип("КартинкаФорматированногоДокумента") Тогда
			Продолжить;
		КонецЕсли;

		ЗначениеКартинки = ЭлементКомментария.Картинка;
		ДанныеКартинки = Неопределено;
		Если ТипЗнч(ЗначениеКартинки) = Тип("Картинка") Тогда
			ДанныеКартинки = ЗначениеКартинки.ПолучитьДвоичныеДанные();
		ИначеЕсли ТипЗнч(ЗначениеКартинки) = Тип("Строка") Тогда
			ПозицияДанных = СтрНайти(НРег(ЗначениеКартинки), ";base64,");
			Если НРег(Лев(ЗначениеКартинки, СтрДлина("data:image/"))) = "data:image/" И ПозицияДанных > 0 Тогда
				ДанныеBase64 = Сред(ЗначениеКартинки, ПозицияДанных + СтрДлина(";base64,"));
				ДанныеBase64 = СтрЗаменить(ДанныеBase64, "_", "/");
				ДанныеBase64 = СтрЗаменить(ДанныеBase64, "-", "+");
				ДанныеBase64 = СтрЗаменить(ДанныеBase64, " ", "");
				// Base64URL может не содержать padding; платформа требует полных блоков по 4 символа.
				НедостающиеСимволы = (4 - СтрДлина(ДанныеBase64) % 4) % 4;
				ДанныеBase64 = ДанныеBase64 + Лев("===", НедостающиеСимволы);
				ДанныеКартинки = Base64Значение(ДанныеBase64);
			КонецЕсли;
		КонецЕсли;

		Если ДанныеКартинки <> Неопределено Тогда
			Если ДанныеКартинки.Размер() > 0 Тогда
				Вложения.Добавить(Base64Строка(ДанныеКартинки));
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры