通过 API 调用创建分阶段用户

我们目前的工作流程是:用户通过向自定义的收件邮箱发送电子邮件来提交数据,从而创建一个临时用户并向 Discourse 群组发送一条私信。

是否可以通过 API 调用来实现相同的工作流程?具体来说:1) 创建临时用户,2) 为该用户生成 API 密钥,然后 3) 以该用户的名义发帖?我在 API 文档中看到如何为现有用户发布群组消息,但不确定步骤 1) 和 2) 目前是否可行。

4 个赞

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 ...
10 个赞

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.

8 个赞

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

1 个赞

能否具体说明,在调用 /admin/email/handle_email API 创建暂存用户并代表其创建主题时,需要包含哪些请求头和字段?

另外,我理解得对吗?这样的用户会收到该主题中新帖子的通知,并且可以通过电子邮件回复该主题?

如果尝试通过 API 调用使用属于活跃用户的邮箱地址来创建暂存用户和主题,会发生什么情况?该主题是否会代表该活跃用户创建?

我已经查到正确的端点是 /admin/email/handle_mail(而不是 handle_email),但仍然不清楚 API 请求中应该包含什么内容。

1 个赞

此端点接受的唯一参数是有效的 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,并设置好类别或群组以接收这些邮件:

是的,我认为是这样。

是的,该主题将以该用户的名义创建。

5 个赞

谢谢,Blake。不过,这对我来说仍然不起作用。我收到了 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 调用创建的邮件出现在上述某个标签页中,这样或许可以看到与之关联的错误信息。

1 个赞

是的,Sidekiq 正在运行。我检查了 /admin/email 选项卡,看起来我的“邮件”实际上被拒绝了。
我得到的是:

我在“高级文本”选项卡中插入了相同的邮件文本,如果日期、发件人、收件人、主题每个部分都从新行开始,并且正文由两个换行符分隔,它似乎可以正常工作。当完全按照 curl 中的方式插入文本时,它返回为空。这是否是原始邮件中的换行符问题?如果是,我该怎么办?

我尝试了 /n%0A$'[text/n]',但都不起作用。

我不太确定。看起来它不接受您邮件中的任何字段。

我使用 Ruby 生成了 curl 命令,并用 Ruby 读取了我编写的邮件文本文件,但看起来确实是一个换行符的问题。

您能让 curl 读取包含实际换行符的邮件文件 吗?

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

3 个赞

你说得对——这确实是个换行符的问题。我尝试从 Postman 发出相同的 API 调用,结果成功了:创建了一个新的暂存用户,并以他的名义创建了一个主题。

但是:没有向该用户的邮箱发送任何邮件!我还在该主题下发布了一条评论,同样没有收到邮件通知。是否有某个设置阻止了邮件发送?我尝试查找相关设置,但没找到。

更新:确实有一个设置阻止了帖子通知的发送 :slight_smile: 所以现在我有两个不同的问题:

  1. 为什么没有发送邮件告知暂存用户主题已创建,并提供该主题的链接?
    (如果我知道的话,我还会添加一些关于如何登录论坛的说明,以及需要编辑哪个模板。)
  2. 为什么帖子通知邮件中没有主题的链接?也没有取消订阅链接。
    模板似乎是一样的——“user_posted”。

对于跟进此事的各位,具体是哪个设置呢?我想我并没有修改过任何内容,只是出于好奇。

我认为这是系统设计如此,这与向 Discourse 群组发送邮件的情况相同。其设计初衷就是像普通邮件一样运作,即用户甚至可能不知道自己正在向 Discourse 论坛发送邮件。如果我给您发一封普通邮件到您的邮箱,您的邮件服务商不会回复确认您已收到邮件,我们只是默认它能正常工作。

以下是临时用户将收到的示例邮件通知:

但非临时用户收到的内容如下:

临时用户与非临时用户之间似乎存在差异。很可能是因为用户处于临时状态,其行为应完全等同于通过普通邮件进行交互。

2 个赞

实际上有好几个。

  • 默认邮件级别 - 默认为“仅在离开时”
  • 邮件时间窗口 - 默认为 10 分钟,因此通知邮件不会立即发送
  • 禁用邮件 - 默认为“否”,但我之前曾更改过并忘记了它::man_facepalming:

嗯,对我来说,帖子通知看起来并不像普通电子邮件——例如,它包含两次指向帖子作者论坛个人资料的链接,但没有指向主题的链接。

此外,我希望告知处于暂存状态的用户,他实际上可以登录论坛。
有没有办法自定义此电子邮件模板?

根据设计,在邮件模板中(例如回复说明),为“暂存用户”省略了若干字段:

我不完全确定这样设计的原因,但代码确实如此。因此,您目前面临的是逆风局,因为您试图实现 Discourse 本身设计为不执行的功能。

是的,您可以编辑邮件模板,但可自定义的范围相当有限。例如,我认为无法让邮件模板对暂存用户和非暂存用户呈现不同的样式。不过,您可以在通知邮件的底部添加一条带有链接的消息,邀请他们访问您的网站,而不是仅通过邮件进行互动。

1 个赞

其实,只要模板对普通用户和试用用户显示完全一致就足够了:slight_smile:
我会想想能做些什么。感谢你的详细解释!

3 个赞

最后一个问题(希望如此):被创建话题的代理用户如何取消订阅该话题的新帖子?