Удаляет указанное сообщение из обсуждения. Вызов метода возможен только в привилегированном режиме.
Синтаксис
УдалитьСообщение(<ИдентификаторСообщения>)Полное описание, параметры и ограничения
МенеджерСистемыВзаимодействия.УдалитьСообщение (CollaborationSystemManager.DeleteMessage)
МенеджерСистемыВзаимодействия (CollaborationSystemManager)
УдалитьСообщение (DeleteMessage)
Доступен, начиная с версии 8.3.11.
Синтаксис:
УдалитьСообщение(<ИдентификаторСообщения>)
Параметры:
<ИдентификаторСообщения> (обязательный)
Тип: ИдентификаторСообщенияСистемыВзаимодействия.
Идентификатор удаляемого сообщения.
Описание:
Удаляет указанное сообщение из обсуждения.
Вызов метода возможен только в привилегированном режиме.
Доступность:
Сервер, толстый клиент, внешнее соединение.
Использование в версии:
Доступен, начиная с версии 8.3.11.
Методическая информация
Практические примеры
Настоящие свои оповещения: видимое/скрытое обсуждение, внутреннее приглашение и отдельное удаление своей карточки
Собственный получатель получает реальные оповещения двух своих обсуждений после сообщений другого своего участника. Уведомление содержит readonly real discussion ID, не создается конструктором. Внутренний URI не открывается; отдельное подтвержденное удаление выбирает только собственную скрытую карточку.
Где и как запускать
Полный серверный общий модуль УчебныеОповещения85 и полный supporting модуль управляемой формы. Новый собственный УчебныйАбонентСВ85, exactly2real users/one own app, localhost:9094; GetCurrentNotifications только server, DeleteMessage только отдельный author-confirmed own scoped target.
Подготовка
Новая пустая CF УчебныйАбонентСВ85 на8.5.1.1343, русский язык, управляемый интерфейс, совместимость Не использовать. Пустые предметные объекты/подписки/задания, ботов/расширений нет. Не используйте реальный абонент, существующий сервер, рабочую базу или чужие данные.
В изолированной VM вручную разверните собственный отдельный сервер взаимодействия, адрес строго http://localhost:9094. Зарегистрируйте собственный новый абонент только для этого урока. В абоненте ровно одно приложение, его имя УчебныйАбонентСВ85. GetSubscriberApplications проверит real ID/name/count, не только строку адреса.
На своем сервере отключите SMTP, внешний доступ, интеграции и совместное использование приложений. Никаких публичных публикаций, чужих аккаунтов или дополнительных приложений. localhost/UUID — дополнительные страховки, не доказательство владельца сервера; VM/абонент проверяете вручную.
В конфигураторе вручную создайте ровно две свои учетные записи Уч85Получатель_<ваш новый канонический ненулевой UUID> и Уч85Отправитель_<другой ваш UUID>, полные имена Учебный получатель/Учебный отправитель. UUID имени — метка; реальные IB UUID и real collaboration IDs получает и подтверждает код.
Зарегистрируйте и синхронизируйте эти два внутренних профиля со своей базой. Нет внешних ID/почты/телефона/ключей сопоставления; не заблокированы. У Получателя заранее вручную назначено администрирование только собственного абонента; Отправитель первоначально не администратор.
Регистрационный адрес этого собственного абонента задайте lab-<реальный IB UUID пользователя Получатель>@example.invalid. Реальный IB UUID найдите в свойствах собственного пользователя или получите в своем сеансе через ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор. Не подставляйте UUID из имени и действительный email.
example.invalid здесь только формальный учебный адрес. Сервер должен быть заранее подготовлен принимать такой адрес без исходящего SMTP/подтверждений на внешние ящики. Если серверная поставка этого не разрешает, сценарий адреса не запускайте и не заменяйте его персональной почтой; ограничение сохраните честно.
Для этого notification-урока создайте отдельный серверный общий модуль УчебныеОповещения85, только Сервер, Привилегированный/Клиент выключены. Вставьте главный код целиком. В форму вставьте полный supporting module; admin-модуль предыдущего урока для работы оповещений не нужен.
В форме создайте строковые реквизиты ПодтверждениеПодготовки/ПодтверждениеОтправки/ПодтверждениеУдаления длиной100, СвойВидимыйКлюч/СвойСкрытыйКлюч длиной100, СобственноеПриглашение неограниченной длины. Поле приглашения только чтение, обычная строка без автоматического открытия URI. Команды: ПодготовитьПолучателя, ОтправитьДвеКарточки, ПроверитьОповещения, УдалитьСвоюСкрытуюКарточку, одноименные обработчики.
В первом собственном сеансе Получателя задайте ДВА СВОИХ ОПОВЕЩЕНИЯ750 и нажмите подготовку один раз. У нового профиля начальный список оповещений должен быть пуст; прежние/неожиданные не очищаются. Два новых обсуждения содержат ровно собственные реальные Receiver/Sender IDs; одно отображаемое, другое скрытое.
Второй собственный сеанс откройте под другим реальным пользователем Отправителем. Копируйте туда только два полученных UUID-ключа. Задайте ДВЕ МОИ КАРТОЧКИ ПОЛУЧАТЕЛЮ и нажмите отправку один раз. Не используйте fake ID, посторонние учетные записи или отправку ВсеПользователиПриложения.
До проверки оповещений не открывайте/не читайте свои обсуждения интерактивно и не подключайте обработчики новых сообщений: UI/handler может пометить сообщение прочитанным. В обоих сеансах отключены сторонние клиенты/боты/параллельные операции.
В первом сеансе вручную нажимайте ПроверитьОповещения. Она вызывает GetCurrentUserNotifications только на сервере: сам тип доступен thick, но метод по справке только server/external. Ноль/один результат — еще не полная готовность; отправку повторять нельзя.
Native приглашение получают только при ПоддерживаетсяВнешнийДоступ=Ложь и ТолькоВидеоконференция=Ложь. Возвращенный внутренний URI хранится лишь в собственной форме, код не разбирает недокументированный маршрут/токен и не открывает ссылку. До завершения оповещений даже вручную не переходите по ней; не публикуйте/не пересылайте внешним людям.
После успешной проверки двух собственных оповещений и карточек отдельный необязательный опыт удаления выполняет только автор Отправитель. Задайте УДАЛИТЬ МОЮ СКРЫТУЮ КАРТОЧКУ750 и нажмите одноименную команду один раз. Это сознательно разрешает удаление одной своей ранее проверенной карточки, не очищение обсуждений/профилей/уведомлений.
Перед удалением своего сообщения повторно проверяется exact owned discussion/participants/author/marker; реальный MessageID берется из единственной строки отбора только этого обсуждения, не из введенного UUID. Входной privilegedMode запрещен; он включается только вокруг native DeleteMessage и выключается при success/catch.
После удаления программа подтверждает пустое свое скрытое обсуждение и неизменную единственную свою видимую карточку750. Повторную notification-ready проверку этого опыта больше не требуйте: удаление карточки не обязано очищать/удалять backend оповещение автоматически.
Любая ошибка/таймаут может оставить частичный собственный результат. Сохраните показанные кандидаты ключей и проверьте свой выделенный сервер вручную; никакого autoretry/cleanup/восстановления/backup. Реальные 1С/network/DB/files операции при создании этого материала не выполнялись.
Функция ПодготовитьДваСвоихОбсуждения85(Подтверждение) Экспорт
Пара = ПроверитьСвоюПару85("Получатель");
Если Подтверждение <> "ДВА СВОИХ ОПОВЕЩЕНИЯ750" Тогда
ВызватьИсключение "Сначала прочитайте подготовку. Обсуждения не созданы";
КонецЕсли;
Если СистемаВзаимодействия.ПоддерживаетсяВнешнийДоступ() Тогда
ВызватьИсключение "Внешний сайт должен быть отключен. Урок не создает внешнее приглашение";
КонецЕсли;
НачальныеОповещения = СистемаВзаимодействия.ПолучитьОповещенияТекущегоПользователя();
Если ТипЗнч(НачальныеОповещения) <> Тип("Массив") Или НачальныеОповещения.Количество() <> 0 Тогда
ВызватьИсключение "Нужен новый собственный получатель без прежних оповещений; чужие не очищаются";
КонецЕсли;
Пакет = Новый Структура("ВидимыйКлюч,СкрытыйКлюч,ВидимоеОбсуждение,СкрытоеОбсуждение,Получатель,Отправитель,Приглашение",
"", "", "", "", Строка(Пара.Получатель), Строка(Пара.Отправитель), "");
Для Индекс = 0 По 1 Цикл
Видимое = Индекс = 0;
Ключ = "Уч85Уведомление_" + Строка(Новый УникальныйИдентификатор);
Сообщить("Свой новый кандидат ключа: " + Ключ);
Если СистемаВзаимодействия.ПолучитьОбсуждение(Ключ) <> Неопределено Тогда
ВызватьИсключение "Ключ занят; существующее обсуждение не меняется";
КонецЕсли;
Обсуждение = СистемаВзаимодействия.СоздатьОбсуждение();
Обсуждение.Ключ = Ключ;
Обсуждение.Заголовок = Ключ + " | Своя карточка750";
Обсуждение.Групповое = Истина;
Обсуждение.Отображаемое = Видимое;
Обсуждение.ТолькоПросмотр = Ложь;
Обсуждение.КонтекстОбсуждения = Неопределено;
Обсуждение.Интеграция = Неопределено;
Обсуждение.ВнешнийИдентификатор = "";
Обсуждение.Участники.Добавить(Пара.Получатель);
Обсуждение.Участники.Добавить(Пара.Отправитель);
Обсуждение.Записать();
Факт = ПроверитьСвоеОбсуждение85(Ключ, Видимое, Пара);
Если Факт.Идентификатор <> Обсуждение.Идентификатор Тогда
ВызватьИсключение "Собственный полученный ID обсуждения не подтвердился";
КонецЕсли;
Если Видимое Тогда
Пакет.ВидимыйКлюч = Ключ;
Пакет.ВидимоеОбсуждение = Строка(Факт.Идентификатор);
Пакет.Приглашение = СистемаВзаимодействия.ПолучитьНавигационнуюСсылкуПриглашенияВОбсуждение(Факт.Идентификатор, Ложь);
Если ТипЗнч(Пакет.Приглашение) <> Тип("Строка") Или Не ЗначениеЗаполнено(Пакет.Приглашение)
Или СтрДлина(Пакет.Приглашение) > 8192 Тогда
ВызватьИсключение "Собственное внутреннее приглашение не получено. Обсуждение могло сохраниться";
КонецЕсли;
Иначе
Пакет.СкрытыйКлюч = Ключ;
Пакет.СкрытоеОбсуждение = Строка(Факт.Идентификатор);
КонецЕсли;
КонецЦикла;
Если Пакет.ВидимоеОбсуждение = Пакет.СкрытоеОбсуждение Тогда
ВызватьИсключение "Нужны два разных реальных собственных обсуждения";
КонецЕсли;
Возврат Пакет;
КонецФункции
Процедура ОтправитьДвеСвоиКарточки85(ВидимыйКлюч, СкрытыйКлюч, Подтверждение) Экспорт
Пара = ПроверитьСвоюПару85("Отправитель");
Если Подтверждение <> "ДВЕ МОИ КАРТОЧКИ ПОЛУЧАТЕЛЮ" Или ВидимыйКлюч = СкрытыйКлюч Тогда
ВызватьИсключение "Нужно отдельное подтверждение отправки двум собственным обсуждениям";
КонецЕсли;
Видимое = ПроверитьСвоеОбсуждение85(ВидимыйКлюч, Истина, Пара);
Скрытое = ПроверитьСвоеОбсуждение85(СкрытыйКлюч, Ложь, Пара);
Если ПолучитьСобственныеСообщения85(Видимое.Идентификатор).Количество() <> 0
Или ПолучитьСобственныеСообщения85(Скрытое.Идентификатор).Количество() <> 0 Тогда
ВызватьИсключение "Обсуждение уже содержит сообщения. Повтор отправки запрещен";
КонецЕсли;
Для Индекс = 0 По 1 Цикл
Если Индекс = 0 Тогда
Обсуждение = ПроверитьСвоеОбсуждение85(ВидимыйКлюч, Истина, Пара);
Иначе
Обсуждение = ПроверитьСвоеОбсуждение85(СкрытыйКлюч, Ложь, Пара);
КонецЕсли;
Сообщение = СистемаВзаимодействия.СоздатьСообщение(Обсуждение.Идентификатор);
Сообщение.Текст = Обсуждение.Ключ + "|Книга|3|250|750";
Сообщение.Данные = Обсуждение.Ключ + "|750";
Сообщение.ФорматДанныхСтроки = "text/plain";
Сообщение.Получатели.Добавить(Пара.Получатель);
Если Сообщение.Получатели.Количество() <> 1 Или Не Сообщение.Получатели.Содержит(Пара.Получатель)
Или Сообщение.Вложения.Количество() <> 0 Или Сообщение.Действия.Количество() <> 0
Или Сообщение.ПанельКнопок.РядыКнопок.Количество() <> 0 Тогда
ВызватьИсключение "В собственной отправке неожиданное содержимое или адресат";
КонецЕсли;
Сообщение.Записать();
Факт = ПолучитьЕдинственнуюСвоюКарточку85(Обсуждение, Пара.Отправитель);
Если Факт.Идентификатор <> Сообщение.Идентификатор Тогда
ВызватьИсключение "Собственная карточка могла сохраниться, но отдельная проверка ID не совпала";
КонецЕсли;
КонецЦикла;
Сообщить("Две свои карточки отдельно подтверждены на сервере. Это не доказательство доставки оповещений");
КонецПроцедуры
Функция ПрочитатьСвоиОповещения85(Пакет) Экспорт
Пара = ПроверитьСвоюПару85("Получатель");
ПроверитьСвоиIDПакета85(Пакет, Пара);
Видимое = ПроверитьСвоеОбсуждение85(Пакет.ВидимыйКлюч, Истина, Пара);
Скрытое = ПроверитьСвоеОбсуждение85(Пакет.СкрытыйКлюч, Ложь, Пара);
Если Строка(Видимое.Идентификатор) <> Пакет.ВидимоеОбсуждение
Или Строка(Скрытое.Идентификатор) <> Пакет.СкрытоеОбсуждение Тогда
ВызватьИсключение "ID собственных обсуждений изменены";
КонецЕсли;
Оповещения = СистемаВзаимодействия.ПолучитьОповещенияТекущегоПользователя();
Если ТипЗнч(Оповещения) <> Тип("Массив") Тогда
ВызватьИсключение "Native GetCurrentUserNotifications должен вернуть Массив";
КонецЕсли;
Видимых = 0;
Скрытых = 0;
Для Каждого Оповещение Из Оповещения Цикл
Если ТипЗнч(Оповещение) <> Тип("ОповещениеСистемыВзаимодействия") Тогда
ВызватьИсключение "Ожидалось настоящее серверное оповещение, не самостоятельно созданный объект";
КонецЕсли;
ИДОбсуждения = Оповещение.Обсуждение;
Если ТипЗнч(ИДОбсуждения) <> Тип("ИдентификаторОбсужденияСистемыВзаимодействия") Тогда
ВызватьИсключение "Оповещение не содержит native ID обсуждения";
КонецЕсли;
Если ИДОбсуждения = Видимое.Идентификатор Тогда
Видимых = Видимых + 1;
ИначеЕсли ИДОбсуждения = Скрытое.Идентификатор Тогда
Скрытых = Скрытых + 1;
Иначе
ВызватьИсключение "В новом собственном профиле неожиданное другое оповещение: оно не выводится и не очищается";
КонецЕсли;
КонецЦикла;
Если Видимых > 1 Или Скрытых > 1 Тогда
ВызватьИсключение "Неожиданное дублирование оповещений своих обсуждений";
КонецЕсли;
Готово = Видимых = 1 И Скрытых = 1;
Если Готово Тогда
ПолучитьЕдинственнуюСвоюКарточку85(Видимое, Пара.Отправитель);
ПолучитьЕдинственнуюСвоюКарточку85(Скрытое, Пара.Отправитель);
КонецЕсли;
Возврат Новый Структура("Готово,Видимых,Скрытых", Готово, Видимых, Скрытых);
КонецФункции
Процедура УдалитьТолькоСвоюСкрытуюКарточку85(ВидимыйКлюч, СкрытыйКлюч, Подтверждение) Экспорт
Пара = ПроверитьСвоюПару85("Отправитель");
Если Подтверждение <> "УДАЛИТЬ МОЮ СКРЫТУЮ КАРТОЧКУ750" Или ВидимыйКлюч = СкрытыйКлюч Тогда
ВызватьИсключение "Удаление не выполняется без отдельного точного подтверждения";
КонецЕсли;
Видимое = ПроверитьСвоеОбсуждение85(ВидимыйКлюч, Истина, Пара);
Скрытое = ПроверитьСвоеОбсуждение85(СкрытыйКлюч, Ложь, Пара);
ПолучитьЕдинственнуюСвоюКарточку85(Видимое, Пара.Отправитель);
СвояКарточка = ПолучитьЕдинственнуюСвоюКарточку85(Скрытое, Пара.Отправитель);
ИДСвоейКарточки = СвояКарточка.Идентификатор;
Если ТипЗнч(ИДСвоейКарточки) <> Тип("ИдентификаторСообщенияСистемыВзаимодействия") Тогда
ВызватьИсключение "Нужен real ID собственного сообщения из exact scoped selection";
КонецЕсли;
ПроверитьСвоеОбсуждение85(СкрытыйКлюч, Ложь, Пара);
Попытка
УстановитьПривилегированныйРежим(Истина);
СистемаВзаимодействия.УдалитьСообщение(ИДСвоейКарточки);
Исключение
УстановитьПривилегированныйРежим(Ложь);
ВызватьИсключение "Удаление могло произойти, но не подтверждено. PrivilegedMode выключен; повторов и автоматического cleanup нет";
КонецПопытки;
УстановитьПривилегированныйРежим(Ложь);
ПроверитьСвоюПару85("Отправитель");
Скрытое = ПроверитьСвоеОбсуждение85(СкрытыйКлюч, Ложь, Пара);
Если ПолучитьСобственныеСообщения85(Скрытое.Идентификатор).Количество() <> 0 Тогда
ВызватьИсключение "Удаление собственного скрытого сообщения отдельно не подтверждено";
КонецЕсли;
Видимое = ПроверитьСвоеОбсуждение85(ВидимыйКлюч, Истина, Пара);
ПолучитьЕдинственнуюСвоюКарточку85(Видимое, Пара.Отправитель);
Сообщить("Удалена только своя скрытая карточка750; своя видимая сохранена. Обсуждение/профили/оповещения отдельно не удалялись");
КонецПроцедуры
Процедура ПроверитьСвоиIDПакета85(Пакет, Пара)
Если ТипЗнч(Пакет) <> Тип("Структура") Или Пакет.Получатель <> Строка(Пара.Получатель)
Или Пакет.Отправитель <> Строка(Пара.Отправитель)
Или Пакет.ВидимыйКлюч = Пакет.СкрытыйКлюч Или Пакет.ВидимоеОбсуждение = Пакет.СкрытоеОбсуждение Тогда
ВызватьИсключение "Нужен собственный пакет двух разных реальных обсуждений";
КонецЕсли;
КонецПроцедуры
Функция ПроверитьСвоеОбсуждение85(Ключ, Видимость, Пара)
Если ТипЗнч(Ключ) <> Тип("Строка") Или Лев(Ключ, СтрДлина("Уч85Уведомление_")) <> "Уч85Уведомление_" Тогда
ВызватьИсключение "Передайте только полученный собственный UUID-ключ";
КонецЕсли;
UUIDКлюча = Новый УникальныйИдентификатор(Сред(Ключ, СтрДлина("Уч85Уведомление_") + 1));
Если Ключ <> "Уч85Уведомление_" + Строка(UUIDКлюча)
Или UUIDКлюча = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000") Тогда
ВызватьИсключение "Канонический собственный UUID-ключ не подтвержден";
КонецЕсли;
Факт = СистемаВзаимодействия.ПолучитьОбсуждение(Ключ);
Если Факт = Неопределено Тогда
ВызватьИсключение "Собственное обсуждение не найдено; IDs не выдумываются";
КонецЕсли;
Если Факт.Ключ <> Ключ Или Факт.Заголовок <> Ключ + " | Своя карточка750"
Или Не Факт.Групповое Или Факт.Отображаемое <> Видимость Или Факт.ТолькоПросмотр
Или Факт.КонтекстОбсуждения <> Неопределено Или Факт.Интеграция <> Неопределено
Или Факт.ВнешнийИдентификатор <> "" Или Факт.Участники.Количество() <> 2
Или Не Факт.Участники.Содержит(Пара.Получатель) Или Не Факт.Участники.Содержит(Пара.Отправитель) Тогда
ВызватьИсключение "Паспорт собственного обсуждения двух участников изменен";
КонецЕсли;
Возврат Факт;
КонецФункции
Функция ПолучитьСобственныеСообщения85(ИДОбсуждения)
Отбор = Новый ОтборСообщенийСистемыВзаимодействия;
Отбор.Обсуждение = ИДОбсуждения;
Отбор.Количество = 2;
Отбор.НаправлениеСортировки = НаправлениеСортировки.Возр;
Возврат СистемаВзаимодействия.ПолучитьСообщения(Отбор);
КонецФункции
Функция ПолучитьЕдинственнуюСвоюКарточку85(Обсуждение, ИДАвтора)
Сообщения = ПолучитьСобственныеСообщения85(Обсуждение.Идентификатор);
Если ТипЗнч(Сообщения) <> Тип("Массив") Или Сообщения.Количество() <> 1 Тогда
ВызватьИсключение "Нужна ровно одна собственная карточка750 в выбранном обсуждении";
КонецЕсли;
Факт = Сообщения[0];
Если Факт.Обсуждение <> Обсуждение.Идентификатор Или Факт.Автор <> ИДАвтора
Или Факт.Текст <> Обсуждение.Ключ + "|Книга|3|250|750" Или Факт.Данные <> Обсуждение.Ключ + "|750"
Или Факт.Вложения.Количество() <> 0 Или Факт.Действия.Количество() <> 0 Тогда
ВызватьИсключение "Собственный автор, marker или содержимое карточки изменены";
КонецЕсли;
Возврат Факт;
КонецФункции
Функция ПроверитьСвоюПару85(Роль)
ПроверитьСвойПустойСтенд();
Если ПривилегированныйРежим() Или (Роль <> "Получатель" И Роль <> "Отправитель") Тогда
ВызватьИсключение "Роль или привилегированный режим неверны";
КонецЕсли;
Если Не СистемаВзаимодействия.ИнформационнаяБазаЗарегистрирована()
Или Не СистемаВзаимодействия.ИспользованиеДоступно()
Или СистемаВзаимодействия.АдресСервера() <> "http://localhost:9094" Тогда
ВызватьИсключение "Нужно собственное изолированное приложение на localhost:9094";
КонецЕсли;
Приложение = СистемаВзаимодействия.ПолучитьПриложение(СистемаВзаимодействия.ИдентификаторТекущегоПриложения());
Если Приложение.Идентификатор <> СистемаВзаимодействия.ИдентификаторТекущегоПриложения()
Или Приложение.Наименование <> "УчебныйАбонентСВ85" Тогда
ВызватьИсключение "Наименование своего нового приложения не совпало";
КонецЕсли;
Пользователи = ПользователиИнформационнойБазы.ПолучитьПользователей();
Текущий = ПользователиИнформационнойБазы.ТекущийПользователь();
Если Пользователи.Количество() <> 2 Или Текущий = Неопределено Тогда
ВызватьИсключение "Нужны ровно две собственные UUID-учетные записи";
КонецЕсли;
Пара = Новый Структура("Получатель,Отправитель", Неопределено, Неопределено);
ТекущийПодтвержден = Ложь;
Для Каждого ПользовательБазы Из Пользователи Цикл
Если Лев(ПользовательБазы.Имя, СтрДлина("Уч85Получатель_")) = "Уч85Получатель_" Тогда
ИмяРоли = "Получатель";
ИначеЕсли Лев(ПользовательБазы.Имя, СтрДлина("Уч85Отправитель_")) = "Уч85Отправитель_" Тогда
ИмяРоли = "Отправитель";
Иначе
ВызватьИсключение "Посторонняя учетная запись недопустима";
КонецЕсли;
Префикс = "Уч85" + ИмяРоли + "_";
UUIDИмени = Новый УникальныйИдентификатор(Сред(ПользовательБазы.Имя, СтрДлина(Префикс) + 1));
Если ПользовательБазы.Имя <> Префикс + Строка(UUIDИмени)
Или UUIDИмени = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000") Тогда
ВызватьИсключение "Имя своего участника должно содержать канонический ненулевой UUID";
КонецЕсли;
ИД = СистемаВзаимодействия.ПолучитьИдентификаторПользователя(ПользовательБазы.УникальныйИдентификатор);
Если ТипЗнч(ИД) <> Тип("ИдентификаторПользователяСистемыВзаимодействия")
Или ИД = Новый ИдентификаторПользователяСистемыВзаимодействия
Или ИД = СистемаВзаимодействия.СтандартныеПользователи.ВсеПользователиПриложения
Или СистемаВзаимодействия.ПолучитьИдентификаторПользователяИнформационнойБазы(ИД) <> ПользовательБазы.УникальныйИдентификатор Тогда
ВызватьИсключение "Реальная связка своего пользователя с базой не подтверждена";
КонецЕсли;
Пользователь = СистемаВзаимодействия.ПолучитьПользователя(ИД);
Если Пользователь.Идентификатор <> ИД Или Пользователь.Имя <> ПользовательБазы.Имя
Или Пользователь.ПолноеИмя <> ПользовательБазы.ПолноеИмя
Или Пользователь.ИдентификаторПользователяИнформационнойБазы <> ПользовательБазы.УникальныйИдентификатор
Или Пользователь.Внешний Или Пользователь.Заблокирован Или Пользователь.ТипВнешнейСистемы <> ""
Или Пользователь.ИдентификаторПользователяВнешнейСистемы <> Неопределено
Или Пользователь.АдресЭлектроннойПочты <> "" Или Пользователь.АдресЭлектроннойПочтыДляАутентификации <> ""
Или Пользователь.НомерТелефона <> "" Или Пользователь.КлючСопоставления <> "" Тогда
ВызватьИсключение "Нужен собственный внутренний учебный паспорт без персональных контактов";
КонецЕсли;
Если Пара[ИмяРоли] <> Неопределено Тогда
ВызватьИсключение "Роль продублирована";
КонецЕсли;
Пара[ИмяРоли] = ИД;
Если ПользовательБазы.УникальныйИдентификатор = Текущий.УникальныйИдентификатор Тогда
Если ИмяРоли <> Роль Или ИД <> СистемаВзаимодействия.ИдентификаторТекущегоПользователя() Тогда
ВызватьИсключение "Войдите под своей учетной записью нужной роли";
КонецЕсли;
ТекущийПодтвержден = Истина;
КонецЕсли;
КонецЦикла;
Если Не ТекущийПодтвержден Или Пара.Получатель = Неопределено Или Пара.Отправитель = Неопределено
Или Пара.Получатель = Пара.Отправитель Тогда
ВызватьИсключение "Не получены два разных реальных собственных ID";
КонецЕсли;
Приложения = СистемаВзаимодействия.ПолучитьПриложенияАбонента();
Если ТипЗнч(Приложения) <> Тип("Массив") Или Приложения.Количество() <> 1 Тогда
ВызватьИсключение "У своего отдельного абонента должно быть ровно одно собственное приложение";
КонецЕсли;
Если ТипЗнч(Приложения[0]) <> Тип("ПриложениеСистемыВзаимодействия")
Или Приложения[0].Идентификатор <> СистемаВзаимодействия.ИдентификаторТекущегоПриложения()
Или Приложения[0].Наименование <> "УчебныйАбонентСВ85" Тогда
ВызватьИсключение "Список собственного абонента содержит другое приложение";
КонецЕсли;
Возврат Пара;
КонецФункции
Процедура ПроверитьСвойПустойСтенд()
Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
КонецЕсли;
Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
КонецЕсли;
Источники = Новый Массив;
Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
Для Каждого Источник Из Источники Цикл
Расширения = РасширенияКонфигурации.Получить(, Источник);
Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
ВызватьИсключение "Native список расширений должен иметь тип Массив";
КонецЕсли;
Если Расширения.Количество() <> 0 Тогда
ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
КонецЕсли;
КонецЦикла;
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
КонецЕсли;
КонецПроцедурыПолный модуль собственной управляемой формы: два сеанса, ручной poll и отдельная own-delete команда
Собственная внешняя обработка → Управляемая форма → Модуль формы.
Полный клиент-серверный модуль собственной управляемой формы; GetCurrentUserNotifications остается на сервере.
Перем СвойПакет85;
Перем НачатаПодготовка85;
Перем НачатаОтправка85;
Перем НачатоУдаление85;
&НаКлиенте
Процедура ПодготовитьПолучателя(Команда)
Если НачатаПодготовка85 = Истина Тогда
ВызватьИсключение "Повтор запрещен; возможный частичный результат проверяйте вручную";
КонецЕсли;
НачатаПодготовка85 = Истина;
СвойПакет85 = ПодготовитьНаСервере85();
СвойВидимыйКлюч = СвойПакет85.ВидимыйКлюч;
СвойСкрытыйКлюч = СвойПакет85.СкрытыйКлюч;
СобственноеПриглашение = СвойПакет85.Приглашение;
Сообщить("Два своих обсуждения подготовлены. Во второй собственный сеанс копируйте только два UUID-ключа. Внутреннее приглашение в поле, не в журнале");
КонецПроцедуры
&НаСервере
Функция ПодготовитьНаСервере85()
Возврат УчебныеОповещения85.ПодготовитьДваСвоихОбсуждения85(ПодтверждениеПодготовки);
КонецФункции
&НаКлиенте
Процедура ОтправитьДвеКарточки(Команда)
Если НачатаОтправка85 = Истина Тогда
ВызватьИсключение "Повтор отправки запрещен; возможный частичный результат проверяйте вручную";
КонецЕсли;
НачатаОтправка85 = Истина;
ОтправитьНаСервере85(СвойВидимыйКлюч, СвойСкрытыйКлюч, ПодтверждениеОтправки);
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ОтправитьНаСервере85(ВидимыйКлюч, СкрытыйКлюч, Фраза)
УчебныеОповещения85.ОтправитьДвеСвоиКарточки85(ВидимыйКлюч, СкрытыйКлюч, Фраза);
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьОповещения(Команда)
Если СвойПакет85 = Неопределено Тогда
ВызватьИсключение "Сначала подготовьте собственный пакет именно в сеансе Получателя";
КонецЕсли;
Результат = ПрочитатьНаСервере85(СвойПакет85);
Сообщить("Native оповещения своих обсуждений: видимых=" + Строка(Результат.Видимых) + ", скрытых=" + Строка(Результат.Скрытых));
Если Результат.Готово Тогда
Сообщить("Получены два настоящих своих оповещения и отдельно подтверждены обе карточки750");
Иначе
Сообщить("Полного результата пока нет. Не повторяйте отправку; позже вручную нажмите только эту проверку");
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПрочитатьНаСервере85(Пакет)
Возврат УчебныеОповещения85.ПрочитатьСвоиОповещения85(Пакет);
КонецФункции
&НаКлиенте
Процедура УдалитьСвоюСкрытуюКарточку(Команда)
Если НачатоУдаление85 = Истина Тогда
ВызватьИсключение "Повтор удаления запрещен; состояние проверяйте вручную";
КонецЕсли;
НачатоУдаление85 = Истина;
УдалитьНаСервере85(СвойВидимыйКлюч, СвойСкрытыйКлюч, ПодтверждениеУдаления);
КонецПроцедуры
&НаСервереБезКонтекста
Процедура УдалитьНаСервере85(ВидимыйКлюч, СкрытыйКлюч, Фраза)
УчебныеОповещения85.УдалитьТолькоСвоюСкрытуюКарточку85(ВидимыйКлюч, СкрытыйКлюч, Фраза);
КонецПроцедурыРазбор по шагам
Проверка пары подтверждает actual IB users ↔ actual collaboration IDs в обе стороны, текущую роль, пустой собственный CF, точную платформу, localhost и единственное свое приложение абонента. Все API-вызовы подготовки выполняются на сервере.
До изменений точная фраза разрешает только два новых own discussions. ExternalAccessSupported=true дает отказ: этот урок не публикует внешних пользователей/сайт и не создает внешнее приглашение.
Пустой начальный GetCurrentUserNotifications защищает от смешивания с прежними результатами. Никакие чужие уведомления/профили не читаются по содержимому, не очищаются и не журналируются.
Создаются два разных реальных обсуждения с двумя собственными участниками, exact UUID key/title, без контекста/интеграции/внешних ID. Отличается только Отображаемое: Истина и Ложь.
GetInviteUrlToConversation получает фактический ID только своего отображаемого обсуждения и явное Ложь. При выключенном внешнем доступе native возвращает внутреннюю ссылку; ее форма не угадывается. Оpaque строка не является API-endpoint/командой и сама ничего не открывает.
Отправитель проходит собственную текущую роль заново, подтверждает оба обсуждения и отсутствие любых прежних сообщений. Одна существующая карточка хотя бы в одном обсуждении блокирует повтор всей отправки.
В каждое собственное обсуждение записывается книга3×250=750; recipients содержит только real Получатель ID. Записанные own message IDs сверяются отдельным scoped server read; факт записи не равен факту доставки alert.
Получатель свежими чтениями подтверждает собственные IDs/participants/displayed. Затем GetCurrentUserNotifications возвращает настоящий Массив объектов ОповещениеСистемыВзаимодействия; readonly Обсуждение содержит typed native ID, а не весь объект обсуждения.
Подсчет сравнивает реальные IDs с двумя подтвержденными своими обсуждениями. Другой ID не раскрывается, не загружается как чужое обсуждение и вызывает безопасный отказ. Дубли одного own ID также не маскируются.
Только один alert каждого собственного обсуждения означает Готово=Истина. Тогда отдельные own scoped reads подтверждают обе реальные карточки750. Частичная доставка0/1 не считается успехом и не вызывает повторную отправку.
GetCurrentUserNotifications по native возвращает alerts всех обсуждений независимо от Отображаемое: скрытый own discussion здесь дает реальный учебный положительный случай, не формальное чтение поля.
Опыт DeleteMessage выполняет только author Sender после отдельной фразы. В обоих обсуждениях должна быть ровно одна собственная карточка; targetrealID выбирается исключительно из own hidden scoped selection с проверенным автором/text/data.
Native DeleteMessage требует privilegedMode. После всех guards режим0→1 только на одну операцию; success и catch устанавливают0. Нет API SetCurrentUser/имперсонации и нет входного привилегированного сеанса.
После выключения режима свежие role/app/user guards выполняются снова. Hidden own message list=0, visible own exact card остается1. Не удаляются обсуждения, профили или notification objects; неизвестна политика удаления alert на конкретном сервере.
Как проверить результат
Пустое подтверждение, другой сервер/приложение/участник, внешняя публикация или непустой начальный список → отказ до создания нового опыта.
Уведомления настоящие typed objects из server GetCurrentUserNotifications; readonly Обсуждение не присваивается, ctor отсутствует/не имитируется.
В положительном маршруте alerts есть для видимого и скрытого своих обсуждений; их actual ID совпадает с отдельно полученными own discussion IDs. Backend список и UI-показ — разные вещи.
Внутреннее приглашение получено по actualown ID и хранится только в собственной форме; нигде не запускается/не логируется/не интерпретируется как выдуманный маршрут.
До выполнения DeleteMessage подтверждены current Sender/own app/exact two participants/one own target card. Удаляется ее actual ID из scoped query, а не любой переданный клиентом UUID.
Входной privilegedMode отклоняется; после native удаления/ошибки он выключен. Hidden=0 и visible=1 подтверждены только свежими чтениями, не completion-signal.
После удаления прежнее условие notification-ready не предъявляется: удаление сообщения не заявлено как способ очистить список оповещений.
Ожидаемый результат
При ручном успешном запуске своего двухпользовательского стенда на сервере подтверждаются две own cards750 и два настоящих alerts, включая скрытое обсуждение. Дополнительный явно разрешенный DeleteMessage удаляет только own hidden card и отдельно подтверждает visible card. Здесь только статическая/native проверка, runtime1С/отправки/удаления отсутствуют.
На что обратить внимание
Оповещение не создается самостоятельно: no native constructor. Его Обсуждение — readonly ИдентификаторОбсуждения, не объект, имя/текст/MessageID.
Сам тип доступен server/thick/external, но GetCurrentUserNotifications объявлен только server/external. Не переносите этот метод в thick-client handler.
Отображаемое=Ложь не обещает отсутствие backend alerts. Но интерфейс/подключенный handler может изменить read status, поэтому исходный опыт выполняется без интерактивного чтения обсуждений.
Нет SLA доставки или гарантии первого полного poll. Ноль/один — честный промежуточный результат; бессмысленное повторение отправки создало бы дубли.
Opaque внутренний URI может содержать данные доступа; не печатайте/не публикуйте его. Здесь его не открывают и не угадывают схему e1c/http/маршрут.
GetInviteUrl native при выключенном внешнем доступе возвращает внутреннее приглашение; OnlyVideo=false разрешает обсуждение. Видеоконференции/провайдеры этим уроком не покрываются.
DeleteMessage требует привилегированного режима и действительно удаляет message. Не применяйте к чужим IDs/массовому списку/production; отдельная фраза ограничивает только own verified hidden750.
Включение privilegedMode не является проверкой собственности. Все guards/selection/author/data выполняются ДО него, без прямого GetMessage по переданному клиентом ID.
При ошибке native удаления физическое изменение может уже произойти; выключение режима — не rollback. Автоматического повторения/очистки/восстановления нет.
Удаление собственной карточки не является очисткой alert. После этого сохраните отдельные критерии результата; не выдавайте отсутствие сообщения за отсутствие уведомления.
UUID-ключ и локальный хост — страховки, не доказательство владельца абонента. Собственная новая VM, real users и единственное own app обязательны.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.