创建自定义自动化

:information_source: 这是草稿,可能需要一些额外的工作。

词汇表

  • trigger: 代表触发器的名称,例如:user_added_to_group
  • triggerable: 代表与触发器相关的代码逻辑,例如:triggers/user_added_to_group_.rb
  • script: 代表脚本的名称,例如:send_pms
  • scriptable: 代表与脚本相关的代码逻辑,例如:scripts/send_pms.rb

插件 API

add_automation_scriptable(name, &block)
add_automation_triggerable(name, &block)

Scriptable API

field

field :name, component: 允许您在自动化界面中添加可自定义的值。

有效组件列表:

# foo 必须是唯一的,并且代表您的字段名称。

field :foo, component: :text # 生成一个文本输入框
field :foo, component: :list # 生成一个多选文本输入框,用户可以在其中填写值
field :foo, component: :choices, extra: { content: [ {id: 1, name: 'your.own.i18n.key.path' } ] } # 生成一个带有自定义内容的组合框
field :foo, component: :boolean # 生成一个复选框输入框
field :foo, component: :category # 生成一个类别选择器
field :foo, component: :group # 生成一个组选择器
field :foo, component: :date_time # 生成一个日期时间选择器
field :foo, component: :tags # 生成一个标签选择器
field :foo, component: :user  # 生成一个用户选择器
field :foo, component: :pms  # 允许创建一种或多种 PM 模板
field :foo, component: :categories  # 允许选择零个或多个类别
field :foo, component: :key-value  # 允许创建键值对
field :foo, component: :message  # 允许使用可替换变量编写 PM
field :foo, component: :trustlevel  # 允许选择一个或多个信任级别
triggerables 和 triggerable!
# 允许您定义脚本允许的 triggerables 列表
triggerables %i[recurring]

# 允许您强制为脚本设置 triggerable,还可以强制设置字段的某些状态
field :recurring, component: :boolean
triggerable! :recurring, state: { foo: false }
placeholders
# 允许您使用占位符语法 `%%sender%%` 将键标记为文本中的可替换项
placeholder :sender

请注意,脚本有责任为占位符提供值,并使用 input = utils.apply_placeholders(input, { sender: 'bob' }) 应用替换。

script

这是自动化的核心,也是所有逻辑发生的地方。

# context 在触发自动化时发送,并且可能因触发器而异
script do |context, fields, automation|
end

本地化

您将使用的每个字段都将依赖于 i18n 键,并根据其触发器/脚本进行命名空间化。

例如,一个具有以下内容的 scriptable:

field :post_created_edited, component: :category

将在 client.en.yml 中需要以下键:

en:
  js:
    discourse_automation:
      scriptables:
        post_created_edited:
          fields:
            restricted_category:
              label: Category
              description: Optional, allows to limit trigger execution to this category

请注意,这里的 description 是可选的。


本文档受版本控制 - 在 github 上建议更改。

7 个赞

当我看到这是一个新话题时,我感到很兴奋:我以为分享了更多细节!:laughing:

作为一个不编写 Ruby 代码但对工作流自动化非常感兴趣的人,我希望能通过示例理解得更多一些……

:thinking:

看来我需要从 Developing Discourse Plugins - Part 1 - Create a basic plugin 开始…… :sweat_smile:

8 个赞

我基本上只是从插件主题中删除了这一部分,这样就不会显得你需要了解它才能使用现有的插件。:slight_smile:

我同意,如果这能更具指导性就更好了。我已经向社区发出了求助信号,看看是否有人有这方面的经验: :crossed_fingers:

5 个赞

一个“hello world”示例会很棒。
脚本应该存放在哪里?我想尝试一下。

4 个赞

我认为您可以使用 Chat GPT 和此插件编写自定义脚本。

也许最好的起点是查看添加到 Data Explorer 插件的自动化脚本:discourse-data-explorer/plugin.rb at main · discourse/discourse-data-explorer · GitHub Automation 插件现有的脚本和触发器:https://github.com/discourse/discourse-automation/tree/main/lib/discourse_automation

