Discourse Automation

:discourse2: Summary Discourse Automation lets you automate actions through scripts and triggers. Customisation is made through an automatically generated UI.
:hammer_and_wrench: Repository Link https://github.com/discourse/discourse-automation
:open_book: Install Guide How to install plugins in Discourse

Features

  • Easy automation of complex workflows
  • Triggers automations at specific dates, periodically, or on specific events
  • Provides automatically generated UIs to specify options for your automation

Vocabulary

  • trigger: represents the name of the trigger, eg: user_added_to_group
  • triggerable: represents the code logic associated to a trigger, eg: triggers/user_added_to_group_.rb
  • script: represents the name of the script, eg: send_pms
  • scriptable: represents the code logic associated to a script, eg: scripts/send_pms.rb

Configuration

Automations can be created and updated from Admin → Plugins → Automations, or directly from /admin/plugins/discourse-automation.

Available scripts

Script name Plugin Description
Banner Topic automation convert a topic into a banner notice
Flag post on Words automation flag a topic on creation/edition if it contains specific words
Gift Exchange automation simple implementation of the secret santa game
Pin Topic automation pin and unpin a topic in the future
Send PMs automation send PMs with support for placeholders
Suspend User By Email automation suspend a user for a specified duration
Topic required words automation enforce the presence of at least one of the specified words in the posts of a topic
Auto Responder automation given a series of keywords and associated replies, automatically respond with the corresponding reply
User Global Notice automation presents a global notice on the site for a specific user
Random Assign assign assign a random user from a given group to the given topic
Close topic automation close a topic, optionally with a closing message

Available triggers

Note that due to their nature, each script only supports certain triggers. For example it wouldn’t make sense for a script enforcing the content of a post to trigger when a user is added to a group.

Trigger name Plugin Description
API Call automation triggers when a certain API endpoint is called
Recurring automation triggers at intervals ranging from every minute to every year
Point in Time automation triggers at a specific date and time
Post created/edited automation triggers when a post of a specified topic is created or edited
User added to group automation triggers when a user is added to a group
User promoted automation triggers when a user is promoted from one specified trust level to another, or for all of them
Stalled wiki automation triggers when a wiki hasn’t been edited for a while
First accepted solution solved triggers when a user achieves their first accepted solution

More scripts and triggers to come!

Plugin API

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

Scriptable API

field

field :name, component: lets you add a customisable value in your automation’s UI.

List of valid components:

# foo must be unique and represents the name of your field.

field :foo, component: :text # generates a text input
field :foo, component: :list # generates a multi select text input where users can fill values
field :foo, component: :choices, extra: { content: [ {id: 1, name: 'your.own.i18n.key.path' } ] } # generates a combo-box with a custom content
field :foo, component: :boolean # generate a checkbox input
field :foo, component: :category # generates a category-chooser
field :foo, component: :group # generates a group-chooser
field :foo, component: :date_time # generates a date time picker
field :foo, component: :tags # generates a tag-chooser
field :foo, component: :user  # generates a user-chooser
field :foo, component: :pms  # allows to create one or more PM templates
field :foo, component: :categories  # allows to select zero or more categories
field :foo, component: :key-value  # allows to create key-value pairs
field :foo, component: :message  # allows to compose a PM with replaceable variables
field :foo, component: :trustlevel  # allows to select one or more trust levels
triggerables and triggerable!
# Lets you define the list of triggerables allowed for a script
triggerables %i[recurring]

# Lets you force a triggerable for you script and also lets you force some state on fields
field :recurring, component: :boolean
triggerable! :recurring, state: { foo: false }
placeholders
# Lets you mark a key as replaceable in texts using the placeholder syntax `%%sender%%`
placeholder :sender

Note that it’s the responsibility of the script to provide values for placeholders and to apply the replacement using input = utils.apply_placeholders(input, { sender: 'bob' })

script

This is the heart of an automation and where all the logic happens.

# context is sent when the automation is triggered, and can differ a lot between triggers
script do |context, fields, automation|
end

Localization

Each field you will use will depend on i18n keys and will be namespaced to their trigger/script.

For example a scriptable with this content:

field :post_created_edited, component: :category

Will require the following keys in 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

Note that description is optional here.

60 Likes

Can you provide any insight on what the ā€œreportā€ is in the context of the gift exchange?

I’m hoping to let users can fill out some sort of form that gives some ideas to the gift buyer. Really hoping that is what this is :slight_smile:

Report is a general helper, which can display a report by its name as seen in the admin. It’s a kind of beta feature ATM as it doesnt support every use cases.

