Thème-Composant v Plugin : quelle est la différence

Quelqu’un peut-il clarifier la différence entre ces trois concepts de Discourse : theme-component, plugin et pluginAPI ?

Surtout entre theme-component et plugin. Si je souhaite personnaliser mon forum, comment savoir lequel développer ?

(désolé si j’ai manqué cette distinction dans le guide d’introduction, mais je ne la vois pas là-bas)

Je ne suis pas débutant avec Discourse, mais je ne suis pas non plus un expert.

  1. Un composant de thème utilise HTML, CSS et JavaScript pour améliorer un thème de base.
    Je précise « thème de base » car il est généralement appelé simplement « thème », et parfois les gens ne font pas la distinction, ce qui oblige à l’inférer. Un thème et/ou un composant de thème peut être installé par un administrateur sans mettre le site hors ligne, et si vous êtes un client de Discourse, vous pouvez également les ajouter. (liste) Voir aussi : Guide pour débutant sur l’utilisation des thèmes Discourse

  2. Un plugin utilise Ruby et peut faire à peu près tout ce qui est possible. Si vous êtes client de Discourse, vous avez un ensemble limité de plugins autorisés à être activés. En revanche, si vous hébergez vous-même le site, vous pouvez en ajouter autant que vous le souhaitez, mais soyez averti : je vois de nombreux posts indiquant que des plugins personnalisés font planter le site lors d’une mise à jour. Ces plugins n’exigent pas non plus de redémarrage lors de l’activation ; je soupçonne qu’un redémarrage pourrait être nécessaire lors de la première installation. D’autres pourront préciser, car la seule expérience que j’ai avec les plugins est de les activer depuis les menus d’administration. (liste) Voir aussi : Guide pour débutant sur la création de plugins Discourse - Partie 1

  3. Je n’ai pas développé de plugin, donc je suppose que vous faites référence à Discourse API Ruby Gem. Voir : Use the Discourse API ruby gem

  4. Il existe également l’API qui utilise des webhooks et est généralement employée avec curl ou un autre langage de programmation. C’est pratique car cela vous libère de l’obligation d’utiliser Ruby.

  5. Bien que je n’aie pas non plus expérimenté cela, vous pourriez programmer au niveau de la base de données PostgreSQL, mais je ne le recommanderais pas sauf si vous êtes très compétent et très confiant dans vos capacités.

J’espère que cela vous aidera.


MODIFICATION

Bonus si vous voulez vous lancer complètement en tant que développeur Discourse

Voir : Comment commencer à créer des choses pour Discourse si vous êtes débutant (comme moi)

Pour compléter la réponse de @EricGT, qui explique déjà très bien les choses :

  • Un thème ou un composant de thème est essentiellement un moyen de modifier n’importe quelle partie de l’application front-end EmberJS de Discourse. Cela peut aller d’une simple personnalisation du HTML ou du CSS à l’ajout de fonctionnalités complexes. Les thèmes sont beaucoup plus élégants en cas de problème : si quelque chose ne fonctionne pas, l’ensemble de votre site ne sera pas nécessairement mis hors ligne.
  • Un plugin affecte principalement l’application côté serveur Rails, mais inclut également toute la puissance d’un thème et la capacité d’agir sur l’application EmberJS, bien que cela soit beaucoup plus complexe. Les échecs de plugins ont tendance à être moins élégants ; si vous pouvez réaliser quelque chose via un thème, commencez par là. Cependant, un plugin est requis si vous avez besoin d’une route personnalisée ou de stocker des données.
  • Le pluginAPI est une API côté client que les thèmes ou composants de thème peuvent utiliser pour modifier plus facilement des parties spécifiques du client Discourse.

Le meilleur point de départ pour personnaliser votre site est un thème. Voici quelques ressources :

Guide du concepteur pour les thèmes Discourse
Guide du développeur pour les thèmes Discourse
Guide pour débutants sur l’utilisation de Theme Creator et de l’interface CLI des thèmes pour commencer à créer un thème Discourse

