Tema-Componente vs Plugin: qual è la differenza

Qualcuno può chiarire la differenza tra questi tre concetti di Discourse: theme-component, plugin e pluginAPI?

In particolare tra theme-component e plugin. Se voglio personalizzare il mio forum, come faccio a sapere quale dei due costruire?

(scusa se ho perso questa distinzione nella intro, ma non la vedo menzionata lì)

Non sono un principiante con Discourse, ma non sono nemmeno un esperto.

  1. Un componente del tema utilizza HTML, CSS e JavaScript per migliorare un tema di base.
    Faccio notare “tema di base” perché spesso viene chiamato semplicemente “tema” e talvolta le persone non specificano la differenza, quindi devi dedurla. Un tema e/o un componente del tema può essere installato da un amministratore senza interrompere il sito e, se sei un cliente di Discourse, puoi anche aggiungerli. (lista) Vedi anche: Guida per principianti all’uso dei temi Discourse

  2. Un plugin utilizza Ruby e può fare praticamente tutto ciò che è possibile. Se sei un cliente di Discourse, hai un set limitato di plugin che possono essere attivati; tuttavia, se ospiti il sito in autonomia, puoi aggiungerne quanti ne vuoi, ma ti avverto che vedo molti post in cui plugin personalizzati rompono il sito durante un aggiornamento. Anche questi non richiedono un riavvio quando vengono attivati; sospetto che un riavvio potrebbe essere necessario alla prima installazione. Altri possono approfondire, poiché la mia unica esperienza con i plugin è stata attivarli dai menu di amministrazione. (lista) Vedi anche: Guida per principianti alla creazione di plugin Discourse - Parte 1

  3. Non ho sviluppato un plugin, quindi ipotizzo che tu ti stia riferendo al Discourse API Ruby Gem. Vedi: Use the Discourse API ruby gem

  4. Esiste anche l’API, che sono webhook e vengono tipicamente utilizzati con curl o un altro linguaggio di programmazione. Questo è utile perché ti libera dall’obbligo di utilizzare Ruby.

  5. Anche se non ho mai sperimentato questo aspetto, potresti programmare a livello del database PostgreSQL, ma non lo consiglierei a meno che tu non sia molto esperto e molto sicuro delle tue capacità.

Spero sia utile.


MODIFICA

Bonus round se vuoi lanciarti completamente come sviluppatore Discourse

Vedi: Come iniziare a creare cose per Discourse se sei un principiante (come me)

Per aggiungere alla risposta di @EricGT, che spiega già molto bene quanto segue:

  • Un tema o un componente di tema è essenzialmente un modo per modificare qualsiasi parte dell’app front-end EmberJS di Discourse. Può essere semplice come personalizzare HTML o CSS, o complesso come aggiungere nuove funzionalità. I temi sono molto più eleganti in caso di errori: significa che l’intero sito non andrà necessariamente in tilt se qualcosa non funziona.
  • Un plugin influisce principalmente sull’app lato server Rails, ma include anche tutta la potenza di un tema e la capacità di modificare l’app EmberJS, sebbene sia molto più complesso. Gli errori nei plugin tendono a essere meno eleganti, quindi se puoi realizzare qualcosa con un tema, inizia da lì. Tuttavia, un plugin è necessario se hai bisogno di una route personalizzata o di memorizzare dati.
  • La pluginAPI è un’API lato client che i temi o i componenti di tema possono utilizzare per modificare più facilmente parti specifiche del client Discourse.

Il punto di partenza migliore per personalizzare il tuo sito è un tema. Ecco alcune risorse:

Guida per i designer ai temi di Discourse
Guida per gli sviluppatori ai temi di Discourse
Guida per principianti all’uso di Theme Creator e Theme CLI per iniziare a creare un tema di Discourse

