Crea automazioni personalizzate

:information_source: Questa è una bozza e potrebbe richiedere ulteriori lavori.

Vocabolario

  • trigger: rappresenta il nome del trigger, ad es. user_added_to_group
  • triggerable: rappresenta la logica del codice associata a un trigger, ad es. triggers/user_added_to_group_.rb
  • script: rappresenta il nome dello script, ad es. send_pms
  • scriptable: rappresenta la logica del codice associata a uno script, ad es. scripts/send_pms.rb

API Plugin

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

API Scriptable

field

field :name, component: ti consente di aggiungere un valore personalizzabile nell’interfaccia utente della tua automazione.

Elenco dei componenti validi:

# foo deve essere univoco e rappresenta il nome del tuo campo.

field :foo, component: :text # genera un input di testo
field :foo, component: :list # genera un input di testo a selezione multipla in cui gli utenti possono inserire valori
field :foo, component: :choices, extra: { content: [ {id: 1, name: 'your.own.i18n.key.path' } ] } # genera una casella combinata con contenuto personalizzato
field :foo, component: :boolean # genera un input checkbox
field :foo, component: :category # genera un selettore di categorie
field :foo, component: :group # genera un selettore di gruppi
field :foo, component: :date_time # genera un selettore di data e ora
field :foo, component: :tags # genera un selettore di tag
field :foo, component: :user  # genera un selettore di utenti
field :foo, component: :pms  # consente di creare uno o più modelli di PM
field :foo, component: :categories  # consente di selezionare zero o più categorie
field :foo, component: :key-value  # consente di creare coppie chiave-valore
field :foo, component: :message  # consente di comporre un PM con variabili sostituibili
field :foo, component: :trustlevel  # consente di selezionare uno o più livelli di fiducia
triggerables e triggerable!
# Consente di definire l'elenco dei triggerable consentiti per uno script
triggerables %i[recurring]

# Consente di forzare un triggerable per il tuo script e anche di forzare alcuni stati sui campi
field :recurring, component: :boolean
triggerable! :recurring, state: { foo: false }
placeholders
# Consente di contrassegnare una chiave come sostituibile nei testi utilizzando la sintassi placeholder `%%sender%%`
placeholder :sender

Nota che è responsabilità dello script fornire valori per i placeholder e applicare la sostituzione utilizzando input = utils.apply_placeholders(input, { sender: 'bob' })

script

Questo è il cuore di un’automazione e dove avviene tutta la logica.

# context viene inviato quando l'automazione viene attivata e può differire molto tra i trigger
script do |context, fields, automation|
end

Localizzazione

Ogni campo che utilizzerai dipenderà dalle chiavi i18n e sarà raggruppato per trigger/script.

Ad esempio, uno scriptable con questo contenuto:

field :post_created_edited, component: :category

Richiederà le seguenti chiavi in client.en.yml:

en:
  js:
    discourse_automation:
      scriptables:
        post_created_edited:
          fields:
            restricted_category:
              label: Categoria
              description: Opzionale, consente di limitare l'esecuzione del trigger a questa categoria

Nota che la descrizione è opzionale qui.


Questo documento è controllato dalla versione - suggerisci modifiche su github.

7 Mi Piace

Quando ho visto che si trattava di un nuovo argomento mi sono emozionato: pensavo fossero stati condivisi maggiori dettagli! :laughing:

Come qualcuno che non programma in Ruby, ma è molto interessato all’automazione del flusso di lavoro, speravo di poter capire un po’ di più con un esempio…

:thinking:

Immagino che dovrò iniziare da Developing Discourse Plugins - Part 1 - Create a basic plugin:sweat_smile:

8 Mi Piace

Ho essenzialmente tagliato questa sezione dall’argomento del plugin in modo che non sembrasse che dovessi conoscerla per utilizzare quelle esistenti. :slight_smile:

Concordo sul fatto che sarebbe fantastico se questo fosse un po’ più passo dopo passo. Ho inviato un segnale per l’assistenza della community qui per vedere se qualcuno ha esperienza in merito: :crossed_fingers:

5 Mi Piace

Un esempio di “hello world” sarebbe fantastico.
Dove dovrebbero essere archiviati gli script? Vorrei sperimentare un po’.

4 Mi Piace