Merci, les gars. C’est utile. Je pense que la distinction clé que je saisis est la suivante :
– si vous voulez modifier quelque chose qui ne concerne que le front-end, créez un thème.
– si vous voulez modifier quelque chose qui nécessite une interaction avec le back-end, créez un plugin.

Est-ce que cela vous semble correct ?

Voici un exemple concret que j’ai en tête et que j’essaie de démêler : je veux permettre à tout modérateur de catégorie d’épingler des sujets dans cette catégorie. Les grandes lignes, je pense, sont :

  1. Vérifier si l’utilisateur est modérateur de la catégorie (cela nécessite d’accéder au back-end pour obtenir des informations sur l’utilisateur et la catégorie).

  2. Si l’utilisateur est modérateur, afficher le bouton d’épinglage (c’est du front-end).

  3. Si l’utilisateur clique sur le bouton d’épinglage, déplacer le sujet en haut (je ne suis pas tout à fait sûr de l’endroit où cela se passe dans le code de Discourse — peut-être à la fois au niveau du front-end et du back-end ?).

Ici, comme je dois communiquer avec le back-end (probablement dans le point 1, peut-être aussi dans le point 3 ?), je devrais utiliser un plugin. Est-ce que cela vous semble correct ?

La partie superficielle peut l’être, mais cela impliquera le backend car cela concerne les droits et la sécurité. Vous ne pouvez pas laisser l’interface utilisateur décider des privilèges dont dispose une personne.

Voulez-vous dire que répondre programmatiquement à la question « Cet utilisateur est-il modérateur de cette catégorie ? » implique plusieurs fichiers répartis entre le frontend et le backend ? Hum…

Dans un thème, vous devriez pouvoir savoir si un utilisateur est modérateur et également effectuer des appels backend si l’API de Discourse expose un point de terminaison accessible depuis le front-end (après tout, le thème peut utiliser JavaScript), donc vous n’avez probablement pas besoin d’un plugin pour [1]. Vous n’en auriez besoin que si vous devez modifier le comportement du backend ou exposer une API.

Mais vous en aurez probablement besoin pour [3], car, comme l’a dit @merefield, cela concerne les droits et la sécurité (si le backend empêche un modérateur d’épingler un sujet, vous devrez le modifier pour commencer à l’autoriser).

Comme je l’ai dit plus haut, cela ne nécessitera probablement pas de plugin juste pour effectuer cette validation (pour savoir si l’utilisateur est modérateur ou non), mais cela en nécessitera probablement à cause de l’action qui consiste à lui permettre d’épingler la catégorie. Si Discourse propose une option permettant à tout modérateur d’épingler un sujet (je ne sais pas si c’est le cas), alors vous n’auriez pas besoin d’un plugin (mais vous n’auriez probablement pas besoin d’un thème non plus, sauf si le bouton d’épinglage n’est pas affiché aux modérateurs, et que vous utilisez un thème uniquement pour l’afficher aux modérateurs et appeler le point de terminaison en JavaScript lorsqu’il clique sur le bouton d’épinglage).

C’est très utile concernant les thèmes vs les plugins, ainsi que pour l’exemple spécifique que j’ai mentionné. Merci.

Jusqu’à présent, ma démarche pour introduire des modifications consistait à trier les spécificités du code de Discourse (où cet objet est-il défini, quel élément contrôle ce modèle, où se trouve la logique qui gère cette action, etc.). Mais cela a été lourd et lent.

Je pense qu’une voie probablement plus efficace serait de me concentrer sur l’API. Ainsi, je n’aurais pas besoin de trier tous les détails du code mature de Discourse, et je pourrais me concentrer sur la création d’un thème plutôt que d’un plugin — ou peut-être simplement apporter des modifications via le tableau de bord « Personnalisation ».

Fondamentalement, comprendre comment fonctionne l’API semble beaucoup plus gérable que de démêler la base de code de Discourse.

Pour rester sur l’exemple que j’ai mentionné : si l’utilisateur est modérateur d’une catégorie, permettre à cet utilisateur d’épingler des sujets sur la page de la catégorie.