Grazie, ragazzi. È utile. Penso che la distinzione chiave che sto cogliendo sia:
– se vuoi modificare qualcosa che riguarda solo il frontend, crea un tema.
– se vuoi modificare qualcosa che richiede interazione con il backend, crea un plugin.

Ha senso?

Ecco un esempio concreto che ho in mente e che sto cercando di chiarire: vorrei permettere a qualsiasi moderatore di una categoria di fissare (pin) gli argomenti in quella categoria. In linea di massima, credo che i passaggi siano:

  1. Verificare se l’utente è un moderatore della categoria (questo richiede di accedere al backend per ottenere informazioni sull’utente e sulla categoria)

  2. Se l’utente è moderatore, mostrare il pulsante per fissare l’argomento (questo è frontend)

  3. Se l’utente clicca sul pulsante per fissare l’argomento, spostarlo in cima (non sono sicuro di dove ciò avvenga nel codice di Discourse – forse anche frontend e backend?)

Qui, poiché devo interagire con il backend (probabilmente nel punto (1), forse anche nel punto (3)?), dovrei usare un plugin. Ha senso?

La parte superficiale potrebbe esserlo, ma coinvolgerà il backend perché riguarda diritti e sicurezza. Non puoi lasciare al frontend la discrezionalità su quali privilegi abbia un utente.

Vuoi dire che rispondere programmaticamente a “Questo utente è un moderatore di questa categoria” coinvolgerà più file tra frontend e backend? Hmm…

In un tema, dovresti essere in grado di verificare se un utente è moderatore e anche effettuare chiamate al backend se l’API di Discourse espone un endpoint che puoi chiamare dal front-end (dopotutto il tema può utilizzare JavaScript), quindi probabilmente non hai bisogno di un plugin per [1]. Ne avresti bisogno solo se devi modificare il comportamento del backend o esporre un’API.

Ma probabilmente ne hai bisogno per [3], perché, come ha detto @merefield, riguarda diritti e sicurezza (se il backend impedisce a un moderatore di fissare un argomento, dovresti modificarlo per iniziare a consentirlo).

Come ho detto sopra, probabilmente non servirà un plugin solo per effettuare quella validazione (per sapere se l’utente è moderatore o meno), ma probabilmente ne servirà uno a causa dell’azione di consentirgli di fissare la categoria. Se Discourse ha un’opzione per permettere a qualsiasi moderatore di fissare un argomento (non so se ce l’ha), allora non avresti bisogno di un plugin (ma probabilmente non avresti bisogno nemmeno di un tema, a meno che il pulsante per fissare non sia visibile ai moderatori, e tu usi un tema solo per mostrarlo ai moderatori e chiamare l’endpoint in JavaScript quando clicca sul pulsante per fissare).

È molto utile per quanto riguarda temi e plugin, così come per l’esempio specifico che ho menzionato. Grazie.

Finora il mio approccio per apportare modifiche è stato analizzare i dettagli del codice di Discourse (dove è definito questo oggetto, cosa controlla questo template, dove si trova la logica che gestisce questa azione, ecc.). Ma questo processo è stato lento.

Penso che un percorso probabilmente più efficiente sarebbe concentrarsi sull’API. In questo modo, non devo analizzare tutti i dettagli del codice maturo di Discourse e posso anche concentrarmi sulla creazione di un tema invece di un plugin, oppure semplicemente apportare modifiche nella dashboard “personalizza”.

In sostanza, capire come funziona l’API sembra molto più gestibile rispetto a comprendere l’intera codebase di Discourse.

Per restare sull’esempio che ho menzionato: se un utente è un moderatore di una categoria, consenti a quell’utente di fissare gli argomenti nella pagina della categoria.

Potrei farlo senza un plugin? Lasciami provare a schizzarlo:

1. Un utente è un moderatore di una categoria?