由于 Meta 上关于添加自定义自动化的信息不多,这里有一个 plugin.rb 文件示例,它添加了一个脚本来更新用户的“活动摘要”电子邮件偏好设置。该脚本可以由 Automation 插件的“user_added_to_group”或“user_removed_from_group”触发器触发。

# frozen_string_literal: true

# name: automation-script-example
# about: An example of how to add a script to an automation
# version: 0.0.1
# authors: scossar

enabled_site_setting :automation_script_example_enabled

after_initialize do
  reloadable_patch do
    if defined?(DiscourseAutomation)
      DiscourseAutomation::Scriptable::USER_UPDATE_SUMMARY_EMAIL_OPTIONS =
        "user_update_summary_email_options"
      add_automation_scriptable(
        DiscourseAutomation::Scriptable::USER_UPDATE_SUMMARY_EMAIL_OPTIONS
      ) do

        field :email_digests, component: :boolean

        version 1
        triggerables [:user_added_to_group, :user_removed_from_group]

        script do |context, fields, automation|
          if automation.script == "user_update_summary_email_options" && (context["kind"] == "user_added_to_group" || context["kind"] == "user_removed_from_group")
            user_id = context["user"].id
            digest_option = fields.dig("email_digests", "value")
            user_option = UserOption.find_by(user_id: user_id)

            if (user_option)
              user_option.update(email_digests: digest_option)
            end
          end
        end
      end
    end
  end
end

完整的插件代码在这里:https://github.com/scossar/automation-script-example。

:warning: 请不要在生产环境中使用此代码。我直到今天晚上才查看 Automation 代码。如果我发现有关代码潜在问题的反馈,我会更新此帖子和 GitHub 仓库。

编辑:我担心的是如何最好地处理由“user_added_to_group”或“user_removed_from_group”触发器触发的多个自动化脚本的情况。插件的初始版本检查了:

fields.has_key?("email_digests")

但这感觉有点不可靠。如果添加了另一个也具有 email_digests 键的脚本怎么办?

更新后的代码将 automation 参数传递给代码块并进行检查:

automation.script == "user_update_summary_email_options"

这应该可以确保脚本不会为错误的自动化运行。

……再想一想,脚本不太可能被它未配置的自动化触发 :slight_smile:

7 个赞

我也想知道——一旦你创建了一个像 @simon 那样的仓库,插件如何访问它?

我们是否必须 fork 整个插件并将其与 https://github.com/discourse/discourse-automation/tree/main/lib/discourse_automation/scripts 中的现有脚本一起放置?或者有更优雅的方法?

1 个赞

你需要像安装其他 Discourse 插件一样安装它:在 Discourse 中安装插件。所以你会安装 Automation 插件并安装你添加自定义脚本的插件。它之所以能工作,是因为这里定义的方法:https://github.com/discourse/discourse-automation/blob/main/lib/plugin/instance.rb。在我上面发布的示例代码中,你会看到自定义脚本是通过调用 add_automation_scriptable 来添加的。