Penso che tu possa scrivere script personalizzati usando Chat GPT insieme a questo plugin.

Probabilmente il posto migliore dove iniziare a cercare è nello script di automazione aggiunto al plugin Data Explorer: discourse-data-explorer/plugin.rb at main · discourse/discourse-data-explorer · GitHub. Vale la pena dare un’occhiata anche agli script e ai trigger esistenti del plugin Automation: https://github.com/discourse/discourse-automation/tree/main/lib/discourse_automation

Dato che non ci sono molte informazioni su Meta riguardo all’aggiunta di automazioni personalizzate, ecco un file plugin.rb di esempio che aggiunge uno script per aggiornare la preferenza dell’email di riepilogo dell’attività di un utente. Lo script può essere attivato dai trigger “user_added_to_group” o “user_removed_from_group” del plugin Automation.

# 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

Il codice completo del plugin è qui: GitHub - scossar/automation-script-example: An example of how to add a custom script to the Discourse Automation plugin..

:warning: per favore, non utilizzare questo codice così com’è su un sito di produzione. Non avevo esaminato il codice di Automation prima di stasera. Se riceverò feedback su potenziali problemi con il codice, aggiornerò questo post e il repository GitHub.

Modifica: la mia preoccupazione era come gestire al meglio il caso di più script di automazione attivati dai trigger ‘user_added_to_group’ o ‘user_removed_from_group’. La versione iniziale del plugin controllava:

fields.has_key?("email_digests")

ma questo sembrava un po’ inaffidabile. E se fosse stato aggiunto un altro script che avesse anche una chiave email_digests?

Il codice aggiornato passa il parametro automation al blocco di codice e controlla:

automation.script == "user_update_summary_email_options"

Ciò dovrebbe garantire che lo script non venga eseguito per l’automazione sbagliata.

… pensandoci ancora un po’, è improbabile che lo script venga attivato da un’automazione per cui non è stato configurato :slight_smile:

7 Mi Piace

Vorrei saperlo anch’io: una volta creato un repository come quello di @simon, come viene accessibile dal plugin?

Dobbiamo fare un fork dell’intero plugin e inserirlo insieme a quelli esistenti in https://github.com/discourse/discourse-automation/tree/main/lib/discourse_automation/scripts? O esiste un modo più elegante?

1 Mi Piace

Devi installarlo come qualsiasi altro plugin di Discourse: Install Plugins in Discourse. Quindi installeresti il plugin Automation e il tuo plugin che aggiunge gli script personalizzati. Il motivo per cui funziona è dovuto ai metodi definiti qui: https://github.com/discourse/discourse-automation/blob/main/lib/plugin/instance.rb. Nell’esempio di codice che ho pubblicato sopra, vedrai che lo script personalizzato viene aggiunto con una chiamata a add_automation_scriptable.