Attualmente non vedo nulla nell’API che mi indichi se un utente è un moderatore di una categoria. Mi aspetterei di trovarlo in una chiamata GET per recuperare una categoria, ma non vedo una tale chiamata lì. O forse nella chiamata GET per recuperare un utente, ma lì non vedo un elenco delle categorie di cui l’utente è moderatore.

Potrei aggiungerle?

In alternativa, potrei creare un campo personalizzato (custom_field) sull’utente o sulla categoria per identificare il ruolo di moderatore, e poi fare una chiamata API a quel campo personalizzato quando viene caricata la pagina della categoria.

2. Se l’utente è un moderatore, mostra il pulsante per fissare.

Se riesco a rispondere alla domanda (1), allora presumo di poter semplicemente aggiungere questo pulsante con JavaScript e CSS lato frontend, mostrandolo solo se l’utente è un moderatore.

3. L’utente (che è moderatore) clicca sul pulsante e ciò fissa l’argomento

Sull’API, gli argomenti sembrano avere effettivamente una proprietà “pinned” (un booleano). Presumo che questo corrisponda al fatto che siano fissati nella loro categoria, dato che sembra che ogni argomento abbia una sola categoria.

Quindi, quando il moderatore preme il pulsante “fissa”, potrei probabilmente aggiornare lo stato “pinned” dell’argomento a True. Se questo non funzionasse, anche i campi personalizzati potrebbero essere una soluzione (anche se non vedo come aggiungere campi personalizzati a un argomento).


Quindi, con questo approccio o qualcosa di simile, sembra che potrei completare questo compito utilizzando l’API, mentre se lo facessi con un plugin richiederebbe molta analisi dei file della codebase di Discourse.

Ha senso?

Hai trovato: Come eseguire il reverse engineering dell’API di Discourse

L’ho già visto in passato, ma ora sto dando un’occhiata più attenta. Grazie per il promemoria.

Sto cercando di fare chiarezza su:
–dove nell’API posso ottenere le informazioni su chi è il moderatore di una determinata categoria (non le vedo tra i dati restituiti per le categorie o gli utenti–ovviamente devono essere da qualche parte)

–è possibile utilizzare l’API per aggiungere nuovi campi a una voce? Ad esempio, potrei usare l’API per aggiungere un campo personalizzato a un argomento? (non credo che gli argomenti abbiano in genere campi personalizzati)

Io guarderei nel database.

Il database ha una tabella posts e potresti aggiungere un campo lì, ma poi uscirai dal recinto e non riceverai alcun supporto.

Grazie, tutto questo è molto utile.

A quale database ti riferisci?


Per confermare, la mia idea qui sarebbe di utilizzare l’API per gestire alcune di queste operazioni che altrimenti richiederebbero un plugin. Quindi, ad esempio, il mio sito stesso effettuerebbe una chiamata all’API per determinare se un utente (o un gruppo, a seconda dei casi) è un moderatore di una categoria. La chiamata sarebbe hardcoded nel pannello di personalizzazione, o in un tema o plugin.

Per effettuare questo tipo di chiamate, dovrò essere autenticato, il che, credo, richiede la creazione di una chiave API dal pannello di amministrazione. Il processo di creazione dell’API nel pannello di amministrazione richiede una “Descrizione” e un “Livello utente”—non sono sicuro di come si applichi questo nel mio caso. Nel mio scenario, voglio che la mia app effettui la chiamata API. Non viene eseguita per un utente specifico. Quindi potrei aver frainteso.

Sai quale sia il Livello utente appropriato per quel tipo di chiamata API o cosa dovrei inserire lì?

Quando Discourse viene installato secondo le istruzioni standard, viene eseguito in un container Docker. La persistenza dei dati è garantita tramite un database PostgreSQL.

Vedi: Plugin Data Explorer

Se disponi dei privilegi di amministratore, puoi scaricare uno dei backup: si tratta di un file SQL compresso in un archivio tar.gz. Puoi utilizzare il file SQL per ricaricare i dati in un altro database PostgreSQL ed eseguire operazioni ancora più avanzate.

