Сообщения электронной почты в Discourse неверно сгруппированы в потоки

Существует несколько способов ссылки на родительский(е) пост(ы), и связь хранится через таблицу PostReply, где reply_post_id обозначает пост, который отвечает, а post_id ссылается на родительский пост. Входящие письма используют заголовок In-Reply-To для установления связи. В интерфейсе Discourse, если вы цитируете несколько постов, создаётся несколько записей PostReply, а если вы используете кнопку «Ответить» на одном посте, она также используется для создания записи PostReply.

Да, извините, я должен был это отметить: add_identification_field_headers больше не будет использоваться, весь новый код находится в add_experimental_identification_field_headers. Спасибо за комментарии непосредственно к коду, я этого не ожидал! Разберусь с ними сегодня.

@cameron-simpson Приношу свои извинения, думаю, вы просмотрели более ранний коммит в этом PR. Я перебазировал код, снова запушил его, чтобы теперь был один коммит со всем актуальным кодом, который мы тестировали на том тестовом сайте. Надеюсь, сообщение коммита там будет полезным и логичным.

Что касается References, то если пользователь отвечает на пост, я использую полную цепочку Message-ID от исходного поста (OP) до родительского поста в порядке следования. Например, если все эти посты образуют прямую цепочку ответов:

  • Пост 1 — discourse/post/500@test.site
  • Пост 2 — discourse/post/501@test.site
  • Пост 3 — discourse/post/502@test.site
  • Пост 4 — discourse/post/503@test.site
  • Пост 5 — discourse/post/504@test.site

То заголовок In-Reply-To для последнего поста будет:

  • In-Reply-To: <discourse/post/503@test.site>

А References будет:

  • References: <discourse/post/500@test.site> <discourse/post/501@test.site> <discourse/post/502@test.site> <discourse/post/503@test.site>

Если создаётся новый пост, который не является прямым ответом на предыдущий пост, например, Пост 6 — discourse/post/505@test.site, то его Message-ID в заголовке In-Reply-To будет <discourse/post/500@test.site> (исходный пост), а References будет <discourse/post/500@test.site>, что также соответствует исходному посту.

Пожалуйста, дайте знать, если это неверно, и я внесу исправления.

3 лайка

От Мартина Бреннана через Discourse Meta, 23 августа 2022 г., 23:59:

@cameron-simpson, приношу свои извинения, думаю, вы могли просмотреть более ранний коммит в этом PR. Я теперь перебил базу кода для него и снова отправил, чтобы создать один коммит со всем актуальным кодом, который мы тестировали на этом тестовом сайте. Надеюсь, сообщение коммита там будет полезным и логичным.

Я ещё раз посмотрю, спасибо.

Для References, если пользователь отвечает на пост, я использую полную цепочку Message-ID от оригинального поста (OP) до родительского поста в порядке следования. Например, если все эти посты являются прямой цепочкой ответов:

  • Пост 1 — discourse/post/500@test.site
  • Пост 2 — discourse/post/501@test.site
  • Пост 3 — discourse/post/502@test.site
  • Пост 4 — discourse/post/503@test.site
  • Пост 5 — discourse/post/504@test.site

Звучит правильно.

Тогда заголовок In-Reply-To для последнего поста будет:

  • In-Reply-To: <discourse/post/503@test.site>
    А References будет:
  • References: <discourse/post/500@test.site> <discourse/post/501@test.site> <discourse/post/502@test.site> <discourse/post/503@test.site>

Тоже верно.

Если создаётся новый пост, который не является прямым ответом на пост выше, например, Пост 6 — discourse/post/505@test.site, то его In-Reply-To Message-ID будет <discourse/post/500@test.site> (оригинальный пост), а References будет <discourse/post/500@test.site>, что также является оригинальным постом.

Всё это верно.

С наилучшими пожеланиями,
Кэмерон Симпсон cs@cskk.id.au

1 лайк

Спасибо. Я также забыл упомянуть, что нам действительно приходится обращаться к базе данных, чтобы воссоздать цепочку References на основе записей PostReply. Вы увидите это в последнем коммите.

@cameron-simpson Я хотел бы запустить процесс внутренней ревью этого кода на следующей неделе (а также провести общую доработку того, что я сделал), так как с 3-го числа я ухожу в отпуск. Таким образом, если ревью будет завершено, я смогу слить код и развернуть его, как только вернусь. Если у вас есть дополнительные замечания, пожалуйста, сообщите мне об этом до этого времени; в противном случае я буду исходить из того, что всё в порядке (что, как нам показалось, подтвердилось во время вчерашнего тестирования :slight_smile: ).

