Creating a staged user with an API call

We currently have a workflow where users submit data by sending an email to a custom incoming email address, creating a staged user and a private message to a Discourse group.

Is it possible to achieve the same workflow using API calls? Basically 1) create staged user, 2) generate API key for that user, then 3) post on that users behalf? I see how to post group messages for existing users using the API docs, but don’t know if steps 1) and 2) are possible currently.

Yes, just create a user via the api. They won’t be “staged” at this point since they actually exist. If they ever need to log in, they can just reset their password.

This is also possible


Here is a rough example of how to create a user, active them, and generate an api key for them.
    def create_user
      user = {
        name: example1,
        email: "example1@example.com",
        password: "ZvAmmkcSWQfsPQLBksg7wK59",
        username: example1,
        active: "false",
        approved: "true",
        approved_by_id: 1,
        approved_at: DateTime.now
      }

      new_user = @client.create_user(user)
      id = new_user['user_id']
      @client.activate(id)
      uri = URI.parse(@config.full_discourse_url)
      http = Net::HTTP.new(uri.host, uri.port)
      http.use_ssl = true
      request = Net::HTTP::Post.new("/admin/users/#{id}/generate_api_key?api_key=#{@client.api_key}&api_username=#{@client.api_username}")
      response = http.request(request)
      result = JSON.parse(response.body)
    end

Another option instead of generating an api key for each user is you can just instantiate a new discourse client using the same admin api key and just specify the new username:

client = DiscourseApi::Client.new("http://127.0.0.1:3000")
client.api_key = "a71cb5058c6be27e42806ad788bc7b0008af9c15170d1be1827a24c8e8334107"
client.api_username = "system"

... create user here...

client2 = DiscourseApi::Client.new("http://127.0.0.1:3000")
client2.api_key = "a71cb5058c6be27e42806ad788bc7b0008af9c15170d1be1827a24c8e8334107"
client2.api_username = example1

... create post here ...

I’m trying to avoid creating a full-fledged user account and picking a username. Essentially I want to replicate whatever is happening in the email trigger (‘custom incoming email address’ in the group settings) where the sender’s email address will be ‘staged,’ such that if/when they do register, they’ll be able to claim any messages that were created on their behalf via the email trigger.

Does that make sense? Is there a way to ‘spoof’ an incoming email using API calls? Thanks for all your help!

You might just have to generate an email and send that to your Discourse instance.

EDIT: Actually there is an /admin/email/handle_mail POST route that you can send an API request to.

Thank you, this is exactly what I was looking for!

Можете уточнить, какие заголовки и поля должны быть в API-вызове к /admin/email/handle_email для создания временного пользователя и темы от его имени?

Также правильно ли я понял, что такой пользователь будет получать уведомления о новых сообщениях в этой теме и сможет отвечать на них по электронной почте?

И что произойдет, если я попытаюсь создать временного пользователя и тему через API-вызов с адресом электронной почты, который принадлежит активному пользователю? Будет ли эта тема создана от имени такого пользователя?

Я уже выяснил, что правильный эндпоинт — /admin/email/handle_mail (а не handle_email), но всё ещё не могу понять, что должно быть в API-запросе.

Единственный параметр, который принимает этот эндпоинт, — это корректное сообщение email:

curl -i -sS -X POST "http://localhost:3000/admin/email/handle_mail" \
-H "Api-Key: 852b2d8556777aeb62346e0d8b36ed248a89b03f0261165a685c0aae9c8c2fdd" \
-H "Api-Username: system" \
-F "email=Date: Mon, 24 Feb 2020 13:13:34 -0700
From: stageduser2@example.com
To: awesome@example.com
Subject: test email5

This is a sample email message.
"

Вам необходимо убедиться, что email_in включён, а категория или группа правильно настроены для получения таких писем:

Да, я так считаю.

Да, тема будет создана от имени этого пользователя.

Спасибо, Блейк. Однако у меня всё ещё не работает. Я получил ответ от API: «email has been received and is queued for processing», но в Discourse ничего не появилось — ни новой темы, ни созданного пользователя.

Вот обзор настроек:
Глобальные:

  • email_in: включено
  • email_in_min_trust: 0
  • enable_staged_users: включено

Категория:

  • Пользовательский адрес входящей почты: установлен как [my_name]@gmail.com
  • Принимать письма от анонимных пользователей без аккаунтов: включено

Вызов API:
curl -i -sS -X POST "[my_domain]/admin/email/handle_mail" -H "Content-Type: multipart/form-data;" -H "Api-Key: [...]" -H "Api-Username: system" -F "email=Date: Mon, 24 Feb 2020 13:13:34 -0700 From: [some_name]@gmail.com To: [my_name]@gmail.com Subject: test API email post This is a sample email message."

Что может быть не так?

Работает ли ваш Sidekiq корректно?

Как я могу это проверить?