Non ho mai creato un tema o un plugin, né ho mai utilizzato l’API da Ruby o con qualsiasi altro linguaggio di programmazione. Ho però accesso amministrativo a un sito di produzione, ed è così che ho ottenuto il backup. Programmo anche in Prolog, che è il linguaggio che sto utilizzando per accedere ai dati e per analizzarli, sfruttando le DCG (grammatiche a clausole definite) per elaborare i post. Se conosci la BNF, le DCG non sono molto diverse, ma per le parti più complesse è necessario comprendere l’unificazione sintattica e la catena di deduzione all’indietro.

Grazie. Affronterò questo punto separatamente.

No, poiché i diritti di accesso per ogni azione sono imposti dal server.

Dovresti esaminare l’override delle funzioni in lib/guardian/ e lib/guardian.rb per permettere ai moderatori specifici della categoria di fissare gli argomenti, quindi utilizzare gli stessi meccanismi del JavaScript del tema (ma all’interno di un plugin) per modificare l’interfaccia utente in modo che l’opzione “fissa argomento” appaia quando appropriato.

Ah, ha senso. Quindi sembra che l’uso dell’API per quello non funzionerebbe (la tua risposta mi fa risparmiare un sacco di tempo).

Potrei provare a farlo in modo leggermente diverso dal comportamento normale di fissaggio. Invece, darei a certi utenti i diritti di “proprietà” su una categoria, il che permetterebbe loro di evidenziare determinati argomenti in quella categoria.

Il modo in cui lo farei con l’API JSON sarebbe: dal mio pannello di personalizzazione, assegnare agli utenti pertinenti un campo personalizzato (come category-name: owner) o qualcosa di simile. E poi, quando viene caricata la pagina della categoria, chiamare l’API per valutare l’utente; se ha quel campo personalizzato, mostrare il pulsante “evidenzia”, e se l’utente preme il pulsante “evidenzia” per un argomento, assegnare quell’argomento al gruppo di evidenziazione della categoria (anche questo un campo personalizzato per quella categoria).

Questa è una bozza approssimativa: non c’è bisogno di confermare passo dopo passo questi passaggi (quando scriverò il codice potrei doverlo comunque aggiustare). Ma la mia domanda per ora è: questo modo di usare l’API JSON, specialmente per creare e recuperare campi personalizzati all’interno della mia app Discourse, può funzionare?

Caro @JQ331,

Ma la mia domanda per ora: questo modo di utilizzare l’API JSON – in particolare per creare e recuperare campi personalizzati all’interno della mia app Discourse – funziona?

Ci sono state delle ottime risposte alle tue domande sulle differenze tra un componente del tema, un plugin e l’API di Discourse, e dubito di poter aggiungere molto altro valore; ma ecco un altro modo di vedere la questione, che potrebbe esserti utile o meno:

Sia i componenti del tema che i plugin utilizzano gli hook dei template (plugin hooks) per eseguire codice nel ciclo di vita di Ember.js (cosa che è utile conoscere, a proposito).

Inoltre, l’API di Discourse è disponibile anche per i componenti del tema e i plugin.

L’API espone fondamentalmente un sottoinsieme, ma non tutto, dei dati presenti nel database PostgreSQL sottostante.

Quando sviluppi funzionalità, sarebbe una buona idea iniziare con l’API e verificare se i dati di cui hai bisogno sono disponibili tramite essa.

Se ci sono alcuni dati di cui hai bisogno che non sono presenti nell’API, devi esaminare il database PostgreSQL per vedere se tali dati esistono nel DB.

Se i dati aggiuntivi di cui hai bisogno esistono nel DB, allora devi esporre quei dati; in generale, questo significa aggiungere dati al serializzatore dei dati di Discourse ed estendere l’API.