Pourrais-je le faire sans plugin ? Laissez-moi essayer de le schématiser :

1. L’utilisateur est-il modérateur d’une catégorie ?

Je ne vois actuellement rien dans l’API qui indiquerait si un utilisateur est modérateur d’une catégorie. Je m’attendrais à ce que cette information figure dans un appel GET pour récupérer une catégorie, mais je n’y vois pas un tel appel. Ou peut-être dans l’appel GET pour récupérer un utilisateur, mais là non plus, je ne vois pas de liste des catégories dont l’utilisateur est modérateur.

Pourrais-je ajouter ces éléments ?

Ou, alternativement, je pourrais créer un champ personnalisé sur l’utilisateur ou la catégorie pour identifier le statut de modérateur, puis effectuer un appel API vers ce champ personnalisé lors du chargement de la page de la catégorie.

2. Si l’utilisateur est modérateur, afficher le bouton d’épinglage.

Si je peux répondre à la question (1), alors je suppose que je peux simplement ajouter ce bouton avec du JavaScript et du CSS côté client, en l’affichant uniquement si l’utilisateur est modérateur.

3. L’utilisateur (qui est modérateur) clique sur le bouton, ce qui épinglé le sujet.

Dans l’API, les sujets semblent bien avoir un attribut « épinglé » (un booléen). Je suppose que cela correspond à leur statut épinglé dans leur catégorie, car il semble que chaque sujet n’appartienne qu’à une seule catégorie.

Donc, ici, lorsque le modérateur clique sur le bouton « Épingler », je pourrais probablement mettre à jour le statut « épinglé » du sujet à True. Si cela ne fonctionne pas, les champs personnalisés pourraient également être une solution ici (bien que je ne voie pas comment ajouter des champs personnalisés à un sujet).


Avec cela, ou quelque chose de similaire, il semble que je puisse accomplir cette tâche via l’API, alors que si je le faisais avec un plugin, cela nécessiterait beaucoup de temps à trier les fichiers de la base de code de Discourse.

Est-ce que cela vous semble correct ?

Avez-vous trouvé : Comment faire de l’ingénierie inverse de l’API Discourse

Je l’ai déjà vu, mais je regarde de plus près maintenant. Merci pour le rappel.

J’essaie de trier :
–où dans l’API je pourrais obtenir des informations sur qui est le modérateur d’une catégorie donnée (je ne le vois pas dans les informations renvoyées sur les catégories ou les utilisateurs – il doit évidemment se trouver quelque part)

–peut-on utiliser l’API pour ajouter de nouveaux champs à une entrée ? Par exemple, pourrais-je utiliser l’API pour ajouter un champ personnalisé à un sujet ? (Je ne pense pas que les sujets soient généralement accompagnés de champs personnalisés)

Je regarderais dans la base de données.

La base de données contient une table posts et vous pourriez y ajouter un champ, mais cela vous ferait sortir du cadre officiel et vous ne seriez plus pris en charge.

Merci — tout cela est très utile.

De quelle base de données parlez-vous ?


Pour confirmer, mon idée ici serait d’utiliser l’API pour effectuer certaines de ces tâches qui nécessiteraient autrement un plugin. Ainsi, par exemple, mon site lui-même ferait un appel à l’API pour déterminer si un utilisateur (ou un groupe, selon le cas) est modérateur d’une catégorie. Cet appel serait codé en dur dans le panneau de personnalisation, ou dans un thème ou un plugin.

Pour effectuer ce type d’appels, je devrai être authentifié, ce qui, à ma connaissance, nécessite la création d’une clé API depuis le panneau d’administration. Le processus de création de clé API dans le panneau d’administration requiert une « Description » et un « Niveau d’utilisateur » — je ne suis pas sûr de savoir comment cela s’applique ici. Dans mon cas, je souhaite que mon application effectue l’appel API. Il n’est pas effectué au nom d’un utilisateur particulier. Il est donc possible que j’aie mal compris.