Вы можете проверить, запущен ли Sidekiq, перейдя по адресу /sidekiq, но, вероятно, сейчас проблема с необработанными письмами, так как запрос к API выполняется успешно. В панели администратора есть несколько вкладок, где можно проверить ошибки отправки писем:

  • /admin/email/sent
  • /admin/email/skipped
  • /admin/email/bounced
  • /admin/email/received
  • /admin/email/rejected

Попробуйте найти созданные вами через API письма на одной из этих вкладок — возможно, вы увидите связанное с ними сообщение об ошибке.

Да, Sidekiq запущен. Я проверил вкладку /admin/email — похоже, что мои «письма» фактически отклоняются.
Вот что я получаю:

Я вставил тот же текст письма во вкладку «Advanced text», и, похоже, всё работает, если каждая часть (Date, From, To, Subject) начинается с новой строки, а тело письма отделено двумя разрывами строк. При вставке текста точно так же, как в curl, возвращается пустой результат. Может ли дело быть в разрывах строк в сыром письме? Если да, что мне следует сделать?

Я пробовал /n, %0A и $'[text/n]', но ни один из вариантов не сработал.

Я не уверен. Похоже, что ни одно из полей в вашем письме не принимается.

Я использовал Ruby для генерации команды curl и для чтения текстового файла с письмом, который я создал, но да, похоже, проблема именно в переносе строки.

Можете ли вы заставить curl прочитать файл с письмом, содержащий реальные переносы строк?

curl -X POST -i -F parametername=@filename host:port/xxx

Вы были правы — это была проблема с переносом строки. Я попробовал тот же вызов API из Postman, и он сработал: был создан новый пользователь в режиме ожидания и создана тема от его имени.

Но: письмо не было отправлено на адрес этого пользователя! Я также оставил комментарий в теме — уведомления по электронной почте тоже не пришло. Есть ли настройка, которая это блокирует? Я пытался её найти, но не смог.

ОБНОВЛЕНИЕ: Действительно, существовала настройка, которая предотвращала отправку уведомлений о новых постах :slight_smile: Теперь у меня два разных вопроса:

  1. Почему не было отправлено письмо новому пользователю с уведомлением о создании темы и ссылкой на неё?
    (Я бы также добавил инструкции о том, как войти на форум, если бы знал, какой шаблон нужно редактировать.)
  2. Почему в письмах с уведомлениями о новых постах нет ссылки на тему? Также отсутствует ссылка для отписки.
    Кажется, используется один и тот же шаблон — “user_posted”.

Какая именно настройка? Для тех, кто следит за обсуждением. Мне кажется, я ничего не менял, так что просто из любопытства.

Думаю, это сделано намеренно. То же самое происходит, если отправить письмо группе в Discourse. Система спроектирована так, чтобы работать как обычная электронная почта: пользователь может даже не осознавать, что отправляет сообщение на форум Discourse. Если я отправляю вам обычное письмо на ваш почтовый ящик, я не получаю подтверждения от вашего почтового провайдера о том, что письмо получено; мы просто доверяем тому, что оно дойдёт.

Вот пример уведомления по электронной почте, которое получит пользователь на этапе создания (staged user):

А вот что получит пользователь, не находящийся на этапе создания (non-staged user):

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

На самом деле их было несколько.

  • default email level — по умолчанию установлено «только при отсутствии»
  • email time window — по умолчанию 10 минут, поэтому уведомление по электронной почте отправляется не сразу
  • disable emails — по умолчанию «нет», но я ранее менял эту настройку и забыл об этом :man_facepalming:

Что ж, для меня уведомление о посте всё равно не похоже на обычное письмо — например, в нём дважды есть ссылка на профиль автора поста на форуме, но нет ссылки на тему.

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

По замыслу в шаблонах электронной почты для пользователей на этапе модерации пропускается несколько полей (например, инструкции для ответа):

Я не до конца уверен в причинах такого решения, но просто констатирую факт: в коде реализовано именно так. Поэтому в данной ситуации вы ведете неравную борьбу, пытаясь сделать то, что Discourse спроектирован не делать.

Да, вы можете отредактировать шаблоны электронной почты, но возможности кастомизации у вас сильно ограничены. Например, я не думаю, что можно настроить шаблон письма так, чтобы он выглядел по-разному для пользователей на этапе модерации и для остальных. Однако вы можете добавить сообщение со ссылкой в конец уведомления, пригласив их посетить ваш сайт вместо того, чтобы взаимодействовать только через электронную почту.

На самом деле, было бы достаточно, если бы шаблон выглядел одинаково для обычных и тестовых пользователей :slight_smile:
Я подумаю, что можно сделать. Спасибо за подробное объяснение!

Один последний вопрос (надеюсь): как пользователь, созданный вручную, может отписаться от получения новых сообщений в теме, созданной от его имени?