Il serializzatore dei dati è semplicemente il processo di creazione dell’oggetto JSON che viene esposto dall’API. Questo può essere esteso per aggiungere più oggetti.

Per esaminare il database PostgreSQL, immagino ci siano molti modi per farlo (ad esempio leggendo il codice su GitHub), ma io lo faccio accedendo direttamente al DB ed esaminando le tabelle, studiandone la struttura e i campi presenti in ciascuna (usando SQL di base).

Quindi, per riassumere (e mantenere il tutto breve), abbiamo bisogno di avere sia l’API che le tabelle del DB come riferimenti; in generale, quando vuoi “estendere l’API” aggiungendo dati non forniti dall’API OOTB (out of the box), creiamo un plugin per quello; e poi quei dati verranno esposti insieme all’API (estesa), così potremo utilizzarli sia nei componenti del tema che nei plugin.

Spero che questa prospettiva sia stata utile o di aiuto in qualche piccolo modo.

Spiegazione eccezionale. Grazie mille per questa risposta. Mette in luce qualcosa che non avevo realizzato prima:

Da queste risposte capisco che (come dici tu) interagire con l’API JSON può essere un buon punto di partenza in molti casi, che potrebbe evitare la necessità di sviluppare un nuovo tema o plugin. Tuttavia, esistono alcuni tipi di dati che non sono esposti dall’API. Per accedere a questi tipi di dati e utilizzarli, dovresti usare il serializzatore dei dati di Discourse per esporli; e per effettuare questa serializzazione, devi utilizzare un plugin.

Sembra che un buon esempio di dati non disponibili tramite l’API siano i proprietari di un gruppo. Lo dico perché (riguardo all’accesso ai proprietari del gruppo):

Un punto di confusione: nell’API di Discourse, quando ottieni un gruppo specifico, una delle caratteristiche restituite è indicata come "is_group_owner": true, quindi non sono sicuro di cosa dovrebbe significare…

Ma sembra che per ottenere il proprietario del gruppo dovrei serializzare la caratteristica del proprietario del gruppo.


Ci sono buoni esempi sull’uso del serializzatore di Discourse? Ho visto questo, ma data la sua importanza, una guida pratica con alcuni esempi sarebbe estremamente utile.

L’esempio più vicino che ho è:

Questo è utile, ma non del tutto corretto (almeno mi restituisce errori che dicono “plugin non valido”). Non sono sicuro di come modificarlo in modo che nella pagina di indice dei gruppi possa accedere ai proprietari di ciascun gruppo.

Non sono sicuro di come tu abbia provato a utilizzare l’esempio del plugin, ma ho fatto funzionare tutto correttamente su un’istanza di sviluppo utilizzando la struttura dei file e il codice che ho pubblicato nel tuo altro argomento.

is_group_owner viene utilizzato nel contesto dell’utente corrente che visualizza i gruppi.

È possibile ottenere le informazioni sul proprietario tramite una chiamata AJAX, ma per quanto ne so, dovrebbe essere eseguita per ogni gruppo individuale nell’elenco, potenzialmente generando un gran numero di richieste. Penso che nel complesso sarebbe difficile far funzionare questo metodo. In ogni caso, se vuoi sperimentare, puoi provare il seguente frammento di codice di prova di concetto in un tema. Sostituisci semplicemente GROUP_NAME con il nome di uno dei tuoi gruppi. (MODIFICA: Ecco anche un componente del tema con un esempio di come può essere utilizzata una chiamata AJAX: discourse-featured-topics/common/head_tag.html at master · awesomerobot/discourse-featured-topics · GitHub)

<script type="text/discourse-plugin" version="0.8.40">
  const { ajax } = require("discourse/lib/ajax");
  ajax(`/groups/GROUP_NAME/members.json`).then(response => {
    console.log(response.owners.map(owner => owner.username))
  });
</script>

Detto questo, utilizzare un plugin sarebbe assolutamente la soluzione più semplice e pulita.