Savez-vous quel niveau d’utilisateur est approprié pour ce type d’appel API, ou ce que je devrais saisir dans ce champ ?

Lorsque Discourse est installé conformément à la procédure standard, il s’exécute dans un conteneur Docker. La persistance des données est assurée par une base de données PostgreSQL.

Voir : Extension Data Explorer

Si vous disposez des droits d’administration, vous pouvez récupérer l’une des sauvegardes ; il s’agit d’un fichier SQL compressé dans une archive tar.gz. Vous pouvez utiliser ce SQL pour recharger les données dans une autre base de données PostgreSQL et aller encore plus loin.

Je n’ai jamais créé de thème ou de plugin, ni utilisé l’API depuis Ruby ou avec un autre langage de programmation. J’ai toutefois un accès administrateur sur un site de production, ce qui m’a permis d’accéder à la sauvegarde. Je programme également en Prolog, ce qui me permet d’accéder aux données et de les utiliser pour analyser les publications à l’aide de DCG. Si vous connaissez la BNF, les DCG ne sont pas très éloignées, mais il faut comprendre l’unification syntaxique et la chaînage à rebours pour les parties les plus sophistiquées.

Merci. Je traiterai cet élément séparément.

Non, car les droits d’accès pour chaque action sont appliqués par le serveur.

Vous devrez examiner la surcharge des fonctions dans lib/guardian/ et lib/guardian.rb pour permettre aux modérateurs spécifiques d’une catégorie d’épingler des sujets, puis utiliser les mêmes mécanismes que le JavaScript du thème (sauf dans le plugin) pour modifier l’interface utilisateur afin que l’option « épingler le sujet » apparaisse au moment opportun.

Ahh, cela a du sens. Donc, il semble que l’utilisation de l’API pour cela ne fonctionnerait pas (votre réponse m’évite potentiellement beaucoup de temps).

Je pourrais essayer une approche légèrement différente du comportement de fixation habituel. Au lieu de cela, je donnerais à certains utilisateurs des droits de « propriété » sur une catégorie, ce qui leur permettrait de mettre en avant certains sujets dans cette catégorie.

Voici comment je procéderais avec l’API JSON : depuis mon tableau de bord de personnalisation, j’attribuerais un champ personnalisé aux utilisateurs concernés (par exemple, category-name: owner) ou quelque chose de similaire. Ensuite, lorsque la page de la catégorie se charge, j’appellerais l’API pour évaluer l’utilisateur ; s’il possède ce champ personnalisé, le bouton « mettre en avant » s’afficherait. Si l’utilisateur clique sur ce bouton pour un sujet, ce dernier serait assigné au groupe de mise en avant de la catégorie (également un champ personnalisé pour cette catégorie).

Ceci est une ébauche grossière — pas besoin de confirmer chaque étape individuellement (de toute façon, je devrai peut-être ajuster cela lorsque je coderai). Mais ma question pour l’instant : cette façon d’utiliser l’API JSON, en particulier pour créer et récupérer des champs personnalisés depuis mon application Discourse, est-elle fonctionnelle ?

Cher @JQ331,

Mais ma question pour l’instant : cette façon d’utiliser l’API JSON – en particulier pour créer et récupérer des champs personnalisés depuis mon application Discourse – peut-elle fonctionner ?

Il y a eu d’excellentes réponses à vos questions concernant la différence entre un composant de thème, un plugin et l’API Discourse, et je doute de pouvoir ajouter beaucoup de valeur ; mais voici une autre façon de voir les choses, que vous trouverez peut-être utile :

Les composants de thème et les plugins utilisent tous deux des crochets de modèle (plugin hooks) pour évaluer du code dans le cycle de vie d’Ember.js (ce qu’il est bon de connaître, d’ailleurs).

De plus, l’API Discourse est également accessible aux composants de thème et aux plugins.

L’API expose essentiellement un sous-ensemble, mais pas la totalité, des données contenues dans la base de données PostgreSQL sous-jacente.

Lorsque vous développez une fonctionnalité, il serait judicieux de commencer par l’API et de déterminer si les données dont vous avez besoin sont disponibles via celle-ci.