Nota: non installare l’automazione di esempio dal mio repository GitHub, prendila solo come esempio di come estendere il plugin Automation. (Ho dimenticato di averci collegato qui e l’ho aggiornato in modo che funzioni solo con la mia versione forkata del plugin Discourse Automation. Il codice a cui ho collegato qui è ancora valido: Create custom Automations - #6 by simon. Aggiornerò l’esempio di script di automazione il prima possibile in modo che funzioni senza le modifiche che ho apportato alla mia versione forkata del plugin Automation.)

La mia preoccupazione era infondata. Questa condizione non è necessaria:

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

Aggiornerò presto l’esempio.

4 Mi Piace

Corretto nel ritenere che le automazioni personalizzate richiedano un’installazione self-hosted (o comunque un accesso diretto al backend al filesystem in cui è installato Discourse)?

2 Mi Piace

Sì, tuttavia siamo molto aperti a integrare nuovi script di automazione nella build della community, cosa stai pensando di costruire?

6 Mi Piace

In particolare, stiamo cercando un modo per sostituire una stringa specifica nei post (non ci interessa molto la sintassi esatta, ma qualcosa come il testo normale @ref `Random.rand!` ) con un link formattato come Random.rand!. Cercare l’URL esatto è un processo complicato con decine di migliaia di possibili destinazioni che è completamente irrealizzabile con le regex (come fa Auto linkify words/watched words) e molto più facile con un ambiente simile a un plugin completo di Turing… quindi ero curioso di sapere se le automazioni potessero farlo.

Quindi stavo cercando un’azione post-modifica, un po’ simile a ciò che fa l’utente @system quando si cita l’intero post precedente (vedi qui). Sarebbe uno script “Modifica post” che si attiverebbe su “Post creato” (o forse dopo la cottura del post)… ma suppongo che il framework di automazione non consentirebbe un’azione “post-modifica” così generale. Penso che sarebbe necessaria un’automazione personalizzata abbastanza specifica per collegare alla documentazione di Julia, il che certamente non ha senso in una community build.

Potrei essere fuori strada qui con le automazioni personalizzate; stavo solo esplorando ciò che è possibile. Naturalmente, essendo un forum per appassionati di linguaggi di programmazione, utenti intrepidi stanno già pensando a bot di programmazione che potrebbero utilizzare l’API di Discourse per fare questo.

1 Mi Piace

Non sono sicuro che l’automazione sia ciò che stai cercando qui, perché qualcosa che sembra critico è l’esperienza dell’“utente finale”. Con l’automazione questo verrebbe sostituito solo a posteriori.

Pensando a questo tipo di problema, probabilmente consiglierei di optare per un plugin personalizzato o un componente del tema.
Un componente del tema potrebbe funzionare così:

  1. L’utente digita: ^Rand
  2. Viene effettuata una chiamata HTTP a un servizio backend che ospiti, che elenca tutte le opzioni con URL
  3. L’utente seleziona quella che desidera e preme Invio
  4. Il Markdown viene sostituito con [Random.rand!](https://docs.julialang.org/en/v1/stdlib/Random/#Random.rand!)

Un plugin che modifica la pipeline di Markdown potrebbe funzionare in modo simile a onebox e semplicemente creare collegamenti automatici mentre digiti, lasciando la sintassi originale. ad esempio: ^Random.rand
Capisco la tua obiezione su linkify non sia ideale, la scoperta è difficile, inoltre potresti dover ospitare un sito web in modo da normalizzarlo in lookup.docs.julialang.org?q=Random.rand!

Certamente un problema molto interessante. Penso che l’UX di un componente del tema possa essere ragionevole qui.

2 Mi Piace

È fantastico, grazie per i pensieri e i suggerimenti qui! Affronterò questo argomento separatamente se e quando avrò altre domande (o risposte :)).

2 Mi Piace

Penso che un plugin personalizzato che si attiva al cambio di post sia quello che vuoi creare. Sospetto che per il tuo caso d’uso, che ha un trigger semplice, sarebbe più facile scrivere un plugin piuttosto che usare il plugin di automazione.

1 Mi Piace

@McUles e @nathank avete trovato le informazioni che cercavate?

Per far funzionare l’automazione personalizzata, ho dovuto modificare i seguenti file:

Creato lo script di automazione personalizzato

Aggiornato: server.en.yml

aggiunto il nome dell’automazione personalizzata; titolo; e descrizione nella sezione scriptables del file yml.

Aggiornato: client.en.yml

aggiunto il nome dell’automazione personalizzata in scriptables; aggiunto la parola chiave ‘field’; all’interno della parola chiave field aggiungere ‘field_name’ seguito da ‘label’ e ‘description’

Aggiornato: scripts.rb

aggiunto il nome dell’automazione personalizzata nell’elenco degli script. Esempio: FILE_NAME = “file_name”

Aggiornato: plugin.rb

all’interno di ‘after_initialize do’, aggiungere il percorso allo script di automazione personalizzato. Esempio: ‘lib/discourse_automation/scripts/file_name’

Non capisco bene cosa hai scritto: si tratta di modifiche al plugin Automations o di componenti importanti di un plugin “sorella” che contiene l’automazione personalizzata?

Sarebbe fantastico se questo fosse unito a l’OP

2 Mi Piace

È questo. Non conoscevo davvero la risposta alla tua domanda, quindi ecco come ho trovato una risposta e anche la risposta a “C’è un esempio, da qualche parte, che potrei vedere?”

Innanzitutto, ottieni questo: GitHub - discourse/all-the-plugins

Quindi esegui grep per qualcosa, come “add_automation_scriptable”, e poi puoi scoprire cosa lo sta usando.

 (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

Quindi forse dai un’occhiata a discourse-assign o data-explorer

2 Mi Piace