注意:不要安装我 GitHub 仓库中的示例自动化,仅将其作为如何扩展 Automation 插件的示例。(我忘了我在这里链接了它,并已更新,使其仅与我 fork 的 Discourse Automation 插件版本一起使用。但我链接到这里的代码仍然有效:Create custom Automations - #6 by simon automation-script-example 插件,使其无需我 fork 的 Automation 插件版本所做的更改即可工作。)

我的担忧是没有根据的。这个条件不是必需的:

if automation.script == "user_update_summary_email_options" && (context["kind"] == "user_added_to_group" || context["kind"] == "user_removed_from_group")

我将很快更新示例。

4 个赞

我是否正确地理解,自定义自动化需要自托管安装(或以其他方式直接访问安装 Discourse 的文件系统的后端)?

2 个赞

是的,但我们非常乐意将新的自动化脚本合并到社区构建中,您打算构建什么?

6 个赞

具体来说,我们正在寻找一种方法来替换帖子中的特定字符串(我们不太关心确切的语法,但类似于纯文本 @ref `Random.rand!` )为一个格式化的链接,例如 Random.rand!。查找确切的 URL 是一个复杂的过程,有数万个可能的 target,使用正则表达式(如自动链接单词/监视单词那样)完全不可行,而在图灵完备的类插件环境中则容易得多……所以我很好奇自动化是否可以做到这一点。

因此,我正在寻找一个帖子编辑操作,有点类似于 @system 用户在引用整个先前帖子时所做的操作(见此处)。它将是一个“编辑帖子”脚本,在“帖子创建”(或可能在帖子渲染后)时触发……但我认为自动化框架不允许这种通用的“帖子编辑”操作。我认为它需要一个非常具体的链接到 Julia 文档的自定义自动化,这在社区构建中当然没有意义。

我可能在自定义自动化的方面走错了方向;我只是在探索可能的功能。当然,作为一个面向编程语言爱好者的论坛,勇敢的用户已经在考虑使用 discourse API 来编写 bot 来完成这项工作。

1 个赞

我不确定自动化是否是您想要的,因为这里感觉很关键的是“最终用户”体验。通过自动化,这只会事后被替换。

在思考这类问题时,我可能会建议使用自定义插件或主题组件。

主题组件可以这样工作:

  1. 用户输入:^Rand
  2. 向您托管的后端服务发出 HTTP 调用,该服务列出了所有带有 URL 的选项
  3. 用户选择他们想要的选项并按 Enter 键
  4. Markdown 被替换为 [Random.rand!](https://docs.julialang.org/en/v1/stdlib/Random/#Random.rand!)

可以修改 Markdown 管道的插件可以类似于 onebox,在您键入时自动链接,保留原始语法。例如:^Random.rand

我理解您对 linkify 的看法并不理想,发现很难,而且您可能需要托管一个网站,以便将其规范化为 lookup.docs.julialang.org?q=Random.rand!

这无疑是一个非常有趣的问题。我认为主题组件的用户体验在这里是合理的。

2 个赞

这太棒了,感谢您的想法和建议!如果我以后有更多问题(或答案: )),我会另开一个话题讨论。

2 个赞

我认为您想创建一个在帖子更改时触发的自定义插件。我怀疑对于您的用例,它有一个简单的触发器,编写插件比使用自动化插件要容易。

1 个赞

@McUles@nathank 你们找到需要的信息了吗?

为了使自定义自动化生效,我必须修改以下文件:

创建自定义自动化脚本

更新:server.en.yml

在 yml 文件的 scriptables 部分添加了自定义自动化名称、标题和描述。

更新:client.en.yml

在 scriptables 中添加了自定义自动化名称;添加了‘field’关键字;在 field 关键字内添加‘field_name’,后跟‘label’和‘description’。

更新:scripts.rb

在脚本列表中添加了自定义自动化名称。示例:FILE_NAME = “file_name”

更新:plugin.rb

在‘after_initialize do’内,添加了自定义自动化脚本的路径。示例:‘lib/discourse_automation/scripts/file_name’

我不太明白你写的是什么——这些是对 Automations 插件的修改,还是包含自定义自动化的姊妹插件的重要组成部分?

如果能将这些内容合并到 原始帖子 中就太好了。

2 个赞

就是这样。我其实不知道你问题的答案,所以这是我找到答案的方法,也是对“有没有一个我可以看到的例子?”的回答。

首先,获取这个:GitHub - discourse/all-the-plugins

然后你 grep 搜索一些东西,比如“add_automation_scriptable”,然后你就可以找出是什么在使用它。

 (main) pfaffman@noreno:~/src/discourse-repos/all-the-plugins/official$ grep -r add_automation_scriptable
discourse-assign/plugin.rb:    add_automation_scriptable("random_assign") do
discourse-chat-integration/plugin.rb:    add_automation_scriptable("send_slack_message") do
discourse-chat-integration/plugin.rb:    add_automation_scriptable("send_chat_integration_message") do
discourse-data-explorer/plugin.rb:      add_automation_scriptable("recurring_data_explorer_result_pm") do
discourse-data-explorer/plugin.rb:      add_automation_scriptable("recurring_data_explorer_result_topic") do

所以也许可以看看 discourse-assigndata-explorer

2 个赞