I dont think we have any existing specific report for secret santa.

1 Like

2 posts were split to a new topic: Automation not respecting encrypt/not encrypt for auto-pms

Wow this is really cool - I wish I’d come across this earlier! I’m grateful it’s included on business plan.

Can it post different replies on a certain schedule? It seems not yet though, from what I see in the description.

For the purpose i’m thinking of:

We have icebreakers and other fun prompts for public topics. What we currently do is very manual:

  • we have a private topic by leaders & staff, where we reply with different icebreaker prompts
  • each day, when it’s time to choose an icebreaker, we change the timestamp of the topic to the current time
  • then we split out the relevant post and move it to the public Icebreaker topic, and @mention the icebreaker group on our community

This is the same process for several community topics and events that we have.

It would be nice if we could have a way to submit a list of posts to be automatically posted as replies on another topic, on a recurring basis (e.g. daily).

Let me know if this is possible with this automation plugin! If not, I’d like to add as a feature request — the ability to schedule a list of replies to a topic in some way.

Edit: I just noticed the new setup for official plugins on Meta. I can create a new feature request / support topic depending on what fits, or also feel free to move this reply to the right category.

1 Like

It looks like our use case is covered! Discourse Team set up the plugin on our forum since it was missing.

I just had to make new automations to schedule different replies, rather than reuse the same one.

4 Likes

This is an awesome plugin for Discourse to automate things.

I had a question in regards auto reply:

Defines a list of key/value groups, where the key is the searched term, and value the text of the reply. Note that value accepts %%KEY%% as a placeholder to be replaced by the value of key in the reply. Note that key will be evaluated as a regex, and special chars like . should be escaped if you actually mean a dot, eg: \.

Is already included, but can it also be added that the reply tags the @username.

1 Like

Is this available with this plugin?

Hi!

The autoresponder replies to the specific post of the user, meaning they will get a reply notification, and it will also be recorded that the post replies to that specific post; just like this post shows that I replied to your post in particular:

image

Is there a particular reason you want to add an explicit @ mention to the user in the text, like @Festinger, in addition to all the above?

3 Likes

Is it possible to create own scripts without any problem? Just putting it in the folder and with the plugin updates, nothing happens? Or do i have to create a plugin that interfaces with this plugin? For example, I need a script to create a topic. There is a post creation script but I need to create automatic topics. Thanks!

2 Likes

Yes it needs a plugin to define a custom script.

Something like this in plugin.rb

after_initialize do
  if defined?(DiscourseAutomation)
    add_automation_scriptable("my_custom_script") do
      # ...
    end
  end
end
2 Likes

I tried but it says:

Couldn’t find script lb-script for automation testing, ensure the associated plugin is installed

Maybe I’m wrong, but should I create a separate file or is it okay to put everything in the plugin.rb file?

1 Like

Show me some code or it will be hard for me to help you :slight_smile:

1 Like

I just tried with the post script copied from the scripts folder of the Automation plugin:

after_initialize do
    if defined?(DiscourseAutomation)
        add_automation_scriptable("lb-script") do
            version 1

            placeholder :creator_username
          
            field :creator, component: :user
            field :topic, component: :text, required: true
            field :post, component: :post, required: true
          
            triggerables %i[recurring point_in_time]
          
            script do |context, fields, automation|
              creator_username = fields.dig("creator", "value") || Discourse.system_user.username
          
              placeholders = { creator_username: creator_username }.merge(context["placeholders"] || {})
          
              creator = User.find_by!(username: creator_username)
          
              PostCreator.new(
                creator,
                topic_id: fields.dig("topic", "value"),
                raw: fields.dig("post", "value"),
              ).create!
            end
        end
    end
end

I lack context around what you are doing here, here is a full blown example in an external plugin: discourse-assign/plugin.rb at main Ā· discourse/discourse-assign Ā· GitHub

1 Like

I don’t understand what the difference is compared to what I did. Obviously I used the post script just to see if it worked. But when I go to create an automation, it doesn’t find me any trigger and it says it can’t find the script. But the code should let me select between the 2 triggers to create a post, right? I’m definitely wrong but I don’t really understand.

are you sure your new plugin is enabled?

Yes, of course. It is absolutely enabled.

Can you try to use assign locally and see if you manage to get to show in the list? If not theres something else going on.

I can confirm that Random Assign works even if the Assign plugin is not enabled. There’s probably something I’m missing, I don’t want to waste your time.

2 Likes