1 лайк

Я думаю, что в целом всё хорошо. Вот мои заметки по результатам ручного анализа цепочки писем с моей стороны (я в основном проверил заголовки вручную):

Тема для тестирования потоков 2022-08-23

пост   msg-id  детали
59/1   98 OP   новые темы для тестирования потоков электронной почты
59/11 109 reply-to-topic in-reply-to 98 ref 98
59/2  100 reply-to-topic in-reply-to 98 ref 98
59/3  via-email uuid@discourse yes welcome in-reply-to 100 ref 98,100
        не отмечено как ответ в веб-интерфейсе
???   me-via-email ...kr@cskk glad to be here in-reply-to uuid@discourse no refs
        не отмечено как ответ в веб-интерфейсе
59/10 108 ответ на более ранний пост in-reply-to ...kr@cskk ref 98,100,0aa@discourse,kr@cskk
59/5  103 спасибо, Кэмерон in-reply-to kr@cskk refs 98,100,0aa@discourse,kr@cskk
???104   me-via-email ...zp@cskk in-reply-to 103 no refs
        не отмечено как ответ в веб-интерфейсе
59/7 105 без проблем in-reply-to zp@cskk refs 98,100,00a@discourse,kr@cskk,103,zp@cskk
        опубликовано в вебе, ответ на 104? то есть zp@@cskk
        не отмечено как ответ в веб-интерфейсе (значит, новая тема?)
        цитирует kr@cskk "рад быть здесь"
        ТРЕБУЕТ ПРОВЕРКИ
59/9 107 ожидаемое поведение или ошибка in-reply-to 106 ref 98,100,0aa@discourse,kr@cskk,103,zp@cskk,105,106
        цитирует 59/8

Заметки:
- ответы по электронной почте не отображаются как ответы в веб-интерфейсе
- множественные ответы в вебе получают только один msg-id в поле in-reply-to
- пользователи не получают копии своих собственных постов по электронной почте (или в вебе); было бы неплохо иметь опцию в настройках для этого
- msg-id в вебе, похоже, соответствуют post.id форума; было бы удобнее использовать topic.id/in-topic.id для упрощения отслеживания в заголовках

Вкратце: я не нашёл ошибок в заголовках, но указал некоторые недостатки выше.

У меня пока не было возможности проверить ваш обновлённый код, но функционально всё выглядит правильно.

Спасибо,
Кэмерон

1 лайк

Спасибо, Кэмерон!

Не могли бы вы немного подробнее об этом рассказать? Вы имеете в виду, что вы не видите это?

Или вы не видите эту часть? В последнем случае мы показываем ответ со стрелкой только в том случае, если пост, на который вы отвечаете, находится выше в теме, а не просто предыдущий:

О, я не думал, что это обязательно. Если вы отвечаете через веб-интерфейс на N постов, то Message-IDs всех этих постов должны отображаться в заголовке In-Reply-To, а затем References следует текущей логике ветки от исходного поста (OP) до единственного родительского поста (в нашем случае я выбираю самый последний созданный пост в качестве единственного родителя)?

Да, это сделано намеренно, чтобы не отправлять вам то, что вы уже «видели». Мы могли бы вынести это в отдельный TODO, чтобы проверить, есть ли у других пользователей потребность в такой функции.

Проблема с topic ID в том, что он слишком хрупкий и недостаточно специфичный/уникальный, кроме того, это может вызвать путаницу, если пост будет перемещен между темами. Может быть, мы можем добавить пользовательский заголовок в письмо, например X-Discourse-Topic-ID или что-то подобное (если это разрешено), чтобы упростить визуальную трассировку?

2 лайка

Нет, я вижу эту иконку.

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

Это не обязательно. Воспринимай это как «качество обслуживания». Ты явно делаешь:

@message.header['In-Reply-To'] = referenced_post_message_ids[0] || topic_canonical_reference_id

и мог бы просто убрать [0] там. Клиенты тогда могли бы использовать только один message-id или делать что-то очень странное по своему усмотрению, и всё это было бы валидным.

«Должны» — слишком сильное слово. Ты можешь включить все message-id, если они легко доступны. Ты не обязан, и код валиден и в текущем виде.