Si certaines données dont vous avez besoin ne figurent pas dans l’API, vous devez examiner la base de données PostgreSQL pour vérifier si ces données y existent.

Si les données supplémentaires dont vous avez besoin existent dans la base de données, vous devez alors les exposer, ce qui signifie généralement ajouter des données au sérialiseur de données de Discourse et étendre l’API.

Le sérialiseur de données est simplement le processus de création de l’objet JSON exposé par l’API. Il peut être étendu pour ajouter davantage d’objets.

Pour examiner la base de données PostgreSQL, je suppose qu’il existe de nombreuses façons de le faire (par exemple en lisant le code sur GitHub), mais je le fais en me connectant directement à la base de données, en examinant les tables et en étudiant leur structure ainsi que les champs présents dans chaque table (en utilisant du SQL de base).

En résumé (et pour rester concis), nous devons utiliser à la fois l’API et les tables de la base de données comme références. En général, lorsque vous souhaitez « étendre l’API » en ajoutant des données non fournies par défaut (OOTB), nous créons un plugin pour cela ; ces données seront alors exposées via l’API étendue, et nous pourrons les utiliser à la fois dans les composants de thème et les plugins.

J’espère que cette perspective vous a été utile, ne serait-ce que légèrement.

Explication remarquable. Merci beaucoup pour cette réponse. Cela met en lumière quelque chose que je n’avais pas réalisé auparavant :

Au vu de ces réponses, je comprends que (comme vous le dites) interagir avec l’API JSON peut être un bon point de départ dans de nombreux cas, ce qui pourrait éviter la nécessité de coder un nouveau thème ou plugin. Cependant, certains types de données ne sont pas exposés par l’API. Pour accéder à ces types de données et les exploiter, vous devrez utiliser le sérialiseur de données de Discourse pour les exposer ; et pour effectuer cette sérialisation, vous aurez besoin d’un plugin.

Il semble qu’un bon exemple de données non disponibles via l’API soit les propriétaires d’un groupe. Je le dis parce que (en ce qui concerne l’accès aux propriétaires de groupe) :

Un point de confusion : dans l’API Discourse, lorsque vous récupérez un groupe spécifique, l’un des attributs retournés est répertorié comme "is_group_owner": true, donc je ne suis pas sûr de ce que cela signifie…

Mais il semble que pour obtenir le propriétaire du groupe, je devrais sérialiser l’attribut du propriétaire du groupe.


Y a-t-il de bons exemples d’utilisation du sérialiseur Discourse ? J’ai vu celui-ci, mais étant donné son importance, un tutoriel avec quelques exemples serait extrêmement utile.

L’exemple le plus proche que j’ai est :

Cela est utile, mais pas tout à fait correct (du moins, cela me donne des erreurs indiquant “plugin invalide”). Je ne sais pas comment l’ajuster afin que sur la page d’index des groupes, je puisse accéder aux propriétaires de chaque groupe.

Je ne sais pas exactement comment vous avez essayé d’utiliser l’exemple de plugin, mais cela fonctionnait correctement sur une instance de développement lorsque j’ai utilisé la structure de fichiers et le code que j’ai publiés dans votre autre sujet.

is_group_owner est utilisé dans le contexte de l’utilisateur actuel qui consulte les groupes.

Vous pouvez obtenir les informations sur le propriétaire via un appel AJAX, mais à ma connaissance, cela devrait être fait pour chaque groupe individuel de la liste, ce qui pourrait entraîner un grand nombre de requêtes. Je pense que globalement, il serait difficile de faire fonctionner cette méthode. En tout cas, si vous souhaitez expérimenter, vous pouvez essayer l’extrait de code de preuve de concept suivant dans un thème. Remplacez simplement GROUP_NAME par le nom de l’un de vos groupes. (EDIT : Voici également un composant de thème avec un exemple de la manière dont un appel AJAX peut être utilisé : 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>

Cela étant dit, utiliser un plugin serait définitivement la solution la plus simple et la plus propre.