Ага. Я сам предпочитаю это, чтобы знать, что мой пост попал в список/на форум — электронная почта очень ориентирована на очереди, а некоторые обработчики почты от провайдеров (кашель, крупный австралийский телеком, кашель) очень… ненадёжны, медленны и т. д. Иногда я видел, что другие люди хотели этого (в списках рассылки, но именно в этом режиме мы, по сути, говорим сейчас). Значение по умолчанию для такой опции, вероятно, должно быть false.

Как гик, я ценю возможность получать хотя бы нефильтрованную ленту, чтобы принимать собственные решения о политике.

Учитывая, что Message-ID по сути непрозрачен и устанавливается один раз, я не считаю это проблемой, если нет возможности повторно отправить тот же message-id — если все твои счётчики строго монотонны, я не ожидаю такого. Мне просто было очень утомительно сопоставлять post.id, например 98, с темой/постом, например 59/1. Было бы удобно иметь что-то вроде category.id/topic.id/post-in-topic.id вместо 98.

Этого тоже было бы достаточно. Это просто удобство на стороне отладочных заголовков.

С уважением,
Cameron

4 лайка

Это всё ещё старый код, на который вы смотрите; вам нужно обратить внимание на add_experimental_identification_field_headers. Однако ваша точка зрения остаётся верной.

В нашей команде инфраструктуры есть кто-то, кто полностью согласится с этим утверждением; у них схожий с вашим рабочий процесс и взгляд на вещи :laughing:

Это справедливо. Возможно, я верну ID темы, так как outbound_message_id действительно устанавливается один раз и не меняется (в зависимости от того, создан ли пост через веб-интерфейс Discourse или получен по входящему письму).

Вероятно, это теперь не понадобится, так как я снова добавляю ID темы в Message-ID.

Ах, я, кажется, должен был это увидеть:

 most_recent_post = referenced_posts.first
      most_recent_post_message_id = Email::MessageIdService.generate_or_use_existing(most_recent_post)
      @message.header["In-Reply-To"] = most_recent_post_message_id

В любом случае, существующий код уже корректен. Полностью ваше решение.

2 лайка

На самом деле я не уверен в этом. У меня есть предчувствие, что нам не нужно включать topic ID в эти Message-ID — наличие только post ID делает всё предельно простым. Попробую такой вариант:

На самом деле они у нас уже есть, и мы удаляем их здесь:

https://github.com/discourse/discourse/blob/d135d0613f44812566b739e77537225f9e7d5c90/lib/email/sender.rb#L179-L181

Мы можем просто оставить их — это не повредит и поможет при визуальной отладке!

Меня это вполне устраивает. Мне просто показалось особенно сложным связать заголовки электронных писем с постами, так как post.id не виден ни в интерфейсе, ни в URL конкретного поста в веб-версии. Наличие этой информации в дополнительном заголовке контекста было бы не менее эффективным.

Спасибо,
Кэмерон

1 лайк

Просто короткое напоминание — PR уже довольно давно без изменений. — Кэмерон

Привет, Кэмерон! Я был на корпоративной встрече, а затем уезжал в отпуск на последние две недели, сегодня только начал возвращаться в рабочий ритм. Если это не будет слито на этой неделе, то точно будет на следующей. Извини за задержки!

От Мартина Бреннана через Discourse Meta, 20 сен 2022, 00:17:

Привет, Кэмерон, я был на корпоративной встрече, а затем ушёл в отпуск на
последние две недели. Сегодня только начинаю втягиваться в рабочий ритм. Если это
не будет слито на этой неделе, то точно будет слито на следующей.
Извините за задержки!

Нет необходимости извиняться. Я знал, что вы были в отъезде, но не был уверен в сроках вашего возвращения. И, наверное, у вас всё ещё понедельник :frowning:

Спасибо,
Кэмерон Симпсон cs@cskk.id.au

2 лайка

Я только что принял PR. Сегодня позже я постараюсь развернуть форум на Python, чтобы вы могли начать им активно пользоваться.

1 лайк

От имени Мартина Бреннана через Discourse Meta, 25 сен 2022, 23:29:

Я только что объединил PR, сегодня позже постараюсь развернуть форум на Python, чтобы вы могли начать им полноценно пользоваться.

Это было бы замечательно. Спасибо, Кэмерон.

2 лайка

Это уже сделано. Если у вас возникнут какие-либо проблемы, пожалуйста, сообщите об этом здесь :+1:

2 лайка

Спасибо. Я дам знать, как это выглядит. Кэмерон